2
0

SubNavButtons.tsx 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. import React, { useCallback } from 'react';
  2. import { IPageInfoAll, isIPageInfoForEntity, isIPageInfoForOperation } from '~/interfaces/page';
  3. import { useSWRxPageInfo } from '../../stores/page';
  4. import { useSWRBookmarkInfo } from '../../stores/bookmark';
  5. import { useSWRxUsersList } from '../../stores/user';
  6. import { useIsGuestUser } from '~/stores/context';
  7. import SubscribeButton from '../SubscribeButton';
  8. import LikeButtons from '../LikeButtons';
  9. import BookmarkButtons from '../BookmarkButtons';
  10. import SeenUserInfo from '../User/SeenUserInfo';
  11. import { toggleBookmark, toggleLike, toggleSubscribe } from '~/client/services/page-operation';
  12. import { AdditionalMenuItemsRendererProps, PageItemControl } from '../Common/Dropdown/PageItemControl';
  13. type CommonProps = {
  14. isCompactMode?: boolean,
  15. disableSeenUserInfoPopover?: boolean,
  16. showPageControlDropdown?: boolean,
  17. additionalMenuItemRenderer?: React.FunctionComponent<AdditionalMenuItemsRendererProps>,
  18. }
  19. type SubNavButtonsSubstanceProps= CommonProps & {
  20. pageId: string,
  21. shareLinkId?: string | null,
  22. revisionId: string,
  23. pageInfo: IPageInfoAll,
  24. }
  25. const SubNavButtonsSubstance = (props: SubNavButtonsSubstanceProps): JSX.Element => {
  26. const {
  27. pageInfo,
  28. pageId, shareLinkId,
  29. isCompactMode, disableSeenUserInfoPopover, showPageControlDropdown, additionalMenuItemRenderer,
  30. } = props;
  31. const { data: isGuestUser } = useIsGuestUser();
  32. const { mutate: mutatePageInfo } = useSWRxPageInfo(pageId, shareLinkId);
  33. const { data: bookmarkInfo, mutate: mutateBookmarkInfo } = useSWRBookmarkInfo(pageId);
  34. const likerIds = isIPageInfoForEntity(pageInfo) ? (pageInfo.likerIds ?? []).slice(0, 15) : [];
  35. const seenUserIds = isIPageInfoForEntity(pageInfo) ? (pageInfo.seenUserIds ?? []).slice(0, 15) : [];
  36. // Put in a mixture of seenUserIds and likerIds data to make the cache work
  37. const { data: usersList } = useSWRxUsersList([...likerIds, ...seenUserIds]);
  38. const likers = usersList != null ? usersList.filter(({ _id }) => likerIds.includes(_id)).slice(0, 15) : [];
  39. const seenUsers = usersList != null ? usersList.filter(({ _id }) => seenUserIds.includes(_id)).slice(0, 15) : [];
  40. const subscribeClickhandler = useCallback(async() => {
  41. if (isGuestUser == null || isGuestUser) {
  42. return;
  43. }
  44. if (!isIPageInfoForOperation(pageInfo)) {
  45. return;
  46. }
  47. await toggleSubscribe(pageId, pageInfo.subscriptionStatus);
  48. mutatePageInfo();
  49. }, [isGuestUser, mutatePageInfo, pageId, pageInfo]);
  50. const likeClickhandler = useCallback(async() => {
  51. if (isGuestUser == null || isGuestUser) {
  52. return;
  53. }
  54. if (!isIPageInfoForOperation(pageInfo)) {
  55. return;
  56. }
  57. await toggleLike(pageId, pageInfo.isLiked);
  58. mutatePageInfo();
  59. }, [isGuestUser, mutatePageInfo, pageId, pageInfo]);
  60. const bookmarkClickHandler = useCallback(async() => {
  61. if (isGuestUser == null || isGuestUser) {
  62. return;
  63. }
  64. if (!isIPageInfoForOperation(pageInfo)) {
  65. return;
  66. }
  67. await toggleBookmark(pageId, pageInfo.isBookmarked);
  68. mutatePageInfo();
  69. mutateBookmarkInfo();
  70. }, [isGuestUser, mutateBookmarkInfo, mutatePageInfo, pageId, pageInfo]);
  71. if (!isIPageInfoForOperation(pageInfo)) {
  72. return <></>;
  73. }
  74. const {
  75. sumOfLikers, isLiked, bookmarkCount, isBookmarked,
  76. } = pageInfo;
  77. return (
  78. <div className="d-flex" style={{ gap: '2px' }}>
  79. <span>
  80. <SubscribeButton
  81. status={pageInfo.subscriptionStatus}
  82. onClick={subscribeClickhandler}
  83. />
  84. </span>
  85. <LikeButtons
  86. hideTotalNumber={isCompactMode}
  87. onLikeClicked={likeClickhandler}
  88. sumOfLikers={sumOfLikers}
  89. isLiked={isLiked}
  90. likers={likers}
  91. />
  92. <BookmarkButtons
  93. hideTotalNumber={isCompactMode}
  94. bookmarkCount={bookmarkCount}
  95. isBookmarked={isBookmarked}
  96. bookmarkedUsers={bookmarkInfo?.bookmarkedUsers}
  97. onBookMarkClicked={bookmarkClickHandler}
  98. />
  99. <SeenUserInfo seenUsers={seenUsers} disabled={disableSeenUserInfoPopover} />
  100. { showPageControlDropdown && (
  101. <PageItemControl
  102. pageId={pageId}
  103. pageInfo={pageInfo}
  104. isEnableActions={!isGuestUser}
  105. additionalMenuItemRenderer={additionalMenuItemRenderer}
  106. />
  107. )}
  108. </div>
  109. );
  110. };
  111. type SubNavButtonsProps= CommonProps & {
  112. pageId: string,
  113. shareLinkId?: string | null,
  114. revisionId?: string | null,
  115. };
  116. export const SubNavButtons = (props: SubNavButtonsProps): JSX.Element => {
  117. const { pageId, shareLinkId, revisionId } = props;
  118. const { data: pageInfo, error } = useSWRxPageInfo(pageId ?? null, shareLinkId);
  119. if (revisionId == null || error != null) {
  120. return <></>;
  121. }
  122. if (!isIPageInfoForOperation(pageInfo)) {
  123. return <></>;
  124. }
  125. return <SubNavButtonsSubstance {...props} pageInfo={pageInfo} pageId={pageId} revisionId={revisionId} />;
  126. };