SearchResultContentSubNavigation.tsx 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. import React, { FC, useCallback } from 'react';
  2. import { pagePathUtils } from '@growi/core';
  3. import PagePathNav from '../PagePathNav';
  4. import { withUnstatedContainers } from '../UnstatedUtils';
  5. import AppContainer from '../../client/services/AppContainer';
  6. import TagLabels from '../Page/TagLabels';
  7. import { toastSuccess, toastError } from '../../client/util/apiNotification';
  8. import { apiPost } from '../../client/util/apiv1-client';
  9. import { useSWRTagsInfo } from '../../stores/page';
  10. import SubNavButtons from '../Navbar/SubNavButtons';
  11. type Props = {
  12. appContainer:AppContainer
  13. pageId: string,
  14. revisionId: string,
  15. path: string,
  16. isSignleLineMode?: boolean,
  17. isCompactMode?: boolean,
  18. }
  19. const SearchResultContentSubNavigation: FC<Props> = (props : Props) => {
  20. const {
  21. appContainer, pageId, revisionId, path, isCompactMode, isSignleLineMode,
  22. } = props;
  23. const { isTrashPage, isDeletablePage } = pagePathUtils;
  24. const { data: tagInfoData, error: tagInfoError, mutate: mutateTagInfo } = useSWRTagsInfo(pageId);
  25. const tagsUpdatedHandler = useCallback(async(newTags) => {
  26. try {
  27. await apiPost('/tags.update', { pageId, tags: newTags });
  28. toastSuccess('updated tags successfully');
  29. mutateTagInfo();
  30. }
  31. catch (err) {
  32. toastError(err, 'fail to update tags');
  33. }
  34. }, [pageId, mutateTagInfo]);
  35. if (tagInfoError != null || tagInfoData == null) {
  36. return <></>;
  37. }
  38. const isPageDeletable = isDeletablePage(path);
  39. const { isSharedUser } = appContainer;
  40. const isAbleToShowPageManagement = !(isTrashPage(path)) && !isSharedUser;
  41. return (
  42. <div className="position-sticky fixed-top shadow">
  43. <div className={`grw-subnav container-fluid d-flex align-items-start justify-content-between ${isCompactMode ? 'grw-subnav-compact d-print-none' : ''}`}>
  44. {/* Left side */}
  45. <div className="grw-path-nav-container">
  46. {!isSharedUser && !isCompactMode && (
  47. <div className="grw-taglabels-container">
  48. <TagLabels tags={tagInfoData.tags} tagsUpdateInvoked={tagsUpdatedHandler} />
  49. </div>
  50. )}
  51. <PagePathNav pageId={pageId} pagePath={path} isCompactMode={isCompactMode} isSingleLineMode={isSignleLineMode} />
  52. </div>
  53. {/* Right side */}
  54. {/*
  55. DeleteCompletely is currently disabled
  56. TODO : Retrive isAbleToDeleteCompleltly state everywhere in the system via swr.
  57. story: https://redmine.weseek.co.jp/issues/82222
  58. */}
  59. <div className="d-flex">
  60. <SubNavButtons
  61. isCompactMode={isCompactMode}
  62. pageId={pageId}
  63. revisionId={revisionId}
  64. path={path}
  65. isDeletable={isPageDeletable}
  66. // isAbleToDeleteCompletely={}
  67. willShowPageManagement={isAbleToShowPageManagement}
  68. >
  69. </SubNavButtons>
  70. </div>
  71. </div>
  72. </div>
  73. );
  74. };
  75. /**
  76. * Wrapper component for using unstated
  77. */
  78. const SearchResultContentSubNavigationUnstatedWrapper = withUnstatedContainers(SearchResultContentSubNavigation, [AppContainer]);
  79. // wrapping tsx component returned by withUnstatedContainers to avoid type error when this component used in other tsx components.
  80. const SearchResultContentSubNavigationWrapper = (props) => {
  81. return <SearchResultContentSubNavigationUnstatedWrapper {...props}></SearchResultContentSubNavigationUnstatedWrapper>;
  82. };
  83. export default SearchResultContentSubNavigationWrapper;