From 2b8a81e84d9db14507a083fe20082375200f228f Mon Sep 17 00:00:00 2001 From: Yongho Kim Date: Sun, 15 Sep 2024 15:42:41 +0900 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20feat:=20=EC=9E=91=EC=84=B1=20?= =?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=A7=80=20=ED=86=A0=EC=8A=A4=ED=8A=B8,=20?= =?UTF-8?q?=EB=AA=A8=EB=8B=AC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- grass-diary/src/components/modal/Modal.tsx | 5 +- grass-diary/src/constants/message.ts | 1 + .../src/pages/CreateDiary/CreateDiary.tsx | 77 ++++++++++++++----- .../src/state/modal/ModalButtonStore.ts | 43 +++++------ grass-diary/src/state/modal/ModalStore.ts | 8 -- grass-diary/src/state/modal/useModal.ts | 19 ----- grass-diary/src/types/modal.ts | 23 ++++++ 7 files changed, 104 insertions(+), 72 deletions(-) diff --git a/grass-diary/src/components/modal/Modal.tsx b/grass-diary/src/components/modal/Modal.tsx index 2b472241..28d6a9ca 100644 --- a/grass-diary/src/components/modal/Modal.tsx +++ b/grass-diary/src/components/modal/Modal.tsx @@ -61,7 +61,10 @@ const Modal = () => { {button1.active && ( setActive(false)} + onClick={() => { + if (button1.clickHandler) button1.clickHandler(); + setActive(false); + }} color={button1.color} interaction={button1.interaction} /> diff --git a/grass-diary/src/constants/message.ts b/grass-diary/src/constants/message.ts index 53b6b1ed..67c8418e 100644 --- a/grass-diary/src/constants/message.ts +++ b/grass-diary/src/constants/message.ts @@ -158,6 +158,7 @@ export const CREATE_MESSAGES = { toast: { temp_save: '작성 중인 일기 내용을 임시저장했어요.', already_written: '오늘 이미 작성한 일기가 있어요.', + write_diary: '일기 내용을 작성해주세요.', }, hashtag: { diff --git a/grass-diary/src/pages/CreateDiary/CreateDiary.tsx b/grass-diary/src/pages/CreateDiary/CreateDiary.tsx index 363f1d66..e4a5eedb 100644 --- a/grass-diary/src/pages/CreateDiary/CreateDiary.tsx +++ b/grass-diary/src/pages/CreateDiary/CreateDiary.tsx @@ -30,7 +30,7 @@ const CreateDiary = () => { const { mutate: createDiary } = useCreateDiary(memberId); const { mutate: postImage } = usePostImage(); const { date } = useTodayDate(); - const { toast } = useToast(); + const { toast, redToast } = useToast(); const [diaryInfo, setDiaryInfo] = useState({ hashArr: [], moodValue: 5, @@ -70,29 +70,59 @@ const CreateDiary = () => { size: '', }); - // 모달 + // 임시 저장 모달 - // useEffect(() => { - // const setting = { - // title: MODAL.create_diary.load_temporary, - // content: MODAL.create_diary.load_temporary_description, - // }; + const temporarySaveModal = () => { + const setting = { + title: MODAL.create_diary.load_temporary, + content: MODAL.create_diary.load_temporary_description, + }; + + const button1 = { + active: true, + text: MODAL.create_diary.continue_entry, + color: semantic.light.accent.solid.hero, + interaction: INTERACTION.accent.subtle(), + }; - // const button1 = { - // active: true, - // text: MODAL.cancel, - // }; + const button2 = { + active: true, + text: MODAL.create_diary.new_entry, + clickHandler: () => { + localStorage.removeItem('diary_draft'); + + setDiaryInfo({ + hashArr: [], + moodValue: 5, + quillContent: '', + isPrivate: true, + year: null, + month: null, + date: null, + day: null, + }); + + setImage({ + imageId: 0, + imageURL: '', + }); + + setImageInfo({ + name: '', + size: '', + }); + }, + }; - // const button2 = { - // active: true, - // text: MODAL.create_diary.continue_entry, - // clickHandler: undefined, - // color: semantic.light.accent.solid.hero, - // interaction: INTERACTION.accent.subtle(), - // }; + modal(setting, button2, button1); + }; - // modal(setting, button1, button2); - // }, []); + useEffect(() => { + const savedDraft = localStorage.getItem('diary_draft'); + if (savedDraft) { + temporarySaveModal(); + } + }, []); // 상태 업데이트 함수 const setDiaryField = (field: Partial) => { @@ -212,6 +242,7 @@ const CreateDiary = () => { toast(CREATE_MESSAGES.toast.already_written); return; } + // 사용자가 이미지를 첨부할 경우 postImage -> createDiary 실행 if (file) { postImage(file, { @@ -308,7 +339,11 @@ const CreateDiary = () => { }, []); const handleSaveDraft = () => { - if (isContentEmpty) return; // 일기 내용이 비어 있으면 저장 요청 불가 + if (isContentEmpty) { + redToast(CREATE_MESSAGES.toast.write_diary); + return; // 일기 내용이 비어 있으면 저장 요청 불가 + } + const draftData = { ...diaryInfo, imageBase64: imageBase64, diff --git a/grass-diary/src/state/modal/ModalButtonStore.ts b/grass-diary/src/state/modal/ModalButtonStore.ts index c56d58c6..fc220217 100644 --- a/grass-diary/src/state/modal/ModalButtonStore.ts +++ b/grass-diary/src/state/modal/ModalButtonStore.ts @@ -1,35 +1,26 @@ import { create } from 'zustand'; -type Button1Props = { - active: boolean; - text: string; - color?: string; - interaction?: string; -}; - -type Button2Props = { - active: boolean; - text: string; - color?: string; - interaction?: string; - clickHandler: () => void; -}; - type Actions = { - setButton1: ({ active, text, color, interaction }: Button1Props) => void; + setButton1: ({ + active, + text, + color, + interaction, + clickHandler, + }: Button1) => void; setButton2: ({ active, text, color, interaction, clickHandler, - }: Button2Props) => void; + }: Button2) => void; setResetActive: () => void; }; interface ModalButtonState { - button1: Button1Props; - button2: Button2Props; + button1: Button1; + button2: Button2; actions: Actions; } @@ -39,6 +30,7 @@ const useModalButtonStore = create(set => ({ text: '', color: '', interaction: '', + clickHandler: () => console.log('button1 default'), }, button2: { active: false, @@ -47,16 +39,22 @@ const useModalButtonStore = create(set => ({ interaction: '', clickHandler: () => console.log('button2 default'), }, - actions: { setResetActive: () => set(state => ({ button1: { ...state.button1, active: false }, button2: { ...state.button2, active: false }, })), - setButton1: ({ active, text, color, interaction }) => + setButton1: ({ active, text, color, interaction, clickHandler }) => set(state => ({ - button1: { ...state.button1, active, text, color, interaction }, + button1: { + ...state.button1, + active, + text, + color, + interaction, + clickHandler, + }, })), setButton2: ({ active, text, color, interaction, clickHandler }) => set(state => ({ @@ -71,7 +69,6 @@ const useModalButtonStore = create(set => ({ })), }, })); - export const useModalButton1 = () => useModalButtonStore(state => state.button1); export const useModalButton2 = () => diff --git a/grass-diary/src/state/modal/ModalStore.ts b/grass-diary/src/state/modal/ModalStore.ts index b69a76eb..e6b8355d 100644 --- a/grass-diary/src/state/modal/ModalStore.ts +++ b/grass-diary/src/state/modal/ModalStore.ts @@ -1,23 +1,16 @@ import { create } from 'zustand'; -type Setting = { - title: string; - content: string; -}; - type Actions = { setLogin: (login: boolean) => void; setActive: (active: boolean) => void; setSetting: ({ title, content }: Setting) => void; }; - type ModalState = { login: boolean; active: boolean; setting: Setting; actions: Actions; }; - const useModalStore = create(set => ({ login: false, active: false, @@ -31,7 +24,6 @@ const useModalStore = create(set => ({ setSetting: setting => set({ setting }), }, })); - export const useModalLogin = () => useModalStore(state => state.login); export const useModalActive = () => useModalStore(state => state.active); export const useModalSetting = () => useModalStore(state => state.setting); diff --git a/grass-diary/src/state/modal/useModal.ts b/grass-diary/src/state/modal/useModal.ts index e7a6bf72..4366c146 100644 --- a/grass-diary/src/state/modal/useModal.ts +++ b/grass-diary/src/state/modal/useModal.ts @@ -1,25 +1,9 @@ import { useModalButtonActions } from './ModalButtonStore'; import { useModalActions } from './ModalStore'; -type Setting = { - title: string; - content: string; -}; - -type Button2 = { - active: boolean; - text: string; - color?: string; - interaction?: string; - clickHandler: () => void; -}; - -type Button1 = Pick; - export const useModal = () => { const { setLogin, setActive, setSetting } = useModalActions(); const { setResetActive, setButton1, setButton2 } = useModalButtonActions(); - const modal = (setting: Setting, button1?: Button1, button2?: Button2) => { setResetActive(); setSetting(setting); @@ -27,17 +11,14 @@ export const useModal = () => { if (button2) setButton2(button2); setActive(true); }; - const loginModal = () => { const setting = { title: '회원가입 및 로그인', content: '', }; - setActive(true); setLogin(true); setSetting(setting); }; - return { modal, loginModal }; }; diff --git a/grass-diary/src/types/modal.ts b/grass-diary/src/types/modal.ts index 9512ee01..a013b238 100644 --- a/grass-diary/src/types/modal.ts +++ b/grass-diary/src/types/modal.ts @@ -18,3 +18,26 @@ type ImageModalProps = { img: string; setImageModal: React.Dispatch>; }; + +// Modal 전역 state props +type Setting = { + title: string; + content: string; +}; + +type Button = { + active: boolean; + text: string; + color?: string; + interaction?: string; +}; + +// Button1은 clickHandler가 선택적 +type Button1 = Button & { + clickHandler?: () => void; +}; + +// Button2는 clickHandler가 필수 +type Button2 = Button & { + clickHandler: () => void; +};