Openstatus www.openstatus.dev
at main 80 lines 2.0 kB view raw
1"use client"; 2 3import { Form } from "@/components/ui/form"; 4import { 5 FormControl, 6 FormField, 7 FormItem, 8 FormLabel, 9} from "@/components/ui/form"; 10import { Input } from "@/components/ui/input"; 11import { zodResolver } from "@hookform/resolvers/zod"; 12import { isTRPCClientError } from "@trpc/client"; 13import { useTransition } from "react"; 14import { useForm } from "react-hook-form"; 15import { toast } from "sonner"; 16import { z } from "zod"; 17 18const schema = z.object({ 19 password: z.string().min(1), 20}); 21 22type FormValues = z.infer<typeof schema>; 23 24export function FormPassword({ 25 onSubmit, 26 ...props 27}: Omit<React.ComponentProps<"form">, "onSubmit"> & { 28 onSubmit: (values: FormValues) => Promise<void>; 29}) { 30 const form = useForm<FormValues>({ 31 resolver: zodResolver(schema), 32 defaultValues: { 33 password: "", 34 }, 35 }); 36 const [isPending, startTransition] = useTransition(); 37 38 function submitAction(values: FormValues) { 39 if (isPending) return; 40 41 startTransition(async () => { 42 try { 43 const promise = onSubmit(values); 44 toast.promise(promise, { 45 loading: "Confirming...", 46 success: "Confirmed", 47 error: (error) => { 48 if (isTRPCClientError(error)) { 49 form.setError("password", { message: error.message }); 50 return error.message; 51 } 52 return "Failed to confirm"; 53 }, 54 }); 55 await promise; 56 } catch (error) { 57 console.error(error); 58 } 59 }); 60 } 61 62 return ( 63 <Form {...form}> 64 <form onSubmit={form.handleSubmit(submitAction)} {...props}> 65 <FormField 66 control={form.control} 67 name="password" 68 render={({ field }) => ( 69 <FormItem> 70 <FormLabel>Password</FormLabel> 71 <FormControl> 72 <Input type="password" {...field} /> 73 </FormControl> 74 </FormItem> 75 )} 76 /> 77 </form> 78 </Form> 79 ); 80}