zerobyte/app/client/modules/notifications/components/notification-forms/generic-form.tsx

180 lines
5 KiB
TypeScript

import { useWatch, type UseFormReturn } from "react-hook-form";
import { FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage } from "~/client/components/ui/form";
import { Input } from "~/client/components/ui/input";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "~/client/components/ui/select";
import { Checkbox } from "~/client/components/ui/checkbox";
import { Textarea } from "~/client/components/ui/textarea";
import { WebhookRequestPreview } from "~/client/components/webhook-request-preview";
import type { NotificationFormValues } from "../create-notification-form";
type Props = {
form: UseFormReturn<NotificationFormValues>;
};
const WebhookPreview = ({ values }: { values: Partial<NotificationFormValues> }) => {
if (values.type !== "generic") return null;
const contentType = values.contentType || "application/json";
const headers = values.headers?.filter(Boolean) || [];
const useJson = values.useJson;
const titleKey = values.titleKey || "title";
const messageKey = values.messageKey || "message";
let body = "";
if (useJson) {
body = JSON.stringify(
{
[titleKey]: "Notification title",
[messageKey]: "Notification message",
},
null,
2,
);
} else {
body = "Notification message";
}
return (
<WebhookRequestPreview
method={values.method || "POST"}
url={values.url}
contentType={contentType}
headers={headers}
body={body}
/>
);
};
export const GenericForm = ({ form }: Props) => {
const watchedValues = useWatch({ control: form.control });
const useJson = useWatch({ control: form.control, name: "useJson" });
return (
<>
<FormField
control={form.control}
name="url"
render={({ field }) => (
<FormItem>
<FormLabel>Webhook URL</FormLabel>
<FormControl>
<Input {...field} placeholder="https://api.example.com/webhook" />
</FormControl>
<FormDescription>The target origin must be listed in WEBHOOK_ALLOWED_ORIGINS.</FormDescription>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="method"
render={({ field }) => (
<FormItem>
<FormLabel>Method</FormLabel>
<Select onValueChange={field.onChange} value={field.value ?? ""}>
<FormControl>
<SelectTrigger>
<SelectValue placeholder="Select method" />
</SelectTrigger>
</FormControl>
<SelectContent>
<SelectItem value="GET">GET</SelectItem>
<SelectItem value="POST">POST</SelectItem>
</SelectContent>
</Select>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="contentType"
render={({ field }) => (
<FormItem>
<FormLabel>Content Type</FormLabel>
<FormControl>
<Input {...field} placeholder="application/json" />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="headers"
render={({ field }) => (
<FormItem>
<FormLabel>Headers</FormLabel>
<FormControl>
<Textarea
{...field}
placeholder="Authorization: Bearer token&#10;X-Custom-Header: value"
value={Array.isArray(field.value) ? field.value.join("\n") : ""}
onChange={(e) =>
field.onChange(
e.target.value
.split("\n")
.map((header) => header.trim())
.filter(Boolean),
)
}
/>
</FormControl>
<FormDescription>
One header per line in Key: Value format. Values are stored as plain text.
</FormDescription>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="useJson"
render={({ field }) => (
<FormItem className="flex flex-row items-center space-x-3">
<FormControl>
<Checkbox checked={field.value} onCheckedChange={(checked) => field.onChange(checked)} />
</FormControl>
<div className="space-y-1 leading-none">
<FormLabel>Use JSON Template</FormLabel>
<FormDescription>Send the message as a JSON object.</FormDescription>
</div>
</FormItem>
)}
/>
{useJson && (
<>
<FormField
control={form.control}
name="titleKey"
render={({ field }) => (
<FormItem>
<FormLabel>Title Key</FormLabel>
<FormControl>
<Input {...field} placeholder="title" />
</FormControl>
<FormDescription>The JSON key for the notification title.</FormDescription>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="messageKey"
render={({ field }) => (
<FormItem>
<FormLabel>Message Key</FormLabel>
<FormControl>
<Input {...field} placeholder="message" />
</FormControl>
<FormDescription>The JSON key for the notification message.</FormDescription>
<FormMessage />
</FormItem>
)}
/>
</>
)}
<WebhookPreview values={watchedValues} />
</>
);
};