'use client'; import { useEffect, useMemo, useState } from 'react'; import { Chrome, Loader2, Save, ToggleLeft, ToggleRight } from 'lucide-react'; import { useAuth } from '@/components/id/auth-provider'; import { AdminShell } from '@/components/id/admin-shell'; import { usePublicSettings } from '@/components/id/public-settings-provider'; import { useToast } from '@/components/id/toast-provider'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { MessagingSettingsSection } from '@/components/id/messaging-settings-section'; import { SettingsFieldRow } from '@/components/id/settings-field-row'; import { apiFetch, buildSystemSettingPayload, SocialProvider, SystemSetting } from '@/lib/api'; import { getSettingMeta, isSettingVisible, MESSAGING_SETTING_KEYS, sortSettingsByCatalog, SYSTEM_SETTING_GROUPS } from '@/lib/system-settings-catalog'; const GROUP_LABELS: Record = { ...SYSTEM_SETTING_GROUPS, 'messaging-email': 'Email (SMTP)', 'messaging-sms': 'SMS' }; const PUBLIC_SETTINGS_REFRESH_KEYS = new Set([ 'PROJECT_NAME', 'PROJECT_TAGLINE', 'PUBLIC_API_URL', 'PUBLIC_FRONTEND_URL', 'ONE_TAP_ENABLED', 'LDAP_ENABLED', 'LDAP_USE_LDAPS' ]); export default function AdminSettingsPage() { const { token, user } = useAuth(); const { showToast } = useToast(); const { refreshPublicSettings } = usePublicSettings(); const [settings, setSettings] = useState([]); const [providers, setProviders] = useState([]); const [loading, setLoading] = useState(true); const [savingGroup, setSavingGroup] = useState(null); const [savingOAuthProvider, setSavingOAuthProvider] = useState(null); useEffect(() => { if (!token || !user?.canManageSettings) return; Promise.all([ apiFetch<{ settings: SystemSetting[] }>('/admin/settings', {}, token), apiFetch<{ providers: SocialProvider[] }>('/admin/settings/oauth/providers', {}, token) ]) .then(([settingsResponse, providersResponse]) => { setSettings(sortSettingsByCatalog(settingsResponse.settings ?? [])); setProviders(providersResponse.providers ?? []); }) .catch((error) => showToast(error instanceof Error ? error.message : 'Не удалось загрузить настройки')) .finally(() => setLoading(false)); }, [showToast, token, user?.canManageSettings]); const groupedSettings = useMemo(() => { const groups = new Map(); for (const setting of settings) { if (MESSAGING_SETTING_KEYS.includes(setting.key)) continue; const meta = getSettingMeta(setting.key); const group = meta?.group ?? 'other'; const list = groups.get(group) ?? []; list.push(setting); groups.set(group, list); } return groups; }, [settings]); async function saveSettingsGroup(groupKey: string, groupSettings: SystemSetting[]) { if (!token) return; const visibleSettings = groupSettings.filter((setting) => isSettingVisible(setting, settings)); if (visibleSettings.length === 0) return; setSavingGroup(groupKey); try { let needsPublicRefresh = false; for (const setting of visibleSettings) { const updated = await apiFetch( '/admin/settings', { method: 'PUT', body: JSON.stringify(buildSystemSettingPayload(setting)) }, token ); setSettings((current) => sortSettingsByCatalog(current.map((item) => (item.key === updated.key ? updated : item)))); if (PUBLIC_SETTINGS_REFRESH_KEYS.has(updated.key)) { needsPublicRefresh = true; } } if (needsPublicRefresh) { await refreshPublicSettings(); } showToast(`Блок «${GROUP_LABELS[groupKey] ?? groupKey}» сохранён`); } catch (error) { showToast(error instanceof Error ? error.message : 'Не удалось сохранить настройки блока'); } finally { setSavingGroup(null); } } function updateSettingValue(key: string, value: string) { setSettings((current) => current.map((item) => (item.key === key ? { ...item, value } : item))); } function toProviderPayload(provider: SocialProvider) { return { providerName: provider.providerName, clientId: provider.clientId, isEnabled: provider.isEnabled }; } async function toggleProvider(provider: SocialProvider) { if (!token) return; try { const updated = await apiFetch( '/admin/settings/oauth/providers', { method: 'PUT', body: JSON.stringify({ ...toProviderPayload(provider), isEnabled: !provider.isEnabled }) }, token ); setProviders((current) => current.map((item) => (item.providerName === updated.providerName ? updated : item))); showToast(updated.isEnabled ? 'Провайдер включён' : 'Провайдер отключён'); } catch (error) { showToast(error instanceof Error ? error.message : 'Не удалось обновить провайдера'); } } async function saveOAuthProvider(provider: SocialProvider) { if (!token) return; setSavingOAuthProvider(provider.providerName); try { await apiFetch('/admin/settings/oauth/providers', { method: 'PUT', body: JSON.stringify(toProviderPayload(provider)) }, token); showToast(`Провайдер ${provider.providerName} сохранён`); } catch (error) { showToast(error instanceof Error ? error.message : 'Ошибка сохранения провайдера'); } finally { setSavingOAuthProvider(null); } } if (!user?.canManageSettings) { return (

У вас нет прав на изменение глобальных настроек.

); } return (

Глобальные настройки

Параметры сгруппированы по блокам — измените нужные поля и сохраните весь блок одной кнопкой.

{loading ? (
Загрузка...
) : ( <> {[...groupedSettings.entries()].map(([groupKey, groupSettings]) => { const visibleSettings = groupSettings.filter((setting) => isSettingVisible(setting, settings)); const saving = savingGroup === groupKey; return (

{SYSTEM_SETTING_GROUPS[groupKey] ?? 'Прочие настройки'}

{visibleSettings.map((setting) => ( updateSettingValue(setting.key, value)} /> ))}
); })}

OAuth Social Providers

{(providers.length ? providers : [ { id: 'google', providerName: 'google', clientId: '', isEnabled: false }, { id: 'yandex', providerName: 'yandex', clientId: '', isEnabled: false } ] ).map((provider) => (
{provider.providerName === 'google' ? ( ) : (
Я
)}

{provider.providerName}

{provider.isEnabled ? 'Провайдер включен глобально.' : 'Провайдер отключен.'}

setProviders((current) => current.map((item) => item.providerName === provider.providerName ? { ...item, clientId: event.target.value } : item ) ) } />
))}
)}
); }