From 25b3666e38e73134828f4abbb80b4f5fdcf15879 Mon Sep 17 00:00:00 2001 From: cje Date: Sun, 18 Feb 2024 13:51:33 +0900 Subject: [PATCH] =?UTF-8?q?[Feature/BAR-236]=20=EC=A0=80=EC=9E=A5=ED=95=98?= =?UTF-8?q?=EB=8A=94=20=ED=8E=98=EC=9D=B4=EC=A7=80=20=ED=8F=B4=EB=8D=94=20?= =?UTF-8?q?=EC=88=98=EC=A0=95/=EC=82=AD=EC=A0=9C=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84=20(#66)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat(domain/저장하는): 폴더 삭제 기능 구현 * feat(domain/저장하는): 폴더 수정 기능 구현 * refactor(EditFolder): 로그 제거 * refactor(WriteInput): 공통 Button 컴포넌트로 변경 * feat(Modal): section 태그로 변경 * feat(NotFoundArchiveCard): 저장된 템플릿이 없을 경우, 메인으로 이동 --- src/api/http.ts | 6 +- src/api/memoFolder/constants/queryKey.ts | 7 ++ src/api/memoFolder/index.ts | 30 ++++- .../mutations/useDeleteMemoFolder.ts | 25 ++++ .../mutations/useUpdateMemoFolder.ts | 25 ++++ src/components/Button/style.css.ts | 5 +- src/components/Dropdown/style.css.ts | 2 +- src/components/Input/WriteInput/index.tsx | 5 +- .../Modal/components/ModalContainer.tsx | 17 ++- .../Modal/components/ModalLayout.tsx | 34 ++++++ src/components/Modal/index.tsx | 6 + src/components/Modal/modals/EditFolder.tsx | 107 ++++++++++++++++++ src/components/Modal/style.css.ts | 30 ++++- .../components/ArchiveFolder/index.tsx" | 30 ++--- .../components/ArchiveFolder/style.css.ts" | 16 --- .../components/DeleteFolderModal/index.tsx" | 49 ++++++++ .../DeleteFolderModal/style.css.ts" | 10 ++ .../components/Folder/index.tsx" | 40 +++++++ .../components/Folder/style.css.ts" | 20 ++++ .../components/NotFoundArchiveCard/index.tsx" | 7 +- src/stores/modal.ts | 16 ++- 21 files changed, 430 insertions(+), 57 deletions(-) create mode 100644 src/api/memoFolder/constants/queryKey.ts create mode 100644 src/api/memoFolder/mutations/useDeleteMemoFolder.ts create mode 100644 src/api/memoFolder/mutations/useUpdateMemoFolder.ts create mode 100644 src/components/Modal/components/ModalLayout.tsx create mode 100644 src/components/Modal/modals/EditFolder.tsx create mode 100644 "src/domain/\354\240\200\354\236\245\355\225\230\353\212\224/components/DeleteFolderModal/index.tsx" create mode 100644 "src/domain/\354\240\200\354\236\245\355\225\230\353\212\224/components/DeleteFolderModal/style.css.ts" create mode 100644 "src/domain/\354\240\200\354\236\245\355\225\230\353\212\224/components/Folder/index.tsx" create mode 100644 "src/domain/\354\240\200\354\236\245\355\225\230\353\212\224/components/Folder/style.css.ts" diff --git a/src/api/http.ts b/src/api/http.ts index df4e82f1..12b9303c 100644 --- a/src/api/http.ts +++ b/src/api/http.ts @@ -93,6 +93,8 @@ export const http = { param?: ParamType, options?: AxiosRequestConfig, ): Promise => instance.put(url, param, options), - delete: (url: string): Promise => - instance.delete(url), + delete: ( + url: string, + param?: ParamType, + ): Promise => instance.delete(url, param && param), }; diff --git a/src/api/memoFolder/constants/queryKey.ts b/src/api/memoFolder/constants/queryKey.ts new file mode 100644 index 00000000..c2bb28a3 --- /dev/null +++ b/src/api/memoFolder/constants/queryKey.ts @@ -0,0 +1,7 @@ +const MEMO_FOLDERS = 'memo-folders'; + +export const MEMO_FOLDERS_KEY = { + all: [MEMO_FOLDERS] as const, + list: () => [...MEMO_FOLDERS_KEY.all, 'list'] as const, + item: (args: unknown[]) => [...MEMO_FOLDERS_KEY.list(), ...args] as const, +}; diff --git a/src/api/memoFolder/index.ts b/src/api/memoFolder/index.ts index 67857cdf..23ae2a81 100644 --- a/src/api/memoFolder/index.ts +++ b/src/api/memoFolder/index.ts @@ -2,7 +2,33 @@ import { http } from '@api/http'; import { type Folder } from './types'; -export const getMemoFolders = () => http.get('/memo-folders'); +const API_URL = '/memo-folders'; + +export const getMemoFolders = () => http.get(API_URL); export const postMemoFolders = (folderName: string) => - http.post('/memo-folders', { folderName }); + http.post(API_URL, { folderName }); + +export const patchMemoFolders = ({ + memoFolderId, + folderName, +}: { + memoFolderId: number; + folderName: string; +}) => + http.patch(API_URL, { + memoFolderId, + folderName, + }); + +export const deleteMemoFolders = ({ + memoFolderId, + deleteAllMemo, +}: { + memoFolderId: number; + deleteAllMemo: boolean; +}) => + http.delete(API_URL, { + memoFolderId, + deleteAllMemo, + }); diff --git a/src/api/memoFolder/mutations/useDeleteMemoFolder.ts b/src/api/memoFolder/mutations/useDeleteMemoFolder.ts new file mode 100644 index 00000000..c523ac37 --- /dev/null +++ b/src/api/memoFolder/mutations/useDeleteMemoFolder.ts @@ -0,0 +1,25 @@ +import { useMutation, useQueryClient } from '@tanstack/react-query'; + +import { useToastStore } from '@stores/toast'; + +import { deleteMemoFolders } from '..'; +import { MEMO_FOLDERS_KEY } from '../constants/queryKey'; + +const useDeleteMemoFolder = () => { + const { showToast } = useToastStore(); + + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: deleteMemoFolders, + onSuccess: () => { + showToast({ message: '선택한 폴더가 삭제되었어요' }); + + queryClient.invalidateQueries({ + queryKey: MEMO_FOLDERS_KEY.all, + }); + }, + }); +}; + +export default useDeleteMemoFolder; diff --git a/src/api/memoFolder/mutations/useUpdateMemoFolder.ts b/src/api/memoFolder/mutations/useUpdateMemoFolder.ts new file mode 100644 index 00000000..21fedab0 --- /dev/null +++ b/src/api/memoFolder/mutations/useUpdateMemoFolder.ts @@ -0,0 +1,25 @@ +import { useMutation, useQueryClient } from '@tanstack/react-query'; + +import { useToastStore } from '@stores/toast'; + +import { patchMemoFolders } from '..'; +import { MEMO_FOLDERS_KEY } from '../constants/queryKey'; + +const useUpdateMemoFolder = () => { + const { showToast } = useToastStore(); + + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: patchMemoFolders, + onSuccess: () => { + showToast({ message: '폴더 이름이 수정되었어요' }); + + queryClient.invalidateQueries({ + queryKey: MEMO_FOLDERS_KEY.all, + }); + }, + }); +}; + +export default useUpdateMemoFolder; diff --git a/src/components/Button/style.css.ts b/src/components/Button/style.css.ts index e7991ba2..8ddb84e1 100644 --- a/src/components/Button/style.css.ts +++ b/src/components/Button/style.css.ts @@ -4,6 +4,9 @@ import { sprinkles } from '@styles/sprinkles.css'; import { COLORS } from '@styles/tokens'; export const button = recipe({ + base: { + whiteSpace: 'nowrap', + }, variants: { state: { default: { @@ -24,7 +27,7 @@ export const button = recipe({ M: [ sprinkles({ typography: '15/Title/Medium' }), { - padding: '15px 24px', + padding: '15px 20px', borderRadius: '8px', }, ], diff --git a/src/components/Dropdown/style.css.ts b/src/components/Dropdown/style.css.ts index b4a46f42..60b042c3 100644 --- a/src/components/Dropdown/style.css.ts +++ b/src/components/Dropdown/style.css.ts @@ -26,7 +26,7 @@ export const menuList = recipe({ borderRadius: '12px', boxShadow: '0px 8px 15px 0px rgba(28, 28, 28, 0.08)', backgroundColor: COLORS['Grey/White'], - zIndex: 100, + zIndex: 50, }, variants: { size: { diff --git a/src/components/Input/WriteInput/index.tsx b/src/components/Input/WriteInput/index.tsx index 10e4a2f6..bebdc1ae 100644 --- a/src/components/Input/WriteInput/index.tsx +++ b/src/components/Input/WriteInput/index.tsx @@ -2,6 +2,7 @@ import type { ChangeEvent, HTMLAttributes, KeyboardEvent } from 'react'; import { useMemo, useRef, useState } from 'react'; import { assignInlineVars } from '@vanilla-extract/dynamic'; +import Button from '@components/Button'; import Icon from '@components/Icon'; import { MAIN_INPUT_MAX_LENGTH } from '@constants/config'; import type { UseInputReturn } from '@hooks/useInput'; @@ -104,14 +105,14 @@ const WriteInput = ({  / 500자 )} - + diff --git a/src/components/Modal/components/ModalContainer.tsx b/src/components/Modal/components/ModalContainer.tsx index f6fd9710..ca098b13 100644 --- a/src/components/Modal/components/ModalContainer.tsx +++ b/src/components/Modal/components/ModalContainer.tsx @@ -8,17 +8,18 @@ import { useModalStore } from '@stores/modal'; import Portal from '../../Portal'; import * as styles from '../style.css'; +import { ModalBody, ModalFooter, ModalHeader } from './ModalLayout'; type ModalSizeType = 'login' | 'common'; -interface ModalContainerProps { +interface ModalRootProps { type?: ModalSizeType; } -const ModalContainer = ({ +const ModalRoot = ({ children, type = 'common', -}: PropsWithChildren) => { +}: PropsWithChildren) => { const dimmedRef = useRef(null); const pathname = usePathname(); @@ -59,14 +60,20 @@ const ModalContainer = ({ return (
-
+
{children} -
+ ); }; +const ModalContainer = Object.assign(ModalRoot, { + Header: ModalHeader, + Body: ModalBody, + Footer: ModalFooter, +}); + export default ModalContainer; diff --git a/src/components/Modal/components/ModalLayout.tsx b/src/components/Modal/components/ModalLayout.tsx new file mode 100644 index 00000000..0c685958 --- /dev/null +++ b/src/components/Modal/components/ModalLayout.tsx @@ -0,0 +1,34 @@ +import { type HTMLAttributes, type PropsWithChildren } from 'react'; + +import * as styles from '../style.css'; + +interface ModalProps extends HTMLAttributes {} + +export const ModalHeader = ({ + children, + ...props +}: PropsWithChildren) => { + return ( +
+ {children} +
+ ); +}; + +export const ModalBody = ({ + children, + ...props +}: PropsWithChildren) => { + return ( +
+ {children} +
+ ); +}; + +export const ModalFooter = ({ + children, + ...props +}: PropsWithChildren) => { + return
{children}
; +}; diff --git a/src/components/Modal/index.tsx b/src/components/Modal/index.tsx index b8e999e0..19da1e81 100644 --- a/src/components/Modal/index.tsx +++ b/src/components/Modal/index.tsx @@ -1,6 +1,8 @@ +import DeleteFolderModal from '@domain/저장하는/components/DeleteFolderModal'; import { useModalStore } from '@stores/modal'; import DeleteArticle from './modals/DeleteArticle'; +import EditFolder from './modals/EditFolder'; import Login from './modals/Login'; import MakeFolder from './modals/MakeFolder'; @@ -13,6 +15,10 @@ const Modal = () => { if (type === 'makeFolder') return ; + if (type === 'editFolder') return ; + + if (type === 'deleteFolder') return ; + return null; }; diff --git a/src/components/Modal/modals/EditFolder.tsx b/src/components/Modal/modals/EditFolder.tsx new file mode 100644 index 00000000..68aba01c --- /dev/null +++ b/src/components/Modal/modals/EditFolder.tsx @@ -0,0 +1,107 @@ +import { type ChangeEvent, useState } from 'react'; +import { useQueryClient } from '@tanstack/react-query'; +import { assignInlineVars } from '@vanilla-extract/dynamic'; +import { AxiosError } from 'axios'; +import clsx from 'clsx'; + +import useUpdateMemoFolder from '@api/memoFolder/mutations/useUpdateMemoFolder'; +import Button from '@components/Button'; +import Icon from '@components/Icon'; +import { useModalStore } from '@stores/modal'; +import { COLORS } from '@styles/tokens'; + +import ModalContainer from '../components/ModalContainer'; +import * as styles from '../style.css'; + +const EditFolder = () => { + const queryClient = useQueryClient(); + + const { closeModal, memoFolderId, folderName } = useModalStore(); + const [value, setValue] = useState(folderName); + const [errorMessage, setErrorMessage] = useState(''); + + const { mutateAsync } = useUpdateMemoFolder(); + + const handleInputChange = (e: ChangeEvent) => { + setErrorMessage(''); + setValue(e.target.value); + }; + + const handleFolderNameEdit = async () => { + if (value.length > 10) return setErrorMessage('10자 내로 입력해주세요!'); + + await mutateAsync( + { memoFolderId, folderName: value }, + { + onSuccess: async () => { + await queryClient.invalidateQueries({ + queryKey: ['memo-folders'], + }); + closeModal(); + }, + onError: (e) => { + if (!(e instanceof AxiosError) || !e.response) throw e; + if ( + (e.response.data as { errorCode: string; message: string }) + .errorCode === 'MF01' + ) + return setErrorMessage('이미 사용 중인 폴더 이름이에요!'); + throw e; + }, + }, + ); + }; + + return ( + + 폴더 수정하기 + +
+ +
+ {errorMessage && ( + +
+ +
+ {errorMessage} +
+ )} +
+ + +
+
+ ); +}; + +export default EditFolder; diff --git a/src/components/Modal/style.css.ts b/src/components/Modal/style.css.ts index 5531d9b1..36a96c14 100644 --- a/src/components/Modal/style.css.ts +++ b/src/components/Modal/style.css.ts @@ -3,13 +3,16 @@ import { recipe } from '@vanilla-extract/recipes'; import { sprinkles } from '@styles/sprinkles.css'; import { COLORS } from '@styles/tokens'; -import { middleLayer, positionCenter, topLayer } from '@styles/utils.css'; +import { fullScreen, middleLayer, topLayer } from '@styles/utils.css'; export const modalStyle = recipe({ base: [ - positionCenter, topLayer, { + position: 'fixed', + top: '50%', + left: '50%', + transform: 'translate(-50%, -50%)', borderRadius: '16px', backgroundColor: COLORS['Grey/White'], }, @@ -29,14 +32,13 @@ export const modalStyle = recipe({ }); export const dimmed = style([ + fullScreen, middleLayer, { backgroundColor: COLORS['Dim/50'], position: 'fixed', - left: '0', - top: '0', - right: '0', - bottom: '0', + left: 0, + top: 0, }, ]); @@ -263,3 +265,19 @@ export const errorIcon = style({ verticalAlign: '-5px', marginRight: '6px', }); + +export const modalHeader = style([ + sprinkles({ typography: '20/Title/Semibold' }), + { + marginBottom: '18px', + color: COLORS['Grey/900'], + }, +]); + +export const modalBody = style([ + sprinkles({ typography: '15/Body/Regular' }), + { + marginBottom: '24px', + color: COLORS['Grey/700'], + }, +]); diff --git "a/src/domain/\354\240\200\354\236\245\355\225\230\353\212\224/components/ArchiveFolder/index.tsx" "b/src/domain/\354\240\200\354\236\245\355\225\230\353\212\224/components/ArchiveFolder/index.tsx" index 436af317..eedcce00 100644 --- "a/src/domain/\354\240\200\354\236\245\355\225\230\353\212\224/components/ArchiveFolder/index.tsx" +++ "b/src/domain/\354\240\200\354\236\245\355\225\230\353\212\224/components/ArchiveFolder/index.tsx" @@ -1,19 +1,18 @@ -import Link from 'next/link'; - import Button from '@components/Button'; -import MenuDropdown from '@components/Dropdown/MenuDropdown'; import Icon from '@components/Icon'; -import { ROUTES } from '@constants/routes'; import { type Folder } from '@domain/저장하는/types'; import useGetMyProfile from '@queries/useGetMyProfile'; +import { useModalStore } from '@stores/modal'; +import FolderItem from '../Folder'; import * as styles from './style.css'; -interface FolderProps { +interface ArchiveFolderProps { folders: Folder[]; } -const ArchiveFolder = ({ folders }: FolderProps) => { +const ArchiveFolder = ({ folders }: ArchiveFolderProps) => { + const { openModal } = useModalStore(); const { data } = useGetMyProfile(); return ( @@ -23,21 +22,12 @@ const ArchiveFolder = ({ folders }: FolderProps) => { 기본
{folders.map((folder) => ( -
- - {folder.name} - - console.log('수정')} - onDelete={() => console.log('삭제')} - /> -
+ ))} - {} - diff --git "a/src/domain/\354\240\200\354\236\245\355\225\230\353\212\224/components/ArchiveFolder/style.css.ts" "b/src/domain/\354\240\200\354\236\245\355\225\230\353\212\224/components/ArchiveFolder/style.css.ts" index b3dd5754..b76d1d1f 100644 --- "a/src/domain/\354\240\200\354\236\245\355\225\230\353\212\224/components/ArchiveFolder/style.css.ts" +++ "b/src/domain/\354\240\200\354\236\245\355\225\230\353\212\224/components/ArchiveFolder/style.css.ts" @@ -38,22 +38,6 @@ export const icon = style({ fill: COLORS['Grey/250'], }); -export const folderButton = style([ - sprinkles({ typography: '16/Title/Medium' }), - utils.flexAlignCenter, - { - width: '100%', - display: 'flex', - justifyContent: 'space-between', - padding: '8px 12px 8px 20px', - }, -]); - -export const folderName = style({ - display: 'inline-block', - width: '100%', -}); - export const createFolderButton = style([ sprinkles({ typography: '16/Title/Medium' }), utils.flexAlignCenter, diff --git "a/src/domain/\354\240\200\354\236\245\355\225\230\353\212\224/components/DeleteFolderModal/index.tsx" "b/src/domain/\354\240\200\354\236\245\355\225\230\353\212\224/components/DeleteFolderModal/index.tsx" new file mode 100644 index 00000000..e8dccdd2 --- /dev/null +++ "b/src/domain/\354\240\200\354\236\245\355\225\230\353\212\224/components/DeleteFolderModal/index.tsx" @@ -0,0 +1,49 @@ +import useDeleteMemoFolder from '@api/memoFolder/mutations/useDeleteMemoFolder'; +import Button from '@components/Button'; +import ModalContainer from '@components/Modal/components/ModalContainer'; +import { useModalStore } from '@stores/modal'; + +import * as styles from './style.css'; + +const DeleteFolderModal = () => { + const { closeModal, memoFolderId } = useModalStore(); + const { mutate: deleteFolder } = useDeleteMemoFolder(); + + const handleAllFolderDelete = () => { + deleteFolder({ memoFolderId, deleteAllMemo: true }); + closeModal(); + }; + + const handleCardMove = () => { + deleteFolder({ memoFolderId, deleteAllMemo: false }); + closeModal(); + }; + + return ( + + + 해당 폴더를 삭제할까요? + + +

+ {`삭제한 폴더는 복구할 수 없어요!\n폴더 내 문장과 템플릿은 어떻게 할까요?`} +

+
+ + + + +
+ ); +}; + +export default DeleteFolderModal; diff --git "a/src/domain/\354\240\200\354\236\245\355\225\230\353\212\224/components/DeleteFolderModal/style.css.ts" "b/src/domain/\354\240\200\354\236\245\355\225\230\353\212\224/components/DeleteFolderModal/style.css.ts" new file mode 100644 index 00000000..8bf7c918 --- /dev/null +++ "b/src/domain/\354\240\200\354\236\245\355\225\230\353\212\224/components/DeleteFolderModal/style.css.ts" @@ -0,0 +1,10 @@ +import { style } from '@vanilla-extract/css'; + +export const button = style({ + width: '164px', +}); + +export const buttonGroup = style({ + display: 'flex', + justifyContent: 'space-between', +}); diff --git "a/src/domain/\354\240\200\354\236\245\355\225\230\353\212\224/components/Folder/index.tsx" "b/src/domain/\354\240\200\354\236\245\355\225\230\353\212\224/components/Folder/index.tsx" new file mode 100644 index 00000000..b776b4ce --- /dev/null +++ "b/src/domain/\354\240\200\354\236\245\355\225\230\353\212\224/components/Folder/index.tsx" @@ -0,0 +1,40 @@ +import Link from 'next/link'; + +import { type Folder } from '@api/memoFolder/types'; +import MenuDropdown from '@components/Dropdown/MenuDropdown'; +import { ROUTES } from '@constants/routes'; +import { useModalStore } from '@stores/modal'; + +import * as styles from './style.css'; + +const FolderItem = ({ folder }: { folder: Folder }) => { + const { openModal, setMemoFolderId, setFolderName } = useModalStore(); + + const handleEditFolderButtonClick = () => { + setMemoFolderId(folder.id); + setFolderName(folder.name); + openModal('editFolder'); + }; + + const handleDeleteFolderButtonClick = () => { + setMemoFolderId(folder.id); + openModal('deleteFolder'); + }; + + return ( +
+ + {folder.name} + + +
+ ); +}; + +export default FolderItem; diff --git "a/src/domain/\354\240\200\354\236\245\355\225\230\353\212\224/components/Folder/style.css.ts" "b/src/domain/\354\240\200\354\236\245\355\225\230\353\212\224/components/Folder/style.css.ts" new file mode 100644 index 00000000..9be21385 --- /dev/null +++ "b/src/domain/\354\240\200\354\236\245\355\225\230\353\212\224/components/Folder/style.css.ts" @@ -0,0 +1,20 @@ +import { style } from '@vanilla-extract/css'; + +import { sprinkles } from '@styles/sprinkles.css'; +import * as utils from '@styles/utils.css'; + +export const folderButton = style([ + sprinkles({ typography: '16/Title/Medium' }), + utils.flexAlignCenter, + { + width: '100%', + display: 'flex', + justifyContent: 'space-between', + padding: '8px 12px 8px 20px', + }, +]); + +export const folderName = style({ + display: 'inline-block', + width: '100%', +}); diff --git "a/src/domain/\354\240\200\354\236\245\355\225\230\353\212\224/components/NotFoundArchiveCard/index.tsx" "b/src/domain/\354\240\200\354\236\245\355\225\230\353\212\224/components/NotFoundArchiveCard/index.tsx" index 3a214a94..365bb6e8 100644 --- "a/src/domain/\354\240\200\354\236\245\355\225\230\353\212\224/components/NotFoundArchiveCard/index.tsx" +++ "b/src/domain/\354\240\200\354\236\245\355\225\230\353\212\224/components/NotFoundArchiveCard/index.tsx" @@ -1,9 +1,14 @@ +import { useRouter } from 'next/router'; + import Empty from '@assets/images/empty.svg'; import Button from '@components/Button'; +import { ROUTES } from '@constants/routes'; import * as styles from './style.css'; const NotFoundArchiveCard = () => { + const router = useRouter(); + return (
@@ -13,7 +18,7 @@ const NotFoundArchiveCard = () => { 자주 사용하는 글과 템플릿을 저장해보세요.
- diff --git a/src/stores/modal.ts b/src/stores/modal.ts index 254a2c3d..042450e3 100644 --- a/src/stores/modal.ts +++ b/src/stores/modal.ts @@ -2,21 +2,35 @@ import { createStore } from 'zustand'; import { shallow } from 'zustand/shallow'; import { useStoreWithEqualityFn as useStore } from 'zustand/traditional'; -type ModalType = 'deleteArticle' | 'login' | 'makeFolder'; +type ModalType = + | 'deleteArticle' + | 'login' + | 'makeFolder' + | 'editFolder' + | 'deleteFolder'; interface State { type: ModalType | null; + folderName: string; + memoFolderId: number; } interface Action { openModal: (type: ModalType) => void; closeModal: () => void; + setFolderName: (folderName: State['folderName']) => void; + setMemoFolderId: (memoFolderId: State['memoFolderId']) => void; } export const modalStore = createStore((set) => ({ type: null, + folderName: '', + memoFolderId: 0, openModal: (type) => set({ type }), closeModal: () => set({ type: null }), + setFolderName: (folderName: State['folderName']) => set({ folderName }), + setMemoFolderId: (memoFolderId: State['memoFolderId']) => + set({ memoFolderId }), })); export const useModalStore = () =>