From f40f9d2a4b8885b8d06a4db1d9b10ccb460f4148 Mon Sep 17 00:00:00 2001 From: BOHA Date: Mon, 23 Mar 2026 11:40:50 +0100 Subject: [PATCH] feat: wire up mandatory 2FA toggle in global settings Connects the existing UI button to GET/POST /api/admin/totp/required endpoints. Fetches current state on load, toggles on click. Co-Authored-By: Claude Opus 4.6 (1M context) --- src/admin/pages/Settings.tsx | 41 +++++++++++++++++++++++++++++++----- 1 file changed, 36 insertions(+), 5 deletions(-) diff --git a/src/admin/pages/Settings.tsx b/src/admin/pages/Settings.tsx index 6efffa6..3f9340f 100644 --- a/src/admin/pages/Settings.tsx +++ b/src/admin/pages/Settings.tsx @@ -122,18 +122,49 @@ export default function Settings() { fetchData() }, [fetchData]) + const canSecurity = hasPermission('settings.security') + const fetch2FARequired = useCallback(async () => { - // TODO: Backend endpoint for 2FA requirement settings not yet implemented - setRequire2FALoading(false) - }, []) + if (!canSecurity) { + setRequire2FALoading(false) + return + } + try { + const response = await apiFetch(`${API_BASE}/totp/required`) + const result = await response.json() + if (result.success) { + setRequire2FA(result.data.require_2fa) + } + } catch { /* ignore */ } + finally { + setRequire2FALoading(false) + } + }, [canSecurity]) useEffect(() => { fetch2FARequired() }, [fetch2FARequired]) const handleToggle2FARequired = async () => { - // TODO: Backend endpoint for 2FA requirement settings not yet implemented - alert.error('Tato funkce zatím není k dispozici') + setRequire2FASaving(true) + try { + const response = await apiFetch(`${API_BASE}/totp/required`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ required: !require2FA }), + }) + const result = await response.json() + if (result.success) { + setRequire2FA(!require2FA) + alert.success(result.message || '2FA nastavení uloženo') + } else { + alert.error(result.error || 'Nepodařilo se uložit nastavení') + } + } catch { + alert.error('Chyba připojení') + } finally { + setRequire2FASaving(false) + } } const generateSlug = (text: string): string => {