import React, { useState, useEffect } from 'react' import { useNavigate, useSearchParams } from 'react-router-dom' import { useAuthStore } from '../store/authStore' import { useSettingsStore } from '../store/settingsStore' import { SUPPORTED_LANGUAGES, useTranslation } from '../i18n' import Navbar from '../components/Layout/Navbar' import CustomSelect from '../components/shared/CustomSelect' import { useToast } from '../components/shared/Toast' import { Save, Map, Palette, User, Moon, Sun, Monitor, Shield, Camera, Trash2, Lock, KeyRound, AlertTriangle, Terminal, Copy, Plus, Check } from 'lucide-react' import { authApi, adminApi, notificationsApi } from '../api/client' import apiClient from '../api/client' import { useAddonStore } from '../store/addonStore' import type { LucideIcon } from 'lucide-react' import type { UserWithOidc } from '../types' import { getApiErrorMessage } from '../types' interface MapPreset { name: string url: string } interface McpToken { id: number name: string token_prefix: string created_at: string last_used_at: string | null } const MAP_PRESETS: MapPreset[] = [ { name: 'OpenStreetMap', url: 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png' }, { name: 'OpenStreetMap DE', url: 'https://tile.openstreetmap.de/{z}/{x}/{y}.png' }, { name: 'CartoDB Light', url: 'https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png' }, { name: 'CartoDB Dark', url: 'https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png' }, { name: 'Stadia Smooth', url: 'https://tiles.stadiamaps.com/tiles/alidade_smooth/{z}/{x}/{y}{r}.png' }, ] interface SectionProps { title: string icon: LucideIcon children: React.ReactNode } function Section({ title, icon: Icon, children }: SectionProps): React.ReactElement { return (
{t('common.loading')}
const options = [ { key: 'notify_trip_invite', label: t('settings.notifyTripInvite') }, { key: 'notify_booking_change', label: t('settings.notifyBookingChange') }, ...(addons.vacay ? [{ key: 'notify_vacay_invite', label: t('settings.notifyVacayInvite') }] : []), ...(memoriesEnabled ? [{ key: 'notify_photos_shared', label: t('settings.notifyPhotosShared') }] : []), ...(addons.collab ? [{ key: 'notify_collab_message', label: t('settings.notifyCollabMessage') }] : []), ...(addons.documents ? [{ key: 'notify_packing_tagged', label: t('settings.notifyPackingTagged') }] : []), { key: 'notify_webhook', label: t('settings.notifyWebhook') }, ] return ({t('settings.subtitle')}
{t('settings.mapDefaultHint')}
{mcpEndpoint}
{mcpJsonConfig}
{t('settings.mcp.clientConfigHint')}
{t('settings.mcp.noTokens')}
) : ({token.name}
{token.token_prefix}... {t('settings.mcp.tokenCreatedAt')} {new Date(token.created_at).toLocaleDateString(locale)} {token.last_used_at && ( · {t('settings.mcp.tokenUsedAt')} {new Date(token.last_used_at).toLocaleDateString(locale)} )}
{t('settings.mcp.modal.createdWarning')}
{mcpCreatedToken}
{t('settings.mcp.deleteTokenMessage')}
{t('settings.mfa.requiredByPolicy')}
{t('settings.mfa.description')}
{demoMode ? ({t('settings.mfa.demoBlocked')}
) : ( <>{user?.mfa_enabled ? t('settings.mfa.enabled') : t('settings.mfa.disabled')}
{!user?.mfa_enabled && !mfaQr && ( )} {!user?.mfa_enabled && mfaQr && ({t('settings.mfa.scanQr')}
{mfaSecret}
{t('settings.mfa.disableTitle')}
{t('settings.mfa.disableHint')}
setMfaDisablePwd(e.target.value)} placeholder={t('settings.currentPassword')} className="w-full px-3 py-2 border border-slate-300 rounded-lg text-sm" /> setMfaDisableCode(e.target.value.replace(/\D/g, '').slice(0, 8))} placeholder={t('settings.mfa.codePlaceholder')} className="w-full px-3 py-2 border border-slate-300 rounded-lg text-sm" />{t('settings.oidcLinked')} {(user as UserWithOidc).oidc_issuer!.replace('https://', '').replace(/\/+$/, '')}
)}{t('settings.deleteBlockedMessage')}
{t('settings.deleteAccountWarning')}