diff --git a/.storybook/preview.ts b/.storybook/preview.tsx similarity index 66% rename from .storybook/preview.ts rename to .storybook/preview.tsx index 5905f704..c6c97c87 100644 --- a/.storybook/preview.ts +++ b/.storybook/preview.tsx @@ -1,4 +1,5 @@ import React from 'react' +import { Providers } from '../src/providers' import type { Preview } from '@storybook/react' import '../src/app/globals.css' @@ -11,6 +12,13 @@ const preview: Preview = { }, }, }, + decorators: [ + (Story) => ( + + + + ), + ], } export default preview diff --git a/src/app/(routes)/document/(create)/@header/default.tsx b/src/app/(routes)/document/(create)/@header/default.tsx index 847784a3..99113684 100644 --- a/src/app/(routes)/document/(create)/@header/default.tsx +++ b/src/app/(routes)/document/(create)/@header/default.tsx @@ -1,4 +1,4 @@ -import DirectorySelectDrawer from '@/features/document/components/directory-select-drawer' +import DirectorySelectDrawer from '@/features/directory/components/directory-select-drawer' import GoBackButton from '@/shared/components/custom/go-back-button' import Text from '@/shared/components/ui/text' diff --git a/src/app/(routes)/document/(create)/file/layout.tsx b/src/app/(routes)/document/(create)/file/layout.tsx index 01240bb6..279e9491 100644 --- a/src/app/(routes)/document/(create)/file/layout.tsx +++ b/src/app/(routes)/document/(create)/file/layout.tsx @@ -1,12 +1,13 @@ import { FunctionComponent, PropsWithChildren } from 'react' import type { Metadata } from 'next' +import { DirectoryProvider } from '@/features/directory/contexts/directory-context' export const metadata: Metadata = {} interface LayoutProps extends PropsWithChildren {} const Layout: FunctionComponent = ({ children }) => { - return
{children}
+ return {children} } export default Layout diff --git a/src/app/(routes)/document/(create)/file/page.tsx b/src/app/(routes)/document/(create)/file/page.tsx index 3ffc8927..d75c325e 100644 --- a/src/app/(routes)/document/(create)/file/page.tsx +++ b/src/app/(routes)/document/(create)/file/page.tsx @@ -1,7 +1,7 @@ import Icon from '@/shared/components/custom/icon' import Text from '@/shared/components/ui/text' -import { EditDocumentProvider } from '@/features/editor/context/edit-document-context' -import TitleInput from '@/features/editor/components/title-input' +import { EditDocumentProvider } from '@/features/modify/context/edit-document-context' +import TitleInput from '@/features/modify/components/title-input' import FixedBottom from '@/shared/components/custom/fixed-bottom' import NewQuizDrawer from '@/features/quiz/components/new-quiz-drawer' import { Button } from '@/shared/components/ui/button' diff --git a/src/app/(routes)/document/(create)/notion/page.tsx b/src/app/(routes)/document/(create)/notion/page.tsx index c9f91559..952a1d49 100644 --- a/src/app/(routes)/document/(create)/notion/page.tsx +++ b/src/app/(routes)/document/(create)/notion/page.tsx @@ -1,4 +1,4 @@ -import { EditDocumentProvider } from '@/features/editor/context/edit-document-context' +import { EditDocumentProvider } from '@/features/modify/context/edit-document-context' import NewQuizDrawer from '@/features/quiz/components/new-quiz-drawer' import FixedBottom from '@/shared/components/custom/fixed-bottom' import Icon from '@/shared/components/custom/icon' diff --git a/src/app/(routes)/document/(create)/ui/header.tsx b/src/app/(routes)/document/(create)/ui/header.tsx index 847784a3..99113684 100644 --- a/src/app/(routes)/document/(create)/ui/header.tsx +++ b/src/app/(routes)/document/(create)/ui/header.tsx @@ -1,4 +1,4 @@ -import DirectorySelectDrawer from '@/features/document/components/directory-select-drawer' +import DirectorySelectDrawer from '@/features/directory/components/directory-select-drawer' import GoBackButton from '@/shared/components/custom/go-back-button' import Text from '@/shared/components/ui/text' diff --git a/src/app/(routes)/document/(main)/@header/default.tsx b/src/app/(routes)/document/(main)/@header/default.tsx index 9cb53bfd..f1886bf1 100644 --- a/src/app/(routes)/document/(main)/@header/default.tsx +++ b/src/app/(routes)/document/(main)/@header/default.tsx @@ -5,18 +5,20 @@ import Text from '@/shared/components/ui/text' import { useEffect, useState } from 'react' import { cn } from '@/shared/lib/utils' import Link from 'next/link' -import { useDirectoryContext } from '@/features/document/contexts/directory-context' import { Drawer, DrawerContent, DrawerTitle, DrawerTrigger } from '@/shared/components/ui/drawer' import SortIconBtn from '@/features/document/components/sort-icon-button' -import DirectoryMenuDots from '@/features/document/components/directory-menu-dots' +import DirectoryMenuDots from '@/features/directory/components/directory-menu-dots' import GoBackButton from '@/shared/components/custom/go-back-button' import { useDirectories } from '@/requests/directory/hooks' import CreateDirectoryDialog from '@/features/directory/components/create-directory-dialog' +import { useDocumentContext } from '@/features/document/contexts/document-context' +import { useDirectoryContext } from '@/features/directory/contexts/directory-context' // Header 컴포넌트 const Header = () => { const { data } = useDirectories() - const { isSelectMode, setIsSelectMode } = useDirectoryContext() + const { selectedDirectory } = useDirectoryContext() + const { isSelectMode, setIsSelectMode } = useDocumentContext() const [isDrawerOpen, setIsDrawerOpen] = useState(false) return ( @@ -33,7 +35,7 @@ const Header = () => { setIsSelectMode(false)} /> - 전공 공부 + {selectedDirectory?.name} 전체 선택 @@ -75,7 +77,8 @@ interface Props { } const DirectorySelectDrawer = ({ isDrawerOpen, setIsDrawerOpen, directories }: Props) => { - const { selectedDirectoryId, setButtonHidden, setSelectedDirectoryId } = useDirectoryContext() + const { selectedDirectory, selectedDirectoryId, selectDirectoryId } = useDirectoryContext() + const { setButtonHidden } = useDocumentContext() useEffect(() => { if (isDrawerOpen) { @@ -85,8 +88,10 @@ const DirectorySelectDrawer = ({ isDrawerOpen, setIsDrawerOpen, directories }: P } }, [isDrawerOpen, setButtonHidden]) - const currentDirectory = directories.find((directory) => directory.id === selectedDirectoryId) - const totalNotes = directories.reduce((acc, directory) => acc + directory.documentCount, 0) + const handleDirectorySelect = (id: number | null) => { + selectDirectoryId(id) + setIsDrawerOpen(false) + } return ( <> @@ -94,8 +99,8 @@ const DirectorySelectDrawer = ({ isDrawerOpen, setIsDrawerOpen, directories }: P @@ -126,7 +131,7 @@ const DirectorySelectDrawer = ({ isDrawerOpen, setIsDrawerOpen, directories }: P - } - /> - - - - - ) -} - -export default CreateWithEditor diff --git a/src/features/document/components/edit-cancel-dialog.tsx b/src/features/modify/components/edit-cancel-dialog.tsx similarity index 100% rename from src/features/document/components/edit-cancel-dialog.tsx rename to src/features/modify/components/edit-cancel-dialog.tsx diff --git a/src/features/editor/components/title-input.tsx b/src/features/modify/components/title-input.tsx similarity index 100% rename from src/features/editor/components/title-input.tsx rename to src/features/modify/components/title-input.tsx diff --git a/src/features/editor/components/visual-editor.tsx b/src/features/modify/components/visual-editor.tsx similarity index 100% rename from src/features/editor/components/visual-editor.tsx rename to src/features/modify/components/visual-editor.tsx diff --git a/src/features/editor/context/edit-document-context.tsx b/src/features/modify/context/edit-document-context.tsx similarity index 100% rename from src/features/editor/context/edit-document-context.tsx rename to src/features/modify/context/edit-document-context.tsx diff --git a/src/features/editor/libs/extensions.ts b/src/features/modify/libs/extensions.ts similarity index 100% rename from src/features/editor/libs/extensions.ts rename to src/features/modify/libs/extensions.ts diff --git a/src/features/editor/styles/remirror-custom.css b/src/features/modify/styles/remirror-custom.css similarity index 100% rename from src/features/editor/styles/remirror-custom.css rename to src/features/modify/styles/remirror-custom.css diff --git a/src/features/pages/documents-in-directory.tsx b/src/features/pages/documents-in-directory.tsx index cd1fdb11..171d89da 100644 --- a/src/features/pages/documents-in-directory.tsx +++ b/src/features/pages/documents-in-directory.tsx @@ -7,11 +7,29 @@ import AddDocumentMenu from '../document/components/add-document-menu' import Image from 'next/image' import Text from '@/shared/components/ui/text' import note_img from '@/../../public/assets/note.png' -import { useGetDocuments } from '@/requests/document/hooks' import Loading from '@/shared/components/custom/loading' +import { useDirectoryContext } from '../directory/contexts/directory-context' +import { useQuery } from '@tanstack/react-query' +import { queries } from '@/shared/lib/tanstack-query/query-keys' +import { useDocumentContext } from '../document/contexts/document-context' +import { useEffect } from 'react' const DocumentsInDirectory = () => { - const { data, isPending } = useGetDocuments() + const { selectedDirectoryId } = useDirectoryContext() + const { checkDoc } = useDocumentContext() + + const params = + selectedDirectoryId !== null ? { directoryId: String(selectedDirectoryId) } : undefined + const { data, isPending } = useQuery(queries.document.list(params)) + + useEffect(() => { + if (data) { + const documentCheckList = + data.documents.map((document) => ({ id: document.id, checked: false })) ?? [] + + checkDoc.set(documentCheckList) + } + }, [data]) if (isPending) { return @@ -33,8 +51,6 @@ const DocumentsInDirectory = () => { ) : ( - // 노트 리스트 렌더링 - // todo: useCheckList 훅 이용해 체크 구현 {data.documents.map((document, idx) => ( { const { id } = useParams() - const { data, isPending } = useGetDocumentDetail(Number(id[0])) + const { data, isPending } = useQuery(queries.document.item(Number(id[0]))) const { editorMarkdownContent: content } = useEditDocumentContext() if (isPending) { diff --git a/src/requests/document/hooks.ts b/src/requests/document/hooks.ts index 9524d8de..36f6505b 100644 --- a/src/requests/document/hooks.ts +++ b/src/requests/document/hooks.ts @@ -3,8 +3,7 @@ import { useMutation } from '@tanstack/react-query' import { useSession } from 'next-auth/react' import { createDocument } from './create-document' -import { useQuery } from '@tanstack/react-query' -import { fetchDocumentDetail, fetchDocuments, updateDocument } from '.' +import { updateDocument } from '.' export const useCreateDocument = () => { const { data: session } = useSession() @@ -23,18 +22,3 @@ export const useUpdateDocument = () => { updateDocument(params.documentId, params.request, session?.user.accessToken || ''), }) } - -export const useGetDocuments = (params?: { directoryId?: string; sortOption?: Document.Sort }) => { - return useQuery({ - queryKey: ['getDocuments', params?.directoryId, params?.sortOption], - queryFn: async () => fetchDocuments(params), - }) -} - -export const useGetDocumentDetail = (documentId: number) => { - return useQuery({ - queryKey: ['getDocumentDetail', documentId], - queryFn: async () => fetchDocumentDetail(documentId), - enabled: !!documentId, - }) -} diff --git a/src/shared/hooks/use-check-list-ignore-ids.ts b/src/shared/hooks/use-check-list-ignore-ids.ts new file mode 100644 index 00000000..0bbff64e --- /dev/null +++ b/src/shared/hooks/use-check-list-ignore-ids.ts @@ -0,0 +1,169 @@ +import { useCallback, useRef } from 'react' +import { useForceUpdate } from './use-force-update' + +interface Item { + id: string | number + checked?: boolean +} + +export function useCheckListIgnoreIds( + initialItems: T[], + options?: { ignoreIds: Item['id'][] } +) { + type IdType = T['id'] + const listRef = useRef(initialItems) + const forceUpdate = useForceUpdate() + + const findItem = useCallback( + (id: IdType) => listRef.current.find(({ id: _id }) => _id === id), + [] + ) + + const findIndex = useCallback( + (id: IdType) => listRef.current.findIndex(({ id: _id }) => _id === id), + [] + ) + + const isChecked = useCallback((id: IdType) => findItem(id)?.checked, [findItem]) + + const isAllChecked = useCallback(() => listRef.current.every(({ checked }) => checked), []) + + const isAllCheckedWithoutIgnored = useCallback(() => { + if (options?.ignoreIds == null || options?.ignoreIds.length === 0) { + return isAllChecked() + } + + return listRef.current.every(({ id, checked }) => { + if (options.ignoreIds.includes(id)) { + return true + } + + return checked + }) + }, [options, isAllChecked]) + + const set = useCallback( + (items: T[]) => { + listRef.current = items + forceUpdate() + }, + [forceUpdate] + ) + + const updateItem = useCallback( + (id: IdType, checked: boolean) => { + const idx = findIndex(id) + if (idx > -1) { + const item = listRef.current[idx] + + if (item.checked !== checked) { + const arr = [...listRef.current] + arr[idx] = { ...item, id, checked } + set(arr) + } + } + }, + [findIndex, set] + ) + + const toggle = useCallback( + (id: IdType) => updateItem(id, !isChecked(id)), + [isChecked, updateItem] + ) + + const check = useCallback( + (id: IdType) => { + updateItem(id, true) + }, + [updateItem] + ) + + const unCheck = useCallback( + (id: IdType) => { + updateItem(id, false) + }, + [updateItem] + ) + + const toggleAll = useCallback(() => { + const toggled = !isAllChecked() + const arr = listRef.current.map((item) => ({ ...item, checked: toggled })) + + set(arr) + }, [isAllChecked, set]) + + const updateAll = useCallback( + (checked: boolean) => { + if (listRef.current.every((item) => item.checked === checked)) { + return + } + set(listRef.current.map((item) => ({ ...item, checked }))) + }, + [set] + ) + + const updateAllWithoutIgnored = useCallback( + (checked: boolean) => { + if ( + listRef.current.every((item) => { + if (options?.ignoreIds.includes(item.id)) return true + + return item.checked === checked + }) + ) { + return + } + set( + listRef.current.map((item) => ({ + ...item, + checked: options?.ignoreIds.includes(item.id) ? false : checked, + })) + ) + }, + [set, options] + ) + + const checkAll = useCallback(() => { + updateAll(true) + }, [updateAll]) + + const checkAllWithoutIgnored = useCallback(() => { + updateAllWithoutIgnored(true) + }, [updateAllWithoutIgnored]) + + const unCheckAll = useCallback(() => { + updateAll(false) + }, [updateAll]) + + const unCheckAllWithoutIgnored = useCallback(() => { + updateAllWithoutIgnored(false) + }, [updateAllWithoutIgnored]) + + const getCheckedList = useCallback(() => { + return listRef.current.filter((item) => item.checked) + }, []) + + const getCheckedIds = useCallback(() => { + return getCheckedList().map(({ id }) => id) + }, [getCheckedList]) + + return { + list: listRef.current, + set, + isChecked, + isAllChecked, + check, + unCheck, + toggle, + updateItem, + toggleAll, + checkAll, + unCheckAll, + updateAll, + getCheckedList, + getCheckedIds, + isAllCheckedWithoutIgnored, + checkAllWithoutIgnored, + unCheckAllWithoutIgnored, + } +} diff --git a/src/shared/hooks/use-check-list.ts b/src/shared/hooks/use-check-list.ts index 14828ff7..794afc7a 100644 --- a/src/shared/hooks/use-check-list.ts +++ b/src/shared/hooks/use-check-list.ts @@ -1,15 +1,14 @@ import { useCallback, useRef } from 'react' import { useForceUpdate } from './use-force-update' +export type UseCheckListReturn = ReturnType> + interface Item { id: string | number checked?: boolean } -export function useCheckList( - initialItems: T[], - options?: { ignoreIds: Item['id'][] } -) { +export function useCheckList(initialItems: T[]) { type IdType = T['id'] const listRef = useRef(initialItems) const forceUpdate = useForceUpdate() @@ -28,20 +27,6 @@ export function useCheckList( const isAllChecked = useCallback(() => listRef.current.every(({ checked }) => checked), []) - const isAllCheckedWithoutIgnored = useCallback(() => { - if (options?.ignoreIds == null || options?.ignoreIds.length === 0) { - return isAllChecked() - } - - return listRef.current.every(({ id, checked }) => { - if (options.ignoreIds.includes(id)) { - return true - } - - return checked - }) - }, [options, isAllChecked]) - const set = useCallback( (items: T[]) => { listRef.current = items @@ -58,7 +43,7 @@ export function useCheckList( if (item.checked !== checked) { const arr = [...listRef.current] - arr[idx] = { ...item, id, checked } + arr[idx] = { ...item, checked } set(arr) } } @@ -102,43 +87,14 @@ export function useCheckList( [set] ) - const updateAllWithoutIgnored = useCallback( - (checked: boolean) => { - if ( - listRef.current.every((item) => { - if (options?.ignoreIds.includes(item.id)) return true - - return item.checked === checked - }) - ) { - return - } - set( - listRef.current.map((item) => ({ - ...item, - checked: options?.ignoreIds.includes(item.id) ? false : checked, - })) - ) - }, - [set, options] - ) - const checkAll = useCallback(() => { updateAll(true) }, [updateAll]) - const checkAllWithoutIgnored = useCallback(() => { - updateAllWithoutIgnored(true) - }, [updateAllWithoutIgnored]) - const unCheckAll = useCallback(() => { updateAll(false) }, [updateAll]) - const unCheckAllWithoutIgnored = useCallback(() => { - updateAllWithoutIgnored(false) - }, [updateAllWithoutIgnored]) - const getCheckedList = useCallback(() => { return listRef.current.filter((item) => item.checked) }, []) @@ -162,8 +118,5 @@ export function useCheckList( updateAll, getCheckedList, getCheckedIds, - isAllCheckedWithoutIgnored, - checkAllWithoutIgnored, - unCheckAllWithoutIgnored, } }