fix(ui): align portal stats and auth feedback

This commit is contained in:
poyrazavsever
2026-07-17 22:59:25 +03:00
parent ec824c0eec
commit 2fb7cebb1d
3 changed files with 13 additions and 28 deletions
+2 -27
View File
@@ -1,8 +1,9 @@
import { Card, CardContent, Badge } from "poyraz-ui/atoms"; 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 Link from "next/link";
import { format } from "date-fns"; import { format } from "date-fns";
import { tr } from "date-fns/locale"; import { tr } from "date-fns/locale";
import { StatCard } from "@/components/system/stat-card";
import { requirePortalBackend } from "@/server/web/portal"; import { requirePortalBackend } from "@/server/web/portal";
export default async function PortalDashboardPage() { export default async function PortalDashboardPage() {
@@ -76,29 +77,3 @@ export default async function PortalDashboardPage() {
</div> </div>
); );
} }
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 (
<Card>
<CardContent className="flex items-center justify-between gap-3 p-4">
<div>
<p className="text-sm text-muted-foreground">{label}</p>
<p className="mt-1 text-2xl font-semibold text-foreground">{value}</p>
</div>
<div className={`flex h-10 w-10 shrink-0 items-center justify-center rounded-sm ${toneClass}`}>
<Icon className="h-5 w-5" />
</div>
</CardContent>
</Card>
);
}
+1 -1
View File
@@ -6,7 +6,7 @@ import { toast } from "poyraz-ui/molecules";
export function ErrorToaster({ message }: { message: string }) { export function ErrorToaster({ message }: { message: string }) {
useEffect(() => { useEffect(() => {
if (message) { if (message) {
toast.error(message); toast.error(message, { id: `route-error:${message}` });
} }
}, [message]) }, [message])
+10
View File
@@ -7,6 +7,10 @@ const repoRoot = process.cwd();
const packageJson = JSON.parse(fs.readFileSync(path.join(repoRoot, "package.json"), "utf8")); const packageJson = JSON.parse(fs.readFileSync(path.join(repoRoot, "package.json"), "utf8"));
const globalsCss = fs.readFileSync(path.join(repoRoot, "app/globals.css"), "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 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 loginActions = fs.readFileSync(path.join(repoRoot, "app/login/actions.ts"), "utf8");
const rootLayout = fs.readFileSync(path.join(repoRoot, "app/layout.tsx"), "utf8"); const rootLayout = fs.readFileSync(path.join(repoRoot, "app/layout.tsx"), "utf8");
const brandingService = fs.readFileSync( const brandingService = fs.readFileSync(
@@ -68,6 +72,11 @@ assert.doesNotMatch(
/<DropdownMenuItem[^>]*\binteractiveMotion=/s, /<DropdownMenuItem[^>]*\binteractiveMotion=/s,
"Poyraz UI 3.0.2 leaks DropdownMenuItem interactiveMotion to the DOM", "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( assert.doesNotMatch(
appShell, appShell,
/<form\s+action=\{signOut\}>/, /<form\s+action=\{signOut\}>/,
@@ -183,6 +192,7 @@ for (const statPage of [
"app/(dashboard)/projects/projects-client.tsx", "app/(dashboard)/projects/projects-client.tsx",
"app/(dashboard)/journal/journal-client.tsx", "app/(dashboard)/journal/journal-client.tsx",
"app/(dashboard)/finance/finance-client.tsx", "app/(dashboard)/finance/finance-client.tsx",
"app/portal/page.tsx",
]) { ]) {
const content = fs.readFileSync(path.join(repoRoot, statPage), "utf8"); const content = fs.readFileSync(path.join(repoRoot, statPage), "utf8");
assert.ok( assert.ok(