agriflow-api / dashboard /app /components /AccountMenu.tsx
masterAAA123's picture
Space deploy v5: orphan snapshot of main, zero binary files
b81a86b
Raw
History Blame Contribute Delete
2.48 kB
"use client";
// Account affordance for the dashboard header.
//
// The site is login-first (see proxy.ts), so by the time a page renders the
// visitor is always either a real signed-in user or a guest. This menu shows
// which, and gives each a way out:
// - real user -> account link (email), sign-out lives on /account
// - guest -> a "Tamu" chip plus "Keluar" to drop the guest cookie and
// return to /login, where they can sign in for real
import Link from "next/link";
import { useEffect, useState } from "react";
import { useRouter } from "next/navigation";
import { useAuth } from "../lib/auth";
import { exitGuest, isGuest } from "../lib/guest";
export default function AccountMenu() {
const { user, loading } = useAuth();
const router = useRouter();
// The guest cookie is not reactive, so read it once on mount. Client-only:
// isGuest() returns false during SSR, which is fine (the menu is decorative).
const [guest, setGuest] = useState(false);
useEffect(() => setGuest(isGuest()), []);
if (loading) return null;
if (user) {
return (
<Link
href="/account"
className="flex items-center gap-2 rounded-lg border border-slate-300 px-3 py-1.5
text-sm font-medium text-slate-700 hover:bg-slate-50"
title={user.email ?? undefined}
>
<span
aria-hidden
className="grid h-6 w-6 place-items-center rounded-full bg-emerald-700 text-xs text-white"
>
{(user.email ?? "?").charAt(0).toUpperCase()}
</span>
<span className="max-w-[12ch] truncate">{user.email}</span>
</Link>
);
}
if (guest) {
return (
<div className="flex items-center gap-2">
<span className="rounded-full bg-slate-100 px-2.5 py-1 text-xs font-medium text-slate-500">
Mode Tamu
</span>
<button
onClick={() => {
exitGuest();
router.push("/login");
}}
className="rounded-lg border border-slate-300 px-3 py-1.5 text-sm font-medium
text-slate-700 hover:bg-slate-50"
>
Keluar
</button>
</div>
);
}
// Fallback (e.g. brief pre-hydration flash): offer the way in.
return (
<Link
href="/login"
className="rounded-lg border border-slate-300 px-3 py-1.5 text-sm font-medium
text-slate-700 hover:bg-slate-50"
>
Masuk
</Link>
);
}