|
1 | 1 | import { requireAdmin } from "@/lib/guard"; |
2 | 2 | import { db } from "@/lib/db"; |
| 3 | +import { |
| 4 | + PageHeader, |
| 5 | + PageShell, |
| 6 | + SectionLabel, |
| 7 | + SubNav, |
| 8 | + UtilityCard, |
| 9 | +} from "@/components/layout/AppChrome"; |
3 | 10 |
|
4 | 11 | import { PendingMemberActions } from "./_components/PendingMemberActions"; |
5 | 12 |
|
@@ -28,74 +35,78 @@ export default async function AdminMembersPage() { |
28 | 35 | }); |
29 | 36 |
|
30 | 37 | return ( |
31 | | - <main className="container mx-auto max-w-2xl p-6"> |
32 | | - <header className="mb-6 flex flex-col gap-1"> |
33 | | - <h1 className="text-2xl font-bold tracking-tight">회원 관리</h1> |
34 | | - <p className="text-xs text-muted-foreground"> |
35 | | - 관리자: {admin.email} |
36 | | - </p> |
37 | | - </header> |
| 38 | + <> |
| 39 | + <SubNav title="회원 관리" /> |
| 40 | + <PageShell width="content" surface="parchment"> |
| 41 | + <PageHeader |
| 42 | + eyebrow="Admin" |
| 43 | + title="회원 관리" |
| 44 | + description={`관리자: ${admin.email}`} |
| 45 | + /> |
38 | 46 |
|
39 | | - <section className="mb-10"> |
40 | | - <h2 className="mb-3 text-sm font-semibold uppercase text-muted-foreground"> |
41 | | - 승인 대기 ({pending.length}) |
42 | | - </h2> |
43 | | - {pending.length === 0 ? ( |
44 | | - <p className="text-sm text-muted-foreground">대기 중인 가입 요청이 없습니다.</p> |
45 | | - ) : ( |
46 | | - <ul className="flex flex-col gap-2"> |
47 | | - {pending.map((u) => ( |
48 | | - <li |
49 | | - key={u.id} |
50 | | - className="flex flex-col gap-2 rounded-md border p-3 sm:flex-row sm:items-center sm:justify-between" |
51 | | - > |
52 | | - <div className="flex flex-col"> |
53 | | - <span className="font-medium">{u.name}</span> |
54 | | - <span className="font-mono text-xs text-muted-foreground"> |
55 | | - {u.email} |
56 | | - </span> |
57 | | - <span className="text-xs text-muted-foreground"> |
58 | | - 가입 요청 {formatDate(u.joinedAt)} |
59 | | - </span> |
60 | | - </div> |
61 | | - <PendingMemberActions userId={u.id} /> |
62 | | - </li> |
63 | | - ))} |
64 | | - </ul> |
65 | | - )} |
66 | | - </section> |
| 47 | + <div className="grid gap-8 lg:grid-cols-[1fr_1fr]"> |
| 48 | + <UtilityCard> |
| 49 | + <SectionLabel>승인 대기 ({pending.length})</SectionLabel> |
| 50 | + {pending.length === 0 ? ( |
| 51 | + <p className="font-text text-sm leading-[1.43] tracking-[-0.224px] text-apple-muted-48"> |
| 52 | + 대기 중인 가입 요청이 없습니다. |
| 53 | + </p> |
| 54 | + ) : ( |
| 55 | + <ul className="flex flex-col gap-3"> |
| 56 | + {pending.map((u) => ( |
| 57 | + <li |
| 58 | + key={u.id} |
| 59 | + className="flex flex-col gap-4 rounded-[18px] border border-apple-hairline bg-apple-parchment p-4" |
| 60 | + > |
| 61 | + <div className="flex flex-col gap-1"> |
| 62 | + <span className="font-text text-[17px] font-semibold leading-[1.24] tracking-[-0.374px]"> |
| 63 | + {u.name} |
| 64 | + </span> |
| 65 | + <span className="font-mono text-xs text-apple-muted-48"> |
| 66 | + {u.email} |
| 67 | + </span> |
| 68 | + <span className="font-text text-xs leading-none tracking-[-0.12px] text-apple-muted-48"> |
| 69 | + 가입 요청 {formatDate(u.joinedAt)} |
| 70 | + </span> |
| 71 | + </div> |
| 72 | + <PendingMemberActions userId={u.id} /> |
| 73 | + </li> |
| 74 | + ))} |
| 75 | + </ul> |
| 76 | + )} |
| 77 | + </UtilityCard> |
67 | 78 |
|
68 | | - <section> |
69 | | - <h2 className="mb-3 text-sm font-semibold uppercase text-muted-foreground"> |
70 | | - 활동 회원 ({active.length}) |
71 | | - </h2> |
72 | | - <ul className="flex flex-col gap-2"> |
73 | | - {active.map((u) => ( |
74 | | - <li |
75 | | - key={u.id} |
76 | | - className="flex flex-col gap-1 rounded-md border p-3 sm:flex-row sm:items-center sm:justify-between" |
77 | | - > |
78 | | - <div className="flex flex-col"> |
79 | | - <span className="font-medium"> |
80 | | - {u.name} |
81 | | - {u.role === "ADMIN" && ( |
82 | | - <span className="ml-2 rounded bg-secondary px-1.5 py-0.5 text-xs"> |
83 | | - ADMIN |
| 79 | + <UtilityCard> |
| 80 | + <SectionLabel>활동 회원 ({active.length})</SectionLabel> |
| 81 | + <ul className="flex flex-col gap-3"> |
| 82 | + {active.map((u) => ( |
| 83 | + <li |
| 84 | + key={u.id} |
| 85 | + className="flex flex-col gap-3 rounded-[18px] border border-apple-hairline bg-apple-parchment p-4 sm:flex-row sm:items-center sm:justify-between" |
| 86 | + > |
| 87 | + <div className="flex flex-col gap-1"> |
| 88 | + <span className="font-text text-[17px] font-semibold leading-[1.24] tracking-[-0.374px]"> |
| 89 | + {u.name} |
| 90 | + {u.role === "ADMIN" && ( |
| 91 | + <span className="ml-2 rounded-full bg-apple-canvas px-2 py-1 font-text text-xs font-normal leading-none tracking-[-0.12px] text-apple-primary"> |
| 92 | + ADMIN |
| 93 | + </span> |
| 94 | + )} |
84 | 95 | </span> |
85 | | - )} |
86 | | - </span> |
87 | | - <span className="font-mono text-xs text-muted-foreground"> |
88 | | - {u.email} |
89 | | - </span> |
90 | | - </div> |
91 | | - <span className="text-xs text-muted-foreground"> |
92 | | - 승인 {u.approvedAt ? formatDate(u.approvedAt) : "—"} |
93 | | - </span> |
94 | | - </li> |
95 | | - ))} |
96 | | - </ul> |
97 | | - </section> |
98 | | - </main> |
| 96 | + <span className="font-mono text-xs text-apple-muted-48"> |
| 97 | + {u.email} |
| 98 | + </span> |
| 99 | + </div> |
| 100 | + <span className="font-text text-xs leading-none tracking-[-0.12px] text-apple-muted-48"> |
| 101 | + 승인 {u.approvedAt ? formatDate(u.approvedAt) : "—"} |
| 102 | + </span> |
| 103 | + </li> |
| 104 | + ))} |
| 105 | + </ul> |
| 106 | + </UtilityCard> |
| 107 | + </div> |
| 108 | + </PageShell> |
| 109 | + </> |
99 | 110 | ); |
100 | 111 | } |
101 | 112 |
|
|
0 commit comments