Skip to content

Commit

Permalink
refactor: SunEditor lazy loading
Browse files Browse the repository at this point in the history
  • Loading branch information
yeolyi committed Mar 9, 2024
1 parent 4e2ad8f commit 8e898ca
Show file tree
Hide file tree
Showing 18 changed files with 94 additions and 94 deletions.
6 changes: 3 additions & 3 deletions app/[locale]/community/news/EditNewsPageContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ import {
isLocalFile,
isLocalImage,
isUploadedFile,
postEditorDefaultValue,
} from '@/components/editor/PostEditorProps';
defaultContent,
} from '@/components/editor/PostEditorTypes';
import PageLayout from '@/components/layout/pageLayout/PageLayout';

import { NEWS_TAGS } from '@/constants/tag';
Expand All @@ -30,7 +30,7 @@ export default function EditNewsPageContent({ id, data }: { id: number; data: Ne
const router = useRouter();

const initialContent: PostEditorContent = {
...postEditorDefaultValue,
...defaultContent,

title: data.title,
titleForMain: data.titleForMain ?? '',
Expand Down
15 changes: 5 additions & 10 deletions app/[locale]/community/news/create/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { useRouter } from '@/navigation';
import { postNews } from '@/apis/news';

import PostEditor from '@/components/editor/PostEditor';
import { PostEditorContent, isLocalFile, isLocalImage } from '@/components/editor/PostEditorProps';
import { PostEditorContent, isLocalFile, isLocalImage } from '@/components/editor/PostEditorTypes';
import PageLayout from '@/components/layout/pageLayout/PageLayout';

import { NEWS_TAGS } from '@/constants/tag';
Expand All @@ -23,14 +23,8 @@ export default function NewsCreatePage() {
const handleCancel = () => router.push(newsPath);

const handleComplete = async (content: PostEditorContent) => {
// HTML 생성을 위한 로그
console.log(content.description);
validateNewsForm(content);

const mainImage =
content.mainImage && isLocalImage(content.mainImage) ? content.mainImage.file : null;

const attachments = content.attachments.filter(isLocalFile).map((x) => x.file);
await postNews({
request: {
title: content.title,
Expand All @@ -42,16 +36,17 @@ export default function NewsCreatePage() {
tags: content.tags,
date: content.date,
},
mainImage,
attachments,
mainImage:
content.mainImage && isLocalImage(content.mainImage) ? content.mainImage.file : null,
attachments: content.attachments.filter(isLocalFile).map((x) => x.file),
});

revalidateNewsTag();
router.replace(newsPath);
};

return (
<PageLayout title="새 소식 쓰기" titleType="big" titleMargin="mb-[2.25rem]">
<PageLayout title="새 소식 작성" titleType="big" titleMargin="mb-[2.75rem]">
<PostEditor
tags={NEWS_TAGS}
showMainImage
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
PostEditorContent,
isLocalFile,
isUploadedFile,
} from '@/components/editor/PostEditorProps';
} from '@/components/editor/PostEditorTypes';
import PageLayout from '@/components/layout/pageLayout/PageLayout';

import { NOTICE_TAGS } from '@/constants/tag';
Expand Down
8 changes: 4 additions & 4 deletions app/[locale]/community/notice/create/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { revalidateNoticeTag } from '@/actions/noticeActions';
import { postNotice } from '@/apis/notice';

import PostEditor from '@/components/editor/PostEditor';
import { PostEditorContent, isLocalFile } from '@/components/editor/PostEditorProps';
import { PostEditorContent, isLocalFile } from '@/components/editor/PostEditorTypes';
import PageLayout from '@/components/layout/pageLayout/PageLayout';

import { NOTICE_TAGS } from '@/constants/tag';
Expand All @@ -26,7 +26,6 @@ export default function NoticeCreatePage() {
const handleComplete = async (content: PostEditorContent) => {
validateNoticeForm(content);

const attachments = content.attachments.filter(isLocalFile).map((x) => x.file);
await postNotice({
request: {
title: content.title,
Expand All @@ -37,14 +36,15 @@ export default function NoticeCreatePage() {
isImportant: content.isImportant,
tags: content.tags,
},
attachments,
attachments: content.attachments.filter(isLocalFile).map((x) => x.file),
});

revalidateNoticeTag();
router.replace(noticePath);
};

return (
<PageLayout title="공지사항 쓰기" titleType="big" titleMargin="mb-[2.25rem]">
<PageLayout title="공지사항 작성" titleType="big" titleMargin="mb-[2.75rem]">
<PostEditor
tags={NOTICE_TAGS}
showIsPinned
Expand Down
2 changes: 1 addition & 1 deletion app/[locale]/community/seminar/EditSeminarPageContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import {
isLocalFile,
isLocalImage,
isUploadedFile,
} from '../../../../components/editor/PostEditorProps';
} from '../../../../components/editor/PostEditorTypes';
import SeminarEditor from '../../../../components/editor/SeminarEditor';
import { SeminarEditorContent } from '../../../../components/editor/SeminarEditorProps';

Expand Down
2 changes: 1 addition & 1 deletion app/[locale]/community/seminar/create/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { revalidateSeminarTag } from '@/actions/seminarActions';

import { postSeminar } from '@/apis/seminar';

import { isLocalFile, isLocalImage } from '@/components/editor/PostEditorProps';
import { isLocalFile, isLocalImage } from '@/components/editor/PostEditorTypes';
import SeminarEditor from '@/components/editor/SeminarEditor';
import { SeminarEditorContent } from '@/components/editor/SeminarEditorProps';
import PageLayout from '@/components/layout/pageLayout/PageLayout';
Expand Down
2 changes: 0 additions & 2 deletions app/[locale]/research/labs/page.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
export const dynamic = 'force-static';

import { getResearchLabs } from '@/apis/research';

import ResearchLabList from '@/app/[locale]/research/labs/ResearchLabList';
Expand Down
50 changes: 23 additions & 27 deletions components/editor/PostEditor.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,27 @@
'use client';

import dynamic from 'next/dynamic';
import { MutableRefObject, useRef, useState } from 'react';
import SunEditorCore from 'suneditor/src/lib/core';

import SunEditorWrapper, { isContentEmpty } from '@/components/editor/common/SunEditorWrapper';

import useModal from '@/utils/hooks/useModal';
import { isContentEmpty } from '@/utils/post';

import { CreateActionButtons, EditActionButtons } from './common/ActionButtons';
import BasicTextInput from './common/BasicTextInput';
import Fieldset from './common/Fieldset';
import FilePicker, { FilePickerProps } from './common/FilePicker';
import ImagePicker, { ImagePickerProps } from './common/ImagePicker';
import { PostEditorContent, PostEditorProps, postEditorDefaultValue } from './PostEditorProps';
import SunEditorFallback from './common/SunEditorFallback';
import { PostEditorContent, PostEditorProps, defaultContent } from './PostEditorTypes';
import Checkbox from '../common/form/Checkbox';
import MuiDateSelector from '../common/MuiDateSelector';
import ModalFrame from '../modal/ModalFrame';

// TODO: 나중에 태그 확정되면 반응형 추가해서 수정
const gridStyle = 'grid-cols-[repeat(7,_max-content)]';
const SunEditorWrapper = dynamic(() => import('@/components/editor/common/SunEditorWrapper'), {
ssr: false,
loading: () => <SunEditorFallback />,
});

export default function PostEditor({
tags,
Expand All @@ -31,23 +34,19 @@ export default function PostEditor({
initialContent,
}: PostEditorProps) {
const editorRef = useRef<SunEditorCore>();
// description(HTML)의 경우 useRef를 사용하기에 여기에 최신값이 반영되지 않음 주의

// description(HTML)는 useRef를 사용하기에 여기에 최신값이 반영되지 않음 주의
const [content, setContent] = useState<PostEditorContent>({
...postEditorDefaultValue,
...defaultContent,
...initialContent,
});

const getContentWithDescription = (): PostEditorContent => {
if (editorRef.current) {
if (isContentEmpty(editorRef.current)) {
return { ...content, description: '' };
} else {
const description = editorRef.current.getContents(false);
return { ...content, description };
}
} else {
return { ...content, description: '' };
}
const getContent = (): PostEditorContent => {
let description = '';
if (editorRef.current && !isContentEmpty(editorRef.current))
description = editorRef.current.getContents(false);

return { ...content, description };
};

const setContentByKey =
Expand All @@ -56,13 +55,14 @@ export default function PostEditor({
setContent((content) => ({ ...content, [key]: value }));
};

const toggleCheck = (tag: string, isChecked: boolean) => {
const toggleTag = (tag: string, isChecked: boolean) => {
let nextTags = [...content.tags];
if (isChecked) nextTags.push(tag);
else nextTags = nextTags.filter((x) => x !== tag);
setContentByKey('tags')(nextTags);
};

// 아래 설정들이 활성화되어있으면 비공개글일 수 없습니다.
if (content.isPinned || content.isImportant || content.isSlide) {
if (content.isPrivate) {
setContentByKey('isPrivate')(false);
Expand Down Expand Up @@ -99,13 +99,13 @@ export default function PostEditor({
/>

<Fieldset title="태그" mb="mb-6" titleMb="mb-3">
<div className={`grid grow gap-x-6 gap-y-2.5 ${gridStyle}`}>
<div className="flex grow flex-wrap gap-x-6 gap-y-2.5">
{tags.map((tag) => (
<Checkbox
key={tag}
label={tag}
isChecked={content.tags.includes(tag)}
toggleCheck={toggleCheck}
toggleCheck={toggleTag}
/>
))}
</div>
Expand Down Expand Up @@ -161,12 +161,8 @@ export default function PostEditor({
</Fieldset>

<div className="flex gap-3 self-end">
{actions.type === 'CREATE' && (
<CreateActionButtons {...actions} getContent={getContentWithDescription} />
)}
{actions.type === 'EDIT' && (
<EditActionButtons {...actions} getContent={getContentWithDescription} />
)}
{actions.type === 'CREATE' && <CreateActionButtons {...actions} getContent={getContent} />}
{actions.type === 'EDIT' && <EditActionButtons {...actions} getContent={getContent} />}
</div>
</form>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { CreateAction, EditAction } from './common/ActionButtons';

// 첨부파일

export type PostEditorFile = LocalFile | UploadedFile;

export interface LocalFile {
Expand All @@ -22,6 +24,8 @@ export const isLocalFile = (file: PostEditorFile): file is LocalFile => file.typ
export const isUploadedFile = (file: PostEditorFile): file is UploadedFile =>
file.type === 'UPLOADED_FILE';

// 이미지

export type PostEditorImage = LocalImage | UploadedImage | null;

export interface LocalImage {
Expand All @@ -37,6 +41,8 @@ export interface UploadedImage {
export const isLocalImage = (image: LocalImage | UploadedImage): image is LocalImage =>
image.type === 'LOCAL_IMAGE';

// Content

export interface PostEditorContent {
title: string;
titleForMain: string;
Expand All @@ -62,7 +68,7 @@ export interface PostEditorProps {
initialContent?: PostEditorContent;
}

export const postEditorDefaultValue: PostEditorContent = {
export const defaultContent: PostEditorContent = {
title: '',
titleForMain: '',
description: '',
Expand Down
9 changes: 7 additions & 2 deletions components/editor/SeminarEditor.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
'use client';

import dynamic from 'next/dynamic';
import { MutableRefObject, useRef, useState } from 'react';
import SunEditorCore from 'suneditor/src/lib/core';

import SunEditorWrapper from '@/components/editor/common/SunEditorWrapper';

import { CreateActionButtons, EditActionButtons } from './common/ActionButtons';
import BasicTextInput from './common/BasicTextInput';
import DateSelector from './common/DateSelector';
import Fieldset from './common/Fieldset';
import FilePicker, { FilePickerProps } from './common/FilePicker';
import ImagePicker, { ImagePickerProps } from './common/ImagePicker';
import SunEditorFallback from './common/SunEditorFallback';
import {
SeminarEditorContent,
SeminarEditorProps,
Expand All @@ -20,6 +20,11 @@ import {
} from './SeminarEditorProps';
import Checkbox from '../common/form/Checkbox';

const SunEditorWrapper = dynamic(() => import('@/components/editor/common/SunEditorWrapper'), {
ssr: false,
loading: () => <SunEditorFallback />,
});

export default function SeminarEditor({ actions, initialContent }: SeminarEditorProps) {
const summaryEditorRef = useRef<SunEditorCore>();
const speakerIntroductionEditorRef = useRef<SunEditorCore>();
Expand Down
2 changes: 1 addition & 1 deletion components/editor/SeminarEditorProps.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { CreateAction, EditAction } from './common/ActionButtons';
import { PostEditorFile, PostEditorImage } from './PostEditorProps';
import { PostEditorFile, PostEditorImage } from './PostEditorTypes';

export interface SeminarEditorContent {
title: string;
Expand Down
2 changes: 1 addition & 1 deletion components/editor/common/FilePicker.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { ChangeEventHandler } from 'react';

import FilePickerRow from './FilePickerRow';
import { PostEditorFile } from '../PostEditorProps';
import { PostEditorFile } from '../PostEditorTypes';

export interface FilePickerProps {
files: PostEditorFile[];
Expand Down
2 changes: 1 addition & 1 deletion components/editor/common/FilePickerRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { MouseEventHandler } from 'react';

import ClearIcon from '@/public/image/clear_icon.svg';

import { PostEditorFile } from '../PostEditorProps';
import { PostEditorFile } from '../PostEditorTypes';

interface FileRowProps {
file: PostEditorFile;
Expand Down
2 changes: 1 addition & 1 deletion components/editor/common/ImagePicker.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import Image from 'next/image';
import { ChangeEventHandler, MouseEventHandler, useEffect, useState } from 'react';

import { LocalImage, PostEditorImage, UploadedImage } from '../PostEditorProps';
import { LocalImage, PostEditorImage, UploadedImage } from '../PostEditorTypes';

export interface ImagePickerProps {
file: PostEditorImage;
Expand Down
15 changes: 15 additions & 0 deletions components/editor/common/SunEditorFallback.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
export default function SunEditorFallback() {
return (
<div className="mx-[3.75rem] mt-3 flex h-[400px] animate-pulse flex-col">
<div className="flex flex-col gap-2">
<div className="h-4 w-2/5 rounded bg-[#ffffff] opacity-30"></div>
<div className="h-4 w-2/5 rounded bg-[#ffffff] opacity-30"></div>
</div>
<div className="mt-4 flex w-3/5 flex-1 flex-col gap-2">
<div className="h-4 rounded bg-[#ffffff] opacity-30"></div>
<div className="h-4 rounded bg-[#ffffff] opacity-30"></div>
<div className="h-4 rounded bg-[#ffffff] opacity-30"></div>
</div>
</div>
);
}
Loading

0 comments on commit 8e898ca

Please sign in to comment.