Files
checkcle/application/src/components/settings/notification-settings/NotificationChannelDialog.tsx
T
2025-05-09 21:28:07 +07:00

350 lines
12 KiB
TypeScript

import React, { useEffect } from "react";
import {
Dialog,
DialogContent,
DialogHeader,
DialogTitle,
DialogFooter
} from "@/components/ui/dialog";
import { Button } from "@/components/ui/button";
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
import { AlertConfiguration, alertConfigService } from "@/services/alertConfigService";
import { useForm } from "react-hook-form";
import { z } from "zod";
import { zodResolver } from "@hookform/resolvers/zod";
import { Input } from "@/components/ui/input";
import {
Form,
FormControl,
FormDescription,
FormField,
FormItem,
FormLabel,
FormMessage,
} from "@/components/ui/form";
import { Switch } from "@/components/ui/switch";
import { Loader2 } from "lucide-react";
interface NotificationChannelDialogProps {
open: boolean;
onClose: (refreshList: boolean) => void;
editingConfig: AlertConfiguration | null;
}
const baseSchema = z.object({
notify_name: z.string().min(1, "Name is required"),
notification_type: z.enum(["telegram", "discord", "slack", "signal", "email"]),
enabled: z.boolean().default(true),
service_id: z.string().default("global"), // Assuming global for now, could be linked to specific services
template_id: z.string().optional(),
});
const telegramSchema = baseSchema.extend({
notification_type: z.literal("telegram"),
telegram_chat_id: z.string().min(1, "Chat ID is required"),
bot_token: z.string().min(1, "Bot token is required"),
});
const discordSchema = baseSchema.extend({
notification_type: z.literal("discord"),
discord_webhook_url: z.string().url("Must be a valid URL"),
});
const slackSchema = baseSchema.extend({
notification_type: z.literal("slack"),
slack_webhook_url: z.string().url("Must be a valid URL"),
});
const signalSchema = baseSchema.extend({
notification_type: z.literal("signal"),
signal_number: z.string().min(1, "Signal number is required"),
});
const emailSchema = baseSchema.extend({
notification_type: z.literal("email"),
// Email specific fields could be added here
});
const formSchema = z.discriminatedUnion("notification_type", [
telegramSchema,
discordSchema,
slackSchema,
signalSchema,
emailSchema
]);
type FormValues = z.infer<typeof formSchema>;
export const NotificationChannelDialog = ({
open,
onClose,
editingConfig
}: NotificationChannelDialogProps) => {
const isEditing = !!editingConfig;
const form = useForm<FormValues>({
resolver: zodResolver(formSchema),
defaultValues: {
notify_name: "",
notification_type: "telegram" as const,
enabled: true,
service_id: "global",
template_id: "",
},
});
const { watch, reset } = form;
const notificationType = watch("notification_type");
const [isSubmitting, setIsSubmitting] = React.useState(false);
useEffect(() => {
if (editingConfig) {
// Handle string vs boolean for enabled field
const enabled = typeof editingConfig.enabled === 'string'
? editingConfig.enabled === "true"
: !!editingConfig.enabled;
reset({
...editingConfig,
enabled
});
} else if (open) {
reset({
notify_name: "",
notification_type: "telegram" as const,
enabled: true,
service_id: "global",
template_id: "",
});
}
}, [editingConfig, open, reset]);
const handleClose = () => {
onClose(false);
};
const onSubmit = async (values: FormValues) => {
setIsSubmitting(true);
try {
// Ensure service_id is always present
const configData = {
...values,
service_id: values.service_id || "global",
};
if (isEditing && editingConfig?.id) {
await alertConfigService.updateAlertConfiguration(editingConfig.id, configData);
} else {
await alertConfigService.createAlertConfiguration(configData as any);
}
onClose(true); // Close with refresh
} finally {
setIsSubmitting(false);
}
};
return (
<Dialog open={open} onOpenChange={() => handleClose()}>
<DialogContent className="sm:max-w-[500px]">
<DialogHeader>
<DialogTitle>
{isEditing ? "Edit Notification Channel" : "Add Notification Channel"}
</DialogTitle>
</DialogHeader>
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-6">
<FormField
control={form.control}
name="notify_name"
render={({ field }) => (
<FormItem>
<FormLabel>Name</FormLabel>
<FormControl>
<Input placeholder="My Notification Channel" {...field} />
</FormControl>
<FormDescription>
A name to identify this notification channel
</FormDescription>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="notification_type"
render={({ field }) => (
<FormItem className="space-y-3">
<FormLabel>Channel Type</FormLabel>
<FormControl>
<RadioGroup
onValueChange={field.onChange}
defaultValue={field.value}
value={field.value}
className="flex flex-col space-y-1"
>
<FormItem className="flex items-center space-x-3 space-y-0">
<FormControl>
<RadioGroupItem value="telegram" />
</FormControl>
<FormLabel className="font-normal">
Telegram
</FormLabel>
</FormItem>
<FormItem className="flex items-center space-x-3 space-y-0">
<FormControl>
<RadioGroupItem value="discord" />
</FormControl>
<FormLabel className="font-normal">
Discord
</FormLabel>
</FormItem>
<FormItem className="flex items-center space-x-3 space-y-0">
<FormControl>
<RadioGroupItem value="slack" />
</FormControl>
<FormLabel className="font-normal">
Slack
</FormLabel>
</FormItem>
<FormItem className="flex items-center space-x-3 space-y-0">
<FormControl>
<RadioGroupItem value="signal" />
</FormControl>
<FormLabel className="font-normal">
Signal
</FormLabel>
</FormItem>
<FormItem className="flex items-center space-x-3 space-y-0">
<FormControl>
<RadioGroupItem value="email" />
</FormControl>
<FormLabel className="font-normal">
Email
</FormLabel>
</FormItem>
</RadioGroup>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
{/* Show different fields based on notification type */}
{notificationType === "telegram" && (
<>
<FormField
control={form.control}
name="telegram_chat_id"
render={({ field }) => (
<FormItem>
<FormLabel>Chat ID</FormLabel>
<FormControl>
<Input placeholder="Telegram Chat ID" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="bot_token"
render={({ field }) => (
<FormItem>
<FormLabel>Bot Token</FormLabel>
<FormControl>
<Input placeholder="Telegram Bot Token" {...field} type="password" />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</>
)}
{notificationType === "discord" && (
<FormField
control={form.control}
name="discord_webhook_url"
render={({ field }) => (
<FormItem>
<FormLabel>Webhook URL</FormLabel>
<FormControl>
<Input placeholder="Discord Webhook URL" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
)}
{notificationType === "slack" && (
<FormField
control={form.control}
name="slack_webhook_url"
render={({ field }) => (
<FormItem>
<FormLabel>Webhook URL</FormLabel>
<FormControl>
<Input placeholder="Slack Webhook URL" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
)}
{notificationType === "signal" && (
<FormField
control={form.control}
name="signal_number"
render={({ field }) => (
<FormItem>
<FormLabel>Signal Number</FormLabel>
<FormControl>
<Input placeholder="+1234567890" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
)}
<FormField
control={form.control}
name="enabled"
render={({ field }) => (
<FormItem className="flex flex-row items-center justify-between rounded-lg border p-3">
<div className="space-y-0.5">
<FormLabel>Enabled</FormLabel>
<FormDescription>
Turn notifications on or off
</FormDescription>
</div>
<FormControl>
<Switch
checked={field.value}
onCheckedChange={field.onChange}
/>
</FormControl>
</FormItem>
)}
/>
<DialogFooter>
<Button variant="outline" type="button" onClick={handleClose}>
Cancel
</Button>
<Button type="submit" disabled={isSubmitting}>
{isSubmitting && <Loader2 className="mr-2 h-4 w-4 animate-spin" />}
{isEditing ? "Update" : "Create"}
</Button>
</DialogFooter>
</form>
</Form>
</DialogContent>
</Dialog>
);
};