import { useCallback, useEffect, useMemo, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { Card } from '@/components/ui/Card'; import { Button } from '@/components/ui/Button'; import { Input } from '@/components/ui/Input'; import { Modal } from '@/components/ui/Modal'; import { EmptyState } from '@/components/ui/EmptyState'; import { LoadingSpinner } from '@/components/ui/LoadingSpinner'; import { useAuthStore, useConfigStore, useNotificationStore } from '@/stores'; import { apiKeysApi } from '@/services/api'; import { maskApiKey } from '@/utils/format'; import styles from './ApiKeysPage.module.scss'; export function ApiKeysPage() { 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 [apiKeys, setApiKeys] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(''); const [modalOpen, setModalOpen] = useState(false); const [editingIndex, setEditingIndex] = useState(null); const [inputValue, setInputValue] = useState(''); const [saving, setSaving] = useState(false); const [deletingIndex, setDeletingIndex] = useState(null); const disableControls = useMemo(() => connectionStatus !== 'connected', [connectionStatus]); const loadApiKeys = useCallback( async (force = false) => { setLoading(true); setError(''); try { const result = (await fetchConfig('api-keys', force)) as string[] | undefined; const list = Array.isArray(result) ? result : []; setApiKeys(list); } catch (err: any) { setError(err?.message || t('notification.refresh_failed')); } finally { setLoading(false); } }, [fetchConfig, t] ); useEffect(() => { loadApiKeys(); }, [loadApiKeys]); useEffect(() => { if (Array.isArray(config?.apiKeys)) { setApiKeys(config.apiKeys); } }, [config?.apiKeys]); const openAddModal = () => { setEditingIndex(null); setInputValue(''); setModalOpen(true); }; const openEditModal = (index: number) => { setEditingIndex(index); setInputValue(apiKeys[index] ?? ''); setModalOpen(true); }; const closeModal = () => { setModalOpen(false); setInputValue(''); setEditingIndex(null); }; const handleSave = async () => { const trimmed = inputValue.trim(); if (!trimmed) { showNotification(`${t('notification.please_enter')} ${t('notification.api_key')}`, 'error'); return; } const isEdit = editingIndex !== null; const nextKeys = isEdit ? apiKeys.map((key, idx) => (idx === editingIndex ? trimmed : key)) : [...apiKeys, trimmed]; setSaving(true); try { if (isEdit && editingIndex !== null) { await apiKeysApi.update(editingIndex, trimmed); showNotification(t('notification.api_key_updated'), 'success'); } else { await apiKeysApi.replace(nextKeys); showNotification(t('notification.api_key_added'), 'success'); } setApiKeys(nextKeys); updateConfigValue('api-keys', nextKeys); clearCache('api-keys'); closeModal(); } catch (err: any) { showNotification(`${t('notification.update_failed')}: ${err?.message || ''}`, 'error'); } finally { setSaving(false); } }; const handleDelete = async (index: number) => { if (!window.confirm(t('api_keys.delete_confirm'))) return; setDeletingIndex(index); try { await apiKeysApi.delete(index); const nextKeys = apiKeys.filter((_, idx) => idx !== index); setApiKeys(nextKeys); updateConfigValue('api-keys', nextKeys); clearCache('api-keys'); showNotification(t('notification.api_key_deleted'), 'success'); } catch (err: any) { showNotification(`${t('notification.delete_failed')}: ${err?.message || ''}`, 'error'); } finally { setDeletingIndex(null); } }; const actionButtons = (
); return (

{t('api_keys.title')}

{error &&
{error}
} {loading ? (
) : apiKeys.length === 0 ? ( {t('api_keys.add_button')} } /> ) : (
{apiKeys.map((key, index) => (
#{index + 1}
{t('api_keys.item_title')}
{maskApiKey(String(key || ''))}
))}
)} } > setInputValue(e.target.value)} disabled={saving} />
); }