PageAttachment.tsx 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. import React, { useCallback, useEffect, useState } from 'react';
  2. import { useTranslation } from 'next-i18next';
  3. import { useSWRxAttachments } from '~/stores/attachment';
  4. import { useEditingMarkdown, useCurrentPageId, useIsGuestUser } from '~/stores/context';
  5. import DeleteAttachmentModal from './PageAttachment/DeleteAttachmentModal';
  6. import PageAttachmentList from './PageAttachment/PageAttachmentList';
  7. import PaginationWrapper from './PaginationWrapper';
  8. // Utility
  9. const checkIfFileInUse = (markdown: string, attachment) => {
  10. return markdown.match(attachment._id);
  11. };
  12. // Custom hook that handles processes related to inUseAttachments
  13. const useInUseAttachments = (attachments) => {
  14. const { data: markdown } = useEditingMarkdown();
  15. const [inUse, setInUse] = useState<any>({});
  16. // Update inUse when either of attachments or markdown is updated
  17. useEffect(() => {
  18. if (markdown == null) {
  19. return;
  20. }
  21. const newInUse = {};
  22. for (const attachment of attachments) {
  23. newInUse[attachment._id] = checkIfFileInUse(markdown, attachment);
  24. }
  25. setInUse(newInUse);
  26. }, [attachments, markdown]);
  27. return inUse;
  28. };
  29. const PageAttachment = (): JSX.Element => {
  30. const { t } = useTranslation();
  31. // Static SWRs
  32. const { data: pageId } = useCurrentPageId();
  33. const { data: isGuestUser } = useIsGuestUser();
  34. // States
  35. const [pageNumber, setPageNumber] = useState(1);
  36. const [attachmentToDelete, setAttachmentToDelete] = useState<any>(undefined);
  37. const [deleting, setDeleting] = useState(false);
  38. const [deleteError, setDeleteError] = useState('');
  39. // SWRs
  40. const { data: dataAttachments, remove } = useSWRxAttachments(pageId, pageNumber);
  41. const {
  42. attachments = [],
  43. totalAttachments = 0,
  44. limit,
  45. } = dataAttachments ?? {};
  46. // Custom hooks
  47. const inUseAttachments = useInUseAttachments(attachments);
  48. // Methods
  49. const onChangePageHandler = useCallback((newPageNumber: number) => {
  50. setPageNumber(newPageNumber);
  51. }, []);
  52. const onAttachmentDeleteClicked = useCallback((attachment) => {
  53. setAttachmentToDelete(attachment);
  54. }, []);
  55. const onAttachmentDeleteClickedConfirmHandler = useCallback(async(attachment) => {
  56. setDeleting(true);
  57. try {
  58. await remove({ attachment_id: attachment._id });
  59. setAttachmentToDelete(null);
  60. setDeleting(false);
  61. }
  62. catch {
  63. setDeleteError('Something went wrong.');
  64. setDeleting(false);
  65. }
  66. }, [remove]);
  67. const onToggleHandler = useCallback(() => {
  68. setAttachmentToDelete(null);
  69. setDeleteError('');
  70. }, []);
  71. // Renderers
  72. const renderDeleteAttachmentModal = useCallback(() => {
  73. if (isGuestUser) {
  74. return <></>;
  75. }
  76. if (attachments.length === 0) {
  77. return (
  78. <div data-testid="page-attachment">
  79. {t('No_attachments_yet')}
  80. </div>
  81. );
  82. }
  83. let deleteInUse = null;
  84. if (attachmentToDelete != null) {
  85. deleteInUse = inUseAttachments[attachmentToDelete._id] || false;
  86. }
  87. const isOpen = attachmentToDelete != null;
  88. return (
  89. <DeleteAttachmentModal
  90. isOpen={isOpen}
  91. animation="false"
  92. toggle={onToggleHandler}
  93. attachmentToDelete={attachmentToDelete}
  94. inUse={deleteInUse}
  95. deleting={deleting}
  96. deleteError={deleteError}
  97. onAttachmentDeleteClickedConfirm={onAttachmentDeleteClickedConfirmHandler}
  98. />
  99. );
  100. // eslint-disable-next-line max-len
  101. }, [attachmentToDelete, attachments.length, deleteError, deleting, inUseAttachments, isGuestUser, onAttachmentDeleteClickedConfirmHandler, onToggleHandler, t]);
  102. return (
  103. <div data-testid="page-attachment">
  104. <PageAttachmentList
  105. attachments={attachments}
  106. inUse={inUseAttachments}
  107. onAttachmentDeleteClicked={onAttachmentDeleteClicked}
  108. isUserLoggedIn={!isGuestUser}
  109. />
  110. {renderDeleteAttachmentModal()}
  111. <PaginationWrapper
  112. activePage={pageNumber}
  113. changePage={onChangePageHandler}
  114. totalItemsCount={totalAttachments}
  115. pagingLimit={limit}
  116. align="center"
  117. />
  118. </div>
  119. );
  120. };
  121. export default PageAttachment;