From 2fb7cebb1d699011a84600a9081a09a6bb1f6d45 Mon Sep 17 00:00:00 2001 From: poyrazavsever Date: Fri, 17 Jul 2026 22:59:25 +0300 Subject: [PATCH] fix(ui): align portal stats and auth feedback --- app/portal/page.tsx | 29 ++--------------------------- components/error-toaster.tsx | 2 +- scripts/phase4-ui-boundary.mjs | 10 ++++++++++ 3 files changed, 13 insertions(+), 28 deletions(-) diff --git a/app/portal/page.tsx b/app/portal/page.tsx index db6afde..2914d3d 100644 --- a/app/portal/page.tsx +++ b/app/portal/page.tsx @@ -1,8 +1,9 @@ import { Card, CardContent, Badge } from "poyraz-ui/atoms"; -import { FolderKanban, CheckCircle2, Clock, BarChart, type LucideIcon } from "lucide-react"; +import { FolderKanban, CheckCircle2, Clock, BarChart } from "lucide-react"; import Link from "next/link"; import { format } from "date-fns"; import { tr } from "date-fns/locale"; +import { StatCard } from "@/components/system/stat-card"; import { requirePortalBackend } from "@/server/web/portal"; export default async function PortalDashboardPage() { @@ -76,29 +77,3 @@ export default async function PortalDashboardPage() { ); } - -function StatCard({ label, value, icon: Icon, tone }: { - label: string; - value: string; - icon: LucideIcon; - tone: "green" | "blue" | "amber"; -}) { - const toneClass = { - green: "bg-emerald-50 text-emerald-700", - blue: "bg-blue-50 text-blue-700", - amber: "bg-amber-50 text-amber-700", - }[tone]; - return ( - - -
-

{label}

-

{value}

-
-
- -
-
-
- ); -} diff --git a/components/error-toaster.tsx b/components/error-toaster.tsx index 816d580..ee4f356 100644 --- a/components/error-toaster.tsx +++ b/components/error-toaster.tsx @@ -6,7 +6,7 @@ import { toast } from "poyraz-ui/molecules"; export function ErrorToaster({ message }: { message: string }) { useEffect(() => { if (message) { - toast.error(message); + toast.error(message, { id: `route-error:${message}` }); } }, [message]) diff --git a/scripts/phase4-ui-boundary.mjs b/scripts/phase4-ui-boundary.mjs index b476bd3..a9079e1 100644 --- a/scripts/phase4-ui-boundary.mjs +++ b/scripts/phase4-ui-boundary.mjs @@ -7,6 +7,10 @@ const repoRoot = process.cwd(); const packageJson = JSON.parse(fs.readFileSync(path.join(repoRoot, "package.json"), "utf8")); const globalsCss = fs.readFileSync(path.join(repoRoot, "app/globals.css"), "utf8"); const appShell = fs.readFileSync(path.join(repoRoot, "components/layout/app-shell.tsx"), "utf8"); +const errorToaster = fs.readFileSync( + path.join(repoRoot, "components/error-toaster.tsx"), + "utf8", +); const loginActions = fs.readFileSync(path.join(repoRoot, "app/login/actions.ts"), "utf8"); const rootLayout = fs.readFileSync(path.join(repoRoot, "app/layout.tsx"), "utf8"); const brandingService = fs.readFileSync( @@ -68,6 +72,11 @@ assert.doesNotMatch( /]*\binteractiveMotion=/s, "Poyraz UI 3.0.2 leaks DropdownMenuItem interactiveMotion to the DOM", ); +assert.match( + errorToaster, + /toast\.error\(message,\s*\{\s*id:/, + "Route error toasts must use a stable id so React development effects cannot duplicate them", +); assert.doesNotMatch( appShell, //, @@ -183,6 +192,7 @@ for (const statPage of [ "app/(dashboard)/projects/projects-client.tsx", "app/(dashboard)/journal/journal-client.tsx", "app/(dashboard)/finance/finance-client.tsx", + "app/portal/page.tsx", ]) { const content = fs.readFileSync(path.join(repoRoot, statPage), "utf8"); assert.ok(