Files

91 lines
3.3 KiB
TypeScript

'use client'
import { useState } from 'react'
type SettingStatus = { set: boolean; updated_at: string | null }
interface Props {
settings: Record<string, SettingStatus>
}
const KEY_LABELS: Record<string, string> = {
DEEPSEEK_API_KEY: 'DeepSeek API Key (AI)',
GOOGLE_AI_API_KEY: 'Google AI API Key (Embeddings)',
}
export function ApiKeyForm({ settings }: Props) {
const [values, setValues] = useState<Record<string, string>>({
DEEPSEEK_API_KEY: '',
GOOGLE_AI_API_KEY: '',
})
const [saving, setSaving] = useState<Record<string, boolean>>({})
const [results, setResults] = useState<Record<string, 'ok' | 'error'>>({})
async function save(key: string) {
setSaving(s => ({ ...s, [key]: true }))
setResults(r => ({ ...r, [key]: undefined as never }))
try {
const res = await fetch('/api/settings', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ key, value: values[key] }),
})
setResults(r => ({ ...r, [key]: res.ok ? 'ok' : 'error' }))
if (res.ok) setValues(v => ({ ...v, [key]: '' }))
} catch {
setResults(r => ({ ...r, [key]: 'error' }))
} finally {
setSaving(s => ({ ...s, [key]: false }))
}
}
return (
<div className="space-y-6">
{Object.keys(KEY_LABELS).map(key => {
const status = settings[key]
return (
<div key={key} className="bg-white rounded-xl shadow-sm p-5">
<div className="flex items-center justify-between mb-1">
<label className="text-sm font-semibold text-gray-800">{KEY_LABELS[key]}</label>
<span className={`text-xs font-medium px-2 py-0.5 rounded-full ${
status?.set
? 'bg-green-100 text-green-700'
: 'bg-yellow-100 text-yellow-700'
}`}>
{status?.set ? 'Configured' : 'Not set'}
</span>
</div>
{status?.set && status.updated_at && (
<p className="text-xs text-gray-600 mb-3">
Last updated {new Date(status.updated_at).toLocaleDateString('en-MY')}
</p>
)}
<div className="flex gap-2 mt-3">
<input
type="password"
value={values[key]}
onChange={e => setValues(v => ({ ...v, [key]: e.target.value }))}
placeholder={status?.set ? 'Enter new key to replace…' : 'Enter API key…'}
className="flex-1 border border-gray-300 rounded-lg px-3 py-2 text-sm text-gray-900 placeholder-gray-500 focus:ring-2 focus:ring-blue-500 focus:border-transparent font-mono"
/>
<button
onClick={() => save(key)}
disabled={saving[key] || !values[key]}
className="bg-blue-600 text-white rounded-lg px-4 py-2 text-sm font-semibold disabled:opacity-50 hover:bg-blue-700"
>
{saving[key] ? 'Saving…' : 'Save'}
</button>
</div>
{results[key] === 'ok' && (
<p className="text-xs text-green-600 mt-2">Saved. Reload the page to confirm.</p>
)}
{results[key] === 'error' && (
<p className="text-xs text-red-600 mt-2">Save failed. Check your permissions.</p>
)}
</div>
)
})}
</div>
)
}