From a68242af6fbd65c524784a7cdb2c7cf892c08af2 Mon Sep 17 00:00:00 2001
From: hyoribogo <97094709+hyoribogo@users.noreply.github.com>
Date: Thu, 28 Dec 2023 22:30:18 +0900
Subject: [PATCH] =?UTF-8?q?=EC=9C=A0=EC=A0=80=20=ED=8E=98=EC=9D=B4?=
=?UTF-8?q?=EC=A7=80=20=EC=8A=A4=ED=83=80=EC=9D=BC=20=EC=9E=91=EC=97=85=20?=
=?UTF-8?q?(#52)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* refactor: 프로필 링크 user/id로 통일
* feat: 레이아웃 추가
* feat: 퀴즈 테이블 컴포넌트 적용
* feat: 유저 페이지 테이블 필터링
* feat: users 테이블 get 로직 구현
* refactor: 유저 정보 컴포넌트 구현
* refactor: my 폴더 삭제
* refactor: return 타입 변경
* feat: 서버 컴포넌트로 변경
* feat: not found 페이지 추가
* refactor: userInfo로 prop 이름 변경
* feat: user 페이지로 링크 처리
---
app/my/page.tsx | 52 ------------------------
app/quizzes/[id]/page.tsx | 3 +-
app/user/[id]/_components/quiz-table.tsx | 15 +++++++
app/user/[id]/_components/user-info.tsx | 9 ++++
app/user/[id]/layout.tsx | 16 ++++++++
app/user/[id]/not-found.tsx | 20 +++++++++
app/user/[id]/page.tsx | 36 ++++++++++++++++
components/common/headers/menu.tsx | 2 +-
components/common/headers/profile.tsx | 2 +-
services/quiz/api.ts | 6 +--
services/user/api.ts | 19 +++++++++
services/user/hook.ts | 6 +++
services/user/options.ts | 14 +++++++
13 files changed, 141 insertions(+), 59 deletions(-)
delete mode 100644 app/my/page.tsx
create mode 100644 app/user/[id]/_components/quiz-table.tsx
create mode 100644 app/user/[id]/_components/user-info.tsx
create mode 100644 app/user/[id]/layout.tsx
create mode 100644 app/user/[id]/not-found.tsx
create mode 100644 app/user/[id]/page.tsx
create mode 100644 services/user/api.ts
create mode 100644 services/user/hook.ts
create mode 100644 services/user/options.ts
diff --git a/app/my/page.tsx b/app/my/page.tsx
deleted file mode 100644
index d1b0b16..0000000
--- a/app/my/page.tsx
+++ /dev/null
@@ -1,52 +0,0 @@
-import { QuizCard } from '@/components/quiz/quiz-card';
-import quizOptions from '@/services/quiz/options';
-import { createClient } from '@/utils/supabase/server';
-import {
- HydrationBoundary,
- QueryClient,
- dehydrate,
-} from '@tanstack/react-query';
-import { cookies } from 'next/headers';
-
-export default async function Page() {
- const cookieStore = cookies();
- const supabase = createClient(cookieStore);
- const {
- data: { user },
- } = await supabase.auth.getUser();
-
- const queryClient = new QueryClient();
-
- const submittedQuiz = await queryClient.fetchQuery(
- quizOptions.submitted(user?.id ?? '')
- );
-
- return (
- <>
-
- {user?.user_metadata.user_name}
-
- 풀었던 퀴즈
-
- {submittedQuiz && submittedQuiz.length ? (
-
- {submittedQuiz.map(
- ({ quiz_id, success, quizzes }) =>
- quizzes && (
-
- )
- )}
-
- ) : (
- 제출한 퀴즈가 없습니다.
- )}
-
- >
- );
-}
diff --git a/app/quizzes/[id]/page.tsx b/app/quizzes/[id]/page.tsx
index efd33e6..9522746 100644
--- a/app/quizzes/[id]/page.tsx
+++ b/app/quizzes/[id]/page.tsx
@@ -37,8 +37,7 @@ export default async function Page({ params }: { params: { id: string } }) {
By{' '}
-
- {/* TODO: 추후 상세 유저 페이지 라우팅 경로로 변경하기 */}
+
{quiz?.users?.name}
diff --git a/app/user/[id]/_components/quiz-table.tsx b/app/user/[id]/_components/quiz-table.tsx
new file mode 100644
index 0000000..2d89af7
--- /dev/null
+++ b/app/user/[id]/_components/quiz-table.tsx
@@ -0,0 +1,15 @@
+import { columns } from '@/components/quiz/table/columns';
+import DataTable from '@/components/quiz/table/data-table';
+import { QuizTable } from '../../../../libs/models';
+
+type QuizTableProps = {
+ quiz: QuizTable[];
+};
+
+export default function QuizTable({ quiz }: QuizTableProps) {
+ return (
+
+
+
+ );
+}
diff --git a/app/user/[id]/_components/user-info.tsx b/app/user/[id]/_components/user-info.tsx
new file mode 100644
index 0000000..11f6d80
--- /dev/null
+++ b/app/user/[id]/_components/user-info.tsx
@@ -0,0 +1,9 @@
+type UserInfoProps = {
+ userInfo: {
+ name: string;
+ };
+};
+
+export default function UserInfo({ userInfo }: UserInfoProps) {
+ return {userInfo.name}
;
+}
diff --git a/app/user/[id]/layout.tsx b/app/user/[id]/layout.tsx
new file mode 100644
index 0000000..ce3b4fd
--- /dev/null
+++ b/app/user/[id]/layout.tsx
@@ -0,0 +1,16 @@
+import BackHeader from '@/components/common/headers/back-header';
+import React from 'react';
+
+type LayoutProps = {
+ children: React.ReactNode;
+};
+
+export default function Layout({ children }: LayoutProps) {
+ return (
+ <>
+
+
+
+ >
+ );
+}
diff --git a/app/user/[id]/not-found.tsx b/app/user/[id]/not-found.tsx
new file mode 100644
index 0000000..ae28c4d
--- /dev/null
+++ b/app/user/[id]/not-found.tsx
@@ -0,0 +1,20 @@
+import Image from 'next/image';
+import Link from 'next/link';
+import TypeTime from '@/assets/images/type-time.png';
+
+export default function NotFound() {
+ return (
+ <>
+
+
+
페이지를 찾을 수 없습니다.
+
+ 홈으로 이동하기
+
+
+ >
+ );
+}
diff --git a/app/user/[id]/page.tsx b/app/user/[id]/page.tsx
new file mode 100644
index 0000000..feab581
--- /dev/null
+++ b/app/user/[id]/page.tsx
@@ -0,0 +1,36 @@
+import {
+ HydrationBoundary,
+ QueryClient,
+ dehydrate,
+} from '@tanstack/react-query';
+import quizOptions from '@/services/quiz/options';
+import userOptions from '@/services/user/options';
+import { Separator } from '@/components/ui/separator';
+import UserInfo from './_components/user-info';
+import QuizTable from './_components/quiz-table';
+import NotFound from './not-found';
+
+export default async function Page({ params }: { params: { id: string } }) {
+ const { id } = params;
+
+ const queryClient = new QueryClient();
+
+ const [userInfo, submittedQuiz] = await Promise.all([
+ queryClient.fetchQuery(userOptions.info(id)),
+ queryClient.fetchQuery(quizOptions.submitted(id)),
+ ]);
+
+ if (userInfo) {
+ return (
+
+ {userInfo && }
+
+
+ 제출한 퀴즈
+
+
+ );
+ }
+
+ return ;
+}
diff --git a/components/common/headers/menu.tsx b/components/common/headers/menu.tsx
index f2d5154..0c9015a 100644
--- a/components/common/headers/menu.tsx
+++ b/components/common/headers/menu.tsx
@@ -48,7 +48,7 @@ export default async function Menu() {
diff --git a/components/common/headers/profile.tsx b/components/common/headers/profile.tsx
index 079070b..3dc6c05 100644
--- a/components/common/headers/profile.tsx
+++ b/components/common/headers/profile.tsx
@@ -13,7 +13,7 @@ export default async function Profile() {
} = await supabase.auth.getUser();
return (
-
+
{
diff --git a/services/user/api.ts b/services/user/api.ts
new file mode 100644
index 0000000..f8d76d8
--- /dev/null
+++ b/services/user/api.ts
@@ -0,0 +1,19 @@
+import { createClient } from '@/utils/supabase/client';
+import { SupabaseClient } from '@supabase/supabase-js';
+
+const userAPI = {
+ getUserInfo: async (id: string) => {
+ const supabase: SupabaseClient = createClient();
+
+ const { data } = await supabase
+ .from('users')
+ .select('name')
+ .eq('id', id)
+ .limit(1)
+ .single();
+
+ return data;
+ },
+};
+
+export default userAPI;
diff --git a/services/user/hook.ts b/services/user/hook.ts
new file mode 100644
index 0000000..58b7d52
--- /dev/null
+++ b/services/user/hook.ts
@@ -0,0 +1,6 @@
+import { useSuspenseQuery } from '@tanstack/react-query';
+import userOptions from './options';
+
+export function useGetUserInfo(id: string) {
+ return useSuspenseQuery(userOptions.info(id));
+}
diff --git a/services/user/options.ts b/services/user/options.ts
new file mode 100644
index 0000000..46a122c
--- /dev/null
+++ b/services/user/options.ts
@@ -0,0 +1,14 @@
+import { queryOptions } from '@tanstack/react-query';
+import userAPI from './api';
+
+const userOptions = {
+ default: ['users'] as const,
+
+ info: (id: string) =>
+ queryOptions({
+ queryKey: [...userOptions.default, 'info', id],
+ queryFn: () => userAPI.getUserInfo(id),
+ }),
+};
+
+export default userOptions;