diff --git a/client/src/api/client.ts b/client/src/api/client.ts index 1e283f3..bae57b6 100644 --- a/client/src/api/client.ts +++ b/client/src/api/client.ts @@ -331,7 +331,7 @@ export const notificationsApi = { getPreferences: () => apiClient.get('/notifications/preferences').then(r => r.data), updatePreferences: (prefs: Record>) => apiClient.put('/notifications/preferences', prefs).then(r => r.data), testSmtp: (email?: string) => apiClient.post('/notifications/test-smtp', { email }).then(r => r.data), - testWebhook: (url: string) => apiClient.post('/notifications/test-webhook', { url }).then(r => r.data), + testWebhook: (url?: string) => apiClient.post('/notifications/test-webhook', { url }).then(r => r.data), } export const inAppNotificationsApi = { diff --git a/client/src/components/Settings/NotificationsTab.tsx b/client/src/components/Settings/NotificationsTab.tsx index 443f203..7ee5a13 100644 --- a/client/src/components/Settings/NotificationsTab.tsx +++ b/client/src/components/Settings/NotificationsTab.tsx @@ -36,13 +36,20 @@ export default function NotificationsTab(): React.ReactElement { const [matrix, setMatrix] = useState(null) const [saving, setSaving] = useState(false) const [webhookUrl, setWebhookUrl] = useState('') + const [webhookIsSet, setWebhookIsSet] = useState(false) const [webhookSaving, setWebhookSaving] = useState(false) const [webhookTesting, setWebhookTesting] = useState(false) useEffect(() => { notificationsApi.getPreferences().then((data: PreferencesMatrix) => setMatrix(data)).catch(() => {}) settingsApi.get().then((data: { settings: Record }) => { - setWebhookUrl((data.settings?.webhook_url as string) || '') + const val = (data.settings?.webhook_url as string) || '' + if (val === '••••••••') { + setWebhookIsSet(true) + setWebhookUrl('') + } else { + setWebhookUrl(val) + } }).catch(() => {}) }, []) @@ -75,6 +82,8 @@ export default function NotificationsTab(): React.ReactElement { setWebhookSaving(true) try { await settingsApi.set('webhook_url', webhookUrl) + if (webhookUrl) setWebhookIsSet(true) + else setWebhookIsSet(false) toast.success(t('settings.webhookUrl.saved')) } catch { toast.error(t('common.error')) @@ -84,10 +93,10 @@ export default function NotificationsTab(): React.ReactElement { } const testWebhookUrl = async () => { - if (!webhookUrl) return + if (!webhookUrl && !webhookIsSet) return setWebhookTesting(true) try { - const result = await notificationsApi.testWebhook(webhookUrl) + const result = await notificationsApi.testWebhook(webhookUrl || undefined) if (result.success) toast.success(t('settings.webhookUrl.testSuccess')) else toast.error(result.error || t('settings.webhookUrl.testFailed')) } catch { @@ -122,7 +131,7 @@ export default function NotificationsTab(): React.ReactElement { type="text" value={webhookUrl} onChange={e => setWebhookUrl(e.target.value)} - placeholder={t('settings.webhookUrl.placeholder')} + placeholder={webhookIsSet ? '••••••••' : t('settings.webhookUrl.placeholder')} style={{ flex: 1, fontSize: 13, padding: '6px 10px', border: '1px solid var(--border-primary)', borderRadius: 6, background: 'var(--bg-primary)', color: 'var(--text-primary)' }} /> diff --git a/client/src/pages/AdminPage.tsx b/client/src/pages/AdminPage.tsx index ae93a99..201e344 100644 --- a/client/src/pages/AdminPage.tsx +++ b/client/src/pages/AdminPage.tsx @@ -1258,9 +1258,9 @@ export default function AdminPage(): React.ReactElement { setSmtpValues(prev => ({ ...prev, admin_webhook_url: e.target.value }))} - placeholder="https://discord.com/api/webhooks/..." + placeholder={smtpValues.admin_webhook_url === '••••••••' ? '••••••••' : 'https://discord.com/api/webhooks/...'} className="w-full px-3 py-2 border border-slate-300 rounded-lg text-sm focus:ring-2 focus:ring-slate-400 focus:border-transparent" /> @@ -1279,10 +1279,11 @@ export default function AdminPage(): React.ReactElement {