i18n 적용
This commit is contained in:
@@ -4,6 +4,9 @@ import { useEffect, useState } from "react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import Link from "next/link";
|
||||
import { FolderKanban, LayoutDashboard, ListChecks, SunMoon } from "lucide-react";
|
||||
import { useAppLocale } from "@/features/i18n/LocaleProvider";
|
||||
import { getDashboardMessages } from "@/features/i18n/messages/dashboard";
|
||||
import { getSubmissionsMessages } from "@/features/i18n/messages/submissions";
|
||||
|
||||
interface SubmissionItem {
|
||||
id: string;
|
||||
@@ -17,6 +20,9 @@ type PageStatus = "idle" | "loading" | "error";
|
||||
|
||||
export default function AllProjectSubmissionsPage() {
|
||||
const router = useRouter();
|
||||
const locale = useAppLocale();
|
||||
const t = getDashboardMessages(locale);
|
||||
const m = getSubmissionsMessages(locale);
|
||||
const [submissions, setSubmissions] = useState<SubmissionItem[]>([]);
|
||||
const [status, setStatus] = useState<PageStatus>("idle");
|
||||
const [errorMessage, setErrorMessage] = useState<string | null>(null);
|
||||
@@ -37,13 +43,13 @@ export default function AllProjectSubmissionsPage() {
|
||||
|
||||
if (res.status === 401) {
|
||||
setStatus("error");
|
||||
setErrorMessage("폼 제출 내역을 조회하려면 로그인이 필요합니다. 다시 로그인해 주세요.");
|
||||
setErrorMessage(m.errorUnauthorized);
|
||||
router.push("/login");
|
||||
return;
|
||||
}
|
||||
|
||||
setStatus("error");
|
||||
setErrorMessage("폼 제출 내역을 불러오는 중 오류가 발생했습니다. 잠시 후 다시 시도해 주세요.");
|
||||
setErrorMessage(m.errorGeneric);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -57,7 +63,7 @@ export default function AllProjectSubmissionsPage() {
|
||||
} catch {
|
||||
if (!cancelled) {
|
||||
setStatus("error");
|
||||
setErrorMessage("폼 제출 내역을 불러오는 중 오류가 발생했습니다. 잠시 후 다시 시도해 주세요.");
|
||||
setErrorMessage(m.errorGeneric);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -92,13 +98,13 @@ export default function AllProjectSubmissionsPage() {
|
||||
});
|
||||
|
||||
if (!res.ok) {
|
||||
setErrorMessage("로그아웃 중 오류가 발생했습니다. 잠시 후 다시 시도해 주세요.");
|
||||
setErrorMessage(m.errorLogout);
|
||||
return;
|
||||
}
|
||||
|
||||
router.push("/login");
|
||||
} catch {
|
||||
setErrorMessage("로그아웃 중 오류가 발생했습니다. 잠시 후 다시 시도해 주세요.");
|
||||
setErrorMessage(m.errorLogout);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -106,8 +112,8 @@ export default function AllProjectSubmissionsPage() {
|
||||
<main className="min-h-screen flex flex-col bg-slate-100 text-slate-900 dark:bg-slate-950 dark:text-slate-50">
|
||||
<header className="border-b border-slate-200 px-6 py-4 flex items-center justify-between bg-white/80 backdrop-blur dark:border-slate-800 dark:bg-slate-950/80">
|
||||
<div>
|
||||
<h1 className="text-2xl font-bold tracking-tight">전체 폼 제출 내역</h1>
|
||||
<p className="text-sm text-slate-500 dark:text-slate-400">로그인한 계정의 모든 프로젝트에 대한 폼 제출 데이터를 확인할 수 있습니다.</p>
|
||||
<h1 className="text-2xl font-bold tracking-tight">{m.headerTitle}</h1>
|
||||
<p className="text-sm text-slate-500 dark:text-slate-400">{m.headerDescription}</p>
|
||||
</div>
|
||||
<div className="flex items-center gap-3 text-sm">
|
||||
<nav className="inline-flex items-center gap-1 rounded-full border border-slate-200 bg-white/80 px-1.5 py-1 shadow-sm dark:border-slate-700 dark:bg-slate-900/80">
|
||||
@@ -116,14 +122,14 @@ export default function AllProjectSubmissionsPage() {
|
||||
className="inline-flex items-center gap-1 px-3 py-1.5 rounded-full text-sm font-medium text-slate-700 hover:bg-slate-100 hover:text-sky-700 dark:text-slate-200 dark:hover:bg-slate-800 dark:hover:text-sky-200"
|
||||
>
|
||||
<LayoutDashboard className="w-4 h-4" aria-hidden="true" />
|
||||
<span>대시보드</span>
|
||||
<span>{t.navDashboard}</span>
|
||||
</Link>
|
||||
<Link
|
||||
href="/projects"
|
||||
className="inline-flex items-center gap-1 px-3 py-1.5 rounded-full text-sm font-medium text-slate-700 hover:bg-slate-100 hover:text-sky-700 dark:text-slate-200 dark:hover:bg-slate-800 dark:hover:text-sky-200"
|
||||
>
|
||||
<FolderKanban className="w-4 h-4" aria-hidden="true" />
|
||||
<span>프로젝트 목록</span>
|
||||
<span>{t.navProjects}</span>
|
||||
</Link>
|
||||
<Link
|
||||
href="/projects/submissions"
|
||||
@@ -131,7 +137,7 @@ export default function AllProjectSubmissionsPage() {
|
||||
className="inline-flex items-center gap-1 px-3 py-1.5 rounded-full text-sm font-semibold bg-emerald-600 text-white shadow-sm hover:bg-emerald-700"
|
||||
>
|
||||
<ListChecks className="w-4 h-4" aria-hidden="true" />
|
||||
<span>전체 제출 내역</span>
|
||||
<span>{t.navSubmissions}</span>
|
||||
</Link>
|
||||
</nav>
|
||||
<button
|
||||
@@ -151,7 +157,7 @@ export default function AllProjectSubmissionsPage() {
|
||||
}}
|
||||
>
|
||||
<SunMoon className="w-4 h-4" aria-hidden="true" />
|
||||
<span>테마 전환</span>
|
||||
<span>{t.themeToggleLabel}</span>
|
||||
</button>
|
||||
<div className="relative">
|
||||
<button
|
||||
@@ -161,7 +167,7 @@ export default function AllProjectSubmissionsPage() {
|
||||
setIsMenuOpen((prev) => !prev);
|
||||
}}
|
||||
>
|
||||
메뉴
|
||||
{t.menuLabel}
|
||||
</button>
|
||||
{isMenuOpen && (
|
||||
<div className="absolute right-0 mt-1 w-32 rounded border border-slate-200 bg-white shadow-lg z-20 dark:border-slate-700 dark:bg-slate-900/95">
|
||||
@@ -173,7 +179,7 @@ export default function AllProjectSubmissionsPage() {
|
||||
void handleLogout();
|
||||
}}
|
||||
>
|
||||
로그아웃
|
||||
{t.logoutLabel}
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
@@ -187,25 +193,25 @@ export default function AllProjectSubmissionsPage() {
|
||||
)}
|
||||
|
||||
{status === "loading" && (
|
||||
<p className="text-xs text-slate-500 mb-3 dark:text-slate-400">폼 제출 내역을 불러오는 중입니다...</p>
|
||||
<p className="text-xs text-slate-500 mb-3 dark:text-slate-400">{m.loadingText}</p>
|
||||
)}
|
||||
|
||||
{submissions.length === 0 && status === "idle" && !errorMessage && (
|
||||
<p className="text-xs text-slate-500 dark:text-slate-400">아직 수집된 폼 제출 내역이 없습니다.</p>
|
||||
{status === "idle" && !errorMessage && submissions.length === 0 && (
|
||||
<p className="text-xs text-slate-500 dark:text-slate-400">{m.emptyText}</p>
|
||||
)}
|
||||
|
||||
{submissions.length > 0 && (
|
||||
<table className="w-full text-xs text-left border-collapse mt-2">
|
||||
<thead>
|
||||
<tr className="border-b border-slate-200 text-slate-600 dark:border-slate-800 dark:text-slate-400">
|
||||
<th className="py-2 pr-4">제출 시각</th>
|
||||
<th className="py-2 pr-4">프로젝트</th>
|
||||
<th className="py-2 pr-4">Slug</th>
|
||||
<th className="py-2 pr-4">이름</th>
|
||||
<th className="py-2 pr-4">이메일</th>
|
||||
<th className="py-2 pr-4">전화번호</th>
|
||||
<th className="py-2 pr-4">생년월일</th>
|
||||
<th className="py-2 pr-4">기타 필드</th>
|
||||
<th className="py-2 pr-4">{m.tableHeaderCreatedAt}</th>
|
||||
<th className="py-2 pr-4">{m.tableHeaderProject}</th>
|
||||
<th className="py-2 pr-4">{m.tableHeaderSlug}</th>
|
||||
<th className="py-2 pr-4">{m.tableHeaderName}</th>
|
||||
<th className="py-2 pr-4">{m.tableHeaderEmail}</th>
|
||||
<th className="py-2 pr-4">{m.tableHeaderPhone}</th>
|
||||
<th className="py-2 pr-4">{m.tableHeaderBirthdate}</th>
|
||||
<th className="py-2 pr-4">{m.tableHeaderOtherFields}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
||||
Reference in New Issue
Block a user