import { useState } from "react"; import { FormActions } from "@/client/components/ui/form-actions"; import { Input } from "@/client/components/ui/input"; export interface ClientFormValues { name: string; redirectUris: string[]; uri: string; skipConsent: boolean; } interface ClientFormProps { mode: "create" | "edit"; initial?: Partial; pending: boolean; error?: string | null; onDismissError?: () => void; onSubmit: (values: ClientFormValues) => Promise; onCancel: () => void; } const SkipConsentNote = () => ( For first-party RPs (anvil, bland) only. Bypasses the per-user grant prompt; tokens are issued straight from{" "} /authorize. Leave off for third-party clients. ); export const ClientForm = ({ mode, initial, pending, error, onDismissError, onSubmit, onCancel }: ClientFormProps) => { const [name, setName] = useState(initial?.name ?? ""); const [redirectUrisText, setRedirectUrisText] = useState((initial?.redirectUris ?? []).join("\n")); const [uri, setUri] = useState(initial?.uri ?? ""); const [skipConsent, setSkipConsent] = useState(initial?.skipConsent ?? false); const [localError, setLocalError] = useState(null); const isEdit = mode === "edit"; const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); if (pending) return; const redirectUris = redirectUrisText .split(/\r?\n/) .map((s) => s.trim()) .filter(Boolean); if (!isEdit && redirectUris.length === 0) { setLocalError("At least one redirect URI is required."); return; } setLocalError(null); await onSubmit({ name: name.trim(), // In edit mode the redirect_uris field is read-only and the worker // ignores anything beyond name/skipConsent/uri, so the original list // is sent back unchanged for completeness only. redirectUris: isEdit ? (initial?.redirectUris ?? []) : redirectUris, uri: uri.trim(), skipConsent, }); }; return (
setName(e.target.value)} required autoFocus={!isEdit} />