feat: 학생 회원 라우트 골격 추가
Co-Authored-By: Claude Sonnet 5
@361dea6b54dfbf95249f46dcea57fa8b9929e22b
+++ app/(protected)/(basic)/students/error.tsx
... | ... | @@ -0,0 +1,32 @@ |
| 1 | +'use client'; | |
| 2 | + | |
| 3 | +import { useEffect } from 'react'; | |
| 4 | + | |
| 5 | +interface ErrorPageProps { | |
| 6 | + error: Error & { digest?: string }; | |
| 7 | + unstable_retry: () => void; | |
| 8 | +} | |
| 9 | + | |
| 10 | +// 원본 메시지·스택은 화면에 내지 않는다 — 개발자 진단용으로만 콘솔에 남기고(프로덕션에서는 | |
| 11 | +// Next.js가 Server Component 에러를 이미 digest 포함 일반화 메시지로 치환해 전달한다), | |
| 12 | +// 사용자에게는 일반화된 문구 + 재시도만 제공한다. Next.js 16.2 문서 권고에 따라 세그먼트 | |
| 13 | +// 재조회까지 수행하는 `unstable_retry()`를 `reset()` 대신 사용한다. | |
| 14 | +export default function ErrorPage({ error, unstable_retry }: ErrorPageProps) { | |
| 15 | + useEffect(() => { | |
| 16 | + console.error(error); | |
| 17 | + }, [error]); | |
| 18 | + | |
| 19 | + return ( | |
| 20 | + <section className="flex flex-1 flex-col items-center justify-center gap-2 p-8"> | |
| 21 | + <h1 className="text-lg text-foreground">문제가 발생했습니다.</h1> | |
| 22 | + <p className="text-sm text-foreground/60">잠시 후 다시 시도해 주세요.</p> | |
| 23 | + <button | |
| 24 | + type="button" | |
| 25 | + onClick={() => unstable_retry()} | |
| 26 | + className="mt-4 bg-foreground px-4 py-2 text-background" | |
| 27 | + > | |
| 28 | + 다시 시도 | |
| 29 | + </button> | |
| 30 | + </section> | |
| 31 | + ); | |
| 32 | +} |
+++ app/(protected)/(basic)/students/loading.tsx
... | ... | @@ -0,0 +1,12 @@ |
| 1 | +import { Spinner } from '@/components/ui/spinner'; | |
| 2 | + | |
| 3 | +// page.tsx가 스트리밍되는 동안의 폴백 — 같은 section 배치(flex-1 items-center justify-center)를 | |
| 4 | +// 써서 콘텐츠 교체 시 레이아웃이 흔들리지 않게 한다. Server Component로 충분해 'use client'를 | |
| 5 | +// 붙이지 않는다. | |
| 6 | +export default function Loading() { | |
| 7 | + return ( | |
| 8 | + <section className="flex flex-1 flex-col items-center justify-center gap-2 p-8"> | |
| 9 | + <Spinner size="lg" /> | |
| 10 | + </section> | |
| 11 | + ); | |
| 12 | +} |
+++ app/(protected)/(basic)/students/page.tsx
... | ... | @@ -0,0 +1,18 @@ |
| 1 | +import type { Metadata } from 'next'; | |
| 2 | +import { verifySession } from '@/lib/auth/dal'; | |
| 3 | + | |
| 4 | +export const metadata: Metadata = { | |
| 5 | + title: '학생 회원', | |
| 6 | +}; | |
| 7 | + | |
| 8 | +// 목록·상세는 이번 범위 밖 — 라우트 골격만 제공한다 (§4.1 승인 범위 한정). | |
| 9 | +export default async function Page() { | |
| 10 | + await verifySession(); | |
| 11 | + | |
| 12 | + return ( | |
| 13 | + <section className="flex flex-1 flex-col items-center justify-center gap-2 p-8"> | |
| 14 | + <h1 className="text-lg text-foreground">학생 회원</h1> | |
| 15 | + <p className="text-sm text-foreground/60">준비 중인 화면입니다.</p> | |
| 16 | + </section> | |
| 17 | + ); | |
| 18 | +} |
Add a comment
Delete comment
Once you delete this comment, you won't be able to recover it. Are you sure you want to delete this comment?