From 370dbd454c96397fe372ecf4485d8bcc3db1deaa Mon Sep 17 00:00:00 2001 From: hanbinchoi Date: Sat, 23 Sep 2023 05:58:06 +0900 Subject: [PATCH 001/117] =?UTF-8?q?[FE}=20=E2=99=BB=EF=B8=8F=20leaf=20?= =?UTF-8?q?=EA=B3=B5=EC=9C=A0=20=ED=8E=98=EC=9D=B4=EC=A7=80=20=EC=A0=91?= =?UTF-8?q?=EA=B7=BC=20=EA=B6=8C=ED=95=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/app/leaf/[userId]/[leafId]/page.tsx | 8 -------- client/src/app/leafs/[id]/page.tsx | 9 --------- 2 files changed, 17 deletions(-) diff --git a/client/src/app/leaf/[userId]/[leafId]/page.tsx b/client/src/app/leaf/[userId]/[leafId]/page.tsx index 20eb0a32..34c359e6 100644 --- a/client/src/app/leaf/[userId]/[leafId]/page.tsx +++ b/client/src/app/leaf/[userId]/[leafId]/page.tsx @@ -37,8 +37,6 @@ export default function Leaf({ params }: LeafProps) { const pathLeafId = params.leafId; const pathUserId = params.userId; - const router = useRouter(); - const userId = useUserStore((state) => state.userId); const isOwner = userId === pathUserId; @@ -67,12 +65,6 @@ export default function Leaf({ params }: LeafProps) { const isEmpty = !diaries || diaries?.length === 0; - useEffectOnce(() => { - if (!userId) { - router.push('/signin'); - } - }); - useEffect(() => { if (results) { setLeaf(results[0].data); diff --git a/client/src/app/leafs/[id]/page.tsx b/client/src/app/leafs/[id]/page.tsx index 9a63349e..93060c0c 100644 --- a/client/src/app/leafs/[id]/page.tsx +++ b/client/src/app/leafs/[id]/page.tsx @@ -38,14 +38,6 @@ export default function Leafs({ params }: LeafsProps) { const { userId } = useUserStore(); const { isModalOpen, modalCategory } = useLeafsStore(); - const router = useRouter(); - - useEffectOnce(() => { - if (!userId) { - router.push('/signin'); - } - }); - const { data: leafs, isLoading, @@ -53,7 +45,6 @@ export default function Leafs({ params }: LeafsProps) { } = useQuery({ queryKey: ['leafs'], queryFn: () => getLeafsByUserId(pathUserId), - enabled: !!userId, }); const { data: user } = useQuery({ From f53979d3f5eb69c99c8fcf48223e913ae85eb519 Mon Sep 17 00:00:00 2001 From: hanbinchoi Date: Sat, 23 Sep 2023 06:20:03 +0900 Subject: [PATCH 002/117] =?UTF-8?q?[FE}=20=E2=99=BB=EF=B8=8F=20Leafs=20=20?= =?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=A7=80=20=EB=A6=AC=ED=8C=A9=ED=86=A0?= =?UTF-8?q?=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/app/leafs/[id]/page.tsx | 110 ++++++++++-------- client/src/components/common/ShareButton.tsx | 1 + client/src/components/leafs/AddLeafButton.tsx | 2 +- .../src/components/leafs/LeafDeleteModal.tsx | 10 +- 4 files changed, 67 insertions(+), 56 deletions(-) diff --git a/client/src/app/leafs/[id]/page.tsx b/client/src/app/leafs/[id]/page.tsx index 93060c0c..5f936684 100644 --- a/client/src/app/leafs/[id]/page.tsx +++ b/client/src/app/leafs/[id]/page.tsx @@ -1,8 +1,8 @@ 'use client'; -import { useRouter } from 'next/navigation'; +import { useEffect, useState } from 'react'; -import { useQuery } from '@tanstack/react-query'; +import { useQueries } from '@tanstack/react-query'; import { motion } from 'framer-motion'; import { getLeafsByUserId } from '@/api/leaf'; @@ -11,8 +11,6 @@ import { getUserInfo } from '@/api/history'; import useLeafsStore from '@/stores/leafsStore'; import useUserStore from '@/stores/userStore'; -import useEffectOnce from '@/hooks/useEffectOnce'; - import Leaf from '@/components/common/Leaf'; import PageTitle from '@/components/common/PageTitle'; import Screws from '@/components/common/Screws'; @@ -25,6 +23,7 @@ import ShareModal from '@/components/common/ShareModal'; import Footer from '@/components/common/Footer'; import { LeafsDataInfo } from '@/types/data'; +import { UserData } from '@/types/common'; import { MOUNT_ANIMATION_VALUES } from '@/constants/values'; @@ -38,19 +37,33 @@ export default function Leafs({ params }: LeafsProps) { const { userId } = useUserStore(); const { isModalOpen, modalCategory } = useLeafsStore(); - const { - data: leafs, - isLoading, - isError, - } = useQuery({ - queryKey: ['leafs'], - queryFn: () => getLeafsByUserId(pathUserId), + const isOwner = userId === pathUserId; + + const [leafs, setLeafs] = useState(); + const [user, setUser] = useState(); + + const results = useQueries({ + queries: [ + { + queryKey: ['leafs'], + queryFn: () => getLeafsByUserId(pathUserId), + }, + { + queryKey: ['user'], + queryFn: () => getUserInfo(pathUserId), + }, + ], }); - const { data: user } = useQuery({ - queryKey: ['user', pathUserId], - queryFn: () => getUserInfo(pathUserId), - }); + const isLoading = results.some((result) => result.isLoading); + const isError = results.some((result) => result.isError); + + useEffect(() => { + if (results) { + setLeafs(results[0].data); + setUser(results[1].data?.data); + } + }, [results]); return ( <> @@ -60,8 +73,6 @@ export default function Leafs({ params }: LeafsProps) { animate="animate" className="flex justify-center items-center h-auto min-h-full pt-[120px] pb-[343px]">
- {leafs && } - {isLoading && (
@@ -74,43 +85,46 @@ export default function Leafs({ params }: LeafsProps) {
)} {leafs && user && ( -
- -
- {userId === pathUserId && } - {leafs?.map((leaf) => { - const { leafId, leafName, leafImageUrl } = leaf; - - return ( - - ); - })} -
- {leafs && ( -
- + <> + +
+ +
+ {isOwner && } + {leafs?.map((leaf) => { + const { leafId, leafName, leafImageUrl } = leaf; + + return ( + + ); + })}
- )} -
+ {leafs && ( +
+ +
+ )} +
+ )}
{isModalOpen && (modalCategory === 'deleteLeaf' ? ( - + ) : ( ))} diff --git a/client/src/components/common/ShareButton.tsx b/client/src/components/common/ShareButton.tsx index ab96c288..5b696ddc 100644 --- a/client/src/components/common/ShareButton.tsx +++ b/client/src/components/common/ShareButton.tsx @@ -26,6 +26,7 @@ export default function ShareButton({ }: ShareButtonProps) { const url = usePathname(); + /** 사용된 장소가 식물 카드 관련 페이지 인지 */ const isLeafs = location === 'leaf' || location === 'leafs'; const { modalOpen: leafsModalOpen, setModalCategory: setLeafsModalCategory } = diff --git a/client/src/components/leafs/AddLeafButton.tsx b/client/src/components/leafs/AddLeafButton.tsx index e7f61c88..1f651fc6 100644 --- a/client/src/components/leafs/AddLeafButton.tsx +++ b/client/src/components/leafs/AddLeafButton.tsx @@ -6,7 +6,7 @@ import Link from 'next/link'; import { motion } from 'framer-motion'; interface AddLeafButtonProps { - userId: number; + userId: string; } export default function AddLeafButton({ userId }: AddLeafButtonProps) { diff --git a/client/src/components/leafs/LeafDeleteModal.tsx b/client/src/components/leafs/LeafDeleteModal.tsx index f7d26c6c..d840002e 100644 --- a/client/src/components/leafs/LeafDeleteModal.tsx +++ b/client/src/components/leafs/LeafDeleteModal.tsx @@ -7,15 +7,11 @@ import ModalPortal from '../common/ModalPortal'; import Modal from '../common/Modal'; interface LeafDeleteModalProps { - pathUserId: string; - userId: string | null; + isOwner: boolean; } -export default function LeafDeleteModal({ - userId, - pathUserId, -}: LeafDeleteModalProps) { - if (userId !== pathUserId) return null; +export default function LeafDeleteModal({ isOwner }: LeafDeleteModalProps) { + if (!isOwner) return null; const { mutate } = useDeleteLeafMutation(); From ea807faa8c5412cfb517363887cd0578eb2ed98e Mon Sep 17 00:00:00 2001 From: hanbinchoi Date: Sat, 23 Sep 2023 06:31:09 +0900 Subject: [PATCH 003/117] =?UTF-8?q?[FE]=20=E2=99=BB=EF=B8=8F=20leaf=20?= =?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=A7=80=20=EB=A6=AC=ED=8C=A9=ED=86=A0?= =?UTF-8?q?=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/app/leaf/[userId]/[leafId]/page.tsx | 59 +++++++++---------- client/src/components/leaf/Diary.tsx | 4 +- client/src/components/leaf/EmptyDiary.tsx | 2 +- 3 files changed, 32 insertions(+), 33 deletions(-) diff --git a/client/src/app/leaf/[userId]/[leafId]/page.tsx b/client/src/app/leaf/[userId]/[leafId]/page.tsx index 34c359e6..be987aca 100644 --- a/client/src/app/leaf/[userId]/[leafId]/page.tsx +++ b/client/src/app/leaf/[userId]/[leafId]/page.tsx @@ -1,7 +1,6 @@ 'use client'; import { useEffect, useState } from 'react'; -import { useRouter } from 'next/navigation'; import { useQueries } from '@tanstack/react-query'; import { motion } from 'framer-motion'; @@ -11,8 +10,6 @@ import { getDiariesByLeafAndUserId, getLeafByLeafId } from '@/api/leaf'; import useLeafStore from '@/stores/leafStore'; import useUserStore from '@/stores/userStore'; -import useEffectOnce from '@/hooks/useEffectOnce'; - import Screws from '@/components/common/Screws'; import LeafInfo from '@/components/leaf/LeafInfo'; import LeafDiary from '@/components/leaf/LeafDiary'; @@ -88,13 +85,6 @@ export default function Leaf({ params }: LeafProps) { animate="animate" className="flex justify-center items-center h-auto min-h-full pt-[120px] pb-[343px]">
- {leaf && ( - - )}
{isLoading ? ( @@ -107,31 +97,38 @@ export default function Leaf({ params }: LeafProps) {
) : ( leaf && ( -
- + - - {isEmpty ? ( - + - ) : ( - - )} -
+ + {isEmpty ? ( + + ) : ( + + )} +
+ ) )}
diff --git a/client/src/components/leaf/Diary.tsx b/client/src/components/leaf/Diary.tsx index 35a3f3c5..cf29107a 100644 --- a/client/src/components/leaf/Diary.tsx +++ b/client/src/components/leaf/Diary.tsx @@ -29,6 +29,8 @@ export default function Diary({ const userId = useUserStore((state) => state.userId); + const isOwner = pathUserId === userId; + const { modalOpen, setModalCategory, setTargetDiary } = useLeafStore(); const startDay = new Date(createdAt); @@ -53,7 +55,7 @@ export default function Diary({ {month + '/' + day}
- {pathUserId === userId && ( + {isOwner && (
Date: Sat, 23 Sep 2023 06:45:55 +0900 Subject: [PATCH 004/117] =?UTF-8?q?[FE]=20=E2=99=BB=EF=B8=8F=20Leafs=20?= =?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=A7=80=202=EC=B0=A8=20=EB=A6=AC=ED=8C=A9?= =?UTF-8?q?=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/app/leafs/[id]/page.tsx | 45 ++++--------------- client/src/components/common/Leaf.tsx | 7 ++- .../src/components/leafs/LeafDeleteModal.tsx | 6 +-- client/src/hooks/useGetLeafsPageQueries.ts | 36 +++++++++++++++ client/src/stores/leafsStore.ts | 5 +++ 5 files changed, 55 insertions(+), 44 deletions(-) create mode 100644 client/src/hooks/useGetLeafsPageQueries.ts diff --git a/client/src/app/leafs/[id]/page.tsx b/client/src/app/leafs/[id]/page.tsx index 5f936684..4f27f8fe 100644 --- a/client/src/app/leafs/[id]/page.tsx +++ b/client/src/app/leafs/[id]/page.tsx @@ -1,13 +1,7 @@ 'use client'; -import { useEffect, useState } from 'react'; - -import { useQueries } from '@tanstack/react-query'; import { motion } from 'framer-motion'; -import { getLeafsByUserId } from '@/api/leaf'; -import { getUserInfo } from '@/api/history'; - import useLeafsStore from '@/stores/leafsStore'; import useUserStore from '@/stores/userStore'; @@ -22,10 +16,9 @@ import ShareButton from '@/components/common/ShareButton'; import ShareModal from '@/components/common/ShareModal'; import Footer from '@/components/common/Footer'; -import { LeafsDataInfo } from '@/types/data'; -import { UserData } from '@/types/common'; - import { MOUNT_ANIMATION_VALUES } from '@/constants/values'; +import useEffectOnce from '@/hooks/useEffectOnce'; +import useGetLeafsPageQueries from '@/hooks/useGetLeafsPageQueries'; interface LeafsProps { params: { id: string }; @@ -35,35 +28,15 @@ export default function Leafs({ params }: LeafsProps) { const pathUserId = params.id; const { userId } = useUserStore(); - const { isModalOpen, modalCategory } = useLeafsStore(); - - const isOwner = userId === pathUserId; + const { isModalOpen, modalCategory, isOwner, setIsOwner } = useLeafsStore(); - const [leafs, setLeafs] = useState(); - const [user, setUser] = useState(); - - const results = useQueries({ - queries: [ - { - queryKey: ['leafs'], - queryFn: () => getLeafsByUserId(pathUserId), - }, - { - queryKey: ['user'], - queryFn: () => getUserInfo(pathUserId), - }, - ], + useEffectOnce(() => { + if (userId === pathUserId) setIsOwner(true); }); - const isLoading = results.some((result) => result.isLoading); - const isError = results.some((result) => result.isError); - - useEffect(() => { - if (results) { - setLeafs(results[0].data); - setUser(results[1].data?.data); - } - }, [results]); + const { leafs, user, isLoading, isError } = useGetLeafsPageQueries({ + pathUserId, + }); return ( <> @@ -124,7 +97,7 @@ export default function Leafs({ params }: LeafsProps) { {isModalOpen && (modalCategory === 'deleteLeaf' ? ( - + ) : ( ))} diff --git a/client/src/components/common/Leaf.tsx b/client/src/components/common/Leaf.tsx index df912153..22175e9e 100644 --- a/client/src/components/common/Leaf.tsx +++ b/client/src/components/common/Leaf.tsx @@ -32,9 +32,8 @@ export default function Leaf({ }: LeafProps) { const router = useRouter(); - const { modalOpen, setDeleteTargetId, setModalCategory } = useLeafsStore(); - - const userId = useUserStore((state) => state.userId); + const { modalOpen, setDeleteTargetId, setModalCategory, isOwner } = + useLeafsStore(); const handleLeafClick = (event: React.MouseEvent) => { if (onClick) { @@ -83,7 +82,7 @@ export default function Leaf({
) : null} - {location === 'leaf' && pathUserId === userId && ( + {location === 'leaf' && isOwner && (
getLeafsByUserId(pathUserId), + }, + { + queryKey: ['user'], + queryFn: () => getUserInfo(pathUserId), + }, + ], + }); + + const leafs: LeafsDataInfo[] = results[0].data; + const user: UserData = results[1].data?.data; + + const isLoading = results.some((results) => results.isLoading); + const isError = results.some((results) => results.isError); + + return { leafs, user, isLoading, isError }; +} diff --git a/client/src/stores/leafsStore.ts b/client/src/stores/leafsStore.ts index 155d4068..7478c9df 100644 --- a/client/src/stores/leafsStore.ts +++ b/client/src/stores/leafsStore.ts @@ -4,23 +4,28 @@ interface LeafsState { isModalOpen: boolean; deleteTargetLeafsId: string | null; modalCategory: 'deleteLeaf' | 'share' | null; + isOwner: boolean; modalOpen: () => void; modalClose: () => void; + setDeleteTargetId: (deleteTargetId: string) => void; setModalCategory: (modalCategory: 'deleteLeaf' | 'share' | null) => void; + setIsOwner: (isOwner: boolean) => void; } const useLeafsStore = create((set) => ({ isModalOpen: false, deleteTargetLeafsId: null, modalCategory: null, + isOwner: false, modalOpen: () => set(() => ({ isModalOpen: true })), modalClose: () => set(() => ({ isModalOpen: false })), setDeleteTargetId: (deleteTargetLeafsId) => set(() => ({ deleteTargetLeafsId })), setModalCategory: (modalCategory) => set(() => ({ modalCategory })), + setIsOwner: (isOwner) => set(() => ({ isOwner })), })); export default useLeafsStore; From 00a7743dbc546c1ef617e0b30b5d89edc4d9fcbc Mon Sep 17 00:00:00 2001 From: hanbinchoi Date: Sat, 23 Sep 2023 07:26:34 +0900 Subject: [PATCH 005/117] =?UTF-8?q?[FE]=20=E2=99=BB=EF=B8=8F=20Leaf=20?= =?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=A7=80=202=EC=B0=A8=20=EB=A6=AC=ED=8C=A9?= =?UTF-8?q?=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/app/leaf/[userId]/[leafId]/page.tsx | 64 ++++--------------- client/src/app/leafs/[id]/page.tsx | 3 +- client/src/components/leaf/Diary.tsx | 15 +---- .../src/components/leaf/DiaryDeleteModal.tsx | 19 ++---- client/src/components/leaf/EmptyDiary.tsx | 8 +-- client/src/components/leaf/LeafDiary.tsx | 4 +- client/src/components/leaf/LeafInfo.tsx | 9 +-- client/src/hooks/useDeleteDiaryMutaion.ts | 18 ++++++ client/src/hooks/useGetLeafPageQueries.ts | 50 +++++++++++++++ client/src/stores/leafStore.ts | 7 ++ 10 files changed, 102 insertions(+), 95 deletions(-) create mode 100644 client/src/hooks/useDeleteDiaryMutaion.ts create mode 100644 client/src/hooks/useGetLeafPageQueries.ts diff --git a/client/src/app/leaf/[userId]/[leafId]/page.tsx b/client/src/app/leaf/[userId]/[leafId]/page.tsx index be987aca..a5384e07 100644 --- a/client/src/app/leaf/[userId]/[leafId]/page.tsx +++ b/client/src/app/leaf/[userId]/[leafId]/page.tsx @@ -1,15 +1,13 @@ 'use client'; -import { useEffect, useState } from 'react'; - -import { useQueries } from '@tanstack/react-query'; import { motion } from 'framer-motion'; -import { getDiariesByLeafAndUserId, getLeafByLeafId } from '@/api/leaf'; - import useLeafStore from '@/stores/leafStore'; import useUserStore from '@/stores/userStore'; +import useEffectOnce from '@/hooks/useEffectOnce'; +import useGetLeafPageQueries from '@/hooks/useGetLeafPageQueries'; + import Screws from '@/components/common/Screws'; import LeafInfo from '@/components/leaf/LeafInfo'; import LeafDiary from '@/components/leaf/LeafDiary'; @@ -22,7 +20,7 @@ import ErrorMessage from '@/components/common/ErrorMessage'; import ShareModal from '@/components/common/ShareModal'; import Footer from '@/components/common/Footer'; -import { DiaryDataInfo, LeafDataInfo } from '@/types/data'; +import { DiaryDataInfo } from '@/types/data'; import { MOUNT_ANIMATION_VALUES } from '@/constants/values'; @@ -36,46 +34,17 @@ export default function Leaf({ params }: LeafProps) { const userId = useUserStore((state) => state.userId); - const isOwner = userId === pathUserId; + const { modalCategory, isModalOpen, isOwner, setIsOwner } = useLeafStore(); - const { modalCategory, isModalOpen, setStartDay, setLastDiaryDay } = - useLeafStore(); - - const [leaf, setLeaf] = useState(); - const [diaries, setDiaries] = useState(); - - const results = useQueries({ - queries: [ - { - queryKey: ['leaf', pathLeafId], - queryFn: () => getLeafByLeafId(pathLeafId), - }, - { - queryKey: ['diaries', pathLeafId], - queryFn: () => getDiariesByLeafAndUserId(pathLeafId, pathUserId), - }, - ], + useEffectOnce(() => { + if (userId === pathUserId) return setIsOwner(true); + return setIsOwner(false); }); - const isLoading = results.some((result) => result.isLoading); - const isError = results.some((result) => result.isError); - - const isEmpty = !diaries || diaries?.length === 0; - - useEffect(() => { - if (results) { - setLeaf(results[0].data); - setDiaries(results[1].data); - } - }, [results]); - - useEffect(() => { - if (leaf?.createdAt) setStartDay(new Date(leaf.createdAt)); - }, [leaf]); - - useEffect(() => { - if (!isEmpty) setLastDiaryDay(new Date(diaries[0].createdAt)); - }, [diaries]); + const { leaf, diaries, isLoading, isError, isEmpty } = useGetLeafPageQueries({ + pathUserId, + pathLeafId, + }); return ( <> @@ -105,27 +74,20 @@ export default function Leaf({ params }: LeafProps) { />
{isEmpty ? ( ) : ( - + )}
diff --git a/client/src/app/leafs/[id]/page.tsx b/client/src/app/leafs/[id]/page.tsx index 4f27f8fe..0c15a284 100644 --- a/client/src/app/leafs/[id]/page.tsx +++ b/client/src/app/leafs/[id]/page.tsx @@ -31,7 +31,8 @@ export default function Leafs({ params }: LeafsProps) { const { isModalOpen, modalCategory, isOwner, setIsOwner } = useLeafsStore(); useEffectOnce(() => { - if (userId === pathUserId) setIsOwner(true); + if (userId === pathUserId) return setIsOwner(true); + return setIsOwner(false); }); const { leafs, user, isLoading, isError } = useGetLeafsPageQueries({ diff --git a/client/src/components/leaf/Diary.tsx b/client/src/components/leaf/Diary.tsx index cf29107a..74c2de23 100644 --- a/client/src/components/leaf/Diary.tsx +++ b/client/src/components/leaf/Diary.tsx @@ -1,24 +1,18 @@ import Image from 'next/image'; import useLeafStore from '@/stores/leafStore'; -import useUserStore from '@/stores/userStore'; import ControlButton from '../common/ControlButton'; import { DiaryDataInfo } from '@/types/data'; -interface DiaryProps extends DiaryDataInfo { - pathUserId: string; -} - export default function Diary({ journalId, createdAt, imageUrl, content, title, - pathUserId, -}: DiaryProps) { +}: DiaryDataInfo) { const diary = { journalId, createdAt, @@ -27,11 +21,8 @@ export default function Diary({ title, }; - const userId = useUserStore((state) => state.userId); - - const isOwner = pathUserId === userId; - - const { modalOpen, setModalCategory, setTargetDiary } = useLeafStore(); + const { modalOpen, setModalCategory, setTargetDiary, isOwner } = + useLeafStore(); const startDay = new Date(createdAt); const [month, day] = [startDay.getMonth() + 1, startDay.getDate()]; diff --git a/client/src/components/leaf/DiaryDeleteModal.tsx b/client/src/components/leaf/DiaryDeleteModal.tsx index a517cc70..f696ef03 100644 --- a/client/src/components/leaf/DiaryDeleteModal.tsx +++ b/client/src/components/leaf/DiaryDeleteModal.tsx @@ -1,10 +1,7 @@ -import { useMutation, useQueryClient } from '@tanstack/react-query'; - -import { deleteDiary } from '@/api/leaf'; - import useLeafStore from '@/stores/leafStore'; import CommonButton from '../common/CommonButton'; +import useDeleteDiaryMutation from '@/hooks/useDeleteDiaryMutaion'; interface DiaryDeleteModalProps { deleteTargetId?: string | null; @@ -19,23 +16,17 @@ export function DiaryDeleteModal({ }: DiaryDeleteModalProps) { if (!deleteTargetId) return null; - const queryClient = useQueryClient(); - - const { mutate } = useMutation({ - mutationFn: () => deleteDiary({ diaryId: deleteTargetId, userId }), - onSuccess: () => { - // 성공 후 새로운 쿼리를 다시 가져올 수 있도록 캐시 무효화 - queryClient.invalidateQueries(['diaries', leafId]); - }, - }); + const { mutate: deleteDiary } = useDeleteDiaryMutation(leafId); const modalClose = useLeafStore((state) => state.modalClose); const handleCancelModal = () => modalClose(); + const handleDeleteDiary = () => { modalClose(); - mutate(); + deleteDiary({ diaryId: deleteTargetId, userId }); }; + return (

diff --git a/client/src/components/leaf/EmptyDiary.tsx b/client/src/components/leaf/EmptyDiary.tsx index d5ef0e57..a5538958 100644 --- a/client/src/components/leaf/EmptyDiary.tsx +++ b/client/src/components/leaf/EmptyDiary.tsx @@ -12,24 +12,18 @@ import { INFOMATION_TEXT } from '@/constants/contents'; import { DefaultProps } from '@/types/common'; interface EmptyDiaryProps extends DefaultProps { - pathUserId: string; - userId: string | null; - info: 'diary' | 'board' | 'likes' | 'comment'; addInfo?: 'addDiary' | 'addBoard'; } export default function EmptyDiary({ - pathUserId, - userId, info, addInfo, className, }: EmptyDiaryProps) { - const isOwner = pathUserId === userId; const router = useRouter(); - const { modalOpen, setModalCategory } = useLeafStore(); + const { modalOpen, setModalCategory, isOwner } = useLeafStore(); const addDiary = () => { modalOpen(); diff --git a/client/src/components/leaf/LeafDiary.tsx b/client/src/components/leaf/LeafDiary.tsx index 1ea30fb3..13d9cb1a 100644 --- a/client/src/components/leaf/LeafDiary.tsx +++ b/client/src/components/leaf/LeafDiary.tsx @@ -4,10 +4,9 @@ import { DiaryDataInfo } from '@/types/data'; interface LeafDiaryProps { diaries: DiaryDataInfo[]; - pathUserId: string; } -export default function LeafDiary({ diaries, pathUserId }: LeafDiaryProps) { +export default function LeafDiary({ diaries }: LeafDiaryProps) { return (

    {diaries.map((diary) => ( @@ -18,7 +17,6 @@ export default function LeafDiary({ diaries, pathUserId }: LeafDiaryProps) { imageUrl={diary.imageUrl} content={diary.content} title={diary.title} - pathUserId={pathUserId} /> ))}
diff --git a/client/src/components/leaf/LeafInfo.tsx b/client/src/components/leaf/LeafInfo.tsx index e222655a..f8675f88 100644 --- a/client/src/components/leaf/LeafInfo.tsx +++ b/client/src/components/leaf/LeafInfo.tsx @@ -11,8 +11,6 @@ interface LeafInfoProps { leafName: string; imageUrl: string; content: string; - createdAt: string; - userId: string | null; } export default function LeafInfo({ @@ -20,14 +18,11 @@ export default function LeafInfo({ imageUrl, content, pathUserId, - userId, }: LeafInfoProps) { const router = useRouter(); - const setModalCategory = useLeafStore((state) => state.setModalCategory); - const modalOpen = useLeafStore((state) => state.modalOpen); - - const isOwner = userId === pathUserId; + const { isOwner, setModalCategory } = useLeafStore(); + const { modalOpen } = useLeafStore(); const navigateToGarden = () => router.push(`/garden/${pathUserId}`); diff --git a/client/src/hooks/useDeleteDiaryMutaion.ts b/client/src/hooks/useDeleteDiaryMutaion.ts new file mode 100644 index 00000000..dd189e6d --- /dev/null +++ b/client/src/hooks/useDeleteDiaryMutaion.ts @@ -0,0 +1,18 @@ +import { useMutation, useQueryClient } from '@tanstack/react-query'; + +import { deleteDiary } from '@/api/leaf'; + +const useDeleteDiaryMutation = (leafId: string) => { + const queryClient = useQueryClient(); + + const { mutate } = useMutation({ + mutationFn: deleteDiary, + onSuccess: () => { + queryClient.invalidateQueries(['diaries', leafId]); + }, + }); + + return { mutate }; +}; + +export default useDeleteDiaryMutation; diff --git a/client/src/hooks/useGetLeafPageQueries.ts b/client/src/hooks/useGetLeafPageQueries.ts new file mode 100644 index 00000000..07527256 --- /dev/null +++ b/client/src/hooks/useGetLeafPageQueries.ts @@ -0,0 +1,50 @@ +import { useEffect } from 'react'; + +import { useQueries } from '@tanstack/react-query'; + +import { getDiariesByLeafAndUserId, getLeafByLeafId } from '@/api/leaf'; + +import useLeafStore from '@/stores/leafStore'; + +import { DiaryDataInfo, LeafDataInfo } from '@/types/data'; + +interface useGetLeafPageQueries { + pathUserId: string; + pathLeafId: string; +} + +export default function useGetLeafPageQueries({ + pathUserId, + pathLeafId, +}: useGetLeafPageQueries) { + const { setStartDay, setLastDiaryDay } = useLeafStore(); + const results = useQueries({ + queries: [ + { + queryKey: ['leaf', pathLeafId], + queryFn: () => getLeafByLeafId(pathLeafId), + }, + { + queryKey: ['diaries', pathLeafId], + queryFn: () => getDiariesByLeafAndUserId(pathLeafId, pathUserId), + }, + ], + }); + const leaf: LeafDataInfo = results[0].data; + const diaries: DiaryDataInfo[] = results[1].data; + + const isLoading = results.some((results) => results.isLoading); + const isError = results.some((results) => results.isError); + + const isEmpty = !diaries || diaries?.length === 0; + + useEffect(() => { + if (leaf?.createdAt) setStartDay(new Date(leaf.createdAt)); + }, [leaf]); + + useEffect(() => { + if (!isEmpty) setLastDiaryDay(new Date(diaries[0].createdAt)); + }, [diaries]); + + return { leaf, diaries, isLoading, isError, isEmpty }; +} diff --git a/client/src/stores/leafStore.ts b/client/src/stores/leafStore.ts index a3731d4a..dc1694fd 100644 --- a/client/src/stores/leafStore.ts +++ b/client/src/stores/leafStore.ts @@ -7,6 +7,7 @@ interface LeafState { targetDiary: DiaryDataInfo | null; lastDiaryDay: Date | null; startDay: Date | null; + isOwner: boolean; modalOpen: () => void; modalClose: () => void; @@ -17,6 +18,7 @@ interface LeafState { setTargetDiary: (diary: DiaryDataInfo) => void; setLastDiaryDay: (day: Date) => void; setStartDay: (day: Date) => void; + setIsOwner: (isOwner: boolean) => void; } const useLeafStore = create((set) => ({ @@ -25,6 +27,7 @@ const useLeafStore = create((set) => ({ targetDiary: null, lastDiaryDay: null, startDay: null, + isOwner: false, modalOpen: () => set(() => ({ isModalOpen: true })), modalClose: () => set(() => ({ isModalOpen: false })), @@ -33,6 +36,10 @@ const useLeafStore = create((set) => ({ setTargetDiary: (diary) => set(() => ({ targetDiary: diary })), setLastDiaryDay: (day) => set(() => ({ lastDiaryDay: day })), setStartDay: (day) => set(() => ({ startDay: day })), + setIsOwner: (isOwner) => + set(() => ({ + isOwner, + })), })); export default useLeafStore; From 216c4c7f3f33ffe3c4d5bb61fd32d73a7820c436 Mon Sep 17 00:00:00 2001 From: hanbinchoi Date: Sat, 14 Oct 2023 01:22:05 +0900 Subject: [PATCH 006/117] =?UTF-8?q?[FE]=20=E2=99=BB=EF=B8=8F=20Leafs=20?= =?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=A7=80=20=EB=A6=AC=ED=8C=A9=ED=86=A0?= =?UTF-8?q?=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/app/leaf/[userId]/[leafId]/page.tsx | 2 +- client/src/app/leafs/[id]/page.tsx | 42 ++++++++++--------- client/src/components/common/SeoHead.tsx | 28 ++++++------- client/src/components/leafs/index.ts | 4 ++ client/src/stores/leafsStore.ts | 11 ----- client/src/stores/modalStore.ts | 10 +++-- 6 files changed, 48 insertions(+), 49 deletions(-) create mode 100644 client/src/components/leafs/index.ts diff --git a/client/src/app/leaf/[userId]/[leafId]/page.tsx b/client/src/app/leaf/[userId]/[leafId]/page.tsx index a5384e07..dc17cbc9 100644 --- a/client/src/app/leaf/[userId]/[leafId]/page.tsx +++ b/client/src/app/leaf/[userId]/[leafId]/page.tsx @@ -8,7 +8,6 @@ import useUserStore from '@/stores/userStore'; import useEffectOnce from '@/hooks/useEffectOnce'; import useGetLeafPageQueries from '@/hooks/useGetLeafPageQueries'; -import Screws from '@/components/common/Screws'; import LeafInfo from '@/components/leaf/LeafInfo'; import LeafDiary from '@/components/leaf/LeafDiary'; import LeafDateInfo from '@/components/leaf/LeafDateInfo'; @@ -19,6 +18,7 @@ import LoadingNotice from '@/components/common/LoadingNotice'; import ErrorMessage from '@/components/common/ErrorMessage'; import ShareModal from '@/components/common/ShareModal'; import Footer from '@/components/common/Footer'; +import Screws from '@/components/common/Screws'; import { DiaryDataInfo } from '@/types/data'; diff --git a/client/src/app/leafs/[id]/page.tsx b/client/src/app/leafs/[id]/page.tsx index 0c15a284..347eb16d 100644 --- a/client/src/app/leafs/[id]/page.tsx +++ b/client/src/app/leafs/[id]/page.tsx @@ -5,20 +5,23 @@ import { motion } from 'framer-motion'; import useLeafsStore from '@/stores/leafsStore'; import useUserStore from '@/stores/userStore'; -import Leaf from '@/components/common/Leaf'; -import PageTitle from '@/components/common/PageTitle'; -import Screws from '@/components/common/Screws'; -import AddLeafButton from '@/components/leafs/AddLeafButton'; -import LeafDeleteModal from '@/components/leafs/LeafDeleteModal'; -import LoadingNotice from '@/components/common/LoadingNotice'; -import ErrorMessage from '@/components/common/ErrorMessage'; -import ShareButton from '@/components/common/ShareButton'; -import ShareModal from '@/components/common/ShareModal'; -import Footer from '@/components/common/Footer'; +import useGetLeafsPageQueries from '@/hooks/useGetLeafsPageQueries'; +import useEffectOnce from '@/hooks/useEffectOnce'; + +import { AddLeafButton, LeafDeleteModal } from '@/components/leafs'; +import { + Leaf, + PageTitle, + Screws, + LoadingNotice, + ErrorMessage, + ShareButton, + ShareModal, + Footer, +} from '@/components/common'; import { MOUNT_ANIMATION_VALUES } from '@/constants/values'; -import useEffectOnce from '@/hooks/useEffectOnce'; -import useGetLeafsPageQueries from '@/hooks/useGetLeafsPageQueries'; +import useModalStore from '@/stores/modalStore'; interface LeafsProps { params: { id: string }; @@ -28,17 +31,18 @@ export default function Leafs({ params }: LeafsProps) { const pathUserId = params.id; const { userId } = useUserStore(); - const { isModalOpen, modalCategory, isOwner, setIsOwner } = useLeafsStore(); + const { isOwner, setIsOwner } = useLeafsStore(); + const { isOpen, type } = useModalStore(); + + const { leafs, user, isLoading, isError } = useGetLeafsPageQueries({ + pathUserId, + }); useEffectOnce(() => { if (userId === pathUserId) return setIsOwner(true); return setIsOwner(false); }); - const { leafs, user, isLoading, isError } = useGetLeafsPageQueries({ - pathUserId, - }); - return ( <> - {isModalOpen && - (modalCategory === 'deleteLeaf' ? ( + {isOpen && + (type === 'deleteLeaf' ? ( ) : ( diff --git a/client/src/components/common/SeoHead.tsx b/client/src/components/common/SeoHead.tsx index ceac1e26..93d9e489 100644 --- a/client/src/components/common/SeoHead.tsx +++ b/client/src/components/common/SeoHead.tsx @@ -1,18 +1,18 @@ -import { useRouter } from 'next/router'; +// import { useRouter } from 'next/router'; -import getMetaDate from '@/hooks/useGetMetaData'; +// import getMetaDate from '@/hooks/useGetMetaData'; -import { ContextType, PageType, Post } from '@/types/common'; +// import { ContextType, PageType, Post } from '@/types/common'; -type MetaDataProps = { - post: Post; - page: PageType; -}; +// type MetaDataProps = { +// post: Post; +// page: PageType; +// }; -export default function SeoHead({ post, page }: MetaDataProps) { - const router = useRouter(); - const metaData = getMetaDate(page, router.query, post); - //TODO: 주석에 원하는대로 값이 나오는지 테스트가 필요하다 - //TODO: og 이미지는 어떻게 할 것인가? - return; -} +// export default function SeoHead({ post, page }: MetaDataProps) { +// const router = useRouter(); +// const metaData = getMetaDate(page, router.query, post); +// //TODO: 주석에 원하는대로 값이 나오는지 테스트가 필요하다 +// //TODO: og 이미지는 어떻게 할 것인가? +// return; +// } diff --git a/client/src/components/leafs/index.ts b/client/src/components/leafs/index.ts new file mode 100644 index 00000000..1a836a4f --- /dev/null +++ b/client/src/components/leafs/index.ts @@ -0,0 +1,4 @@ +import AddLeafButton from './AddLeafButton'; +import LeafDeleteModal from './LeafDeleteModal'; + +export { AddLeafButton, LeafDeleteModal }; diff --git a/client/src/stores/leafsStore.ts b/client/src/stores/leafsStore.ts index 7478c9df..842230d6 100644 --- a/client/src/stores/leafsStore.ts +++ b/client/src/stores/leafsStore.ts @@ -1,30 +1,19 @@ import { create } from 'zustand'; interface LeafsState { - isModalOpen: boolean; deleteTargetLeafsId: string | null; - modalCategory: 'deleteLeaf' | 'share' | null; isOwner: boolean; - modalOpen: () => void; - modalClose: () => void; - setDeleteTargetId: (deleteTargetId: string) => void; - setModalCategory: (modalCategory: 'deleteLeaf' | 'share' | null) => void; setIsOwner: (isOwner: boolean) => void; } const useLeafsStore = create((set) => ({ - isModalOpen: false, deleteTargetLeafsId: null, - modalCategory: null, isOwner: false, - modalOpen: () => set(() => ({ isModalOpen: true })), - modalClose: () => set(() => ({ isModalOpen: false })), setDeleteTargetId: (deleteTargetLeafsId) => set(() => ({ deleteTargetLeafsId })), - setModalCategory: (modalCategory) => set(() => ({ modalCategory })), setIsOwner: (isOwner) => set(() => ({ isOwner })), })); diff --git a/client/src/stores/modalStore.ts b/client/src/stores/modalStore.ts index f2239082..882a5986 100644 --- a/client/src/stores/modalStore.ts +++ b/client/src/stores/modalStore.ts @@ -11,9 +11,11 @@ export type GardenType = | 'emptyInventory' | 'share'; -export type ModalType = PostType | GardenType | null; +export type LeafsType = 'deleteLeaf' | 'share'; -export interface GardenModalState { +export type ModalType = PostType | GardenType | LeafsType | null; + +export interface modalState { isOpen: boolean; type: ModalType; @@ -22,7 +24,7 @@ export interface GardenModalState { close: () => void; } -const useGardenModalStore = create((set) => ({ +const useModalStore = create((set) => ({ isOpen: false, type: null, @@ -31,4 +33,4 @@ const useGardenModalStore = create((set) => ({ close: () => set(() => ({ isOpen: false })), })); -export default useGardenModalStore; +export default useModalStore; From 516facc26e0aef2389489806ecbf9827b958633c Mon Sep 17 00:00:00 2001 From: hanbinchoi Date: Sat, 14 Oct 2023 01:39:43 +0900 Subject: [PATCH 007/117] =?UTF-8?q?[FE]=20=E2=99=BB=EF=B8=8F=20Share?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EA=B4=80=EB=A0=A8=20=EC=BB=B4=ED=8F=AC?= =?UTF-8?q?=EB=84=8C=ED=8A=B8=20=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/app/leaf/[userId]/[leafId]/page.tsx | 11 +++-- client/src/components/common/ShareButton.tsx | 45 ++++++------------- client/src/components/common/ShareModal.tsx | 42 ++++++----------- client/src/components/leaf/LeafModal.tsx | 4 +- client/src/constants/contents.ts | 10 +++++ client/src/stores/modalStore.ts | 5 +-- 6 files changed, 49 insertions(+), 68 deletions(-) diff --git a/client/src/app/leaf/[userId]/[leafId]/page.tsx b/client/src/app/leaf/[userId]/[leafId]/page.tsx index dc17cbc9..86b2aeed 100644 --- a/client/src/app/leaf/[userId]/[leafId]/page.tsx +++ b/client/src/app/leaf/[userId]/[leafId]/page.tsx @@ -2,6 +2,7 @@ import { motion } from 'framer-motion'; +import useModalStore from '@/stores/modalStore'; import useLeafStore from '@/stores/leafStore'; import useUserStore from '@/stores/userStore'; @@ -34,7 +35,9 @@ export default function Leaf({ params }: LeafProps) { const userId = useUserStore((state) => state.userId); - const { modalCategory, isModalOpen, isOwner, setIsOwner } = useLeafStore(); + const { isOwner, setIsOwner } = useLeafStore(); + + const { type, isOpen } = useModalStore(); useEffectOnce(() => { if (userId === pathUserId) return setIsOwner(true); @@ -101,13 +104,13 @@ export default function Leaf({ params }: LeafProps) { )}
- {isModalOpen && + {isOpen && isOwner && - (modalCategory === 'share' ? ( + (type === 'share' ? ( ) : ( diff --git a/client/src/components/common/ShareButton.tsx b/client/src/components/common/ShareButton.tsx index 0c6ac6ca..b9ec9845 100644 --- a/client/src/components/common/ShareButton.tsx +++ b/client/src/components/common/ShareButton.tsx @@ -6,15 +6,14 @@ import { usePathname } from 'next/navigation'; import { twMerge } from 'tailwind-merge'; import { motion } from 'framer-motion'; -import useLeafsStore from '@/stores/leafsStore'; -import useLeafStore from '@/stores/leafStore'; -import useGardenModalStore from '@/stores/gardenModalStore'; +import useModalStore from '@/stores/modalStore'; -import CommonButton from './CommonButton'; +import { CommonButton } from '@/components/common'; import { DefaultProps } from '@/types/common'; import { SHARE_URL } from '@/constants/values'; +import { SHARE_BUTTON_TEXT } from '@/constants/contents'; interface ShareButtonProps extends DefaultProps { location: 'leafs' | 'leaf' | 'garden'; @@ -28,16 +27,9 @@ export default function ShareButton({ }: ShareButtonProps) { const url = usePathname(); - /** 사용된 장소가 식물 카드 관련 페이지 인지 */ - const isLeafs = location === 'leaf' || location === 'leafs'; - - const { modalOpen: leafsModalOpen, setModalCategory: setLeafsModalCategory } = - useLeafsStore(); - - const { modalOpen: leafModalOpen, setModalCategory: setLeafModalCategory } = - useLeafStore(); + const { open, changeType } = useModalStore(); - const { open: gardenModalOpen, changeType } = useGardenModalStore(); + const isLeafs = location === 'leaf' || location === 'leafs'; const handleShareUrl = () => { const base = SHARE_URL; @@ -45,20 +37,8 @@ export default function ShareButton({ navigator.clipboard.writeText(links); - if (location === 'leafs') { - setLeafsModalCategory('share'); - leafsModalOpen(); - } - - if (location === 'leaf') { - setLeafModalCategory('share'); - leafModalOpen(); - } - - if (location === 'garden') { - changeType('share'); - gardenModalOpen(); - } + changeType('share'); + open(); }; if (isLeafs && position === 'top') @@ -76,10 +56,11 @@ export default function ShareButton({ src="/assets/icon/share.svg" width={16} height={18} - alt="공유하기" + alt={SHARE_BUTTON_TEXT.button} /> ); + if (isLeafs && position === 'bottom') return ( - 공유하기 + {SHARE_BUTTON_TEXT.button} ); + if (!isLeafs && position === 'top') return ( ); + if (!isLeafs && position === 'bottom') return ( - 공유하기 + {SHARE_BUTTON_TEXT.button} ); } diff --git a/client/src/components/common/ShareModal.tsx b/client/src/components/common/ShareModal.tsx index a702e430..3ec74549 100644 --- a/client/src/components/common/ShareModal.tsx +++ b/client/src/components/common/ShareModal.tsx @@ -1,55 +1,39 @@ -import useLeafsStore from '@/stores/leafsStore'; -import useLeafStore from '@/stores/leafStore'; -import useGardenModalStore from '@/stores/gardenModalStore'; +import useModalStore from '@/stores/modalStore'; -import CommonButton from './CommonButton'; -import Modal from './Modal'; -import ModalPortal from './ModalPortal'; +import { CommonButton, Modal, ModalPortal } from '@/components/common'; + +import { SHARE_MODAL_TEXT } from '@/constants/contents'; interface ShareModalProps { location: 'leafs' | 'leaf' | 'garden'; } export default function ShareModal({ location }: ShareModalProps) { - const { - modalClose: leafsModalClose, - setModalCategory: setLeafsModalCategory, - } = useLeafsStore(); - const { modalClose: leafModalClose, setModalCategory: setLeafModalCategory } = - useLeafStore(); - const { close: gardenModalClose, changeType } = useGardenModalStore(); + const { close, changeType } = useModalStore(); const handleModalCancel = () => { - if (location === 'leafs') { - setLeafsModalCategory(null); - leafsModalClose(); - } - if (location === 'leaf') { - setLeafModalCategory(null); - leafModalClose(); - } - if (location === 'garden') { - changeType(null); - gardenModalClose(); - } + changeType(null); + close(); + return; }; return (

- 현재 페이지 주소가 + {SHARE_MODAL_TEXT.firstLine[0]}
- 복사되었습니다. + {SHARE_MODAL_TEXT.firstLine[1]}

- 다른 사람에게 공유해보세요! + {SHARE_MODAL_TEXT.secondLine[0]} + {SHARE_MODAL_TEXT.secondLine[1]}

- 확인 + {SHARE_MODAL_TEXT.button}
diff --git a/client/src/components/leaf/LeafModal.tsx b/client/src/components/leaf/LeafModal.tsx index 1abcb7b9..832e5519 100644 --- a/client/src/components/leaf/LeafModal.tsx +++ b/client/src/components/leaf/LeafModal.tsx @@ -5,8 +5,10 @@ import { DiaryDeleteModal } from './DiaryDeleteModal'; import ModalPortal from '../common/ModalPortal'; import Modal from '../common/Modal'; +import { ModalType } from '@/stores/modalStore'; + interface LeafModalProps { - modalCategory: 'add' | 'edit' | 'delete' | 'share' | null; + modalCategory: ModalType; leafId: string; userId: string; } diff --git a/client/src/constants/contents.ts b/client/src/constants/contents.ts index 25a044ca..c250fc4b 100644 --- a/client/src/constants/contents.ts +++ b/client/src/constants/contents.ts @@ -111,3 +111,13 @@ export const FOOTER_LINK = { hanbin: 'https://github.com/hanbinchoi', doyeon: 'https://github.com/shimdokite', }; + +export const SHARE_BUTTON_TEXT = { + button: '공유하기', +}; + +export const SHARE_MODAL_TEXT = { + firstLine: ['현재 페이지 주소가', '복사되었습니다.'], + secondLine: ['다른 사람에게 ', '공유해보세요!'], + button: '확인', +}; diff --git a/client/src/stores/modalStore.ts b/client/src/stores/modalStore.ts index 882a5986..7054932b 100644 --- a/client/src/stores/modalStore.ts +++ b/client/src/stores/modalStore.ts @@ -1,7 +1,6 @@ import { create } from 'zustand'; export type PostType = 'post' | 'comment'; - export type GardenType = | 'leafExist' | 'noLeafExist' @@ -10,10 +9,10 @@ export type GardenType = | 'purchase' | 'emptyInventory' | 'share'; - export type LeafsType = 'deleteLeaf' | 'share'; +export type LeafType = 'add' | 'delete' | 'edit' | 'share'; -export type ModalType = PostType | GardenType | LeafsType | null; +export type ModalType = PostType | GardenType | LeafsType | LeafType | null; export interface modalState { isOpen: boolean; From 504b927ab7b922c8b49c95a3370265d017a8a5c9 Mon Sep 17 00:00:00 2001 From: hanbinchoi Date: Sat, 14 Oct 2023 01:50:48 +0900 Subject: [PATCH 008/117] =?UTF-8?q?[FE]=20=E2=99=BB=EF=B8=8F=20Leaf=20?= =?UTF-8?q?=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EB=A6=AC=ED=8C=A9?= =?UTF-8?q?=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/components/common/Leaf.tsx | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/client/src/components/common/Leaf.tsx b/client/src/components/common/Leaf.tsx index 22175e9e..89e89551 100644 --- a/client/src/components/common/Leaf.tsx +++ b/client/src/components/common/Leaf.tsx @@ -6,10 +6,9 @@ import { useRouter } from 'next/navigation'; import { motion } from 'framer-motion'; import useLeafsStore from '@/stores/leafsStore'; -import useUserStore from '@/stores/userStore'; +import useModalStore from '@/stores/modalStore'; -import ControlButton from './ControlButton'; -import LeafName from './LeafName'; +import { ControlButton, LeafName } from '@/components/common'; interface LeafProps { location: 'garden' | 'leaf'; @@ -32,15 +31,14 @@ export default function Leaf({ }: LeafProps) { const router = useRouter(); - const { modalOpen, setDeleteTargetId, setModalCategory, isOwner } = - useLeafsStore(); + const { setDeleteTargetId, isOwner } = useLeafsStore(); + const { open, changeType } = useModalStore(); const handleLeafClick = (event: React.MouseEvent) => { if (onClick) { onClick(event); return null; } - if (location === 'leaf') { router.push(`/leaf/${pathUserId}/${leafId}`); return null; @@ -58,8 +56,8 @@ export default function Leaf({ ) => { e.stopPropagation(); setDeleteTargetId(leafId); - setModalCategory('deleteLeaf'); - modalOpen(); + changeType('deleteLeaf'); + open(); }; return ( From 9cf02d7714a725597df073257b64e59a93a29574 Mon Sep 17 00:00:00 2001 From: hanbinchoi Date: Sat, 14 Oct 2023 01:50:49 +0900 Subject: [PATCH 009/117] =?UTF-8?q?[FE]=20=E2=99=BB=EF=B8=8F=20Leaf=20?= =?UTF-8?q?=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EB=A6=AC=ED=8C=A9?= =?UTF-8?q?=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/leafs/LeafDeleteModal.tsx | 33 +++++++++---------- client/src/constants/contents.ts | 6 ++++ 2 files changed, 22 insertions(+), 17 deletions(-) diff --git a/client/src/components/leafs/LeafDeleteModal.tsx b/client/src/components/leafs/LeafDeleteModal.tsx index 180100f5..d5d3715f 100644 --- a/client/src/components/leafs/LeafDeleteModal.tsx +++ b/client/src/components/leafs/LeafDeleteModal.tsx @@ -1,52 +1,51 @@ import useLeafsStore from '@/stores/leafsStore'; +import useModalStore from '@/stores/modalStore'; import useDeleteLeafMutation from '@/hooks/useDeleteLeafMutaion'; -import CommonButton from '../common/CommonButton'; -import ModalPortal from '../common/ModalPortal'; -import Modal from '../common/Modal'; +import { CommonButton, ModalPortal, Modal } from '@/components/common'; +import { LEAF_DELETE_MODAL_TEXT } from '@/constants/contents'; export default function LeafDeleteModal() { const { isOwner } = useLeafsStore(); + const { deleteTargetLeafsId } = useLeafsStore(); + const { close } = useModalStore(); - if (!isOwner) return null; - - const { mutate } = useDeleteLeafMutation(); - - const { deleteTargetLeafsId, modalClose } = useLeafsStore(); + const { mutate: deleteLeaf } = useDeleteLeafMutation(); const handleLeafDelete = () => { if (!deleteTargetLeafsId) return; - mutate(deleteTargetLeafsId); - modalClose(); + deleteLeaf(deleteTargetLeafsId); + close(); }; const handleModalCancel = () => { - modalClose(); + close(); }; + if (!isOwner) return null; return (

- 정원에 설치된 식물 카드는 + {LEAF_DELETE_MODAL_TEXT.firstLine[0]}
- 연결이 해제 + {LEAF_DELETE_MODAL_TEXT.firstLine[1]}
- 됩니다. + {LEAF_DELETE_MODAL_TEXT.firstLine[2]}

- 그래도 삭제하시겠습니까? + {LEAF_DELETE_MODAL_TEXT.secondLine}

- 삭제 + {LEAF_DELETE_MODAL_TEXT.button[0]} - 취소 + {LEAF_DELETE_MODAL_TEXT.button[1]}
diff --git a/client/src/constants/contents.ts b/client/src/constants/contents.ts index c250fc4b..5ced0329 100644 --- a/client/src/constants/contents.ts +++ b/client/src/constants/contents.ts @@ -121,3 +121,9 @@ export const SHARE_MODAL_TEXT = { secondLine: ['다른 사람에게 ', '공유해보세요!'], button: '확인', }; + +export const LEAF_DELETE_MODAL_TEXT = { + firstLine: ['정원에 설치된 식물 카드는', '연결이 해제', '됩니다.'], + secondLine: '그래도 삭제하시겠습니까?', + button: ['삭제', '취소'], +}; From d72ac801f528ee4764b53d3cd55213b0f17b1e62 Mon Sep 17 00:00:00 2001 From: hanbinchoi Date: Sat, 14 Oct 2023 02:45:08 +0900 Subject: [PATCH 010/117] =?UTF-8?q?[FE]=20=E2=99=BB=EF=B8=8F=20ControlButt?= =?UTF-8?q?on=20=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EB=A6=AC=ED=8C=A9?= =?UTF-8?q?=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/components/common/ControlButton.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/client/src/components/common/ControlButton.tsx b/client/src/components/common/ControlButton.tsx index 0d060079..630dc55f 100644 --- a/client/src/components/common/ControlButton.tsx +++ b/client/src/components/common/ControlButton.tsx @@ -1,6 +1,7 @@ import { twMerge } from 'tailwind-merge'; import { DefaultProps, addPrefixToHandler } from '@/types/common'; + import { CONTROL_BUTTON_TITLES } from '@/constants/contents'; interface ControlButtonProps From d5a20b4eb77b100458b39f3979bed71fc74e2115 Mon Sep 17 00:00:00 2001 From: hanbinchoi Date: Sat, 14 Oct 2023 02:45:19 +0900 Subject: [PATCH 011/117] =?UTF-8?q?[FE]=20=E2=99=BB=EF=B8=8F=20ImageUpload?= =?UTF-8?q?=20=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EB=A6=AC=ED=8C=A9?= =?UTF-8?q?=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/components/common/ImageUpload.tsx | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/client/src/components/common/ImageUpload.tsx b/client/src/components/common/ImageUpload.tsx index c87d8c0d..a9977079 100644 --- a/client/src/components/common/ImageUpload.tsx +++ b/client/src/components/common/ImageUpload.tsx @@ -7,12 +7,12 @@ import { UseFormSetValue, } from 'react-hook-form'; -import NoImage from './NoImage'; -import CommonButton from './CommonButton'; -import Preview from './Preview'; +import { NoImage, CommonButton, Preview } from '@/components/common'; import { InputValues } from '@/types/common'; +import { IMAGE_UPLOAD_TEXT } from '@/constants/contents'; + import isValidFileSize from '@/utils/isValidFileSize'; interface ImageUploadProps { @@ -39,7 +39,6 @@ function ImageUpload({ imageUrl, ); - // 이미지 미리보기 설정하는 함수 const setPreview = (e: React.ChangeEvent) => { if (e.target.files?.length) { setIsImageUpdated && setIsImageUpdated(true); @@ -53,7 +52,7 @@ function ImageUpload({ return; } - alert('2mb 이하 이미지를 선택해주세요.'); + alert(IMAGE_UPLOAD_TEXT.fileSizeWarn); } return; }; @@ -75,7 +74,7 @@ function ImageUpload({ 'image', required ? { - required: '이미지를 필수로 등록해야 합니다.', + required: IMAGE_UPLOAD_TEXT.noImageUploadError, } : {}, )} @@ -92,7 +91,7 @@ function ImageUpload({ size="sm" className="mt-3 mb-3 leading-4" onClick={handleImageUpload}> - 이미지 등록 + {IMAGE_UPLOAD_TEXT.imageUpload} {Object.keys(errors).length ? ( @@ -101,7 +100,7 @@ function ImageUpload({

) : (

- 2mb 이하의 이미지만 등록이 가능합니다. + {IMAGE_UPLOAD_TEXT.noImageUploadError}

)}
From aec0ec51e5311742e7a326fa36bad15e404a401e Mon Sep 17 00:00:00 2001 From: hanbinchoi Date: Sat, 14 Oct 2023 02:45:25 +0900 Subject: [PATCH 012/117] =?UTF-8?q?[FE]=20=E2=99=BB=EF=B8=8F=20Diary=20?= =?UTF-8?q?=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EB=A6=AC=ED=8C=A9?= =?UTF-8?q?=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/components/leaf/Diary.tsx | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/client/src/components/leaf/Diary.tsx b/client/src/components/leaf/Diary.tsx index 74c2de23..d3a1d39e 100644 --- a/client/src/components/leaf/Diary.tsx +++ b/client/src/components/leaf/Diary.tsx @@ -1,8 +1,9 @@ import Image from 'next/image'; import useLeafStore from '@/stores/leafStore'; +import useModalStore from '@/stores/modalStore'; -import ControlButton from '../common/ControlButton'; +import { ControlButton } from '../common'; import { DiaryDataInfo } from '@/types/data'; @@ -13,6 +14,9 @@ export default function Diary({ content, title, }: DiaryDataInfo) { + const { setTargetDiary, isOwner } = useLeafStore(); + const { open, changeType } = useModalStore(); + const diary = { journalId, createdAt, @@ -20,23 +24,19 @@ export default function Diary({ content, title, }; - - const { modalOpen, setModalCategory, setTargetDiary, isOwner } = - useLeafStore(); - const startDay = new Date(createdAt); const [month, day] = [startDay.getMonth() + 1, startDay.getDate()]; const handleEditDiary = () => { - modalOpen(); + open(); setTargetDiary(diary); - setModalCategory('edit'); + changeType('edit'); }; const handleDeleteDiary = () => { - modalOpen(); + open(); setTargetDiary(diary); - setModalCategory('delete'); + changeType('delete'); }; return ( From 94491898c81143b65f741e5f241493212f411f97 Mon Sep 17 00:00:00 2001 From: hanbinchoi Date: Sat, 14 Oct 2023 02:45:34 +0900 Subject: [PATCH 013/117] =?UTF-8?q?[FE]=20=E2=99=BB=EF=B8=8F=20DiaryDelete?= =?UTF-8?q?Modal=20=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EB=A6=AC?= =?UTF-8?q?=ED=8C=A9=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/leaf/DiaryDeleteModal.tsx | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/client/src/components/leaf/DiaryDeleteModal.tsx b/client/src/components/leaf/DiaryDeleteModal.tsx index f696ef03..faeddfe3 100644 --- a/client/src/components/leaf/DiaryDeleteModal.tsx +++ b/client/src/components/leaf/DiaryDeleteModal.tsx @@ -1,24 +1,27 @@ import useLeafStore from '@/stores/leafStore'; -import CommonButton from '../common/CommonButton'; import useDeleteDiaryMutation from '@/hooks/useDeleteDiaryMutaion'; +import { CommonButton } from '../common'; + +import { DIARY_DELETE_MODAL_TEXT } from '@/constants/contents'; + interface DiaryDeleteModalProps { deleteTargetId?: string | null; leafId: string; userId: string; } -export function DiaryDeleteModal({ +export default function DiaryDeleteModal({ userId, leafId, deleteTargetId, }: DiaryDeleteModalProps) { - if (!deleteTargetId) return null; + const modalClose = useLeafStore((state) => state.modalClose); const { mutate: deleteDiary } = useDeleteDiaryMutation(leafId); - const modalClose = useLeafStore((state) => state.modalClose); + if (!deleteTargetId) return null; const handleCancelModal = () => modalClose(); @@ -30,11 +33,12 @@ export function DiaryDeleteModal({ return (

- 선택한 일지를 + {DIARY_DELETE_MODAL_TEXT.firstLine}

{/* 그래도
*/} - 삭제하시겠습니까? + {DIARY_DELETE_MODAL_TEXT.secondLine[0]} + {DIARY_DELETE_MODAL_TEXT.secondLine[1]}

- 삭제 + {DIARY_DELETE_MODAL_TEXT.button[0]} - 취소 + {DIARY_DELETE_MODAL_TEXT.button[1]}
From 7f797e187fb2182927b7f3e253c61b4ee82d7123 Mon Sep 17 00:00:00 2001 From: hanbinchoi Date: Sat, 14 Oct 2023 02:45:44 +0900 Subject: [PATCH 014/117] =?UTF-8?q?[FE]=20=E2=99=BB=EF=B8=8F=20DiaryForm?= =?UTF-8?q?=20=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EB=A6=AC=ED=8C=A9?= =?UTF-8?q?=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/components/leaf/DiaryForm.tsx | 61 ++++++++++-------------- client/src/hooks/useDiaryFormMutaion.ts | 47 ++++++++++++++++++ 2 files changed, 73 insertions(+), 35 deletions(-) create mode 100644 client/src/hooks/useDiaryFormMutaion.ts diff --git a/client/src/components/leaf/DiaryForm.tsx b/client/src/components/leaf/DiaryForm.tsx index a379d5aa..db61efc2 100644 --- a/client/src/components/leaf/DiaryForm.tsx +++ b/client/src/components/leaf/DiaryForm.tsx @@ -1,20 +1,23 @@ import { useState } from 'react'; import { useForm } from 'react-hook-form'; -import { useMutation, useQueryClient } from '@tanstack/react-query'; -import ImageUpload from '../common/ImageUpload'; -import PageTitle from '../common/PageTitle'; -import TextInput from '../common/TextInput'; -import TextArea from '../common/TextArea'; -import CommonButton from '../common/CommonButton'; +import useModalStore from '@/stores/modalStore'; -import useLeafStore from '@/stores/leafStore'; +import useDiaryFormMutaion from '@/hooks/useDiaryFormMutaion'; -import { addDiary, editDiary } from '@/api/leaf'; +import { + ImageUpload, + PageTitle, + TextInput, + TextArea, + CommonButton, +} from '@/components/common'; import { InputValues } from '@/types/common'; +import { DIARY_FORM_TEXT } from '@/constants/contents'; + interface DiaryFormProps { imageUrl?: string; content?: string; @@ -33,7 +36,11 @@ export default function DiaryForm({ diaryId, mode, }: DiaryFormProps) { - const queryClient = useQueryClient(); + const [isImageUpdated, setIsImageUpdated] = useState(false); + // const [isChecked, setIsChecked] = useState(false); + const { close } = useModalStore(); + + const mutate = useDiaryFormMutaion(mode, { userId, leafId, diaryId }); const { register, @@ -48,34 +55,18 @@ export default function DiaryForm({ }, }); - const { mutate } = useMutation({ - mutationFn: - mode === 'edit' - ? (inputs: InputValues) => - editDiary({ diaryId, inputs, userId, isImageUpdated }) - : (inputs: InputValues) => - addDiary({ leafId, inputs, isImageUpdated, userId }), - - onSuccess: () => { - queryClient.invalidateQueries(['diaries', leafId]); - }, - }); - - const [isImageUpdated, setIsImageUpdated] = useState(false); - const [isChecked, setIsChecked] = useState(false); - - const modalClose = useLeafStore((state) => state.modalClose); - const handleSubmitDiary = (inputs: InputValues) => { - mutate(inputs); - modalClose(); + if (mutate) { + mutate({ inputs, isImageUpdated }); + close(); + } }; - const handleModalCancel = () => modalClose(); + const handleModalCancel = () => close(); return (
- +
@@ -92,7 +83,7 @@ export default function DiaryForm({ - 내용 :{' '} + {DIARY_FORM_TEXT.secondLabel}