'use client'; import { useEffect, useState } from 'react'; import { useRouter, useParams } from 'next/navigation'; const SIZE_PRESETS = [5_000, 10_000, 25_000, 50_000, 75_000, 100_000, 150_000]; interface AccountConfig { id: number; prefix: string; profitTarget: number; consistency: number; minDayPnL: number; minTradingDays: number; accountSize: number; maxPositionSize: number; } interface FirmConfig { id: number; firm: string; accounts: AccountConfig[]; } interface RowState extends AccountConfig { dirty: boolean; saving: boolean; error: string; useCustomSize: boolean; confirmDelete: boolean; } function initRow(acc: AccountConfig): RowState { return { ...acc, dirty: false, saving: false, error: '', useCustomSize: !SIZE_PRESETS.includes(acc.accountSize), confirmDelete: false, }; } function newRow(): RowState { return { id: -(Date.now()), prefix: '', profitTarget: 3000, consistency: 0.5, minDayPnL: -999, minTradingDays: 5, accountSize: 50_000, maxPositionSize: 0, dirty: true, saving: false, error: '', useCustomSize: false, confirmDelete: false, }; } function fmtSize(n: number) { return n >= 1000 ? `${n / 1000}k` : String(n); } function TrashIcon() { return ( ); } const inputCls = 'border border-slate-200 rounded-md px-2 py-1.5 text-sm text-slate-800 focus:outline-none focus:ring-2 focus:ring-blue-400 bg-white w-full'; export default function FirmSettingsPage() { const router = useRouter(); const params = useParams(); const id = params.id as string; const [firmName, setFirmName] = useState(''); const [rows, setRows] = useState([]); const [loadError, setLoadError] = useState(''); useEffect(() => { fetch(`/api/firms/${id}`) .then((r) => { if (!r.ok) throw new Error('Not found'); return r.json() as Promise; }) .then((firm) => { setFirmName(firm.firm); setRows(firm.accounts.map(initRow)); }) .catch(() => setLoadError('Failed to load firm')); }, [id]); const updateRow = (rowId: number, patch: Partial) => { setRows((prev) => prev.map((r) => (r.id === rowId ? { ...r, ...patch, dirty: true } : r)) ); }; const saveRow = async (row: RowState) => { setRows((prev) => prev.map((r) => (r.id === row.id ? { ...r, saving: true, error: '' } : r)) ); try { const body = { prefix: row.prefix, profitTarget: row.profitTarget, consistency: row.consistency, minDayPnL: row.minDayPnL, minTradingDays: row.minTradingDays, accountSize: row.accountSize, maxPositionSize: row.maxPositionSize, }; if (row.id < 0) { const res = await fetch(`/api/firms/${id}/accounts`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body), }); if (!res.ok) throw new Error('Failed'); const created = await res.json() as AccountConfig; setRows((prev) => prev.map((r) => r.id === row.id ? { ...initRow(created), dirty: false } : r ) ); } else { const res = await fetch(`/api/account-configs/${row.id}`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body), }); if (!res.ok) throw new Error('Failed'); setRows((prev) => prev.map((r) => r.id === row.id ? { ...r, saving: false, dirty: false, error: '' } : r ) ); } } catch { setRows((prev) => prev.map((r) => r.id === row.id ? { ...r, saving: false, error: 'Save failed' } : r ) ); } }; const confirmDeleteRow = (rowId: number) => { setRows((prev) => prev.map((r) => (r.id === rowId ? { ...r, confirmDelete: true } : r)) ); }; const cancelDeleteRow = (rowId: number) => { setRows((prev) => prev.map((r) => (r.id === rowId ? { ...r, confirmDelete: false } : r)) ); }; const deleteRow = async (row: RowState) => { if (row.id < 0) { setRows((prev) => prev.filter((r) => r.id !== row.id)); return; } try { const res = await fetch(`/api/account-configs/${row.id}`, { method: 'DELETE' }); if (!res.ok) throw new Error('Failed'); setRows((prev) => prev.filter((r) => r.id !== row.id)); } catch { setRows((prev) => prev.map((r) => r.id === row.id ? { ...r, confirmDelete: false, error: 'Delete failed' } : r ) ); } }; if (loadError) { return (

{loadError}

); } return (
{/* Header */}

{firmName || '…'}

/ Settings
{/* Account Types */}

Account Types

{rows.length === 0 && firmName && ( )} {rows.map((row) => ( {/* Prefix */} {/* Account Size */} {/* Profit Target */} {/* Consistency */} {/* Min Day P&L */} {/* Min Trading Days */} {/* Max Contracts */} {/* Actions */} ))} {/* Add row */}
Prefix Account Size Profit Target Consistency Min Day P&L Min Trading Days Max Contracts
No account types yet
updateRow(row.id, { prefix: e.target.value })} />
{row.useCustomSize && ( updateRow(row.id, { accountSize: Number(e.target.value) }) } /> )}
$ updateRow(row.id, { profitTarget: Number(e.target.value) }) } />
updateRow(row.id, { consistency: Number(e.target.value) / 100 }) } /> %
$ updateRow(row.id, { minDayPnL: e.target.value === '' ? -999 : Number(e.target.value), }) } />
updateRow(row.id, { minTradingDays: Number(e.target.value) }) } /> updateRow(row.id, { maxPositionSize: e.target.value === '' ? 0 : Number(e.target.value), }) } />
{row.error && ( {row.error} )} {row.confirmDelete ? ( <> Delete? ) : ( <> )}
); }