마이페이지, 리포트, 메일인증
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import Link from "next/link";
|
||||
import { FolderKanban, LayoutDashboard, ListChecks, SunMoon } from "lucide-react";
|
||||
import { BarChart2, FolderKanban, LayoutDashboard, ListChecks, SunMoon } from "lucide-react";
|
||||
import { useAppLocale } from "@/features/i18n/LocaleProvider";
|
||||
import { getDashboardMessages } from "@/features/i18n/messages/dashboard";
|
||||
|
||||
@@ -46,6 +46,7 @@ export default function DashboardPage() {
|
||||
const [status, setStatus] = useState<PageStatus>("idle");
|
||||
const [errorMessage, setErrorMessage] = useState<string | null>(null);
|
||||
const [isMenuOpen, setIsMenuOpen] = useState(false);
|
||||
const [emailVerified, setEmailVerified] = useState<boolean | null>(null);
|
||||
|
||||
// 마운트 시 대시보드 개요 데이터를 불러온다.
|
||||
useEffect(() => {
|
||||
@@ -103,6 +104,31 @@ export default function DashboardPage() {
|
||||
};
|
||||
}, [router]);
|
||||
|
||||
// 마운트 시 현재 사용자 이메일 인증 여부를 확인한다.
|
||||
useEffect(() => {
|
||||
let cancelled = false;
|
||||
|
||||
const loadMe = async () => {
|
||||
try {
|
||||
const res = await fetch("/api/auth/me");
|
||||
if (cancelled || !res.ok) return;
|
||||
|
||||
const data = (await res.json().catch(() => null)) as any;
|
||||
if (!cancelled && data) {
|
||||
setEmailVerified(Boolean(data.emailVerified));
|
||||
}
|
||||
} catch {
|
||||
// ignore – 인증 여부를 알 수 없으면 배너만 표시하지 않는다.
|
||||
}
|
||||
};
|
||||
|
||||
void loadMe();
|
||||
|
||||
return () => {
|
||||
cancelled = true;
|
||||
};
|
||||
}, []);
|
||||
|
||||
const safeSummary: SummaryStats =
|
||||
summary ?? {
|
||||
totalProjects: 0,
|
||||
@@ -170,6 +196,13 @@ export default function DashboardPage() {
|
||||
<ListChecks className="w-4 h-4" aria-hidden="true" />
|
||||
<span>{t.navSubmissions}</span>
|
||||
</Link>
|
||||
<Link
|
||||
href="/reports"
|
||||
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"
|
||||
>
|
||||
<BarChart2 className="w-4 h-4" aria-hidden="true" />
|
||||
<span>{t.navReports ?? "Reports"}</span>
|
||||
</Link>
|
||||
</nav>
|
||||
<button
|
||||
type="button"
|
||||
@@ -191,6 +224,16 @@ export default function DashboardPage() {
|
||||
</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">
|
||||
<button
|
||||
type="button"
|
||||
className="w-full px-3 py-2 text-left text-xs text-slate-700 hover:bg-slate-100 dark:text-slate-200 dark:hover:bg-slate-800"
|
||||
onClick={() => {
|
||||
setIsMenuOpen(false);
|
||||
router.push("/mypage");
|
||||
}}
|
||||
>
|
||||
{t.myPageLabel}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="w-full px-3 py-2 text-left text-xs text-slate-700 hover:bg-slate-100 dark:text-slate-200 dark:hover:bg-slate-800"
|
||||
@@ -212,6 +255,12 @@ export default function DashboardPage() {
|
||||
<p className="text-xs text-red-500 dark:text-red-300">{errorMessage}</p>
|
||||
)}
|
||||
|
||||
{emailVerified === false && (
|
||||
<p className="text-xs text-amber-700 mb-1 dark:text-amber-300">
|
||||
{t.emailNotVerifiedBanner}
|
||||
</p>
|
||||
)}
|
||||
|
||||
{status === "loading" && (
|
||||
<p className="text-xs text-slate-400">{t.loadingText}</p>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user