// TradeForm.jsx — slide-in drawer for add/edit trade const TradeFormDrawer = ({ trade, onSave, onClose }) => { const { useState, useRef, useEffect } = React; const isEdit = !!trade?.id; const blankExit = () => ({ id: genId(), price: '', quantity: '', contracts: '', date: '' }); const blankLeg = (legType = 'long', optionType = 'call') => ({ id: genId(), legType, optionType, strike: '', expiry: '', contracts: '', premium: '' }); const initLegs = (t) => { if (!t) return [blankLeg()]; if (t.legs && t.legs.length > 0) return t.legs.map(l => ({ ...l, strike: l.strike ?? '', expiry: l.expiry ?? '', contracts: l.contracts ?? '', premium: l.premium ?? '' })); // legacy single-option trade return [{ id: genId(), legType: t.direction === 'long' ? 'long' : 'short', optionType: t.optionType || 'call', strike: t.strike ?? '', expiry: t.expiry ?? '', contracts: t.contracts ?? '', premium: t.premium ?? '' }]; }; const initForm = () => trade ? { ...trade, strategy: trade.strategy || 'single', legs: initLegs(trade), entryPrice: trade.entryPrice ?? '', stopLoss: trade.stopLoss ?? '', quantity: trade.quantity ?? '', exits: trade.exits.length > 0 ? trade.exits.map(e => ({ ...e })) : [blankExit()], signals: [...(trade.signals || [])], customSignal: trade.customSignal || '', labels: [...(trade.labels || [])], customLabel: trade.customLabel || '', notes: trade.notes || '', } : { symbol: '', type: 'stock', direction: 'long', quantity: '', entryPrice: '', stopLoss: '', strategy: 'single', legs: [blankLeg()], exits: [blankExit()], signals: [], customSignal: '', labels: [], customLabel: '', notes: '', snapshot: null, status: 'closed', date: new Date().toISOString().slice(0, 10), }; const [form, setForm] = useState(initForm); const [errors, setErrors] = useState({}); const [snapshotPreview, setSnapshotPreview] = useState(trade?.snapshot || null); const fileRef = useRef(); const set = (k, v) => setForm(f => ({ ...f, [k]: v })); const setExit = (i, k, v) => setForm(f => { const exits = [...f.exits]; exits[i] = { ...exits[i], [k]: v }; return { ...f, exits }; }); const addExit = () => setForm(f => ({ ...f, exits: [...f.exits, blankExit()] })); const removeExit = (i) => setForm(f => ({ ...f, exits: f.exits.filter((_, j) => j !== i) })); const toggleSignal = (s) => setForm(f => ({ ...f, signals: f.signals.includes(s) ? f.signals.filter(x => x !== s) : [...f.signals, s] })); const toggleLabel = (l) => setForm(f => ({ ...f, labels: (f.labels || []).includes(l) ? f.labels.filter(x => x !== l) : [...(f.labels || []), l] })); const changeStrategy = (stratId) => { const templates = STRATEGY_LEG_TEMPLATES[stratId] || []; const newLegs = stratId === 'custom' ? (form.legs.length > 0 ? form.legs : [blankLeg()]) : templates.map(t => blankLeg(t.legType, t.optionType)); setForm(f => ({ ...f, strategy: stratId, legs: newLegs.length > 0 ? newLegs : [blankLeg()] })); }; const setLeg = (i, k, v) => setForm(f => { const legs = [...f.legs]; legs[i] = { ...legs[i], [k]: v }; return { ...f, legs }; }); const addLeg = () => setForm(f => ({ ...f, legs: [...f.legs, blankLeg()] })); const removeLeg = (i) => setForm(f => ({ ...f, legs: f.legs.filter((_, j) => j !== i) })); const handleSnapshot = (e) => { const file = e.target.files[0]; if (!file) return; const reader = new FileReader(); reader.onload = ev => { setSnapshotPreview(ev.target.result); set('snapshot', ev.target.result); }; reader.readAsDataURL(file); }; const validate = () => { const e = {}; if (!form.symbol.trim()) e.symbol = 'Required'; if (!form.date) e.date = 'Required'; if (form.type === 'stock') { if (!form.entryPrice) e.entryPrice = 'Required'; if (!form.quantity) e.quantity = 'Required'; } else { const leg0 = form.legs[0] || {}; if (!leg0.premium) e.premium = 'Required'; if (!leg0.contracts) e.contracts = 'Required'; if (!leg0.strike) e.strike = 'Required'; } setErrors(e); return Object.keys(e).length === 0; }; const handleSave = () => { if (!validate()) return; const cleanExits = form.exits.filter(e => e.price !== '' && e.date !== '').map(e => ({ ...e, price: parseFloat(e.price), quantity: e.quantity ? parseInt(e.quantity) : undefined, contracts: e.contracts ? parseInt(e.contracts) : undefined, })); const cleanLegs = form.legs.map(l => ({ ...l, strike: l.strike ? parseFloat(l.strike) : undefined, contracts: l.contracts ? parseInt(l.contracts) : undefined, premium: l.premium ? parseFloat(l.premium) : undefined, })); // For backward-compat, keep root-level option fields from leg[0] const leg0 = cleanLegs[0] || {}; onSave({ ...form, id: form.id || genId(), symbol: form.symbol.toUpperCase().trim(), entryPrice: form.type === 'stock' ? parseFloat(form.entryPrice) : undefined, quantity: form.type === 'stock' ? parseInt(form.quantity) : undefined, stopLoss: form.stopLoss ? parseFloat(form.stopLoss) : null, // Option fields strategy: form.type === 'option' ? form.strategy : undefined, legs: form.type === 'option' ? cleanLegs : undefined, optionType: form.type === 'option' ? leg0.optionType : undefined, strike: form.type === 'option' ? leg0.strike : undefined, expiry: form.type === 'option' ? leg0.expiry : undefined, contracts: form.type === 'option' ? leg0.contracts : undefined, premium: form.type === 'option' ? leg0.premium : undefined, exits: cleanExits, status: cleanExits.length > 0 ? 'closed' : 'open', labels: form.labels || [], customLabel: form.customLabel || '', snapshot: snapshotPreview, }); }; const inputCls = (k) => ({ background: 'var(--surface3)', border: `1px solid ${errors[k] ? '#f04060' : 'var(--border)'}`, borderRadius: '6px', color: 'var(--text)', padding: '9px 12px', fontSize: '13px', outline: 'none', width: '100%', boxSizing: 'border-box', fontFamily: form.type !== 'stock' && k === 'symbol' ? 'JetBrains Mono, monospace' : 'Space Grotesk, sans-serif', transition: 'border-color 0.15s' }); const labelStyle = { fontSize: '11px', color: 'var(--muted)', fontWeight: 600, textTransform: 'uppercase', letterSpacing: '0.07em', display: 'block', marginBottom: '6px' }; const sectionStyle = { marginBottom: '20px' }; const rowStyle = { display: 'grid', gap: '12px' }; const segBtn = (active, onClick, label) => React.createElement('button', { onClick, type: 'button', style: { flex: 1, padding: '8px', fontSize: '13px', fontWeight: 500, border: 'none', borderRadius: '6px', cursor: 'pointer', transition: 'all 0.15s', background: active ? '#5588ff' : 'var(--surface2)', color: active ? '#fff' : 'var(--muted)', fontFamily: 'Space Grotesk, sans-serif' } }, label); return React.createElement('div', { style: { position: 'fixed', inset: 0, zIndex: 1000, display: 'flex' } }, [ // Overlay React.createElement('div', { key: 'ov', onClick: onClose, style: { flex: 1, background: 'rgba(0,0,0,0.6)' } }), // Drawer React.createElement('div', { key: 'drawer', style: { width: '440px', background: 'var(--sidebar)', borderLeft: '1px solid var(--border)', display: 'flex', flexDirection: 'column', height: '100vh', overflowY: 'auto' } }, [ // Header React.createElement('div', { key: 'hdr', style: { padding: '20px 24px', borderBottom: '1px solid var(--border)', display: 'flex', justifyContent: 'space-between', alignItems: 'center', position: 'sticky', top: 0, background: 'var(--sidebar)', zIndex: 1 } }, [ React.createElement('h2', { key: 't', style: { margin: 0, fontSize: '16px', fontWeight: 700, color: 'var(--text)' } }, isEdit ? 'Edit Trade' : 'New Trade'), React.createElement('button', { key: 'x', onClick: onClose, style: { background: 'none', border: 'none', color: 'var(--muted)', fontSize: '20px', cursor: 'pointer', lineHeight: 1 } }, '×') ]), // Form body React.createElement('div', { key: 'body', style: { padding: '24px', flex: 1 } }, [ // Symbol + Date React.createElement('div', { key: 'sym-date', style: { ...sectionStyle, ...rowStyle, gridTemplateColumns: '1fr 1fr' } }, [ React.createElement('div', { key: 'sym' }, [ React.createElement('label', { key: 'l', style: labelStyle }, 'Symbol'), React.createElement('input', { value: form.symbol, onChange: e => set('symbol', e.target.value.toUpperCase()), placeholder: 'AAPL', style: { ...inputCls('symbol'), fontFamily: 'JetBrains Mono, monospace', letterSpacing: '0.06em' } }), errors.symbol && React.createElement('span', { key: 'err', style: { color: '#f04060', fontSize: '11px' } }, errors.symbol) ]), React.createElement('div', { key: 'dt' }, [ React.createElement('label', { key: 'l', style: labelStyle }, 'Date'), React.createElement('input', { type: 'date', value: form.date, onChange: e => set('date', e.target.value), style: { ...inputCls('date'), colorScheme: 'dark' } }) ]) ]), // Type toggle React.createElement('div', { key: 'type', style: sectionStyle }, [ React.createElement('label', { key: 'l', style: labelStyle }, 'Instrument'), React.createElement('div', { key: 'btns', style: { display: 'flex', gap: '6px', background: 'var(--surface3)', border: '1px solid var(--border)', borderRadius: '8px', padding: '4px' } }, [ segBtn(form.type === 'stock', () => set('type', 'stock'), 'Stock'), segBtn(form.type === 'option', () => set('type', 'option'), 'Option'), ]) ]), // Direction React.createElement('div', { key: 'dir', style: sectionStyle }, [ React.createElement('label', { key: 'l', style: labelStyle }, 'Direction'), React.createElement('div', { key: 'btns', style: { display: 'flex', gap: '6px', background: 'var(--surface3)', border: '1px solid var(--border)', borderRadius: '8px', padding: '4px' } }, [ React.createElement('button', { onClick: () => set('direction', 'long'), type: 'button', style: { flex: 1, padding: '8px', fontSize: '13px', fontWeight: 500, border: 'none', borderRadius: '6px', cursor: 'pointer', background: form.direction === 'long' ? 'rgba(0,210,122,0.18)' : 'var(--surface2)', color: form.direction === 'long' ? '#00d27a' : 'var(--muted)', fontFamily: 'Space Grotesk, sans-serif' } }, 'Long ↑'), React.createElement('button', { onClick: () => set('direction', 'short'), type: 'button', style: { flex: 1, padding: '8px', fontSize: '13px', fontWeight: 500, border: 'none', borderRadius: '6px', cursor: 'pointer', background: form.direction === 'short' ? 'rgba(240,64,96,0.18)' : 'var(--surface2)', color: form.direction === 'short' ? '#f04060' : 'var(--muted)', fontFamily: 'Space Grotesk, sans-serif' } }, 'Short ↓'), ]) ]), // Stock fields form.type === 'stock' && React.createElement('div', { key: 'stock-fields', style: { ...sectionStyle, ...rowStyle, gridTemplateColumns: '1fr 1fr 1fr' } }, [ React.createElement('div', { key: 'ep' }, [ React.createElement('label', { key: 'l', style: labelStyle }, 'Entry $'), React.createElement('input', { type: 'number', step: '0.01', value: form.entryPrice, onChange: e => set('entryPrice', e.target.value), placeholder: '0.00', style: inputCls('entryPrice') }), errors.entryPrice && React.createElement('span', { key: 'err', style: { color: '#f04060', fontSize: '11px' } }, errors.entryPrice) ]), React.createElement('div', { key: 'qty' }, [ React.createElement('label', { key: 'l', style: labelStyle }, 'Shares'), React.createElement('input', { type: 'number', value: form.quantity, onChange: e => set('quantity', e.target.value), placeholder: '100', style: inputCls('quantity') }), errors.quantity && React.createElement('span', { key: 'err', style: { color: '#f04060', fontSize: '11px' } }, errors.quantity) ]), React.createElement('div', { key: 'sl' }, [ React.createElement('label', { key: 'l', style: labelStyle }, 'Stop Loss'), React.createElement('input', { type: 'number', step: '0.01', value: form.stopLoss, onChange: e => set('stopLoss', e.target.value), placeholder: 'Optional', style: inputCls('stopLoss') }) ]), ]), // Option fields — strategy + legs form.type === 'option' && React.createElement('div', { key: 'opt-fields' }, [ // Strategy selector React.createElement('div', { key: 'strat', style: sectionStyle }, [ React.createElement('label', { key: 'l', style: labelStyle }, 'Strategy'), React.createElement('div', { key: 'grid', style: { display: 'grid', gridTemplateColumns: 'repeat(2, 1fr)', gap: '6px' } }, OPTION_STRATEGIES.map(s => React.createElement('button', { key: s.id, onClick: () => changeStrategy(s.id), type: 'button', style: { padding: '8px 10px', textAlign: 'left', borderRadius: '6px', border: '1px solid', cursor: 'pointer', fontFamily: 'Space Grotesk, sans-serif', transition: 'all 0.15s', borderColor: form.strategy === s.id ? '#5588ff' : 'var(--border)', background: form.strategy === s.id ? 'rgba(85,136,255,0.12)' : 'var(--surface3)', } }, [ React.createElement('div', { key: 'n', style: { fontSize: '12px', fontWeight: 600, color: form.strategy === s.id ? '#5588ff' : 'var(--text)' } }, s.label), React.createElement('div', { key: 'd', style: { fontSize: '10px', color: 'var(--muted)', marginTop: '2px' } }, s.desc) ]) ) ) ]), // Legs React.createElement('div', { key: 'legs', style: sectionStyle }, [ React.createElement('div', { key: 'hdr', style: { display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '8px' } }, [ React.createElement('label', { key: 'l', style: { ...labelStyle, margin: 0 } }, `Legs (${form.legs.length})`), form.strategy === 'custom' && React.createElement('button', { key: 'add', onClick: addLeg, type: 'button', style: { background: 'none', border: '1px solid var(--border)', borderRadius: '4px', color: '#5588ff', fontSize: '12px', cursor: 'pointer', padding: '3px 10px' } }, '+ Add Leg') ]), React.createElement('div', { key: 'list', style: { display: 'flex', flexDirection: 'column', gap: '10px' } }, form.legs.map((leg, i) => { const tmpl = (STRATEGY_LEG_TEMPLATES[form.strategy] || [])[i]; const hint = tmpl?.hint || `Leg ${i + 1}`; const isLong = leg.legType === 'long'; const isCall = leg.optionType === 'call'; return React.createElement('div', { key: leg.id, style: { background: 'var(--surface3)', border: '1px solid var(--border)', borderRadius: '8px', padding: '12px' } }, [ // Leg header React.createElement('div', { key: 'h', style: { display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '10px' } }, [ React.createElement('div', { key: 'left', style: { display: 'flex', alignItems: 'center', gap: '8px' } }, [ React.createElement('span', { key: 'n', style: { fontSize: '10px', color: 'var(--muted)', fontWeight: 700, textTransform: 'uppercase', letterSpacing: '0.08em' } }, `Leg ${i + 1}`), React.createElement('span', { key: 'h', style: { fontSize: '11px', color: 'var(--text2)' } }, hint) ]), form.strategy === 'custom' && form.legs.length > 1 && React.createElement('button', { key: 'rm', onClick: () => removeLeg(i), type: 'button', style: { background: 'none', border: 'none', color: '#f04060', fontSize: '14px', cursor: 'pointer' } }, '×') ]), // Buy/Sell + Call/Put toggles React.createElement('div', { key: 'toggles', style: { display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '8px', marginBottom: '10px' } }, [ React.createElement('div', { key: 'lt', style: { display: 'flex', background: 'var(--surface2)', border: '1px solid var(--border)', borderRadius: '6px', padding: '3px', gap: '3px' } }, [ React.createElement('button', { onClick: () => setLeg(i, 'legType', 'long'), type: 'button', style: { flex: 1, padding: '5px', fontSize: '12px', border: 'none', borderRadius: '4px', cursor: 'pointer', fontFamily: 'Space Grotesk, sans-serif', background: isLong ? 'rgba(0,210,122,0.18)' : 'transparent', color: isLong ? '#00d27a' : 'var(--muted)' } }, 'Buy'), React.createElement('button', { onClick: () => setLeg(i, 'legType', 'short'), type: 'button', style: { flex: 1, padding: '5px', fontSize: '12px', border: 'none', borderRadius: '4px', cursor: 'pointer', fontFamily: 'Space Grotesk, sans-serif', background: !isLong ? 'rgba(240,64,96,0.18)' : 'transparent', color: !isLong ? '#f04060' : 'var(--muted)' } }, 'Sell'), ]), React.createElement('div', { key: 'ot', style: { display: 'flex', background: 'var(--surface2)', border: '1px solid var(--border)', borderRadius: '6px', padding: '3px', gap: '3px' } }, [ React.createElement('button', { onClick: () => setLeg(i, 'optionType', 'call'), type: 'button', style: { flex: 1, padding: '5px', fontSize: '12px', border: 'none', borderRadius: '4px', cursor: 'pointer', fontFamily: 'Space Grotesk, sans-serif', background: isCall ? 'rgba(0,210,122,0.18)' : 'transparent', color: isCall ? '#00d27a' : 'var(--muted)' } }, 'Call'), React.createElement('button', { onClick: () => setLeg(i, 'optionType', 'put'), type: 'button', style: { flex: 1, padding: '5px', fontSize: '12px', border: 'none', borderRadius: '4px', cursor: 'pointer', fontFamily: 'Space Grotesk, sans-serif', background: !isCall ? 'rgba(240,64,96,0.18)' : 'transparent', color: !isCall ? '#f04060' : 'var(--muted)' } }, 'Put'), ]), ]), // Fields: Strike, Expiry, Contracts, Premium React.createElement('div', { key: 'fields', style: { display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '8px' } }, [ React.createElement('div', { key: 'str' }, [ React.createElement('label', { key: 'l', style: { ...labelStyle, fontSize: '10px' } }, 'Strike'), React.createElement('input', { type: 'number', step: '0.5', value: leg.strike, onChange: e => setLeg(i, 'strike', e.target.value), placeholder: '500', style: { ...inputCls(i === 0 ? 'strike' : ''), padding: '7px 10px' } }), i === 0 && errors.strike && React.createElement('span', { key: 'err', style: { color: '#f04060', fontSize: '11px' } }, errors.strike) ]), React.createElement('div', { key: 'exp' }, [ React.createElement('label', { key: 'l', style: { ...labelStyle, fontSize: '10px' } }, 'Expiry'), React.createElement('input', { type: 'date', value: leg.expiry, onChange: e => setLeg(i, 'expiry', e.target.value), style: { ...inputCls(''), padding: '7px 10px', colorScheme: 'dark' } }) ]), React.createElement('div', { key: 'cts' }, [ React.createElement('label', { key: 'l', style: { ...labelStyle, fontSize: '10px' } }, 'Contracts'), React.createElement('input', { type: 'number', value: leg.contracts, onChange: e => setLeg(i, 'contracts', e.target.value), placeholder: '5', style: { ...inputCls(i === 0 ? 'contracts' : ''), padding: '7px 10px' } }), i === 0 && errors.contracts && React.createElement('span', { key: 'err', style: { color: '#f04060', fontSize: '11px' } }, errors.contracts) ]), React.createElement('div', { key: 'prem' }, [ React.createElement('label', { key: 'l', style: { ...labelStyle, fontSize: '10px' } }, isLong ? 'Premium (debit)' : 'Premium (credit)'), React.createElement('input', { type: 'number', step: '0.01', value: leg.premium, onChange: e => setLeg(i, 'premium', e.target.value), placeholder: '2.50', style: { ...inputCls(i === 0 ? 'premium' : ''), padding: '7px 10px' } }), i === 0 && errors.premium && React.createElement('span', { key: 'err', style: { color: '#f04060', fontSize: '11px' } }, errors.premium) ]), ]) ]); }) ) ]), ]), // Exits React.createElement('div', { key: 'exits', style: sectionStyle }, [ React.createElement('div', { key: 'hdr', style: { display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '8px' } }, [ React.createElement('label', { key: 'l', style: { ...labelStyle, margin: 0 } }, 'Exit Prices'), React.createElement('button', { key: 'add', onClick: addExit, type: 'button', style: { background: 'none', border: '1px solid var(--border)', borderRadius: '4px', color: '#5588ff', fontSize: '12px', cursor: 'pointer', padding: '3px 10px' } }, '+ Add Exit') ]), React.createElement('div', { key: 'list', style: { display: 'flex', flexDirection: 'column', gap: '8px' } }, form.exits.map((ex, i) => React.createElement('div', { key: ex.id, style: { background: 'var(--surface3)', border: '1px solid var(--border)', borderRadius: '6px', padding: '10px 12px' } }, [ React.createElement('div', { key: 'top', style: { display: 'flex', justifyContent: 'space-between', marginBottom: '8px' } }, [ React.createElement('span', { key: 'l', style: { fontSize: '11px', color: 'var(--muted)', fontWeight: 600 } }, `EXIT ${i + 1}`), form.exits.length > 1 && React.createElement('button', { key: 'rm', onClick: () => removeExit(i), type: 'button', style: { background: 'none', border: 'none', color: '#f04060', fontSize: '14px', cursor: 'pointer' } }, '×') ]), React.createElement('div', { key: 'fields', style: { display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: '8px' } }, [ React.createElement('div', { key: 'p' }, [ React.createElement('label', { key: 'l', style: { ...labelStyle, fontSize: '10px' } }, 'Price'), React.createElement('input', { type: 'number', step: '0.01', value: ex.price, onChange: e => setExit(i, 'price', e.target.value), placeholder: '0.00', style: { ...inputCls(''), padding: '7px 10px' } }) ]), form.type === 'stock' ? React.createElement('div', { key: 'q' }, [ React.createElement('label', { key: 'l', style: { ...labelStyle, fontSize: '10px' } }, 'Shares'), React.createElement('input', { type: 'number', value: ex.quantity, onChange: e => setExit(i, 'quantity', e.target.value), placeholder: '50', style: { ...inputCls(''), padding: '7px 10px' } }) ]) : React.createElement('div', { key: 'c' }, [ React.createElement('label', { key: 'l', style: { ...labelStyle, fontSize: '10px' } }, 'Contracts'), React.createElement('input', { type: 'number', value: ex.contracts, onChange: e => setExit(i, 'contracts', e.target.value), placeholder: '5', style: { ...inputCls(''), padding: '7px 10px' } }) ]), React.createElement('div', { key: 'd' }, [ React.createElement('label', { key: 'l', style: { ...labelStyle, fontSize: '10px' } }, 'Date'), React.createElement('input', { type: 'date', value: ex.date, onChange: e => setExit(i, 'date', e.target.value), style: { ...inputCls(''), padding: '7px 10px', colorScheme: 'dark' } }) ]), ]) ]) ) ) ]), // Labels React.createElement('div', { key: 'labels', style: sectionStyle }, [ React.createElement('label', { key: 'l', style: labelStyle }, 'Labels'), React.createElement('div', { key: 'tags', style: { display: 'flex', flexWrap: 'wrap', gap: '6px', marginBottom: '10px' } }, PREDEFINED_LABELS.map(l => React.createElement(LabelTag, { key: l, label: l, active: (form.labels || []).includes(l), onClick: () => toggleLabel(l) })) ), React.createElement('input', { key: 'custom', value: form.customLabel || '', onChange: e => set('customLabel', e.target.value), placeholder: 'Custom label…', style: inputCls('') }) ]), // Signals React.createElement('div', { key: 'signals', style: sectionStyle }, [ React.createElement('label', { key: 'l', style: labelStyle }, 'Entry Signal'), React.createElement('div', { key: 'tags', style: { display: 'flex', flexWrap: 'wrap', gap: '6px', marginBottom: '10px' } }, PREDEFINED_SIGNALS.map(s => React.createElement(SignalTag, { key: s, label: s, active: form.signals.includes(s), onClick: () => toggleSignal(s) })) ), React.createElement('input', { key: 'custom', value: form.customSignal, onChange: e => set('customSignal', e.target.value), placeholder: 'Custom signal tag…', style: inputCls('') }) ]), // Notes React.createElement('div', { key: 'notes', style: sectionStyle }, [ React.createElement('label', { key: 'l', style: labelStyle }, 'Notes'), React.createElement('textarea', { value: form.notes, onChange: e => set('notes', e.target.value), placeholder: 'Trade rationale, observations…', rows: 3, style: { ...inputCls(''), resize: 'vertical', lineHeight: 1.5 } }) ]), // Snapshot React.createElement('div', { key: 'snap', style: { ...sectionStyle } }, [ React.createElement('label', { key: 'l', style: labelStyle }, 'Chart Snapshot'), snapshotPreview ? React.createElement('div', { key: 'prev', style: { position: 'relative' } }, [ React.createElement('img', { key: 'img', src: snapshotPreview, alt: 'Chart', style: { width: '100%', maxHeight: '180px', objectFit: 'cover', borderRadius: '6px', border: '1px solid var(--border)' } }), React.createElement('button', { key: 'rm', onClick: () => { setSnapshotPreview(null); set('snapshot', null); }, style: { position: 'absolute', top: '6px', right: '6px', background: 'rgba(0,0,0,0.7)', border: 'none', borderRadius: '4px', color: '#fff', fontSize: '14px', cursor: 'pointer', padding: '2px 8px' } }, '×') ]) : React.createElement('div', { key: 'upload', onClick: () => fileRef.current?.click(), style: { border: '1px dashed #1e2440', borderRadius: '6px', padding: '24px', textAlign: 'center', cursor: 'pointer', color: 'var(--muted)', fontSize: '13px', transition: 'border-color 0.15s' }, onMouseEnter: e => e.currentTarget.style.borderColor = '#5588ff', onMouseLeave: e => e.currentTarget.style.borderColor = 'var(--border)' }, [ React.createElement('div', { key: 'icon', style: { fontSize: '24px', marginBottom: '6px', opacity: 0.5 } }, '📊'), React.createElement('div', { key: 'txt' }, 'Click to upload chart screenshot'), ]), React.createElement('input', { key: 'file', ref: fileRef, type: 'file', accept: 'image/*', onChange: handleSnapshot, style: { display: 'none' } }) ]), // P&L + R (manual override for now) React.createElement('div', { key: 'pnl-row', style: { ...sectionStyle, ...rowStyle, gridTemplateColumns: '1fr 1fr' } }, [ React.createElement('div', { key: 'pnl' }, [ React.createElement('label', { key: 'l', style: labelStyle }, 'Realized P&L ($)'), React.createElement('input', { type: 'number', step: '0.01', value: form.pnl ?? '', onChange: e => set('pnl', e.target.value ? parseFloat(e.target.value) : null), placeholder: 'Auto-calc', style: inputCls('pnl') }) ]), React.createElement('div', { key: 'r' }, [ React.createElement('label', { key: 'l', style: labelStyle }, 'R Multiple'), React.createElement('input', { type: 'number', step: '0.01', value: form.rMultiple ?? '', onChange: e => set('rMultiple', e.target.value ? parseFloat(e.target.value) : null), placeholder: 'e.g. 2.5', style: inputCls('rMultiple') }) ]), ]), ]), // Footer React.createElement('div', { key: 'footer', style: { padding: '16px 24px', borderTop: '1px solid var(--border)', display: 'flex', gap: '10px', position: 'sticky', bottom: 0, background: 'var(--sidebar)' } }, [ React.createElement('button', { key: 'cancel', onClick: onClose, style: { flex: 1, padding: '10px', background: 'var(--surface2)', border: '1px solid var(--border)', borderRadius: '8px', color: 'var(--text2)', fontSize: '14px', cursor: 'pointer', fontFamily: 'Space Grotesk, sans-serif' } }, 'Cancel'), React.createElement('button', { key: 'save', onClick: handleSave, style: { flex: 2, padding: '10px', background: '#5588ff', border: 'none', borderRadius: '8px', color: '#fff', fontSize: '14px', fontWeight: 600, cursor: 'pointer', fontFamily: 'Space Grotesk, sans-serif' } }, isEdit ? 'Save Changes' : 'Add Trade'), ]) ]) ]); }; Object.assign(window, { TradeFormDrawer });