import { useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { Card } from '@/components/ui/Card'; import { ToggleSwitch } from '@/components/ui/ToggleSwitch'; import { Button } from '@/components/ui/Button'; import { Input } from '@/components/ui/Input'; import { useAuthStore, useConfigStore, useNotificationStore } from '@/stores'; import { configApi } from '@/services/api'; import type { Config } from '@/types'; import styles from './Settings/Settings.module.scss'; type PendingKey = | 'debug' | 'proxy' | 'retry' | 'switchProject' | 'switchPreview' | 'usage' | 'loggingToFile' | 'wsAuth'; export function SettingsPage() { const { t } = useTranslation(); const { showNotification } = useNotificationStore(); const connectionStatus = useAuthStore((state) => state.connectionStatus); const config = useConfigStore((state) => state.config); const fetchConfig = useConfigStore((state) => state.fetchConfig); const updateConfigValue = useConfigStore((state) => state.updateConfigValue); const clearCache = useConfigStore((state) => state.clearCache); const [loading, setLoading] = useState(true); const [proxyValue, setProxyValue] = useState(''); const [retryValue, setRetryValue] = useState(0); const [pending, setPending] = useState>({} as Record); const [error, setError] = useState(''); const disableControls = connectionStatus !== 'connected'; useEffect(() => { const load = async () => { setLoading(true); setError(''); try { const data = (await fetchConfig()) as Config; setProxyValue(data?.proxyUrl ?? ''); setRetryValue(typeof data?.requestRetry === 'number' ? data.requestRetry : 0); } catch (err: any) { setError(err?.message || t('notification.refresh_failed')); } finally { setLoading(false); } }; load(); }, [fetchConfig, t]); useEffect(() => { if (config) { setProxyValue(config.proxyUrl ?? ''); if (typeof config.requestRetry === 'number') { setRetryValue(config.requestRetry); } } }, [config?.proxyUrl, config?.requestRetry]); const setPendingFlag = (key: PendingKey, value: boolean) => { setPending((prev) => ({ ...prev, [key]: value })); }; const toggleSetting = async ( section: PendingKey, rawKey: 'debug' | 'usage-statistics-enabled' | 'logging-to-file' | 'ws-auth', value: boolean, updater: (val: boolean) => Promise, successMessage: string ) => { const previous = (() => { switch (rawKey) { case 'debug': return config?.debug ?? false; case 'usage-statistics-enabled': return config?.usageStatisticsEnabled ?? false; case 'logging-to-file': return config?.loggingToFile ?? false; case 'ws-auth': return config?.wsAuth ?? false; default: return false; } })(); setPendingFlag(section, true); updateConfigValue(rawKey, value); try { await updater(value); clearCache(rawKey); showNotification(successMessage, 'success'); } catch (err: any) { updateConfigValue(rawKey, previous); showNotification(`${t('notification.update_failed')}: ${err?.message || ''}`, 'error'); } finally { setPendingFlag(section, false); } }; const handleProxyUpdate = async () => { const previous = config?.proxyUrl ?? ''; setPendingFlag('proxy', true); updateConfigValue('proxy-url', proxyValue); try { await configApi.updateProxyUrl(proxyValue.trim()); clearCache('proxy-url'); showNotification(t('notification.proxy_updated'), 'success'); } catch (err: any) { setProxyValue(previous); updateConfigValue('proxy-url', previous); showNotification(`${t('notification.update_failed')}: ${err?.message || ''}`, 'error'); } finally { setPendingFlag('proxy', false); } }; const handleProxyClear = async () => { const previous = config?.proxyUrl ?? ''; setPendingFlag('proxy', true); updateConfigValue('proxy-url', ''); try { await configApi.clearProxyUrl(); clearCache('proxy-url'); setProxyValue(''); showNotification(t('notification.proxy_cleared'), 'success'); } catch (err: any) { setProxyValue(previous); updateConfigValue('proxy-url', previous); showNotification(`${t('notification.update_failed')}: ${err?.message || ''}`, 'error'); } finally { setPendingFlag('proxy', false); } }; const handleRetryUpdate = async () => { const previous = config?.requestRetry ?? 0; const parsed = Number(retryValue); if (!Number.isFinite(parsed) || parsed < 0) { showNotification(t('login.error_invalid'), 'error'); setRetryValue(previous); return; } setPendingFlag('retry', true); updateConfigValue('request-retry', parsed); try { await configApi.updateRequestRetry(parsed); clearCache('request-retry'); showNotification(t('notification.retry_updated'), 'success'); } catch (err: any) { setRetryValue(previous); updateConfigValue('request-retry', previous); showNotification(`${t('notification.update_failed')}: ${err?.message || ''}`, 'error'); } finally { setPendingFlag('retry', false); } }; const quotaSwitchProject = config?.quotaExceeded?.switchProject ?? false; const quotaSwitchPreview = config?.quotaExceeded?.switchPreviewModel ?? false; return (

{t('basic_settings.title')}

{error &&
{error}
}
toggleSetting('debug', 'debug', value, configApi.updateDebug, t('notification.debug_updated')) } /> toggleSetting( 'usage', 'usage-statistics-enabled', value, configApi.updateUsageStatistics, t('notification.usage_statistics_updated') ) } /> toggleSetting( 'loggingToFile', 'logging-to-file', value, configApi.updateLoggingToFile, t('notification.logging_to_file_updated') ) } /> toggleSetting( 'wsAuth', 'ws-auth', value, configApi.updateWsAuth, t('notification.ws_auth_updated') ) } />
setProxyValue(e.target.value)} disabled={disableControls || loading} />
setRetryValue(Number(e.target.value))} disabled={disableControls || loading} className={styles.retryInput} />
(async () => { const previous = config?.quotaExceeded?.switchProject ?? false; const nextQuota = { ...(config?.quotaExceeded || {}), switchProject: value }; setPendingFlag('switchProject', true); updateConfigValue('quota-exceeded', nextQuota); try { await configApi.updateSwitchProject(value); clearCache('quota-exceeded'); showNotification(t('notification.quota_switch_project_updated'), 'success'); } catch (err: any) { updateConfigValue('quota-exceeded', { ...(config?.quotaExceeded || {}), switchProject: previous }); showNotification(`${t('notification.update_failed')}: ${err?.message || ''}`, 'error'); } finally { setPendingFlag('switchProject', false); } })() } /> (async () => { const previous = config?.quotaExceeded?.switchPreviewModel ?? false; const nextQuota = { ...(config?.quotaExceeded || {}), switchPreviewModel: value }; setPendingFlag('switchPreview', true); updateConfigValue('quota-exceeded', nextQuota); try { await configApi.updateSwitchPreviewModel(value); clearCache('quota-exceeded'); showNotification(t('notification.quota_switch_preview_updated'), 'success'); } catch (err: any) { updateConfigValue('quota-exceeded', { ...(config?.quotaExceeded || {}), switchPreviewModel: previous }); showNotification(`${t('notification.update_failed')}: ${err?.message || ''}`, 'error'); } finally { setPendingFlag('switchPreview', false); } })() } />
); }