'use client'; import { useState, useEffect, useCallback } from 'react'; import { Trash2, Plus, Save } from 'lucide-react'; import { PageHeader } from '@/components/shared/page-header'; import { ConfirmationDialog } from '@/components/shared/confirmation-dialog'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; import { Switch } from '@/components/ui/switch'; import { Textarea } from '@/components/ui/textarea'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; import { Separator } from '@/components/ui/separator'; import { apiFetch } from '@/lib/api/client'; interface Setting { key: string; value: unknown; portId: string | null; updatedBy: string | null; updatedAt: string; } /** Well-known settings with their display metadata */ const KNOWN_SETTINGS: Array<{ key: string; label: string; description: string; type: 'boolean' | 'number' | 'json'; defaultValue: unknown; }> = [ { key: 'ai_interest_scoring', label: 'AI Interest Scoring', description: 'Enable AI-powered interest scoring based on engagement signals', type: 'boolean', defaultValue: false, }, { key: 'ai_email_drafts', label: 'AI Email Drafts', description: 'Enable AI-assisted email draft generation', type: 'boolean', defaultValue: false, }, { key: 'invoice_net10_discount', label: 'Net-10 Invoice Discount (%)', description: 'Discount percentage applied when payment terms are net-10', type: 'number', defaultValue: 2, }, { key: 'pipeline_weights', label: 'Pipeline Stage Weights', description: 'Probability weights for revenue forecast by pipeline stage (JSON)', type: 'json', defaultValue: { open: 0.05, details_sent: 0.1, in_communication: 0.2, signed_eoi_nda: 0.4, deposit_10pct: 0.6, contract: 0.8, completed: 1.0, }, }, { key: 'berth_rules', label: 'Berth Status Rules', description: 'Auto/suggest/off rules for berth status transitions (JSON)', type: 'json', defaultValue: [], }, ]; export function SettingsManager() { const [portSettings, setPortSettings] = useState([]); const [loading, setLoading] = useState(true); const [saving, setSaving] = useState(null); const [values, setValues] = useState>({}); const [customKey, setCustomKey] = useState(''); const [customValue, setCustomValue] = useState(''); const fetchSettings = useCallback(async () => { setLoading(true); try { const res = await apiFetch<{ data: { portSettings: Setting[]; globalSettings: Setting[] } }>( '/api/v1/admin/settings', ); setPortSettings(res.data.portSettings); // Build values map from existing settings const vals: Record = {}; for (const s of res.data.portSettings) { vals[s.key] = s.value; } setValues(vals); } finally { setLoading(false); } }, []); useEffect(() => { void fetchSettings(); }, [fetchSettings]); async function saveSetting(key: string, value: unknown) { setSaving(key); try { await apiFetch('/api/v1/admin/settings', { method: 'PUT', body: { key, value }, }); await fetchSettings(); } finally { setSaving(null); } } async function handleDeleteSetting(key: string) { await apiFetch('/api/v1/admin/settings', { method: 'DELETE', body: { key }, }); await fetchSettings(); } async function handleAddCustom() { if (!customKey.trim()) return; let parsed: unknown; try { parsed = JSON.parse(customValue); } catch { parsed = customValue; } await saveSetting(customKey, parsed); setCustomKey(''); setCustomValue(''); } function getEffectiveValue(key: string, defaultValue: unknown): unknown { return values[key] ?? defaultValue; } if (loading) { return (
Loading...
); } // Custom settings = port settings that aren't in KNOWN_SETTINGS const knownKeys = new Set(KNOWN_SETTINGS.map((s) => s.key)); const customSettings = portSettings.filter((s) => !knownKeys.has(s.key)); return (
{/* Feature Flags */} Feature Flags Enable or disable optional features {KNOWN_SETTINGS.filter((s) => s.type === 'boolean').map((setting) => (

{setting.description}

saveSetting(setting.key, checked)} />
))}
{/* Numeric Settings */} Business Rules Configure financial and operational parameters {KNOWN_SETTINGS.filter((s) => s.type === 'number').map((setting) => (

{setting.description}

setValues((prev) => ({ ...prev, [setting.key]: parseFloat(e.target.value) || 0, })) } />
))}
{/* JSON Settings */} Advanced Configuration JSON-based settings for pipeline weights and berth rules {KNOWN_SETTINGS.filter((s) => s.type === 'json').map((setting) => { const currentValue = getEffectiveValue(setting.key, setting.defaultValue); const jsonStr = values[`${setting.key}_edit`] !== undefined ? String(values[`${setting.key}_edit`]) : JSON.stringify(currentValue, null, 2); return (

{setting.description}