Skip to content

Commit

Permalink
Merge pull request #895 from KEEPER31337/feature/toast_UI_이미지_핸들러_#454
Browse files Browse the repository at this point in the history
Feature/toast UI 이미지 핸들러 #454
  • Loading branch information
publdaze authored May 23, 2024
2 parents 6f79dbc + 2208ece commit 1d46312
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 2 deletions.
17 changes: 17 additions & 0 deletions src/api/postApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,22 @@ const useUploadPostMutation = () => {
return useMutation(fetcher);
};

const useUploadPostImageMutation = () => {
const fetcher = async ({ file }: { file: Blob }) => {
const formData = new FormData();
formData.append('file', file);

const { data } = await axios.post('/posts/files', formData, {
headers: {
'content-type': 'multipart/form-data',
},
});
return data;
};

return useMutation(fetcher);
};

const useGetPostListQuery = ({ categoryId, searchType, search, page, size }: BoardSearch) => {
const fetcher = () =>
axios.get('/posts', { params: { categoryId, searchType, search, page, size } }).then(({ data }) => data);
Expand Down Expand Up @@ -251,6 +267,7 @@ const useGetMemberTempPostsQuery = ({ page, size = 10 }: PageAndSize) => {

export {
useUploadPostMutation,
useUploadPostImageMutation,
useGetPostListQuery,
useGetRecentPostsQuery,
useGetTrendPostsQuery,
Expand Down
46 changes: 46 additions & 0 deletions src/components/Editor/StandardEditor.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import React from 'react';
import toast from 'react-hot-toast';
import { useMediaQuery, useTheme } from '@mui/material';
import { HookMap } from '@toast-ui/editor';
import { Editor, EditorProps } from '@toast-ui/react-editor';
import { useUploadPostImageMutation } from '@api/postApi';
import { FILE, MAX_FILE_SIZE } from '@constants/apiResponseMessage';
import { getServerImgUrl } from '@utils/converter';

import '@toast-ui/editor/dist/toastui-editor.css';
import '@toast-ui/editor/dist/theme/toastui-editor-dark.css';
Expand All @@ -13,11 +18,52 @@ const StandardEditor = ({ forwardedRef, ...props }: StandardEditorProps) => {
const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down('sm'));

const { mutate: uploadPostImageMutation } = useUploadPostImageMutation();

const handleImageUpload: HookMap['addImageBlobHook'] = (blob) => {
if (blob.size > MAX_FILE_SIZE) {
toast.error(FILE.error.exceedFileSize, {
style: {
maxWidth: 1500,
},
});
return;
}

const editor = forwardedRef?.current.getInstance();
if (!editor) return;

const [startPos] = editor.getSelection();

const IMAGE_MARKDOWN_LOADING_MSG = `![Uploading image...]()`;
editor.insertText(`${IMAGE_MARKDOWN_LOADING_MSG}\n`);

// selection 타입을 명확히 하여 마크다운 위치 계산
const [startLinePos, startCharPos] = startPos as Exclude<typeof startPos, number>;
const endPos = [startLinePos, startCharPos + IMAGE_MARKDOWN_LOADING_MSG.length] as Exclude<typeof startPos, number>;

uploadPostImageMutation(
{ file: blob },
{
onSuccess: ({ fileName, filePath }) => {
editor.replaceSelection(`![${fileName}](${getServerImgUrl(filePath)})`, startPos, endPos);
},
onError: () => {
editor.deleteSelection(startPos, endPos);
toast.error(FILE.error.uploadFail);
},
},
);
};

return (
<Editor
ref={forwardedRef}
initialValue={props.initialValue ?? ''}
placeholder="내용을 입력해주세요."
hooks={{
addImageBlobHook: handleImageUpload,
}}
previewStyle={isMobile ? 'tab' : 'vertical'}
minHeight="300px"
initialEditType={isMobile ? 'wysiwyg' : 'markdown'}
Expand Down
15 changes: 13 additions & 2 deletions src/constants/apiResponseMessage.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { formatFileSize } from '@utils/converter';

export const COMMON = {} as const;

export const PASSWORD = {
Expand Down Expand Up @@ -47,11 +49,20 @@ export const LOGIN_ID = {
error: {
existing: '이미 존재하는 아이디입니다.',
},
};
} as const;

export const STUDENT_ID = {
success: {},
error: {
existing: '이미 존재하는 학번입니다.',
},
};
} as const;

export const MAX_FILE_SIZE = 30 * 1024 * 1024; // Byte
export const FILE = {
success: {},
error: {
uploadFail: '업로드가 실패하였습니다.',
exceedFileSize: `파일이 제한된 크기(${formatFileSize(MAX_FILE_SIZE)})를 초과하였습니다.`,
},
} as const;

0 comments on commit 1d46312

Please sign in to comment.