"use client"; import { useEffect, useState } from "react"; import { Pencil, User } from "lucide-react"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Popover, PopoverContent, PopoverTrigger, } from "@/components/ui/popover"; import { DEFAULT_DEV_EMAIL, getClientIdentity, setClientIdentity, } from "@/lib/dev-identity"; /** * Tiny dev-only identity switcher. The project is in "no auth" mode * (PB users collection is empty), so the claim endpoint reads * caller identity from a cookie. This widget lets the user see and * change the current value, which is also how to test the * multi-user race scenarios in /sprint. * * Hidden in production builds via an env check — only renders when * `NEXT_PUBLIC_DEV_IDENTITY_SWITCHER` is "true". The /sprint page * sets it via its own dev flag, but we re-check here as a safety * belt. */ export function DevIdentitySwitcher({ onChange, }: { onChange?: (email: string) => void; }) { const [email, setEmail] = useState(DEFAULT_DEV_EMAIL); const [draft, setDraft] = useState(""); const [open, setOpen] = useState(false); useEffect(() => { // Sync the displayed identity from the cookie on mount. This is a // legitimate "external source → state" sync (the cookie is the // external source); we can't derive this during render because // document.cookie is a side-effectful read. const current = getClientIdentity(); // eslint-disable-next-line react-hooks/set-state-in-effect setEmail(current); setDraft(current); }, []); const handleOpenChange = (next: boolean) => { if (next) { // Reset draft to the current value when opening, so cancelling // a half-typed edit doesn't leak into the field next time. setDraft(email); } setOpen(next); }; const handleSave = () => { const next = draft.trim() || DEFAULT_DEV_EMAIL; setClientIdentity(next); setEmail(next); setOpen(false); onChange?.(next); }; const displayName = shortName(email); return ( {displayName}

Dev identity

Used for claim attribution and the “claimed by me” badge. Switch to test multi-user race scenarios.

setDraft(e.target.value)} placeholder={DEFAULT_DEV_EMAIL} onKeyDown={(e) => { if (e.key === "Enter") { e.preventDefault(); handleSave(); } }} />
); } function shortName(email: string): string { const at = email.indexOf("@"); return at > 0 ? email.slice(0, at) : email; }