import { Button } from '@/components/ui/button' import { Input } from '@/components/ui/input' import { Label } from '@/components/ui/label' import { pb } from '@/lib/stores' import { Separator } from '@/components/ui/separator' import { Card } from '@/components/ui/card' import { BellIcon, LoaderCircleIcon, PlusIcon, SaveIcon, Trash2Icon } from 'lucide-react' import { ChangeEventHandler, useEffect, useState } from 'react' import { toast } from '@/components/ui/use-toast' import { InputTags } from '@/components/ui/input-tags' import { UserSettings } from '@/types' import { saveSettings } from './layout' import * as v from 'valibot' import { isAdmin } from '@/lib/utils' import { useTranslation } from 'react-i18next' interface ShoutrrrUrlCardProps { url: string onUrlChange: ChangeEventHandler onRemove: () => void } const NotificationSchema = v.object({ emails: v.array(v.pipe(v.string(), v.email())), webhooks: v.array(v.pipe(v.string(), v.url())), }) const SettingsNotificationsPage = ({ userSettings }: { userSettings: UserSettings }) => { const { t } = useTranslation() const [webhooks, setWebhooks] = useState(userSettings.webhooks ?? []) const [emails, setEmails] = useState(userSettings.emails ?? []) const [isLoading, setIsLoading] = useState(false) // update values when userSettings changes useEffect(() => { setWebhooks(userSettings.webhooks ?? []) setEmails(userSettings.emails ?? []) }, [userSettings]) function addWebhook() { setWebhooks([...webhooks, '']) // focus on the new input queueMicrotask(() => { const inputs = document.querySelectorAll('#webhooks input') as NodeListOf inputs[inputs.length - 1]?.focus() }) } const removeWebhook = (index: number) => setWebhooks(webhooks.filter((_, i) => i !== index)) function updateWebhook(index: number, value: string) { const newWebhooks = [...webhooks] newWebhooks[index] = value setWebhooks(newWebhooks) } async function updateSettings() { setIsLoading(true) try { const parsedData = v.parse(NotificationSchema, { emails, webhooks }) await saveSettings(parsedData) } catch (e: any) { toast({ title: 'Failed to save settings', description: e.message, variant: 'destructive', }) } setIsLoading(false) } return (

{t('settings.notifications.title')}

{t('settings.notifications.subtitle_1')}

{t('settings.notifications.subtitle_2')}{' '} {t('settings.notifications.subtitle_3')}

{t('settings.notifications.email.title')}

{isAdmin() && (

{t('settings.notifications.email.please')}{' '} {t('settings.notifications.email.configure_an_SMTP_server')} {' '} {t('settings.notifications.email.to_ensure_alerts_are_delivered')}{' '}

)}

{t('settings.notifications.email.des')}

{t('settings.notifications.webhook_push.title')}

{t('settings.notifications.webhook_push.des_1')}{' '} Shoutrrr {' '} {t('settings.notifications.webhook_push.des_2')}

{webhooks.length > 0 && (
{webhooks.map((webhook, index) => ( ) => updateWebhook(index, e.target.value) } onRemove={() => removeWebhook(index)} /> ))}
)}
) } const ShoutrrrUrlCard = ({ url, onUrlChange, onRemove }: ShoutrrrUrlCardProps) => { const [isLoading, setIsLoading] = useState(false) const sendTestNotification = async () => { setIsLoading(true) const res = await pb.send('/api/beszel/send-test-notification', { url }) if ('err' in res && !res.err) { toast({ title: 'Test notification sent', description: 'Check your notification service', }) } else { toast({ title: 'Error', description: res.err ?? 'Failed to send test notification', variant: 'destructive', }) } setIsLoading(false) } return (
) } export default SettingsNotificationsPage