import React from 'react' import { adminApi, authApi } from '../../api/client' import { getApiErrorMessage } from '../../types' import { Eye, EyeOff, Save, CheckCircle, XCircle, Loader2, Sun, RefreshCw, AlertTriangle } from 'lucide-react' import type { TranslationFn } from '../../types' import type { useAdmin } from './useAdmin' interface AdminSettingsTabProps { admin: ReturnType t: TranslationFn } // "Settings" admin tab: auth methods, require-MFA, allowed file types, API keys, // OIDC config and the danger zone. Pure layout around the useAdmin hook. export default function AdminSettingsTab({ admin, t }: AdminSettingsTabProps): React.ReactElement { const { toast, setPlacesPhotosEnabled, setPlacesAutocompleteEnabled, setPlacesDetailsEnabled, placesPhotosEnabled, setPlacesPhotosEnabledState, placesAutocompleteEnabled, setPlacesAutocompleteEnabledState, placesDetailsEnabled, setPlacesDetailsEnabledState, oidcConfig, setOidcConfig, savingOidc, setSavingOidc, passwordLogin, setPasswordLogin, passwordRegistration, setPasswordRegistration, oidcLogin, setOidcLogin, oidcRegistration, setOidcRegistration, envOverrideOidcOnly, oidcConfigured, requireMfa, passkeyLogin, setPasskeyLogin, passkeyConfigured, webauthnRpId, setWebauthnRpId, webauthnOrigins, setWebauthnOrigins, savingWebauthn, handleSaveWebauthn, allowedFileTypes, setAllowedFileTypes, savingFileTypes, setSavingFileTypes, mapsKey, setMapsKey, showKeys, savingKeys, validating, validation, setShowRotateJwtModal, handleToggleAuthSetting, handleToggleRequireMfa, toggleKey, handleSaveApiKeys, handleValidateKey, } = admin return (
{/* Authentication Methods */}

{t('admin.authMethods')}

{envOverrideOidcOnly && (

{t('admin.envOverrideHint')}

)} {/* Password Login */}

{t('admin.passwordLogin')}

{t('admin.passwordLoginHint')}

{/* Password Registration */}

{t('admin.passwordRegistration')}

{t('admin.passwordRegistrationHint')}

{/* SSO Login (only when OIDC configured) */} {oidcConfigured && (

{t('admin.oidcLogin')}

{t('admin.oidcLoginHint')}

)} {/* SSO Registration (only when OIDC configured) */} {oidcConfigured && (

{t('admin.oidcRegistration')}

{t('admin.oidcRegistrationHint')}

)}
{/* Passkey (WebAuthn) login */}

{t('admin.passkey.title')}

{t('admin.passkey.cardHint')}

{t('admin.passkey.login')}

{t('admin.passkey.loginHint')}

{passkeyLogin && !passkeyConfigured && (

{t('admin.passkey.notConfigured')}

)}

{t('admin.passkey.rpIdHint')}

setWebauthnRpId(e.target.value)} placeholder="trek.example.org" 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" />

{t('admin.passkey.originsHint')}

setWebauthnOrigins(e.target.value)} placeholder="https://trek.example.org" 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" />
{/* Require 2FA for all users */}

{t('admin.requireMfa')}

{t('admin.requireMfa')}

{t('admin.requireMfaHint')}

{/* Allowed File Types */}

{t('admin.fileTypes')}

{t('admin.fileTypesHint')}

setAllowedFileTypes(e.target.value)} placeholder="jpg,png,pdf,doc,docx,xls,xlsx,txt,csv" 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" />

{t('admin.fileTypesFormat')}

{/* API Keys */}

{t('admin.apiKeys')}

{t('admin.apiKeysHint')}

{/* Google Maps Key */}
setMapsKey(e.target.value)} placeholder={t('settings.keyPlaceholder')} className="w-full pr-10 px-3 py-2 border border-slate-300 rounded-lg text-sm focus:ring-2 focus:ring-slate-400 focus:border-transparent" />

{t('admin.mapsKeyHintLong')}

{validation.maps === true && (

{t('admin.keyValid')}

)} {validation.maps === false && (

{t('admin.keyInvalid')}

)}
{/* Place Photos Toggle */}

{t('admin.placesPhotos.title')}

{t('admin.placesPhotos.subtitle')}

{/* Place Autocomplete Toggle */}

{t('admin.placesAutocomplete.title')}

{t('admin.placesAutocomplete.subtitle')}

{/* Place Details Toggle */}

{t('admin.placesDetails.title')}

{t('admin.placesDetails.subtitle')}

{/* Open-Meteo Weather Info */}
{t('admin.weather.title')}
{t('admin.weather.badge')}

{t('admin.weather.description')}

{t('admin.weather.locationHint')}

{t('admin.weather.forecast')}

{t('admin.weather.forecastDesc')}

{t('admin.weather.climate')}

{t('admin.weather.climateDesc')}

{t('admin.weather.requests')}

{t('admin.weather.requestsDesc')}

{/* OIDC / SSO Configuration */}

{t('admin.oidcTitle')}

{t('admin.oidcSubtitle')}

setOidcConfig(c => ({ ...c, display_name: e.target.value }))} placeholder='z.B. Google, Authentik, Keycloak' 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" />
setOidcConfig(c => ({ ...c, issuer: e.target.value }))} placeholder='https://accounts.google.com' 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" />

{t('admin.oidcIssuerHint')}

setOidcConfig(c => ({ ...c, discovery_url: e.target.value }))} placeholder='https://auth.example.com/application/o/trek/.well-known/openid-configuration' 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" />

Override the auto-constructed discovery URL. Required for providers like Authentik where the endpoint is not at {'/.well-known/openid-configuration'}.

setOidcConfig(c => ({ ...c, client_id: e.target.value }))} 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" />
setOidcConfig(c => ({ ...c, client_secret: e.target.value }))} placeholder={oidcConfig.client_secret_set ? '••••••••' : ''} 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" />
{/* Danger Zone */}

Danger Zone

Rotate JWT Secret

Generate a new JWT signing secret. All active sessions will be invalidated immediately.

) }