feat(simple): add manage existing holding flow

This commit is contained in:
root 2026-05-06 18:13:34 +00:00
parent f51172518e
commit 1f03bb83cd

View File

@ -667,6 +667,10 @@ export function SimpleView() {
() => simpleHoldings.find((holding) => holding.symbol === normalizedSymbol) || null,
[simpleHoldings, normalizedSymbol],
);
const availableSellHoldings = useMemo(
() => [...simpleHoldings].sort((left, right) => left.symbol.localeCompare(right.symbol)),
[simpleHoldings],
);
const supportedSymbols = useMemo(() => {
const fromState = Object.keys(symbolState || {}).map(normalizeKnownSymbol).filter(Boolean) as string[];
@ -751,6 +755,24 @@ export function SimpleView() {
setDraft((prev) => ({ ...prev, [key]: value }));
}
function applyHoldingToDraft(holding: SimpleHolding) {
setMarketPriceSource(null);
setDraft((prev) => ({
...prev,
side: 'sell',
symbol: holding.symbol,
quantity: String(holding.size),
currentMarketPrice: '',
}));
}
useEffect(() => {
if (draft.side !== 'sell') return;
if (matchingHolding) return;
if (availableSellHoldings.length === 0) return;
applyHoldingToDraft(availableSellHoldings[0]);
}, [draft.side, matchingHolding, availableSellHoldings]);
async function copyIdentifier(kind: 'trade' | 'order', value: string | null | undefined) {
if (!value) return;
try {
@ -950,7 +972,7 @@ export function SimpleView() {
<CardHeader>
<div>
<CardTitle className="uppercase">{editingSetupId ? 'Edit setup' : 'New setup'}</CardTitle>
<CardDescription>Saved trigger workflow, not an immediate broker order</CardDescription>
<CardDescription>Build a short-term buy plan or attach a managed profit exit to an existing holding.</CardDescription>
</div>
<Button
type="button"
@ -974,6 +996,74 @@ export function SimpleView() {
<CardContent>
<form className="space-y-6" onSubmit={handleSubmit}>
<div className="grid gap-3 md:grid-cols-2">
<button
type="button"
onClick={() => {
setError(null);
setMessage(null);
setDraft((prev) => ({ ...prev, side: 'buy' }));
}}
className={`rounded-[1.25rem] border px-4 py-4 text-left transition ${
draft.side === 'buy'
? 'border-[var(--primary)] bg-[var(--accent-soft)]'
: 'border-[var(--border)] bg-[var(--card-elevated)]'
}`}
>
<div className="text-[11px] font-black uppercase tracking-[0.24em] text-[var(--muted-foreground)]">Create plan</div>
<div className="mt-1 text-sm font-semibold text-[var(--foreground)]">New short-term buy plan</div>
<div className="mt-1 text-sm text-[var(--muted-foreground)]">Arm a dip-buy trigger and let the app manage the profit exit after fill.</div>
</button>
<button
type="button"
onClick={() => {
setError(null);
setMessage(null);
if (availableSellHoldings.length > 0) {
applyHoldingToDraft(availableSellHoldings[0]);
} else {
setDraft((prev) => ({ ...prev, side: 'sell' }));
}
}}
className={`rounded-[1.25rem] border px-4 py-4 text-left transition ${
draft.side === 'sell'
? 'border-[var(--primary)] bg-[var(--accent-soft)]'
: 'border-[var(--border)] bg-[var(--card-elevated)]'
}`}
>
<div className="text-[11px] font-black uppercase tracking-[0.24em] text-[var(--muted-foreground)]">Manage holding</div>
<div className="mt-1 text-sm font-semibold text-[var(--foreground)]">Attach an exit plan</div>
<div className="mt-1 text-sm text-[var(--muted-foreground)]">Choose an existing holding and place it back under managed profit-taking.</div>
</button>
</div>
{draft.side === 'sell' && (
<label className="space-y-2">
<span className="text-[11px] font-black uppercase tracking-[0.24em] text-zinc-700">Existing holding</span>
<Select
value={matchingHolding?.symbol || normalizedSymbol}
onChange={(e) => {
const selected = availableSellHoldings.find((holding) => holding.symbol === e.target.value);
if (selected) applyHoldingToDraft(selected);
}}
disabled={availableSellHoldings.length === 0}
>
{availableSellHoldings.length === 0 ? (
<option value="">No eligible holdings available</option>
) : (
availableSellHoldings.map((holding) => (
<option key={`${holding.symbol}:${holding.tradeId || 'holding'}`} value={holding.symbol}>
{holding.symbol} · {holding.size} @ {holding.entryPrice.toFixed(4)}
</option>
))
)}
</Select>
<span className="block text-[11px] text-[var(--muted-foreground)]">
Trade Plans can manage an existing filled holding by attaching a profit exit target to it.
</span>
</label>
)}
<div className="grid gap-4 md:grid-cols-2">
<label className="space-y-2">
<span className="text-[11px] font-black uppercase tracking-[0.24em] text-zinc-700">Symbol</span>
@ -1037,7 +1127,7 @@ export function SimpleView() {
onChange={(e) => updateDraft('side', e.target.value as SimpleSide)}
>
<option value="buy">Buy the dip + profit exit</option>
<option value="sell">Sell existing Simple holding at profit</option>
<option value="sell">Manage existing holding at profit</option>
</Select>
</label>
</div>