Openstatus
www.openstatus.dev
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}