"use client"; import { useEffect, useRef, useState } from "react"; import { Check, Eye, EyeOff, Loader2, Save } from "lucide-react"; import { useSetUserApiKey } from "@/hooks/use-auth"; import type { UserApiKeyStatus } from "@/lib/types"; /** One provider's own-key row: label, editable masked textbox with a * hide/unhide toggle, credit/free-tier info, and a blue Update button - all * with the same crossfade-icon transition language as the admin-only * server-key box's Show/Hide toggle (api-key-row.tsx). Unlike that box, * this one is per-user and editable: each user only ever sees/sets their * own key here, never anyone else's. * * `liveCredits`, when passed, overrides the number shown for the numeric * "N credits remaining" line - used for NinjaPear, which sources its * balance from useSystemStatus()'s already-fetched ninjapear_credit_balance * (the same number shown in System configuration below) rather than this * component making its own separate, redundant live call. */ export function UserApiKeyRow({ apiKey, liveCredits, }: { apiKey: UserApiKeyStatus; liveCredits?: number | null; }) { const [value, setValue] = useState(apiKey.value ?? ""); const [revealed, setRevealed] = useState(false); const [justSaved, setJustSaved] = useState(false); const savedTimeout = useRef | null>(null); const setKey = useSetUserApiKey(); useEffect( () => () => { if (savedTimeout.current) clearTimeout(savedTimeout.current); }, [], ); const dirty = value !== (apiKey.value ?? ""); const credits = liveCredits !== undefined ? liveCredits : apiKey.credits; const handleUpdate = () => { setKey.mutate( { provider: apiKey.provider, payload: { key: value } }, { onSuccess: (updated) => { setValue(updated.value ?? ""); setJustSaved(true); if (savedTimeout.current) clearTimeout(savedTimeout.current); savedTimeout.current = setTimeout(() => setJustSaved(false), 1800); }, }, ); }; return (
{apiKey.free && ( Free{apiKey.requires_government_id ? " ยท requires government ID approval" : ""} )}
setValue(e.target.value)} placeholder={apiKey.configured ? undefined : "Not set"} className="focus-ring block w-full rounded-md border border-slate-300 px-3 py-2 font-mono text-sm text-slate-900 shadow-sm transition-colors duration-150 placeholder:font-sans placeholder:text-slate-400" />

{apiKey.configured ? credits !== null && credits !== undefined ? `${credits} credits remaining. ${apiKey.credits_note ?? ""}` : (apiKey.credits_note ?? "") : (apiKey.credits_note ?? "")}

{setKey.isError && (

Couldn't save that key. Try again.

)}
); }