From fc9f523eee4024c8f713dc10d0d1943be82402c6 Mon Sep 17 00:00:00 2001 From: jgjgill <79239852+jgjgill@users.noreply.github.com> Date: Wed, 27 Dec 2023 21:43:14 +0900 Subject: [PATCH] =?UTF-8?q?=EB=8C=93=EA=B8=80=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84=20(#44)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: react-hook-form 설치 * fix: 퀴즈 데이터 호출에서 유저 api 호출 방식 변경 * fix: 헤더 뒤로가기 컴포넌트 수정 * chore: 퀴즈 관련 페이지 레이아웃 구성 * feat: 정답 페이지 기본 기능 구성 정답 api 호출 에러 및 로딩 페이지 구성 임시 스타일 적용 * fix: 헤더 유저 프로필 라우팅 변경 * refactor: 테이블 난이도 텍스트 변경 * feat: 댓글 기본 구조 작업 스타일 및 form 적용 * feat: 댓글 가져오기 기능 구현 * feat: 댓글 작성 기능 * style: 줄바꿈 적용 * fix: 쿼리키 및 댓글 추가 로딩 관련 코드 수정 * fix: api 병렬 처리 진행 * fix: 퀴즈 테이블 관련 api 호출 방식 변경 --- app/(main)/page.tsx | 6 +- app/(main)/quiz-table.tsx | 8 +- .../[id]/{ => (trying)}/choice-form.tsx | 2 +- app/quizzes/[id]/{ => (trying)}/layout.tsx | 0 app/quizzes/[id]/{ => (trying)}/loading.tsx | 0 app/quizzes/[id]/{ => (trying)}/page.tsx | 0 .../[id]/{ => (trying)}/questions/page.tsx | 0 app/quizzes/[id]/answer/page.tsx | 7 -- .../[id]/answers/_components/comments.tsx | 108 ++++++++++++++++++ .../[id]/answers/_components/quiz-answer.tsx | 29 +++++ app/quizzes/[id]/answers/error.tsx | 23 ++++ app/quizzes/[id]/answers/layout.tsx | 16 +++ app/quizzes/[id]/answers/loading.tsx | 3 + app/quizzes/[id]/answers/page.tsx | 37 ++++++ app/quizzes/[id]/quiz.tsx | 19 --- components/common/buttons/back-button.tsx | 15 +++ components/common/headers/back-header.tsx | 16 +-- components/common/headers/profile.tsx | 2 +- components/quiz/table/columns.tsx | 17 +-- components/ui/avatar.tsx | 49 ++++++++ components/ui/separator.tsx | 30 +++++ components/ui/skeleton.tsx | 15 +++ components/ui/textarea.tsx | 23 ++++ libs/database.types.ts | 42 +++++++ libs/models.ts | 6 +- package-lock.json | 83 ++++++++++++++ package.json | 5 + services/comment/api.ts | 34 ++++++ services/comment/hooks.ts | 13 +++ services/comment/options.ts | 14 +++ services/quiz/api.ts | 36 ++++-- services/quiz/hooks.ts | 15 ++- services/quiz/options.ts | 11 +- 33 files changed, 604 insertions(+), 80 deletions(-) rename app/quizzes/[id]/{ => (trying)}/choice-form.tsx (97%) rename app/quizzes/[id]/{ => (trying)}/layout.tsx (100%) rename app/quizzes/[id]/{ => (trying)}/loading.tsx (100%) rename app/quizzes/[id]/{ => (trying)}/page.tsx (100%) rename app/quizzes/[id]/{ => (trying)}/questions/page.tsx (100%) delete mode 100644 app/quizzes/[id]/answer/page.tsx create mode 100644 app/quizzes/[id]/answers/_components/comments.tsx create mode 100644 app/quizzes/[id]/answers/_components/quiz-answer.tsx create mode 100644 app/quizzes/[id]/answers/error.tsx create mode 100644 app/quizzes/[id]/answers/layout.tsx create mode 100644 app/quizzes/[id]/answers/loading.tsx create mode 100644 app/quizzes/[id]/answers/page.tsx delete mode 100644 app/quizzes/[id]/quiz.tsx create mode 100644 components/common/buttons/back-button.tsx create mode 100644 components/ui/avatar.tsx create mode 100644 components/ui/separator.tsx create mode 100644 components/ui/skeleton.tsx create mode 100644 components/ui/textarea.tsx create mode 100644 services/comment/api.ts create mode 100644 services/comment/hooks.ts create mode 100644 services/comment/options.ts diff --git a/app/(main)/page.tsx b/app/(main)/page.tsx index 597e111..9d45c75 100644 --- a/app/(main)/page.tsx +++ b/app/(main)/page.tsx @@ -19,12 +19,12 @@ export default async function Page() { const cookieStore = cookies(); const supabase = createClient(cookieStore); - await queryClient.prefetchQuery(quizOptions.all()); - const { data: { user }, } = await supabase.auth.getUser(); + await queryClient.prefetchQuery(quizOptions.all(user?.id)); + const signOut = async () => { 'use server'; @@ -57,7 +57,7 @@ export default async function Page() { rightArea={HeaderRightArea} /> - +
diff --git a/app/(main)/quiz-table.tsx b/app/(main)/quiz-table.tsx index 83774cf..c8e09ea 100644 --- a/app/(main)/quiz-table.tsx +++ b/app/(main)/quiz-table.tsx @@ -4,8 +4,12 @@ import { columns } from '@/components/quiz/table/columns'; import DataTable from '@/components/quiz/table/data-table'; import { useGetQuizzes } from '@/services/quiz/hooks'; -export default function QuizTable() { - const { data: quizzes } = useGetQuizzes(); +type QuizTableProps = { + userId?: string; +}; + +export default function QuizTable({ userId }: QuizTableProps) { + const { data: quizzes } = useGetQuizzes(userId); return
{quizzes && }
; } diff --git a/app/quizzes/[id]/choice-form.tsx b/app/quizzes/[id]/(trying)/choice-form.tsx similarity index 97% rename from app/quizzes/[id]/choice-form.tsx rename to app/quizzes/[id]/(trying)/choice-form.tsx index 4b55534..6ef5175 100644 --- a/app/quizzes/[id]/choice-form.tsx +++ b/app/quizzes/[id]/(trying)/choice-form.tsx @@ -39,7 +39,7 @@ export default function ChoiceForm({ quizId, children }: ChoiceFormProps) { choiceId: choice.id, }, { - onSuccess: () => router.push(`/quizzes/${quizId}/answer`), + onSuccess: () => router.push(`/quizzes/${quizId}/answers`), onError: (error) => setErrorMessage(error.message), } ); diff --git a/app/quizzes/[id]/layout.tsx b/app/quizzes/[id]/(trying)/layout.tsx similarity index 100% rename from app/quizzes/[id]/layout.tsx rename to app/quizzes/[id]/(trying)/layout.tsx diff --git a/app/quizzes/[id]/loading.tsx b/app/quizzes/[id]/(trying)/loading.tsx similarity index 100% rename from app/quizzes/[id]/loading.tsx rename to app/quizzes/[id]/(trying)/loading.tsx diff --git a/app/quizzes/[id]/page.tsx b/app/quizzes/[id]/(trying)/page.tsx similarity index 100% rename from app/quizzes/[id]/page.tsx rename to app/quizzes/[id]/(trying)/page.tsx diff --git a/app/quizzes/[id]/questions/page.tsx b/app/quizzes/[id]/(trying)/questions/page.tsx similarity index 100% rename from app/quizzes/[id]/questions/page.tsx rename to app/quizzes/[id]/(trying)/questions/page.tsx diff --git a/app/quizzes/[id]/answer/page.tsx b/app/quizzes/[id]/answer/page.tsx deleted file mode 100644 index 00003a0..0000000 --- a/app/quizzes/[id]/answer/page.tsx +++ /dev/null @@ -1,7 +0,0 @@ -export default function Page() { - return ( - <> -
{'수정 예정'}
- - ); -} diff --git a/app/quizzes/[id]/answers/_components/comments.tsx b/app/quizzes/[id]/answers/_components/comments.tsx new file mode 100644 index 0000000..f83ffb4 --- /dev/null +++ b/app/quizzes/[id]/answers/_components/comments.tsx @@ -0,0 +1,108 @@ +'use client'; + +import FullButton from '@/components/common/buttons/full-button'; +import { Avatar, AvatarFallback } from '@/components/ui/avatar'; +import { Textarea } from '@/components/ui/textarea'; +import { useForm } from 'react-hook-form'; +import { z } from 'zod'; +import { zodResolver } from '@hookform/resolvers/zod'; +import { Skeleton } from '@/components/ui/skeleton'; +import { + useGetCommentsOfQuiz, + usePostCommentOfQuiz, +} from '@/services/comment/hooks'; +import dayjs from 'dayjs'; +import { useQueryClient } from '@tanstack/react-query'; +import commentOptions from '@/services/comment/options'; + +type CommentsProps = { + disable: boolean; + quizId: number; + userId?: string; +}; + +const FormSchema = z.object({ + content: z.string().min(1, { + message: '댓글을 입력해주세요.', + }), +}); + +export default function Comments({ disable, quizId, userId }: CommentsProps) { + const queryClient = useQueryClient(); + + const { data: comments = [] } = useGetCommentsOfQuiz(quizId); + + const { mutate: postCommentOfQuiz, isPending } = usePostCommentOfQuiz(); + + const { + handleSubmit, + register, + formState: { errors }, + setValue, + } = useForm>({ + resolver: zodResolver(FormSchema), + reValidateMode: 'onSubmit', + }); + + const onSubmit = (data: z.infer) => { + if (!userId) { + return; + } + + const { content } = data; + postCommentOfQuiz( + { content, quizId, userId }, + { + onSuccess: () => { + queryClient.invalidateQueries({ + queryKey: [...commentOptions.quiz(quizId).queryKey], + }); + setValue('content', ''); + }, + } + ); + }; + + return ( +
+

댓글 ({comments?.length})

+ +
+