From f6fc2c8ad01cd8ede9e9df9292661be300f5006c Mon Sep 17 00:00:00 2001 From: "nageuna922@gmail.com" Date: Thu, 21 Nov 2024 21:59:27 +0900 Subject: [PATCH 01/13] feat: document card check --- .../swipeable-document-card/index.tsx | 27 ++- .../document/contexts/directory-context.tsx | 11 ++ src/shared/hooks/use-check-list-ignore-ids.ts | 169 ++++++++++++++++++ src/shared/hooks/use-check-list.ts | 55 +----- 4 files changed, 206 insertions(+), 56 deletions(-) create mode 100644 src/shared/hooks/use-check-list-ignore-ids.ts diff --git a/src/features/document/components/swipeable-document-card/index.tsx b/src/features/document/components/swipeable-document-card/index.tsx index 4138cc1f..85829f7f 100644 --- a/src/features/document/components/swipeable-document-card/index.tsx +++ b/src/features/document/components/swipeable-document-card/index.tsx @@ -37,7 +37,7 @@ const SwipeableDocumentCard = ({ className, reviewCount, }: DocumentProps) => { - const { isSelectMode } = useDirectoryContext() + const { isSelectMode, checkDoc } = useDirectoryContext() const [isSwiped, setIsSwiped] = useState(false) const [isDragging, setIsDragging] = useState(false) const x = useMotionValue(0) @@ -45,6 +45,14 @@ const SwipeableDocumentCard = ({ const router = useRouter() const { setPreviousPath } = usePreviousPath() + const isChecked = checkDoc.isChecked(id) + + const handleCheckedChange = (checked: boolean) => { + if (!isSelectMode) return + + checked ? checkDoc.check(id) : checkDoc.unCheck(id) + } + const handleDragEnd = (event: MouseEvent | TouchEvent | PointerEvent, info: PanInfo) => { if (info.offset.x < -30) { setIsSwiped(true) // 30px 이상 드래그하면 스와이프 @@ -59,7 +67,11 @@ const SwipeableDocumentCard = ({ return (
{ - if (!isSelectMode && !isDragging && !isSwiped) { + if (isSelectMode) { + handleCheckedChange(!isChecked) + return + } + if (!isDragging && !isSwiped) { setPreviousPath('/document') router.push(`/document/${id}`) } @@ -75,16 +87,21 @@ const SwipeableDocumentCard = ({ `flex h-[104px] max-w-full items-center rounded-[16px] px-[16px] py-[17px]`, isSwiped && 'translate-x-[-116px]' )} - drag="x" + drag={isSelectMode ? false : 'x'} dragConstraints={{ left: -130, right: 0 }} - onDrag={() => setIsDragging(true)} + onDrag={() => !isSelectMode && setIsDragging(true)} onDragEnd={handleDragEnd} animate={controls} style={{ x }} transition={{ type: 'spring', stiffness: 300, damping: 30 }} > {isSelectMode ? ( - + ) : ( void isExpandedBtns: boolean setIsExpandedBtns: (value: boolean) => void + checkDoc: UseCheckListReturn<{ id: number; checked: boolean }> } const DirectoryContext = createContext(null) @@ -30,6 +33,12 @@ export function DirectoryProvider({ const [buttonHidden, setButtonHidden] = useState(initialValues?.buttonHidden ?? false) const [isExpandedBtns, setIsExpandedBtns] = useState(initialValues?.isExpandedBtns ?? false) + const { data } = useGetDocuments() + const documentCheckList = + data?.documents.map((document) => ({ id: document.id, checked: false })) ?? [] + + const checkDoc = useCheckList(documentCheckList) + const values = useMemo( () => ({ selectedDirectoryId, @@ -40,6 +49,7 @@ export function DirectoryProvider({ setButtonHidden, isExpandedBtns, setIsExpandedBtns, + checkDoc, }), [ selectedDirectoryId, @@ -50,6 +60,7 @@ export function DirectoryProvider({ setButtonHidden, isExpandedBtns, setIsExpandedBtns, + checkDoc, ] ) 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, } } From 5ab29bf60272fcadc64cc18d535d09cdc39e832b Mon Sep 17 00:00:00 2001 From: "nageuna922@gmail.com" Date: Thu, 21 Nov 2024 22:41:14 +0900 Subject: [PATCH 02/13] feat: query client for storybook --- src/app/(routes)/document/(main)/layout.tsx | 17 ++++++++++------- .../swipeable-document-card/index.stories.tsx | 13 +++++++++---- .../components/custom/client-layout/index.tsx | 13 +++++++++++++ 3 files changed, 32 insertions(+), 11 deletions(-) create mode 100644 src/shared/components/custom/client-layout/index.tsx diff --git a/src/app/(routes)/document/(main)/layout.tsx b/src/app/(routes)/document/(main)/layout.tsx index 9827006d..a769526f 100644 --- a/src/app/(routes)/document/(main)/layout.tsx +++ b/src/app/(routes)/document/(main)/layout.tsx @@ -1,7 +1,8 @@ import { FunctionComponent, PropsWithChildren } from 'react' -import type { Metadata } from 'next' +import { Metadata } from 'next' import BottomNavLayout from '@/shared/components/custom/bottom-nav-layout' import { DirectoryProvider } from '@/features/document/contexts/directory-context' +import ClientLayout from '@/shared/components/custom/client-layout' export const metadata: Metadata = {} @@ -12,12 +13,14 @@ interface LayoutProps extends PropsWithChildren { const Layout: FunctionComponent = ({ header, children }) => { return ( - -
- {header} - {children} -
-
+ + +
+ {header} + {children} +
+
+
) } diff --git a/src/features/document/components/swipeable-document-card/index.stories.tsx b/src/features/document/components/swipeable-document-card/index.stories.tsx index 9a8a2c40..f26fcaef 100644 --- a/src/features/document/components/swipeable-document-card/index.stories.tsx +++ b/src/features/document/components/swipeable-document-card/index.stories.tsx @@ -1,6 +1,9 @@ import type { Meta, StoryObj } from '@storybook/react' import SwipeableDocumentCard from '.' import { DirectoryProvider } from '../../contexts/directory-context' +import { QueryClient, QueryClientProvider } from '@tanstack/react-query' + +const queryClient = new QueryClient() const meta: Meta = { title: 'document/SwipeableDocumentCard', @@ -13,7 +16,7 @@ const meta: Meta = { argTypes: { createType: { control: 'radio', - options: ['write', 'file', 'notion'], + options: ['TEXT', 'FILE', 'NOTION'], description: '노트의 타입, 직접 작성 / 파일 첨부 / 노션 연동을 의미', }, title: { control: 'text', description: '노트의 제목' }, @@ -25,9 +28,11 @@ const meta: Meta = { }, decorators: [ (Story) => ( - - - + + + + + ), ], } diff --git a/src/shared/components/custom/client-layout/index.tsx b/src/shared/components/custom/client-layout/index.tsx new file mode 100644 index 00000000..6dd75922 --- /dev/null +++ b/src/shared/components/custom/client-layout/index.tsx @@ -0,0 +1,13 @@ +'use client' + +import { getQueryClient } from '@/shared/lib/tanstack-query/client' +import { QueryClientProvider } from '@tanstack/react-query' +import { useMemo } from 'react' + +const ClientLayout = ({ children }: { children: React.ReactNode }) => { + const queryClient = useMemo(() => getQueryClient(), []) + + return {children} +} + +export default ClientLayout From ff88b00921c8d3b9679692ef72bc0b06f57a8d2e Mon Sep 17 00:00:00 2001 From: "nageuna922@gmail.com" Date: Fri, 22 Nov 2024 15:47:47 +0900 Subject: [PATCH 03/13] fix: merge and fix error --- .../document/(create)/@header/default.tsx | 2 +- .../document/(create)/file/layout.tsx | 3 +- .../(routes)/document/(create)/file/page.tsx | 4 +- .../document/(create)/notion/page.tsx | 2 +- .../(routes)/document/(create)/ui/header.tsx | 2 +- .../document/(main)/@header/default.tsx | 23 ++-- .../document/(main)/index.stories.tsx | 9 +- src/app/(routes)/document/(main)/layout.tsx | 12 +-- .../document/[id]/modify/@header/default.tsx | 8 +- .../(routes)/document/[id]/modify/layout.tsx | 2 +- src/app/(routes)/main/index.stories.tsx | 9 +- src/app/(routes)/main/page.tsx | 6 +- .../directory-menu-dots/index.stories.tsx | 2 +- .../components/directory-menu-dots/index.tsx | 6 +- .../directory-select-drawer/index.stories.tsx | 0 .../directory-select-drawer/index.tsx | 100 ++++++++++++++++++ .../directory/contexts/directory-context.tsx | 2 +- .../document/components/add-document-menu.tsx | 4 +- .../animate-buttons/index.stories.tsx | 8 +- .../components/animate-buttons/index.tsx | 4 +- .../document/components/document-list.tsx | 4 +- .../swipeable-document-card/index.stories.tsx | 6 +- .../swipeable-document-card/index.tsx | 4 +- ...ctory-context.tsx => document-context.tsx} | 21 ++-- src/features/editor/index.tsx | 59 ----------- .../components/edit-cancel-dialog.tsx | 0 .../components/title-input.tsx | 0 .../components/visual-editor.tsx | 0 .../context/edit-document-context.tsx | 0 .../{editor => modify}/libs/extensions.ts | 0 .../styles/remirror-custom.css | 0 src/features/pages/modify-document.tsx | 6 +- 32 files changed, 179 insertions(+), 129 deletions(-) rename src/features/{document => directory}/components/directory-menu-dots/index.stories.tsx (89%) rename src/features/{document => directory}/components/directory-menu-dots/index.tsx (93%) rename src/features/{document => directory}/components/directory-select-drawer/index.stories.tsx (100%) create mode 100644 src/features/directory/components/directory-select-drawer/index.tsx rename src/features/document/contexts/{directory-context.tsx => document-context.tsx} (69%) delete mode 100644 src/features/editor/index.tsx rename src/features/{document => modify}/components/edit-cancel-dialog.tsx (100%) rename src/features/{editor => modify}/components/title-input.tsx (100%) rename src/features/{editor => modify}/components/visual-editor.tsx (100%) rename src/features/{editor => modify}/context/edit-document-context.tsx (100%) rename src/features/{editor => modify}/libs/extensions.ts (100%) rename src/features/{editor => modify}/styles/remirror-custom.css (100%) 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..e703c929 100644 --- a/src/app/(routes)/document/(main)/@header/default.tsx +++ b/src/app/(routes)/document/(main)/@header/default.tsx @@ -5,18 +5,19 @@ 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 { isSelectMode, setIsSelectMode } = useDocumentContext() const [isDrawerOpen, setIsDrawerOpen] = useState(false) return ( @@ -75,7 +76,8 @@ interface Props { } const DirectorySelectDrawer = ({ isDrawerOpen, setIsDrawerOpen, directories }: Props) => { - const { selectedDirectoryId, setButtonHidden, setSelectedDirectoryId } = useDirectoryContext() + const { selectedDirectoryId, selectDirectoryId } = useDirectoryContext() + const { setButtonHidden } = useDocumentContext() useEffect(() => { if (isDrawerOpen) { @@ -88,6 +90,11 @@ const DirectorySelectDrawer = ({ isDrawerOpen, setIsDrawerOpen, directories }: P 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 ( <> @@ -95,7 +102,7 @@ const DirectorySelectDrawer = ({ isDrawerOpen, setIsDrawerOpen, directories }: P
- + - + ) } diff --git a/src/features/document/components/directory-menu-dots/index.stories.tsx b/src/features/directory/components/directory-menu-dots/index.stories.tsx similarity index 89% rename from src/features/document/components/directory-menu-dots/index.stories.tsx rename to src/features/directory/components/directory-menu-dots/index.stories.tsx index 1f4876e7..3008b4db 100644 --- a/src/features/document/components/directory-menu-dots/index.stories.tsx +++ b/src/features/directory/components/directory-menu-dots/index.stories.tsx @@ -1,6 +1,6 @@ import { Meta, StoryObj } from '@storybook/react' import DirectoryMenuDots from '.' -import { DirectoryProvider } from '../../contexts/directory-context' +import { DirectoryProvider } from '../../../document/contexts/document-context' const meta = { title: 'document/DirectoryMenuDots', diff --git a/src/features/document/components/directory-menu-dots/index.tsx b/src/features/directory/components/directory-menu-dots/index.tsx similarity index 93% rename from src/features/document/components/directory-menu-dots/index.tsx rename to src/features/directory/components/directory-menu-dots/index.tsx index 2055c224..5339ffef 100644 --- a/src/features/document/components/directory-menu-dots/index.tsx +++ b/src/features/directory/components/directory-menu-dots/index.tsx @@ -8,12 +8,12 @@ import { DropdownMenuTrigger, } from '@/shared/components/ui/dropdown-menu' import Text from '@/shared/components/ui/text' -import { useDirectoryContext } from '../../contexts/directory-context' import DirectoryDialog from '@/features/quiz/components/directory-dialog' -import SetDirectoryNameDialog from '../../../directory/components/set-directory-name-dialog' +import SetDirectoryNameDialog from '../set-directory-name-dialog' +import { useDocumentContext } from '../../../document/contexts/document-context' const DirectoryMenuDots = () => { - const { setIsSelectMode } = useDirectoryContext() + const { setIsSelectMode } = useDocumentContext() return ( diff --git a/src/features/document/components/directory-select-drawer/index.stories.tsx b/src/features/directory/components/directory-select-drawer/index.stories.tsx similarity index 100% rename from src/features/document/components/directory-select-drawer/index.stories.tsx rename to src/features/directory/components/directory-select-drawer/index.stories.tsx diff --git a/src/features/directory/components/directory-select-drawer/index.tsx b/src/features/directory/components/directory-select-drawer/index.tsx new file mode 100644 index 00000000..4035dfbc --- /dev/null +++ b/src/features/directory/components/directory-select-drawer/index.tsx @@ -0,0 +1,100 @@ +/* eslint-disable @typescript-eslint/no-unused-vars */ +'use client' + +import Icon from '@/shared/components/custom/icon' +import { + Drawer, + DrawerClose, + DrawerContent, + DrawerTitle, + DrawerTrigger, +} from '@/shared/components/ui/drawer' +import Text from '@/shared/components/ui/text' +import { cn } from '@/shared/lib/utils' +import { useState } from 'react' + +// MoveDocumentDrawer 컴포넌트 +const DirectorySelectDrawer = () => { + const [selectedDirectoryId, setSelectedDirectoryId] = useState('0') + + // 목데이터 + const directoryList = [ + { + id: '0', + directoryName: '📊 전공 공부', + documentCount: 3, + }, + { + id: '1', + directoryName: '📊 전공 공부', + documentCount: 12, + }, + { + id: '2', + directoryName: '📊 전공 공부', + documentCount: 15, + }, + ] + + return ( + + + + + + +
+ 폴더 선택 + + + +
+ +
+
+ + + 전체 노트 + + + 노트 30개 + + +
+ {/* 폴더 개수만큼 렌더링 */} + {directoryList.map((directory) => ( + + ))} +
+
+ +
+
+
+ ) +} + +export default DirectorySelectDrawer diff --git a/src/features/directory/contexts/directory-context.tsx b/src/features/directory/contexts/directory-context.tsx index d742aed9..425c535e 100644 --- a/src/features/directory/contexts/directory-context.tsx +++ b/src/features/directory/contexts/directory-context.tsx @@ -8,7 +8,7 @@ interface DirectoryContextValues { selectedDirectory: Directory.Item | null selectedDirectoryId: number | null - selectDirectoryId: (id: number) => void + selectDirectoryId: (id: number | null) => void } const DirectoryContext = createContext(null) diff --git a/src/features/document/components/add-document-menu.tsx b/src/features/document/components/add-document-menu.tsx index 4f7d03ba..58631277 100644 --- a/src/features/document/components/add-document-menu.tsx +++ b/src/features/document/components/add-document-menu.tsx @@ -4,10 +4,10 @@ import Text from '@/shared/components/ui/text' import DimmedBackground from './dimmed-background' import AnimatedButtons from './animate-buttons' import { cn } from '@/shared/lib/utils' -import { useDirectoryContext } from '../contexts/directory-context' +import { useDocumentContext } from '../contexts/document-context' const AddDocumentMenu = () => { - const { isExpandedBtns } = useDirectoryContext() + const { isExpandedBtns } = useDocumentContext() return (
{ - const { setIsExpandedBtns } = useDirectoryContext() + const { setIsExpandedBtns } = useDocumentContext() useEffect(() => { setIsExpandedBtns(isExpandedBtns) @@ -30,13 +30,13 @@ const meta = { }, decorators: [ (Story, context) => ( - +
-
+ ), ], } satisfies Meta diff --git a/src/features/document/components/animate-buttons/index.tsx b/src/features/document/components/animate-buttons/index.tsx index 3dbc4ab6..fff98166 100644 --- a/src/features/document/components/animate-buttons/index.tsx +++ b/src/features/document/components/animate-buttons/index.tsx @@ -5,10 +5,10 @@ import { Button, ButtonProps } from '@/shared/components/ui/button' import Icon, { IconProps } from '@/shared/components/custom/icon' import { useEffect, useState } from 'react' import { cn } from '@/shared/lib/utils' -import { useDirectoryContext } from '../../contexts/directory-context' import Text from '@/shared/components/ui/text' import { useRouter } from 'next/navigation' import { addDocumentButtons } from '../../config' +import { useDocumentContext } from '../../contexts/document-context' type Custom = number | 'plus' | 'cancel' @@ -16,7 +16,7 @@ type Custom = number | 'plus' | 'cancel' const AnimatedButtons = () => { const router = useRouter() const [isFirstRender, setIsFirstRender] = useState(true) - const { buttonHidden, isExpandedBtns, setIsExpandedBtns } = useDirectoryContext() + const { buttonHidden, isExpandedBtns, setIsExpandedBtns } = useDocumentContext() useEffect(() => { setIsFirstRender(false) diff --git a/src/features/document/components/document-list.tsx b/src/features/document/components/document-list.tsx index 6455ca26..4c8dbcba 100644 --- a/src/features/document/components/document-list.tsx +++ b/src/features/document/components/document-list.tsx @@ -2,12 +2,12 @@ import { PropsWithChildren, useEffect } from 'react' import Icon from '@/shared/components/custom/icon' -import { useDirectoryContext } from '../contexts/directory-context' import usePreviousPath from '@/shared/hooks/use-previous-path' +import { useDocumentContext } from '../contexts/document-context' const DocumentList = ({ children }: PropsWithChildren) => { const { getPreviousPath } = usePreviousPath() - const { isSelectMode, setIsExpandedBtns } = useDirectoryContext() + const { isSelectMode, setIsExpandedBtns } = useDocumentContext() // 메인 페이지에서 '첫 노트 추가하기' 클릭 시 활성화된 상태로 노출 useEffect(() => { diff --git a/src/features/document/components/swipeable-document-card/index.stories.tsx b/src/features/document/components/swipeable-document-card/index.stories.tsx index f26fcaef..986249c2 100644 --- a/src/features/document/components/swipeable-document-card/index.stories.tsx +++ b/src/features/document/components/swipeable-document-card/index.stories.tsx @@ -1,7 +1,7 @@ import type { Meta, StoryObj } from '@storybook/react' import SwipeableDocumentCard from '.' -import { DirectoryProvider } from '../../contexts/directory-context' import { QueryClient, QueryClientProvider } from '@tanstack/react-query' +import { DocumentProvider } from '../../contexts/document-context' const queryClient = new QueryClient() @@ -29,9 +29,9 @@ const meta: Meta = { decorators: [ (Story) => ( - + - + ), ], diff --git a/src/features/document/components/swipeable-document-card/index.tsx b/src/features/document/components/swipeable-document-card/index.tsx index 85829f7f..24ea826c 100644 --- a/src/features/document/components/swipeable-document-card/index.tsx +++ b/src/features/document/components/swipeable-document-card/index.tsx @@ -10,9 +10,9 @@ import DocumentTypeIcon from '@/features/document/components/document-type-icon' import Tag from '@/shared/components/ui/tag' import { useRouter } from 'next/navigation' import MoveDocumentDrawer from '@/features/document/components/move-document-drawer' -import { useDirectoryContext } from '../../contexts/directory-context' import DeleteDocumentDialog from '../delete-document-dialog' import usePreviousPath from '@/shared/hooks/use-previous-path' +import { useDocumentContext } from '../../contexts/document-context' interface DocumentProps { id: number @@ -37,7 +37,7 @@ const SwipeableDocumentCard = ({ className, reviewCount, }: DocumentProps) => { - const { isSelectMode, checkDoc } = useDirectoryContext() + const { isSelectMode, checkDoc } = useDocumentContext() const [isSwiped, setIsSwiped] = useState(false) const [isDragging, setIsDragging] = useState(false) const x = useMotionValue(0) diff --git a/src/features/document/contexts/directory-context.tsx b/src/features/document/contexts/document-context.tsx similarity index 69% rename from src/features/document/contexts/directory-context.tsx rename to src/features/document/contexts/document-context.tsx index aa3a4879..1d6a5d36 100644 --- a/src/features/document/contexts/directory-context.tsx +++ b/src/features/document/contexts/document-context.tsx @@ -4,11 +4,9 @@ import { useGetDocuments } from '@/requests/document/hooks' import { useCheckList, UseCheckListReturn } from '@/shared/hooks/use-check-list' import { PropsWithChildren, createContext, useContext, useMemo, useState } from 'react' -interface DirectoryContextValues { +interface DocumentContextValues { buttonHidden: boolean setButtonHidden: (value: boolean) => void - selectedDirectoryId: number | null - setSelectedDirectoryId: (id: number | null) => void isSelectMode: boolean setIsSelectMode: (value: boolean) => void isExpandedBtns: boolean @@ -16,7 +14,7 @@ interface DirectoryContextValues { checkDoc: UseCheckListReturn<{ id: number; checked: boolean }> } -const DirectoryContext = createContext(null) +const DocumentContext = createContext(null) interface InitialValues { isSelectMode?: boolean @@ -24,11 +22,10 @@ interface InitialValues { isExpandedBtns?: boolean } -export function DirectoryProvider({ +export function DocumentProvider({ initialValues, children, }: PropsWithChildren & { initialValues?: InitialValues }) { - const [selectedDirectoryId, setSelectedDirectoryId] = useState(null) const [isSelectMode, setIsSelectMode] = useState(initialValues?.isSelectMode ?? false) const [buttonHidden, setButtonHidden] = useState(initialValues?.buttonHidden ?? false) const [isExpandedBtns, setIsExpandedBtns] = useState(initialValues?.isExpandedBtns ?? false) @@ -41,8 +38,6 @@ export function DirectoryProvider({ const values = useMemo( () => ({ - selectedDirectoryId, - setSelectedDirectoryId, isSelectMode, setIsSelectMode, buttonHidden, @@ -52,8 +47,6 @@ export function DirectoryProvider({ checkDoc, }), [ - selectedDirectoryId, - setSelectedDirectoryId, isSelectMode, setIsSelectMode, buttonHidden, @@ -64,14 +57,14 @@ export function DirectoryProvider({ ] ) - return {children} + return {children} } -export const useDirectoryContext = () => { - const values = useContext(DirectoryContext) +export const useDocumentContext = () => { + const values = useContext(DocumentContext) if (values == null) { - throw new Error('DirectoryProvider 내에서 사용해주세요.') + throw new Error('DocumentProvider 내에서 사용해주세요.') } return values diff --git a/src/features/editor/index.tsx b/src/features/editor/index.tsx deleted file mode 100644 index 9f6353fe..00000000 --- a/src/features/editor/index.tsx +++ /dev/null @@ -1,59 +0,0 @@ -import TitleInput from './components/title-input' -import { EditDocumentProvider } from './context/edit-document-context' -import dynamic from 'next/dynamic' -import Icon from '@/shared/components/custom/icon' -import Text from '@/shared/components/ui/text' -import Loading from '@/shared/components/custom/loading' -import FixedBottom from '@/shared/components/custom/fixed-bottom' -import NewQuizDrawer from '../quiz/components/new-quiz-drawer' -import { Button } from '@/shared/components/ui/button' - -// Remirror가 브라우저 전용 라이브러리라 서버에서 렌더링될 때 오류 발생, 이를 해결하기 위해 dynamic import를 사용 -const VisualEditor = dynamic(() => import('./components/visual-editor'), { - ssr: false, - loading: () => , -}) - -const CreateWithEditor = () => { - return ( - <> - {/*
*/} - - -
- - -
-
- - - 최소 500자, 최대 15000자 입력 가능 - -
- - {0} / 15000 - -
- - - - - - 퀴즈 만들기 - - } - /> - -
-
- - ) -} - -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/modify-document.tsx b/src/features/pages/modify-document.tsx index 72b5bde6..93c96706 100644 --- a/src/features/pages/modify-document.tsx +++ b/src/features/pages/modify-document.tsx @@ -6,9 +6,9 @@ import { MAX_CHARACTERS, MIN_CHARACTERS } from '../document/config' import { useParams } from 'next/navigation' import { useGetDocumentDetail } from '@/requests/document/hooks' import Loading from '@/shared/components/custom/loading' -import TitleInput from '../editor/components/title-input' -import VisualEditor from '../editor/components/visual-editor' -import { useEditDocumentContext } from '../editor/context/edit-document-context' +import TitleInput from '../modify/components/title-input' +import VisualEditor from '../modify/components/visual-editor' +import { useEditDocumentContext } from '../modify/context/edit-document-context' const ModifyDocument = () => { const { id } = useParams() From 2c6c06be8ef0abe23dfa539639750e4e95792c7e Mon Sep 17 00:00:00 2001 From: "nageuna922@gmail.com" Date: Fri, 22 Nov 2024 16:58:09 +0900 Subject: [PATCH 04/13] =?UTF-8?q?feat:=20directory=20id=EC=97=90=20?= =?UTF-8?q?=EB=94=B0=EB=A5=B8=20documents=20=EA=B0=80=EC=A0=B8=EC=98=A4?= =?UTF-8?q?=EA=B8=B0=20+=20queries=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../document/(main)/@header/default.tsx | 14 +++++------ .../document/[id]/(main)/@header/default.tsx | 5 ++-- .../document/contexts/document-context.tsx | 6 +++-- .../document/screens/document-content.tsx | 5 ++-- src/features/pages/documents-in-directory.tsx | 24 +++++++++++++++---- src/features/pages/modify-document.tsx | 5 ++-- 6 files changed, 39 insertions(+), 20 deletions(-) diff --git a/src/app/(routes)/document/(main)/@header/default.tsx b/src/app/(routes)/document/(main)/@header/default.tsx index e703c929..f1886bf1 100644 --- a/src/app/(routes)/document/(main)/@header/default.tsx +++ b/src/app/(routes)/document/(main)/@header/default.tsx @@ -17,6 +17,7 @@ import { useDirectoryContext } from '@/features/directory/contexts/directory-con // Header 컴포넌트 const Header = () => { const { data } = useDirectories() + const { selectedDirectory } = useDirectoryContext() const { isSelectMode, setIsSelectMode } = useDocumentContext() const [isDrawerOpen, setIsDrawerOpen] = useState(false) @@ -34,7 +35,7 @@ const Header = () => { setIsSelectMode(false)} /> - 전공 공부 + {selectedDirectory?.name} 전체 선택 @@ -76,7 +77,7 @@ interface Props { } const DirectorySelectDrawer = ({ isDrawerOpen, setIsDrawerOpen, directories }: Props) => { - const { selectedDirectoryId, selectDirectoryId } = useDirectoryContext() + const { selectedDirectory, selectedDirectoryId, selectDirectoryId } = useDirectoryContext() const { setButtonHidden } = useDocumentContext() useEffect(() => { @@ -87,9 +88,6 @@ 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) @@ -101,8 +99,8 @@ const DirectorySelectDrawer = ({ isDrawerOpen, setIsDrawerOpen, directories }: P diff --git a/src/app/(routes)/document/[id]/(main)/@header/default.tsx b/src/app/(routes)/document/[id]/(main)/@header/default.tsx index f0e03603..5d4fb704 100644 --- a/src/app/(routes)/document/[id]/(main)/@header/default.tsx +++ b/src/app/(routes)/document/[id]/(main)/@header/default.tsx @@ -15,15 +15,16 @@ import Link from 'next/link' import { useParams, useRouter } from 'next/navigation' import usePreviousPath from '@/shared/hooks/use-previous-path' import GoBackButton from '@/shared/components/custom/go-back-button' -import { useGetDocumentDetail } from '@/requests/document/hooks' import { getRelativeTime } from '@/shared/utils/date' +import { useQuery } from '@tanstack/react-query' +import { queries } from '@/shared/lib/tanstack-query/query-keys' // Header 컴포넌트 const Header = () => { const router = useRouter() const { id } = useParams() const { getPreviousPath } = usePreviousPath({ getCustomPath: true }) - const { data } = useGetDocumentDetail(Number(id[0])) + const { data } = useQuery(queries.document.item(Number(id[0]))) const handleClickCancel = () => { const previousPath = getPreviousPath() diff --git a/src/features/document/contexts/document-context.tsx b/src/features/document/contexts/document-context.tsx index 1d6a5d36..3549e515 100644 --- a/src/features/document/contexts/document-context.tsx +++ b/src/features/document/contexts/document-context.tsx @@ -1,7 +1,8 @@ 'use client' -import { useGetDocuments } from '@/requests/document/hooks' import { useCheckList, UseCheckListReturn } from '@/shared/hooks/use-check-list' +import { queries } from '@/shared/lib/tanstack-query/query-keys' +import { useQuery } from '@tanstack/react-query' import { PropsWithChildren, createContext, useContext, useMemo, useState } from 'react' interface DocumentContextValues { @@ -30,7 +31,8 @@ export function DocumentProvider({ const [buttonHidden, setButtonHidden] = useState(initialValues?.buttonHidden ?? false) const [isExpandedBtns, setIsExpandedBtns] = useState(initialValues?.isExpandedBtns ?? false) - const { data } = useGetDocuments() + const { data } = useQuery(queries.document.list()) + const documentCheckList = data?.documents.map((document) => ({ id: document.id, checked: false })) ?? [] diff --git a/src/features/document/screens/document-content.tsx b/src/features/document/screens/document-content.tsx index 4155d16e..5f80467a 100644 --- a/src/features/document/screens/document-content.tsx +++ b/src/features/document/screens/document-content.tsx @@ -1,13 +1,14 @@ 'use client' -import { useGetDocumentDetail } from '@/requests/document/hooks' import Loading from '@/shared/components/custom/loading' import Text from '@/shared/components/ui/text' +import { queries } from '@/shared/lib/tanstack-query/query-keys' +import { useQuery } from '@tanstack/react-query' import { useParams } from 'next/navigation' const DocumentContent = () => { const { id } = useParams() - const { data, isPending } = useGetDocumentDetail(Number(id[0])) + const { data, isPending } = useQuery(queries.document.item(Number(id[0]))) return (
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) { From ce3bedeb1e438f8bc72d08246eaf6fb1db5d723d Mon Sep 17 00:00:00 2001 From: "nageuna922@gmail.com" Date: Fri, 22 Nov 2024 16:58:50 +0900 Subject: [PATCH 05/13] =?UTF-8?q?fix:=20=EB=B6=88=ED=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20=EC=BD=94=EB=93=9C=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/requests/document/hooks.ts | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) 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, - }) -} From 931bfe774a7430f42c4d0c6d1da6034451567ed2 Mon Sep 17 00:00:00 2001 From: "nageuna922@gmail.com" Date: Fri, 22 Nov 2024 17:17:27 +0900 Subject: [PATCH 06/13] fix: build error --- .../directory-menu-dots/index.stories.tsx | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/features/directory/components/directory-menu-dots/index.stories.tsx b/src/features/directory/components/directory-menu-dots/index.stories.tsx index 3008b4db..9b248179 100644 --- a/src/features/directory/components/directory-menu-dots/index.stories.tsx +++ b/src/features/directory/components/directory-menu-dots/index.stories.tsx @@ -1,6 +1,7 @@ import { Meta, StoryObj } from '@storybook/react' import DirectoryMenuDots from '.' -import { DirectoryProvider } from '../../../document/contexts/document-context' +import { DocumentProvider } from '@/features/document/contexts/document-context' +import ClientLayout from '@/shared/components/custom/client-layout' const meta = { title: 'document/DirectoryMenuDots', @@ -11,13 +12,15 @@ const meta = { }, decorators: [ (Story) => ( - -
-
- + + +
+
+ +
-
- + + ), ], } satisfies Meta From 39e074a47bf766e0f48cf906b70fc5ea9f2f3eeb Mon Sep 17 00:00:00 2001 From: "nageuna922@gmail.com" Date: Fri, 22 Nov 2024 17:24:04 +0900 Subject: [PATCH 07/13] fix: import --- .../directory-select-drawer/index.stories.tsx | 18 ---- .../directory-select-drawer/index.tsx | 54 +++++------ .../directory-select-drawer/index.tsx | 92 ------------------- 3 files changed, 23 insertions(+), 141 deletions(-) delete mode 100644 src/features/directory/components/directory-select-drawer/index.stories.tsx delete mode 100644 src/features/document/components/directory-select-drawer/index.tsx diff --git a/src/features/directory/components/directory-select-drawer/index.stories.tsx b/src/features/directory/components/directory-select-drawer/index.stories.tsx deleted file mode 100644 index e0bfbc02..00000000 --- a/src/features/directory/components/directory-select-drawer/index.stories.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import { Meta, StoryObj } from '@storybook/react' -import DirectorySelectDrawer from '.' - -const meta = { - title: 'document/DirectorySelectDrawer', - component: DirectorySelectDrawer, - tags: ['autodocs'], - parameters: { - layout: 'centered', - }, -} satisfies Meta - -export default meta -type Story = StoryObj - -export const Default: Story = { - args: {}, -} diff --git a/src/features/directory/components/directory-select-drawer/index.tsx b/src/features/directory/components/directory-select-drawer/index.tsx index 4035dfbc..faf53faa 100644 --- a/src/features/directory/components/directory-select-drawer/index.tsx +++ b/src/features/directory/components/directory-select-drawer/index.tsx @@ -1,6 +1,8 @@ /* eslint-disable @typescript-eslint/no-unused-vars */ 'use client' +import CreateDirectoryDialog from '@/features/directory/components/create-directory-dialog' +import { useDirectoryContext } from '@/features/directory/contexts/directory-context' import Icon from '@/shared/components/custom/icon' import { Drawer, @@ -13,34 +15,23 @@ import Text from '@/shared/components/ui/text' import { cn } from '@/shared/lib/utils' import { useState } from 'react' -// MoveDocumentDrawer 컴포넌트 const DirectorySelectDrawer = () => { - const [selectedDirectoryId, setSelectedDirectoryId] = useState('0') + const [open, setOpen] = useState(false) + const { directories, selectDirectoryId, selectedDirectoryId, selectedDirectory } = + useDirectoryContext() - // 목데이터 - const directoryList = [ - { - id: '0', - directoryName: '📊 전공 공부', - documentCount: 3, - }, - { - id: '1', - directoryName: '📊 전공 공부', - documentCount: 12, - }, - { - id: '2', - directoryName: '📊 전공 공부', - documentCount: 15, - }, - ] + const handleDirectorySelect = (id: number) => { + selectDirectoryId(id) + setOpen(false) + } + + const totalNotes = directories.reduce((acc, directory) => acc + directory.documentCount, 0) return ( - + @@ -64,13 +55,16 @@ const DirectorySelectDrawer = () => { 전체 노트 - 노트 30개 + 노트 {totalNotes}개
- {/* 폴더 개수만큼 렌더링 */} - {directoryList.map((directory) => ( -
- + + diff --git a/src/features/document/components/directory-select-drawer/index.tsx b/src/features/document/components/directory-select-drawer/index.tsx deleted file mode 100644 index faf53faa..00000000 --- a/src/features/document/components/directory-select-drawer/index.tsx +++ /dev/null @@ -1,92 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-vars */ -'use client' - -import CreateDirectoryDialog from '@/features/directory/components/create-directory-dialog' -import { useDirectoryContext } from '@/features/directory/contexts/directory-context' -import Icon from '@/shared/components/custom/icon' -import { - Drawer, - DrawerClose, - DrawerContent, - DrawerTitle, - DrawerTrigger, -} from '@/shared/components/ui/drawer' -import Text from '@/shared/components/ui/text' -import { cn } from '@/shared/lib/utils' -import { useState } from 'react' - -const DirectorySelectDrawer = () => { - const [open, setOpen] = useState(false) - const { directories, selectDirectoryId, selectedDirectoryId, selectedDirectory } = - useDirectoryContext() - - const handleDirectorySelect = (id: number) => { - selectDirectoryId(id) - setOpen(false) - } - - const totalNotes = directories.reduce((acc, directory) => acc + directory.documentCount, 0) - - return ( - - - - - - -
- 폴더 선택 - - - -
- -
-
- - - 전체 노트 - - - 노트 {totalNotes}개 - - -
- {directories.map((directory) => ( - - ))} -
-
- - -
-
-
- ) -} - -export default DirectorySelectDrawer From b36450bc165542753923c0a06a0bc6836054cd83 Mon Sep 17 00:00:00 2001 From: "nageuna922@gmail.com" Date: Fri, 22 Nov 2024 21:33:53 +0900 Subject: [PATCH 08/13] fix: storybook --- .storybook/{preview.ts => preview.tsx} | 8 ++++++++ .../(routes)/document/(main)/index.stories.tsx | 9 +++------ src/app/(routes)/main/index.stories.tsx | 9 +++------ .../directory-menu-dots/index.stories.tsx | 15 ++++++--------- .../components/custom/client-layout/index.tsx | 13 ------------- 5 files changed, 20 insertions(+), 34 deletions(-) rename .storybook/{preview.ts => preview.tsx} (66%) delete mode 100644 src/shared/components/custom/client-layout/index.tsx 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/(main)/index.stories.tsx b/src/app/(routes)/document/(main)/index.stories.tsx index bea02b50..1fd0f94d 100644 --- a/src/app/(routes)/document/(main)/index.stories.tsx +++ b/src/app/(routes)/document/(main)/index.stories.tsx @@ -2,7 +2,6 @@ import { Meta, StoryObj } from '@storybook/react' import Layout from './layout' import Header from './@header/default' import DirectoryPage from './page' -import ClientLayout from '@/shared/components/custom/client-layout' const meta = { title: 'Page/Directory', @@ -24,10 +23,8 @@ export default meta export const Default: StoryObj = { render: () => ( - - }> - - - + }> + + ), } diff --git a/src/app/(routes)/main/index.stories.tsx b/src/app/(routes)/main/index.stories.tsx index 4768494c..80518031 100644 --- a/src/app/(routes)/main/index.stories.tsx +++ b/src/app/(routes)/main/index.stories.tsx @@ -2,7 +2,6 @@ import { Meta, StoryObj } from '@storybook/react' import Header from './@header/default' import Home from './page' import Layout from './layout' -import ClientLayout from '@/shared/components/custom/client-layout' const meta = { title: 'Page/Main', @@ -26,10 +25,8 @@ type Story = StoryObj export const Default: Story = { render: () => ( - - }> - - - + }> + + ), } diff --git a/src/features/directory/components/directory-menu-dots/index.stories.tsx b/src/features/directory/components/directory-menu-dots/index.stories.tsx index 9b248179..afa3e27b 100644 --- a/src/features/directory/components/directory-menu-dots/index.stories.tsx +++ b/src/features/directory/components/directory-menu-dots/index.stories.tsx @@ -1,7 +1,6 @@ import { Meta, StoryObj } from '@storybook/react' import DirectoryMenuDots from '.' import { DocumentProvider } from '@/features/document/contexts/document-context' -import ClientLayout from '@/shared/components/custom/client-layout' const meta = { title: 'document/DirectoryMenuDots', @@ -12,15 +11,13 @@ const meta = { }, decorators: [ (Story) => ( - - -
-
- -
+ +
+
+
- - +
+
), ], } satisfies Meta diff --git a/src/shared/components/custom/client-layout/index.tsx b/src/shared/components/custom/client-layout/index.tsx deleted file mode 100644 index 6dd75922..00000000 --- a/src/shared/components/custom/client-layout/index.tsx +++ /dev/null @@ -1,13 +0,0 @@ -'use client' - -import { getQueryClient } from '@/shared/lib/tanstack-query/client' -import { QueryClientProvider } from '@tanstack/react-query' -import { useMemo } from 'react' - -const ClientLayout = ({ children }: { children: React.ReactNode }) => { - const queryClient = useMemo(() => getQueryClient(), []) - - return {children} -} - -export default ClientLayout From 30fa96ccfc6b05d18c816d08a061886aac6161e3 Mon Sep 17 00:00:00 2001 From: "nageuna922@gmail.com" Date: Fri, 22 Nov 2024 21:48:30 +0900 Subject: [PATCH 09/13] fix: expend buttons bug --- .../document/components/add-first-document/index.tsx | 8 ++++---- src/features/document/components/document-list.tsx | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/features/document/components/add-first-document/index.tsx b/src/features/document/components/add-first-document/index.tsx index 016726d3..8c1d152a 100644 --- a/src/features/document/components/add-first-document/index.tsx +++ b/src/features/document/components/add-first-document/index.tsx @@ -2,15 +2,15 @@ import Icon from '@/shared/components/custom/icon' import Text from '@/shared/components/ui/text' -import usePreviousPath from '@/shared/hooks/use-previous-path' import Link from 'next/link' const AddFirstDocument = ({ userName }: { userName: string }) => { - usePreviousPath() - return (
diff --git a/src/features/document/components/document-list.tsx b/src/features/document/components/document-list.tsx index 4c8dbcba..cc496e97 100644 --- a/src/features/document/components/document-list.tsx +++ b/src/features/document/components/document-list.tsx @@ -2,18 +2,18 @@ import { PropsWithChildren, useEffect } from 'react' import Icon from '@/shared/components/custom/icon' -import usePreviousPath from '@/shared/hooks/use-previous-path' import { useDocumentContext } from '../contexts/document-context' +import { useSearchParams } from 'next/navigation' const DocumentList = ({ children }: PropsWithChildren) => { - const { getPreviousPath } = usePreviousPath() + const searchParams = useSearchParams() + const ref = searchParams.get('ref') const { isSelectMode, setIsExpandedBtns } = useDocumentContext() // 메인 페이지에서 '첫 노트 추가하기' 클릭 시 활성화된 상태로 노출 useEffect(() => { - const previousPath = getPreviousPath() - if (previousPath === '/main') setIsExpandedBtns(true) - }, [getPreviousPath, setIsExpandedBtns]) + ref === 'add-first-document' && setIsExpandedBtns(true) + }, [ref, setIsExpandedBtns]) return ( <> From e103b95698980510691545e5db36143f15f1930e Mon Sep 17 00:00:00 2001 From: "nageuna922@gmail.com" Date: Sat, 23 Nov 2024 11:26:43 +0900 Subject: [PATCH 10/13] fix: document markdown debugging --- package-lock.json | 29 +++++++++++ package.json | 2 + .../document/[id]/(main)/@header/default.tsx | 6 +-- .../document/[id]/modify/@header/default.tsx | 4 +- .../components/document-detail-controller.tsx | 2 +- .../swipeable-document-card/index.tsx | 17 ++++++- .../document/screens/document-content.tsx | 51 ++++++++++++++++++- src/features/pages/documents-in-directory.tsx | 2 +- src/features/pages/modify-document.tsx | 2 +- src/types/document.d.ts | 2 + yarn.lock | 17 +++++++ 11 files changed, 123 insertions(+), 11 deletions(-) diff --git a/package-lock.json b/package-lock.json index 498e502b..e4468158 100644 --- a/package-lock.json +++ b/package-lock.json @@ -56,8 +56,10 @@ "react-syntax-highlighter": "^15.5.0", "recharts": "^2.12.7", "refractor": "^4.8.1", + "remark": "^15.0.1", "remark-gfm": "^4.0.0", "remirror": "^2.0.39", + "strip-markdown": "^6.0.0", "tailwind-merge": "^2.2.2", "tailwind-scrollbar-hide": "^1.1.7", "tailwindcss-animate": "^1.0.7", @@ -20273,6 +20275,21 @@ "node": ">= 0.10" } }, + "node_modules/remark": { + "version": "15.0.1", + "resolved": "https://registry.npmjs.org/remark/-/remark-15.0.1.tgz", + "integrity": "sha512-Eht5w30ruCXgFmxVUSlNWQ9iiimq07URKeFS3hNc8cUWy1llX4KDWfyEDZRycMc+znsN9Ux5/tJ/BFdgdOwA3A==", + "dependencies": { + "@types/mdast": "^4.0.0", + "remark-parse": "^11.0.0", + "remark-stringify": "^11.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/remark-gfm": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-4.0.0.tgz", @@ -21765,6 +21782,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/strip-markdown": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-markdown/-/strip-markdown-6.0.0.tgz", + "integrity": "sha512-mSa8FtUoX3ExJYDkjPUTC14xaBAn4Ik5GPQD45G5E2egAmeV3kHgVSTfIoSDggbF6Pk9stahVgqsLCNExv6jHw==", + "dependencies": { + "@types/mdast": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/style-loader": { "version": "3.3.4", "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-3.3.4.tgz", diff --git a/package.json b/package.json index b6c05d0e..b9c5f006 100644 --- a/package.json +++ b/package.json @@ -66,8 +66,10 @@ "react-syntax-highlighter": "^15.5.0", "recharts": "^2.12.7", "refractor": "^4.8.1", + "remark": "^15.0.1", "remark-gfm": "^4.0.0", "remirror": "^2.0.39", + "strip-markdown": "^6.0.0", "tailwind-merge": "^2.2.2", "tailwind-scrollbar-hide": "^1.1.7", "tailwindcss-animate": "^1.0.7", diff --git a/src/app/(routes)/document/[id]/(main)/@header/default.tsx b/src/app/(routes)/document/[id]/(main)/@header/default.tsx index 5d4fb704..323ee536 100644 --- a/src/app/(routes)/document/[id]/(main)/@header/default.tsx +++ b/src/app/(routes)/document/[id]/(main)/@header/default.tsx @@ -24,7 +24,7 @@ const Header = () => { const router = useRouter() const { id } = useParams() const { getPreviousPath } = usePreviousPath({ getCustomPath: true }) - const { data } = useQuery(queries.document.item(Number(id[0]))) + const { data } = useQuery(queries.document.item(Number(id))) const handleClickCancel = () => { const previousPath = getPreviousPath() @@ -58,7 +58,7 @@ const Header = () => { 130 - + {/* 노션일 경우 아래 아이콘 렌더링 */} @@ -149,7 +149,7 @@ const Header = () => { {/* data: 노트 제목, 문제 수, 글자 수, 마지막 수정 날짜 */}
-

{data?.name}

+

{data?.documentName}

{data?.totalQuizCount}문제 diff --git a/src/app/(routes)/document/[id]/modify/@header/default.tsx b/src/app/(routes)/document/[id]/modify/@header/default.tsx index f010bcc5..212e0ab4 100644 --- a/src/app/(routes)/document/[id]/modify/@header/default.tsx +++ b/src/app/(routes)/document/[id]/modify/@header/default.tsx @@ -22,11 +22,11 @@ const Header = () => { const file = new File([blob], `${title}.md`, { type: 'text/markdown' }) updateDocumentMutate( - { documentId: Number(id[0]), request: { name: title, file } }, + { documentId: Number(id), request: { name: title, file } }, { onSuccess: () => { toast({ description: '노트가 수정되었어요' }) - router.push(`/document/${id[0]}`) + router.push('/document/' + String(id)) }, } ) diff --git a/src/features/document/components/document-detail-controller.tsx b/src/features/document/components/document-detail-controller.tsx index 6cc2f3d8..142168f7 100644 --- a/src/features/document/components/document-detail-controller.tsx +++ b/src/features/document/components/document-detail-controller.tsx @@ -22,7 +22,7 @@ const DocumentDetailController = () => { {tabs.map((tab) => ( { + const result = unified() + .use(remarkParse) // 마크다운 파싱 + .use(stripMarkdown) // 문법 제거 + .use(remarkStringify) + .processSync(markdown) // 동기 처리 + + return String(result) // 결과 반환 + } + return (
{ @@ -122,8 +136,9 @@ const SwipeableDocumentCard = ({ typography="text1-regular" className="w-[calc(100%-55px)] truncate text-nowrap break-all text-text-sub" > - {content} + {getTextRemoveMarkdownSyntax(content)} + {quizCount}문제 diff --git a/src/features/document/screens/document-content.tsx b/src/features/document/screens/document-content.tsx index 5f80467a..1b027562 100644 --- a/src/features/document/screens/document-content.tsx +++ b/src/features/document/screens/document-content.tsx @@ -5,16 +5,63 @@ import Text from '@/shared/components/ui/text' import { queries } from '@/shared/lib/tanstack-query/query-keys' import { useQuery } from '@tanstack/react-query' import { useParams } from 'next/navigation' +import { ClassAttributes, HTMLAttributes } from 'react' +import Markdown, { ExtraProps } from 'react-markdown' +import SyntaxHighlighter from 'react-syntax-highlighter' +import { dracula } from 'react-syntax-highlighter/dist/esm/styles/prism' +import remarkGfm from 'remark-gfm' const DocumentContent = () => { const { id } = useParams() - const { data, isPending } = useQuery(queries.document.item(Number(id[0]))) + const { data, isPending } = useQuery(queries.document.item(Number(id))) + + const formattedContent = data?.content.replace(/\n/g, '\n\n') return (
- {isPending ? : data && {data.content}} + {isPending ? ( + + ) : ( + data && ( + + + {formattedContent} + + + ) + )}
) } export default DocumentContent + +const handleMarkDownCodeBlock = ( + props: ClassAttributes & HTMLAttributes & ExtraProps +) => { + // style, node, ref는 사용하지 않음 + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const { children, className, style, node, ref, ...rest } = props + const match = /language-(\w+)/.exec(className || '') + return match ? ( + + {String(children).replace(/\n$/, '')} + + ) : ( + + {children} + + ) +} + +const handleParagraph = (props: HTMLAttributes) => { + return ( + <> +

{props.children}

+
+ + ) +} diff --git a/src/features/pages/documents-in-directory.tsx b/src/features/pages/documents-in-directory.tsx index 171d89da..aa424c6a 100644 --- a/src/features/pages/documents-in-directory.tsx +++ b/src/features/pages/documents-in-directory.tsx @@ -58,7 +58,7 @@ const DocumentsInDirectory = () => { id={document.id} createType={document.documentType} title={document.name} - content={document.content.slice(0, 40)} + content={document.previewContent ?? ''} quizCount={document.totalQuizCount} characterCount={document.characterCount} directory={document.directory.name} diff --git a/src/features/pages/modify-document.tsx b/src/features/pages/modify-document.tsx index f40d827c..51cfc1e4 100644 --- a/src/features/pages/modify-document.tsx +++ b/src/features/pages/modify-document.tsx @@ -13,7 +13,7 @@ import { queries } from '@/shared/lib/tanstack-query/query-keys' const ModifyDocument = () => { const { id } = useParams() - const { data, isPending } = useQuery(queries.document.item(Number(id[0]))) + const { data, isPending } = useQuery(queries.document.item(Number(id))) const { editorMarkdownContent: content } = useEditDocumentContext() if (isPending) { diff --git a/src/types/document.d.ts b/src/types/document.d.ts index dfe18e3f..254ba7be 100644 --- a/src/types/document.d.ts +++ b/src/types/document.d.ts @@ -31,7 +31,9 @@ type DocumentItem = { id: number documentType: CreateType name: string + documentName?: string status: DocumentStatus + previewContent?: string content: string characterCount: number totalQuizCount: number diff --git a/yarn.lock b/yarn.lock index adc013a8..78dd9595 100644 --- a/yarn.lock +++ b/yarn.lock @@ -11069,6 +11069,16 @@ remark-stringify@^11.0.0: mdast-util-to-markdown "^2.0.0" unified "^11.0.0" +remark@^15.0.1: + version "15.0.1" + resolved "https://registry.npmjs.org/remark/-/remark-15.0.1.tgz" + integrity sha512-Eht5w30ruCXgFmxVUSlNWQ9iiimq07URKeFS3hNc8cUWy1llX4KDWfyEDZRycMc+znsN9Ux5/tJ/BFdgdOwA3A== + dependencies: + "@types/mdast" "^4.0.0" + remark-parse "^11.0.0" + remark-stringify "^11.0.0" + unified "^11.0.0" + remirror@^2.0.39, remirror@2.0.40: version "2.0.40" resolved "https://registry.npmjs.org/remirror/-/remirror-2.0.40.tgz" @@ -11810,6 +11820,13 @@ strip-json-comments@^3.1.1: resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== +strip-markdown@^6.0.0: + version "6.0.0" + resolved "https://registry.npmjs.org/strip-markdown/-/strip-markdown-6.0.0.tgz" + integrity sha512-mSa8FtUoX3ExJYDkjPUTC14xaBAn4Ik5GPQD45G5E2egAmeV3kHgVSTfIoSDggbF6Pk9stahVgqsLCNExv6jHw== + dependencies: + "@types/mdast" "^4.0.0" + style-loader@^3.3.1: version "3.3.4" resolved "https://registry.npmjs.org/style-loader/-/style-loader-3.3.4.tgz" From 08e9d0827cea15b4a39f9924d00224c8a349a47e Mon Sep 17 00:00:00 2001 From: "nageuna922@gmail.com" Date: Sat, 23 Nov 2024 12:02:06 +0900 Subject: [PATCH 11/13] refactor: document type --- .../document/[id]/(main)/@header/default.tsx | 2 +- .../components/document-type-icon.tsx | 2 +- .../swipeable-document-card/index.tsx | 2 +- src/features/pages/documents-in-directory.tsx | 2 +- src/features/pages/modify-document.tsx | 2 +- .../search/components/search-item/index.tsx | 2 +- src/types/document.d.ts | 29 +++++++++++++------ 7 files changed, 26 insertions(+), 15 deletions(-) diff --git a/src/app/(routes)/document/[id]/(main)/@header/default.tsx b/src/app/(routes)/document/[id]/(main)/@header/default.tsx index 323ee536..2158c6a7 100644 --- a/src/app/(routes)/document/[id]/(main)/@header/default.tsx +++ b/src/app/(routes)/document/[id]/(main)/@header/default.tsx @@ -132,7 +132,7 @@ const Header = () => { title="노트를 삭제할까요?" content={ - {data?.name} 노트와{' '} + {data?.documentName} 노트와{' '} {data?.totalQuizCount}개의 문제가{' '}
모두 삭제됩니다. diff --git a/src/features/document/components/document-type-icon.tsx b/src/features/document/components/document-type-icon.tsx index 622df959..9b0bede6 100644 --- a/src/features/document/components/document-type-icon.tsx +++ b/src/features/document/components/document-type-icon.tsx @@ -2,7 +2,7 @@ import Icon from '@/shared/components/custom/icon' import { cn } from '@/shared/lib/utils' interface Props { - type: Document.Item['documentType'] + type: Document.ListItem['documentType'] containerClassName: HTMLElement['className'] iconClassName: HTMLElement['className'] } diff --git a/src/features/document/components/swipeable-document-card/index.tsx b/src/features/document/components/swipeable-document-card/index.tsx index 09f95cc9..6fe7d390 100644 --- a/src/features/document/components/swipeable-document-card/index.tsx +++ b/src/features/document/components/swipeable-document-card/index.tsx @@ -20,7 +20,7 @@ import stripMarkdown from 'strip-markdown' interface DocumentProps { id: number - createType: Document.Item['documentType'] + createType: Document.ListItem['documentType'] title: string content: string quizCount: number diff --git a/src/features/pages/documents-in-directory.tsx b/src/features/pages/documents-in-directory.tsx index aa424c6a..65e942e7 100644 --- a/src/features/pages/documents-in-directory.tsx +++ b/src/features/pages/documents-in-directory.tsx @@ -62,7 +62,7 @@ const DocumentsInDirectory = () => { quizCount={document.totalQuizCount} characterCount={document.characterCount} directory={document.directory.name} - className={cn(idx === 9 && 'mb-[30px]')} + className={cn(idx === data.documents.length - 1 && 'mb-[30px]')} reviewCount={document.reviewNeededQuizCount} /> ))} diff --git a/src/features/pages/modify-document.tsx b/src/features/pages/modify-document.tsx index 51cfc1e4..56c00f5d 100644 --- a/src/features/pages/modify-document.tsx +++ b/src/features/pages/modify-document.tsx @@ -22,7 +22,7 @@ const ModifyDocument = () => { return ( <> - +
diff --git a/src/features/search/components/search-item/index.tsx b/src/features/search/components/search-item/index.tsx index 94512dcb..4df3cbec 100644 --- a/src/features/search/components/search-item/index.tsx +++ b/src/features/search/components/search-item/index.tsx @@ -5,7 +5,7 @@ import { cn } from '@/shared/lib/utils' import DocumentTypeIcon from '@/features/document/components/document-type-icon' interface Props { - createType: Document.Item['documentType'] + createType: Document.ListItem['documentType'] documentTitle: string matchingSentence: string resultType: 'document' | 'quiz' diff --git a/src/types/document.d.ts b/src/types/document.d.ts index 254ba7be..8b78d7b7 100644 --- a/src/types/document.d.ts +++ b/src/types/document.d.ts @@ -27,22 +27,32 @@ type Quiz = { quizType: QuizType } -type DocumentItem = { +type DocumentBase = { id: number documentType: CreateType - name: string - documentName?: string status: DocumentStatus - previewContent?: string - content: string - characterCount: number totalQuizCount: number - updatedAt: string + characterCount: number directory: Directory + updatedAt: string +} + +type DocumentDetailItem = DocumentBase & { + documentName: string + content: string quizzes: Quiz[] +} + +type DocumentListItem = DocumentBase & { + name: string + documentType: CreateType + previewContent: string + createdAt: string reviewNeededQuizCount: number } +type DocumentItem = DocumentDetailItem | DocumentListItem + type SearchedDocument = { documentId: number documentName: string @@ -159,8 +169,9 @@ interface SearchDocumentsResponse { } declare namespace Document { - type Item = DocumentItem - type List = DocumentItem[] + type Item = DocumentDetailItem + type List = DocumentListItem[] + type ListItem = DocumentListItem type Status = DocumentStatus type Sort = SortOption From d11d9210178cdfd89787ece6b90d424098c107aa Mon Sep 17 00:00:00 2001 From: "nageuna922@gmail.com" Date: Sat, 23 Nov 2024 16:08:51 +0900 Subject: [PATCH 12/13] =?UTF-8?q?refactor:=20=ED=83=80=EC=9E=85=EB=AA=85?= =?UTF-8?q?=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../document/components/document-type-icon.tsx | 2 +- .../components/swipeable-document-card/index.tsx | 2 +- .../search/components/search-item/index.tsx | 2 +- src/requests/document/index.tsx | 13 ++++++++----- src/types/document.d.ts | 4 ++-- 5 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/features/document/components/document-type-icon.tsx b/src/features/document/components/document-type-icon.tsx index 9b0bede6..bb865344 100644 --- a/src/features/document/components/document-type-icon.tsx +++ b/src/features/document/components/document-type-icon.tsx @@ -2,7 +2,7 @@ import Icon from '@/shared/components/custom/icon' import { cn } from '@/shared/lib/utils' interface Props { - type: Document.ListItem['documentType'] + type: Document.ItemInList['documentType'] containerClassName: HTMLElement['className'] iconClassName: HTMLElement['className'] } diff --git a/src/features/document/components/swipeable-document-card/index.tsx b/src/features/document/components/swipeable-document-card/index.tsx index 6fe7d390..3742ee0d 100644 --- a/src/features/document/components/swipeable-document-card/index.tsx +++ b/src/features/document/components/swipeable-document-card/index.tsx @@ -20,7 +20,7 @@ import stripMarkdown from 'strip-markdown' interface DocumentProps { id: number - createType: Document.ListItem['documentType'] + createType: Document.ItemInList['documentType'] title: string content: string quizCount: number diff --git a/src/features/search/components/search-item/index.tsx b/src/features/search/components/search-item/index.tsx index 4df3cbec..bf7e6594 100644 --- a/src/features/search/components/search-item/index.tsx +++ b/src/features/search/components/search-item/index.tsx @@ -5,7 +5,7 @@ import { cn } from '@/shared/lib/utils' import DocumentTypeIcon from '@/features/document/components/document-type-icon' interface Props { - createType: Document.ListItem['documentType'] + createType: Document.ItemInList['documentType'] documentTitle: string matchingSentence: string resultType: 'document' | 'quiz' diff --git a/src/requests/document/index.tsx b/src/requests/document/index.tsx index 81f4f3f4..f8804142 100644 --- a/src/requests/document/index.tsx +++ b/src/requests/document/index.tsx @@ -40,11 +40,14 @@ export const fetchDocumentDetail = async (documentId: number) => { try { const session = await auth() - const { data } = await http.get(API_ENDPOINTS.DOCUMENT.GET.BY_ID(documentId), { - headers: { - Authorization: `Bearer ${session?.user.accessToken}`, - }, - }) + const { data } = await http.get( + API_ENDPOINTS.DOCUMENT.GET.BY_ID(documentId), + { + headers: { + Authorization: `Bearer ${session?.user.accessToken}`, + }, + } + ) return data } catch (error: unknown) { console.error(error) diff --git a/src/types/document.d.ts b/src/types/document.d.ts index cbcd2909..20fba261 100644 --- a/src/types/document.d.ts +++ b/src/types/document.d.ts @@ -167,9 +167,9 @@ interface SearchDocumentsResponse { } declare namespace Document { - type Item = DocumentDetailItem + type DetailItem = DocumentDetailItem + type ItemInList = DocumentListItem type List = DocumentListItem[] - type ListItem = DocumentListItem type Status = DocumentStatus type Sort = SortOption From 03d019df9f653d653e15dbb19c3d36c1edb6325b Mon Sep 17 00:00:00 2001 From: "nageuna922@gmail.com" Date: Sat, 23 Nov 2024 17:05:45 +0900 Subject: [PATCH 13/13] fix: modify document --- .../document/[id]/modify/@header/default.tsx | 17 +++++++++--- .../(routes)/document/[id]/modify/layout.tsx | 11 +++++--- .../modify/components/visual-editor.tsx | 2 +- src/requests/document/hooks.ts | 4 +-- src/requests/document/index.tsx | 27 ++++++++++++------- 5 files changed, 41 insertions(+), 20 deletions(-) diff --git a/src/app/(routes)/document/[id]/modify/@header/default.tsx b/src/app/(routes)/document/[id]/modify/@header/default.tsx index 212e0ab4..f7df524b 100644 --- a/src/app/(routes)/document/[id]/modify/@header/default.tsx +++ b/src/app/(routes)/document/[id]/modify/@header/default.tsx @@ -15,14 +15,20 @@ const Header = () => { const { documentTitle: title, editorMarkdownContent: content } = useEditDocumentContext() const { selectedDirectory } = useDirectoryContext() - const handleClickSave = () => { - if (title.trim().length === 0 || content.trim().length === 0) return + const handleClickSave = (id: number, title: string, content: string) => { + // eslint-disable-next-line no-console + console.log(title, content) + + if (title.trim().length === 0 || content.trim().length === 0) { + alert('제목과 내용을 입력해주세요') + return + } const blob = new Blob([content], { type: 'text/markdown' }) const file = new File([blob], `${title}.md`, { type: 'text/markdown' }) updateDocumentMutate( - { documentId: Number(id), request: { name: title, file } }, + { documentId: id, requestBody: { name: title, file } }, { onSuccess: () => { toast({ description: '노트가 수정되었어요' }) @@ -46,7 +52,10 @@ const Header = () => { {selectedDirectory?.emoji} {selectedDirectory?.name}
-
diff --git a/src/app/(routes)/document/[id]/modify/layout.tsx b/src/app/(routes)/document/[id]/modify/layout.tsx index 1c77c5a5..08b68b0d 100644 --- a/src/app/(routes)/document/[id]/modify/layout.tsx +++ b/src/app/(routes)/document/[id]/modify/layout.tsx @@ -1,6 +1,7 @@ import { FunctionComponent, PropsWithChildren } from 'react' import type { Metadata } from 'next' import { EditDocumentProvider } from '@/features/modify/context/edit-document-context' +import { DirectoryProvider } from '@/features/directory/contexts/directory-context' export const metadata: Metadata = {} @@ -10,10 +11,12 @@ interface LayoutProps extends PropsWithChildren { const Layout: FunctionComponent = ({ header, children }) => { return ( - - {header} - {children} - + + + {header} + {children} + + ) } diff --git a/src/features/modify/components/visual-editor.tsx b/src/features/modify/components/visual-editor.tsx index e89754dc..9c96df70 100644 --- a/src/features/modify/components/visual-editor.tsx +++ b/src/features/modify/components/visual-editor.tsx @@ -39,7 +39,7 @@ export default function VisualEditor({ prevContent }: VisualEditorProps) { css` &.ProseMirror { padding: 16px 20px; - margin-bottom: 100px; + padding-bottom: 100px; width: 100%; /* min-width: 100vw; */ max-width: 430px; diff --git a/src/requests/document/hooks.ts b/src/requests/document/hooks.ts index 36f6505b..74cd5036 100644 --- a/src/requests/document/hooks.ts +++ b/src/requests/document/hooks.ts @@ -18,7 +18,7 @@ export const useUpdateDocument = () => { const { data: session } = useSession() return useMutation({ - mutationFn: (params: { documentId: number; request: Document.Request.UpdateContent }) => - updateDocument(params.documentId, params.request, session?.user.accessToken || ''), + mutationFn: (params: { documentId: number; requestBody: Document.Request.UpdateContent }) => + updateDocument(params.documentId, params.requestBody, session?.user.accessToken || ''), }) } diff --git a/src/requests/document/index.tsx b/src/requests/document/index.tsx index f8804142..2a662acc 100644 --- a/src/requests/document/index.tsx +++ b/src/requests/document/index.tsx @@ -57,18 +57,27 @@ export const fetchDocumentDetail = async (documentId: number) => { export const updateDocument = async ( documentId: number, - request: Document.Request.UpdateContent, + requestBody: Document.Request.UpdateContent, accessToken: string ) => { - const params = { request } - try { - await http.patch(API_ENDPOINTS.DOCUMENT.PATCH.UPDATE_CONTENT(documentId), null, { - params, - headers: { - Authorization: `Bearer ${accessToken}`, - }, - }) + const formData = new FormData() + formData.append('name', requestBody.name) + formData.append('file', requestBody.file) + + const response = await http.patch( + API_ENDPOINTS.DOCUMENT.PATCH.UPDATE_CONTENT(documentId), + formData, + { + headers: { + Authorization: `Bearer ${accessToken}`, + 'Content-Type': 'multipart/form-data', + }, + } + ) + + // eslint-disable-next-line no-console + console.log(response) // 디버깅용 } catch (error: unknown) { console.error(error) throw error