Skip to content
File

Blob: src/client/components/admin/invite-form.tsx

typescript62 lines
1import { useState } from "react";
2 
3import { FormActions } from "@/client/components/ui/form-actions";
4import { Input } from "@/client/components/ui/input";
5 
6export interface InviteFormValues {
7 email: string;
8 days: number;
9}
10 
11interface InviteFormProps {
12 pending: boolean;
13 error?: string | null;
14 onDismissError?: () => void;
15 onSubmit: (values: InviteFormValues) => Promise<void>;
16 onCancel: () => void;
17}
18 
19export const InviteForm = ({ pending, error, onDismissError, onSubmit, onCancel }: InviteFormProps) => {
20 const [email, setEmail] = useState("");
21 const [days, setDays] = useState(7);
22 
23 const trimmedEmail = email.trim();
24 const canSubmit = trimmedEmail.length > 0 && days >= 1 && days <= 90;
25 
26 const handleSubmit = async (e: React.FormEvent) => {
27 e.preventDefault();
28 if (pending || !canSubmit) return;
29 await onSubmit({ email: trimmedEmail, days });
30 };
31 
32 return (
33 <form onSubmit={handleSubmit} className="flex flex-col gap-4">
34 <Input
35 label="Email"
36 helper="The invite is bound to this address; the recipient must use it to sign up."
37 type="email"
38 required
39 autoFocus
40 value={email}
41 onChange={(e) => setEmail(e.target.value)}
42 />
43 <Input
44 label="Expires in (days)"
45 type="number"
46 min={1}
47 max={90}
48 value={days}
49 onChange={(e) => setDays(Number(e.target.value))}
50 />
51 <FormActions
52 pending={pending}
53 error={error}
54 onDismissError={onDismissError}
55 submitLabel="Mint invite"
56 onCancel={onCancel}
57 submitDisabled={!canSubmit}
58 />
59 </form>
60 );
61};