import { useState, useEffect, useCallback } from 'react' import { Bell, Loader2, Mail, Server, Webhook } from 'lucide-react' import { useTranslation } from 'react-i18next' import { toast } from 'sonner' import { ROLE } from '@/lib/roles' import { Button } from '@/components/ui/button' import { Input } from '@/components/ui/input' import { Label } from '@/components/ui/label' import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group' import { Switch } from '@/components/ui/switch' import { PasswordInput } from '@/components/password-input' import { updateUserSettings } from '../../api' import { DEFAULT_QUOTA_WARNING_THRESHOLD, NOTIFICATION_METHODS, } from '../../constants' import { parseUserSettings } from '../../lib' import type { UserProfile, UserSettings, NotifyType } from '../../types' const NOTIFICATION_ICONS: Record = { email: Mail, webhook: Webhook, bark: Bell, gotify: Server, } // ============================================================================ // Settings Tab Component // ============================================================================ interface NotificationTabProps { profile: UserProfile | null onUpdate: () => void } export function NotificationTab({ profile, onUpdate }: NotificationTabProps) { const { t } = useTranslation() const isAdmin = (profile?.role ?? 0) >= ROLE.ADMIN const [loading, setLoading] = useState(false) const [settings, setSettings] = useState({ notify_type: 'email', quota_warning_threshold: DEFAULT_QUOTA_WARNING_THRESHOLD, notification_email: '', webhook_url: '', webhook_secret: '', bark_url: '', gotify_url: '', gotify_token: '', gotify_priority: 5, accept_unset_model_ratio_model: false, record_ip_log: false, upstream_model_update_notify_enabled: false, }) // Update form field helper const updateField = useCallback( (field: K, value: UserSettings[K]) => { setSettings((prev) => ({ ...prev, [field]: value })) }, [] ) useEffect(() => { if (profile?.setting) { const parsed = parseUserSettings(profile.setting) setSettings({ notify_type: parsed.notify_type || 'email', quota_warning_threshold: parsed.quota_warning_threshold ?? DEFAULT_QUOTA_WARNING_THRESHOLD, notification_email: parsed.notification_email ?? '', webhook_url: parsed.webhook_url ?? '', webhook_secret: parsed.webhook_secret ?? '', bark_url: parsed.bark_url ?? '', gotify_url: parsed.gotify_url ?? '', gotify_token: parsed.gotify_token ?? '', gotify_priority: parsed.gotify_priority ?? 5, accept_unset_model_ratio_model: parsed.accept_unset_model_ratio_model || false, record_ip_log: parsed.record_ip_log || false, upstream_model_update_notify_enabled: parsed.upstream_model_update_notify_enabled || false, }) } }, [profile]) const handleSave = async () => { try { setLoading(true) const response = await updateUserSettings(settings) if (response.success) { toast.success(t('Settings updated successfully')) onUpdate() } else { toast.error(response.message || t('Failed to update settings')) } } catch (_error) { toast.error(t('Failed to update settings')) } finally { setLoading(false) } } return (
{/* Notification Type */}
updateField('notify_type', value as NotifyType) } className='grid grid-cols-4 gap-1.5 sm:gap-3' > {NOTIFICATION_METHODS.map((method) => { const Icon = NOTIFICATION_ICONS[method.value] const isSelected = settings.notify_type === method.value return ( ) })}
{/* Warning Threshold */}
updateField('quota_warning_threshold', Number(e.target.value)) } placeholder={t('Enter threshold')} />

{t('Get notified when balance falls below this value')}

{/* Email Settings */} {settings.notify_type === 'email' && (
updateField('notification_email', e.target.value)} placeholder={t('Leave empty to use account email')} />
)} {/* Webhook Settings */} {settings.notify_type === 'webhook' && ( <>
updateField('webhook_url', e.target.value)} placeholder={t('https://example.com/webhook')} />
updateField('webhook_secret', e.target.value)} placeholder={t('Enter secret key')} />
)} {/* Bark Settings */} {settings.notify_type === 'bark' && (
updateField('bark_url', e.target.value)} placeholder={t('https://api.day.app/yourkey/{{title}}/{{content}}')} />

{t('Template variables:')} {'{{title}}'}, {'{{content}}'}

)} {/* Gotify Settings */} {settings.notify_type === 'gotify' && ( <>
updateField('gotify_url', e.target.value)} placeholder={t('https://gotify.example.com')} />

{t('Enter the full URL of your Gotify server')}

updateField('gotify_token', e.target.value)} placeholder={t('Enter application token')} />

{t('Token obtained from your Gotify application')}

updateField('gotify_priority', Number(e.target.value)) } placeholder='5' />

{t( 'Priority level from 0 (lowest) to 10 (highest), default is 5' )}

{t('Setup Instructions')}
  1. {t('1. Create an application in your Gotify server')}
  2. {t('2. Copy the application token')}
  3. {t('3. Enter your Gotify server URL and token above')}

{t('Learn more:')}{' '} {t('Gotify Documentation')}

)} {/* Divider */}
{/* Preferences Section */}

{t('Preferences')}

{t('Configure your account behavior preferences')}

{/* Receive Upstream Model Update Notifications (admin only) */} {isAdmin && (

{t( 'Only available for admins. When enabled, you will receive a summary notification via your selected method when the scheduled model check detects upstream model changes or check failures.' )}

updateField('upstream_model_update_notify_enabled', checked) } />
)} {/* Accept Unset Model Price */}

{t('Allow using models without price configuration')}

updateField('accept_unset_model_ratio_model', checked) } />
{/* Record IP Log */}

{t('Log IP address for usage and error logs')}

updateField('record_ip_log', checked)} />
{/* Save Button */}
) }