Something went wrong. Try again.
[READ-ONLY] Mirror of https://github.com/openstatusHQ/openstatus. ๐ซ Status page with uptime monitoring & API monitoring as code ๐ซ openstatus.dev
bun drizzle-orm monitoring monitoring-as-code nextjs observability on-call open-source shadcn-ui status-page statuspage synthetic-monitoring tinybird turso uptime uptime-checker uptime-monitor
Something went wrong. Try again.
6.0 kB ยท 210 lines
TSX
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211"use client";
import { zodResolver } from "@hookform/resolvers/zod";import { Button } from "@openstatus/ui/components/ui/button";import { Checkbox } from "@openstatus/ui/components/ui/checkbox";import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage,} from "@openstatus/ui/components/ui/form";import { Input } from "@openstatus/ui/components/ui/input";import { SelectItem } from "@openstatus/ui/components/ui/select";import { SelectContent, SelectValue,} from "@openstatus/ui/components/ui/select";import { SelectTrigger } from "@openstatus/ui/components/ui/select";import { Select } from "@openstatus/ui/components/ui/select";import { Textarea } from "@openstatus/ui/components/ui/textarea";import { cn } from "@openstatus/ui/lib/utils";import { useTransition } from "react";import { useForm } from "react-hook-form";import { toast } from "sonner";import { z } from "zod";
export const types = [ { label: "Report a bug", value: "bug" as const, }, { label: "Book a demo", value: "demo" as const, }, { label: "Suggest a feature", value: "feature" as const, }, { label: "Report a security issue", value: "security" as const, }, { label: "Something else", value: "question" as const, },];
export const schema = z.object({ name: z.string().min(1, { error: "Name is required", }), type: z.enum(["bug", "demo", "feature", "security", "question"]), email: z.email({ error: "Invalid email address", }), message: z.string().min(1, { error: "Message is required", }), blocker: z.boolean(),});
export type FormValues = z.infer<typeof schema>;
interface ContactFormProps { defaultValues?: Partial<FormValues>; onSubmit: (data: FormValues) => Promise<void>; className?: string;}
export function ContactForm({ defaultValues, onSubmit, className,}: ContactFormProps) { const form = useForm<FormValues>({ resolver: zodResolver(schema), defaultValues: { name: defaultValues?.name ?? "", email: defaultValues?.email ?? "", type: defaultValues?.type ?? undefined, message: defaultValues?.message ?? "", blocker: defaultValues?.blocker ?? false, }, }); const [isPending, startTransition] = useTransition(); const watchType = form.watch("type");
async function submitAction(values: FormValues) { if (isPending) return;
startTransition(async () => { try { const promise = onSubmit(values); toast.promise(promise, { loading: "Sending message...", success: "Message sent. We'll get back to you soon.", error: "Failed to send message. Please try again.", }); await promise; } catch (error) { console.error(error); } }); }
return ( <Form {...form}> <form onSubmit={form.handleSubmit(submitAction)} className={cn("grid gap-4 sm:grid-cols-2", className)} > <FormField control={form.control} name="name" render={({ field }) => ( <FormItem> <FormLabel>Name</FormLabel> <FormControl> <Input placeholder="Max" {...field} /> </FormControl> <FormMessage /> </FormItem> )} /> <FormField control={form.control} name="email" render={({ field }) => ( <FormItem> <FormLabel>Email</FormLabel> <FormControl> <Input placeholder="max@openstatus.dev" {...field} /> </FormControl> <FormMessage /> </FormItem> )} /> <FormField control={form.control} name="type" render={({ field }) => ( <FormItem className="sm:col-span-full"> <FormLabel>Type</FormLabel> <Select onValueChange={field.onChange} defaultValue={field.value}> <FormControl> <SelectTrigger className="w-full"> <SelectValue placeholder="What you need help with" /> </SelectTrigger> </FormControl> <SelectContent> {types.map((type) => ( <SelectItem key={type.value} value={type.value}> {type.label} </SelectItem> ))} </SelectContent> </Select> <FormMessage /> </FormItem> )} /> {watchType ? ( <FormField control={form.control} name="message" render={({ field }) => ( <FormItem className="sm:col-span-full"> <FormLabel>Message</FormLabel> <FormControl> <Textarea placeholder="Tell us about it..." {...field} /> </FormControl> <FormMessage /> </FormItem> )} /> ) : null} {watchType === "bug" ? ( <FormField control={form.control} name="blocker" render={({ field }) => ( <FormItem className="flex flex-row items-start sm:col-span-full"> <FormControl> <Checkbox checked={field.value} onCheckedChange={field.onChange} /> </FormControl> <FormLabel className="leading-none font-normal"> This bug prevents me from using the product. </FormLabel> </FormItem> )} /> ) : null} <Button type="submit" className="w-full sm:col-span-full" disabled={isPending} > {isPending ? "Submitting..." : "Submit"} </Button> </form> </Form> );}