From 19046ed8d0ecdf2c57ef0a7ed74beaa4f577ee07 Mon Sep 17 00:00:00 2001 From: mj Date: Sun, 21 Jul 2024 07:02:12 +0900 Subject: [PATCH] Feat change the export of files implemented by the client to server API calls --- .../src/components/common/DownloadMenu.tsx | 23 +--- frontend/src/hooks/useFileExport.ts | 116 +++++++++--------- 2 files changed, 61 insertions(+), 78 deletions(-) diff --git a/frontend/src/components/common/DownloadMenu.tsx b/frontend/src/components/common/DownloadMenu.tsx index bb9e92a1..1b911a57 100644 --- a/frontend/src/components/common/DownloadMenu.tsx +++ b/frontend/src/components/common/DownloadMenu.tsx @@ -1,6 +1,6 @@ import { SaveAlt as SaveAltIcon } from "@mui/icons-material"; import { IconButton, Menu, MenuItem, Paper } from "@mui/material"; -import { MouseEvent, useCallback, useState } from "react"; +import { MouseEvent, useState } from "react"; import { useFileExport } from "../../hooks/useFileExport"; const DownloadMenu = () => { @@ -14,22 +14,7 @@ const DownloadMenu = () => { setAnchorEl(null); }; - const { exportToPDF, exportToTXT, exportToDOCX } = useFileExport(); - - const handleExportToPDF = useCallback(() => { - exportToPDF(); - handleClose(); - }, [exportToPDF]); - - const handleExportToTXT = useCallback(() => { - exportToTXT(); - handleClose(); - }, [exportToTXT]); - - const handleExportToDOCX = useCallback(() => { - exportToDOCX(); - handleClose(); - }, [exportToDOCX]); + const { handleExportToPDF, handleExportToHTML, handleExportToMarkdown } = useFileExport(); return ( @@ -44,8 +29,8 @@ const DownloadMenu = () => { onClose={handleClose} > Download as PDF - Download as TXT - Download as DOCX + Download as HTML + Download as Markd ); diff --git a/frontend/src/hooks/useFileExport.ts b/frontend/src/hooks/useFileExport.ts index 3f9c52e4..1b87616b 100644 --- a/frontend/src/hooks/useFileExport.ts +++ b/frontend/src/hooks/useFileExport.ts @@ -1,77 +1,75 @@ -import { Document, Packer, Paragraph, TextRun } from "docx"; -import { saveAs } from "file-saver"; -import jspdfHtml2canvas from "jspdf-html2canvas"; +import axios from "axios"; import { useSnackbar } from "notistack"; -import { useCallback, useContext } from "react"; +import { useCallback } from "react"; import { useSelector } from "react-redux"; -import { PreviewRefContext } from "../contexts/PreviewRefContext"; +import { selectDocument } from "../store/documentSlice"; import { selectEditor } from "../store/editorSlice"; -import { documentNameStorage } from "../utils/localStorage"; -interface useFileExportReturn { - exportToPDF: () => Promise; - exportToTXT: () => void; - exportToDOCX: () => void; +export const enum FileExtension { + Markdown = "markdown", + HTML = "html", + PDF = "pdf", } -export const useFileExport = (): useFileExportReturn => { - const editorStore = useSelector(selectEditor); - const markdown = editorStore.doc?.getRoot().content?.toString() || ""; - - const { previewRef } = useContext(PreviewRefContext); +interface UseFileExportReturn { + handleExportToPDF: () => void; + handleExportToHTML: () => void; + handleExportToMarkdown: () => void; +} +export const useFileExport = (): UseFileExportReturn => { const { enqueueSnackbar } = useSnackbar(); + const editorStore = useSelector(selectEditor); + const documentStore = useSelector(selectDocument); - const documentName = documentNameStorage.getDocumentName() || 'codepair_document'; + const markdown = editorStore.doc?.getRoot().content?.toString() || ""; + const documentName = documentStore.data?.title || "codepair_document"; - const exportToPDF = useCallback(async () => { - if (previewRef.current?.mdp && previewRef.current.mdp.current instanceof HTMLDivElement) { + const handleExportFile = useCallback( + async (exportType: string) => { try { - await jspdfHtml2canvas(previewRef.current.mdp.current, { - output: `${documentName}`, - jsPDF: { - format: "a4", - orientation: "portrait", - }, - html2canvas: { - scale: 3, + enqueueSnackbar(`${exportType.toUpperCase()} 파일 내보내기 시작...`, { + variant: "info", + }); + + const response = await axios.post( + "/files/export-markdown", + { + exportType, + content: markdown, + fileName: documentName, }, + { + responseType: "blob", + } + ); + + const blob = new Blob([response.data], { type: `application/${exportType}` }); + const url = window.URL.createObjectURL(blob); + const link = document.createElement("a"); + link.href = url; + link.setAttribute("download", `${encodeURIComponent(documentName)}.${exportType}`); + document.body.appendChild(link); + link.click(); + if (link.parentNode) link.parentNode.removeChild(link); + window.URL.revokeObjectURL(url); + + enqueueSnackbar(`${exportType.toUpperCase()} 파일이 성공적으로 내보내졌습니다.`, { + variant: "success", }); } catch (error) { - if(previewRef.current.mdp.current) { - enqueueSnackbar("Content is empty", { variant: "error" }); - } else { - enqueueSnackbar("Failed to export PDF", { variant: "error" }); - } + console.error("오류:", error); + enqueueSnackbar(`${exportType.toUpperCase()} 파일 내보내기에 실패했습니다.`, { + variant: "error", + }); } - } else { - enqueueSnackbar("Please try again", { variant: "error" }); - } - }, [previewRef, enqueueSnackbar, documentName]); - - const exportToTXT = useCallback(() => { - const blob = new Blob([markdown], { type: "text/plain;charset=utf-8" }); - saveAs(blob, documentName); - }, [documentName, markdown]); - - const exportToDOCX = useCallback(() => { - const doc = new Document({ - sections: [ - { - properties: {}, - children: [ - new Paragraph({ - children: [new TextRun(markdown)], - }), - ], - }, - ], - }); + }, + [markdown, documentName, enqueueSnackbar] + ); - Packer.toBlob(doc).then((blob) => { - saveAs(blob, documentName); - }); - }, [markdown, documentName]); + const handleExportToPDF = () => handleExportFile(FileExtension.PDF); + const handleExportToHTML = () => handleExportFile(FileExtension.HTML); + const handleExportToMarkdown = () => handleExportFile(FileExtension.Markdown); - return { exportToPDF, exportToTXT, exportToDOCX }; + return { handleExportToPDF, handleExportToHTML, handleExportToMarkdown }; };