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.8 kB ยท 198 lines
TSX
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199"use client";
import { zodResolver } from "@hookform/resolvers/zod";import type { NotificationProvider } from "@openstatus/db/src/schema";import { Badge } from "@openstatus/ui/components/ui/badge";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 { cn } from "@openstatus/ui/lib/utils";import { isTRPCClientError } from "@trpc/client";import { useTransition } from "react";import { useForm } from "react-hook-form";import { toast } from "sonner";import { z } from "zod";
import { EmptyStateContainer, EmptyStateTitle,} from "@/components/content/empty-state";import { FormCard, FormCardContent, FormCardDescription, FormCardFooter, FormCardHeader, FormCardTitle,} from "@/components/forms/form-card";import { config } from "@/data/notifications.client";
const schema = z.object({ notifiers: z.array(z.number()),});
type FormValues = z.infer<typeof schema>;
export function FormNotifiers({ defaultValues, onSubmit, notifiers, ...props}: Omit<React.ComponentProps<"form">, "onSubmit"> & { defaultValues?: FormValues; onSubmit: (values: FormValues) => Promise<void>; notifiers: { id: number; name: string; provider: NotificationProvider }[];}) { const form = useForm<FormValues>({ resolver: zodResolver(schema), defaultValues: defaultValues ?? { notifiers: [], }, }); const watchNotifiers = form.watch("notifiers"); const [isPending, startTransition] = useTransition();
function submitAction(values: FormValues) { if (isPending) return;
startTransition(async () => { try { const promise = onSubmit(values); toast.promise(promise, { loading: "Saving...", success: () => "Saved", error: (error) => { if (isTRPCClientError(error)) { return error.message; } return "Failed to save"; }, }); await promise; } catch (error) { console.error(error); } }); }
return ( <Form {...form}> <form onSubmit={form.handleSubmit(submitAction)} {...props}> <FormCard> <FormCardHeader> <FormCardTitle>Notifications</FormCardTitle> <FormCardDescription> Get notified when your monitor is degraded or down. </FormCardDescription> </FormCardHeader> <FormCardContent> {notifiers.length > 0 ? ( <FormField control={form.control} name="notifiers" render={() => ( <FormItem> <div className="flex items-center justify-between"> <FormLabel className="text-base"> List of Notifications </FormLabel> <Button variant="ghost" size="sm" type="button" className={cn( watchNotifiers.length === notifiers.length && "text-muted-foreground", )} onClick={() => { const allSelected = notifiers.every((item) => watchNotifiers.includes(item.id), );
if (!allSelected) { form.setValue( "notifiers", notifiers.map((item) => item.id), ); } else { form.setValue("notifiers", []); } }} > Select all </Button> </div> {notifiers.map((item) => ( <FormField key={item.id} control={form.control} name="notifiers" render={({ field }) => { const Icon = config[item.provider].icon; const label = config[item.provider].label; return ( <FormItem key={item.id} className="flex items-center" > <FormControl> <Checkbox checked={ field.value?.includes(item.id) || false } onCheckedChange={(checked) => { return checked ? field.onChange([ ...field.value, item.id, ]) : field.onChange( field.value?.filter( (value) => value !== item.id, ), ); }} /> </FormControl> <FormLabel className="text-sm font-normal"> {item.name}{" "} <Badge variant="secondary" className="px-1.5 py-px font-mono text-[10px]" > <Icon className="size-2.5" /> {label} </Badge> </FormLabel> </FormItem> ); }} /> ))} <FormMessage /> </FormItem> )} /> ) : ( <EmptyStateContainer> <EmptyStateTitle>No notifications</EmptyStateTitle> </EmptyStateContainer> )} </FormCardContent> <FormCardFooter> <Button type="submit" disabled={isPending}> {isPending ? "Submitting..." : "Submit"} </Button> </FormCardFooter> </FormCard> </form> </Form> );}