Taichi Masuyama 3 лет назад
Родитель
Сommit
3f4b608545
1 измененных файлов с 155 добавлено и 0 удалено
  1. 155 0
      packages/app/src/components/PageAttachment.tsx

+ 155 - 0
packages/app/src/components/PageAttachment.tsx

@@ -0,0 +1,155 @@
+import React, { useCallback, useEffect, useState } from 'react';
+
+import { useTranslation } from 'next-i18next';
+
+import { useSWRxAttachments } from '~/stores/attachment';
+import { useCurrentMarkdown, useCurrentPageId, useIsGuestUser } from '~/stores/context';
+
+import DeleteAttachmentModal from './PageAttachment/DeleteAttachmentModal';
+import PageAttachmentList from './PageAttachment/PageAttachmentList';
+import PaginationWrapper from './PaginationWrapper';
+
+// Utility
+const checkIfFileInUse = (markdown: string, attachment) => {
+  if (markdown == null) {
+    return false;
+  }
+
+  return markdown.match(attachment._id);
+};
+
+// Custom hook that handles processes related to inUseAttachments
+const useInUseAttachments = (attachments) => {
+  const { data: markdown } = useCurrentMarkdown();
+  const [inUse, setInUse] = useState<any>({});
+
+  // Update inUse when either of attachments or markdown is updated
+  useEffect(() => {
+    if (markdown == null) {
+      return;
+    }
+
+    const newInUse = {};
+
+    for (const attachment of attachments) {
+      newInUse[attachment._id] = checkIfFileInUse(markdown, attachment);
+    }
+
+    setInUse(newInUse);
+  }, [attachments, markdown]);
+
+  return inUse;
+};
+
+const PageAttachment = (): JSX.Element => {
+  const { t } = useTranslation();
+
+  // Static SWRs
+  const { data: pageId } = useCurrentPageId();
+  const { data: isGuestUser } = useIsGuestUser();
+
+  // States
+  const [pageNumber, setPageNumber] = useState(1);
+  const [attachmentToDelete, setAttachmentToDelete] = useState<any>(undefined);
+  const [deleting, setDeleting] = useState(false);
+  const [deleteError, setDeleteError] = useState('');
+
+  // SWRs
+  const { data: dataAttachments, remove } = useSWRxAttachments(pageId, pageNumber);
+  const {
+    attachments = [],
+    totalAttachments = 0,
+    limit,
+  } = dataAttachments ?? {};
+
+  // Custom hooks
+  const inUseAttachments = useInUseAttachments(attachments);
+
+  // Methods
+  const onChangePageHandler = useCallback((newPageNumber: number) => {
+    setPageNumber(newPageNumber);
+  }, []);
+
+  const onAttachmentDeleteClicked = useCallback((attachment) => {
+    setAttachmentToDelete(attachment);
+  }, []);
+
+  const onAttachmentDeleteClickedConfirmHandler = useCallback(async(attachment) => {
+    setDeleting(true);
+
+    try {
+      await remove({ attachment_id: attachment._id });
+
+      setAttachmentToDelete(null);
+      setDeleting(false);
+    }
+    catch {
+      setDeleteError('Something went wrong.');
+      setDeleting(false);
+    }
+  }, [remove]);
+
+  const onToggleHandler = useCallback(() => {
+    setAttachmentToDelete(null);
+    setDeleteError('');
+  }, []);
+
+  // Renderers
+  const renderDeleteAttachmentModal = useCallback(() => {
+    if (isGuestUser) {
+      return <></>;
+    }
+
+    if (attachments.length === 0) {
+      return (
+        <div data-testid="page-attachment">
+          {t('No_attachments_yet')}
+        </div>
+      );
+    }
+
+    let deleteInUse = null;
+    if (attachmentToDelete != null) {
+      deleteInUse = inUseAttachments[attachmentToDelete._id] || false;
+    }
+
+    const isOpen = attachmentToDelete != null;
+
+    return (
+      <DeleteAttachmentModal
+        isOpen={isOpen}
+        animation="false"
+        toggle={onToggleHandler}
+        attachmentToDelete={attachmentToDelete}
+        inUse={deleteInUse}
+        deleting={deleting}
+        deleteError={deleteError}
+        onAttachmentDeleteClickedConfirm={onAttachmentDeleteClickedConfirmHandler}
+      />
+    );
+  // eslint-disable-next-line max-len
+  }, [attachmentToDelete, attachments.length, deleteError, deleting, inUseAttachments, isGuestUser, onAttachmentDeleteClickedConfirmHandler, onToggleHandler, t]);
+
+  return (
+    <div data-testid="page-attachment">
+      <PageAttachmentList
+        attachments={attachments}
+        inUse={inUseAttachments}
+        onAttachmentDeleteClicked={onAttachmentDeleteClicked}
+        isUserLoggedIn={!isGuestUser}
+      />
+
+      {renderDeleteAttachmentModal()}
+
+      <PaginationWrapper
+        activePage={pageNumber}
+        changePage={onChangePageHandler}
+        totalItemsCount={totalAttachments}
+        pagingLimit={limit}
+        align="center"
+      />
+    </div>
+  );
+};
+
+export default PageAttachment;