chore(web): tighten event handler types
This commit is contained in:
parent
416adb134e
commit
eef63cbb8f
@ -1,4 +1,5 @@
|
|||||||
import { useState, useRef, useEffect, useMemo } from 'react';
|
import { useState, useRef, useEffect, useMemo } from 'react';
|
||||||
|
import type { ChangeEvent } from 'react';
|
||||||
import { createPortal } from 'react-dom';
|
import { createPortal } from 'react-dom';
|
||||||
import { tradingRuntime } from '../lib/runtime';
|
import { tradingRuntime } from '../lib/runtime';
|
||||||
import { getPlatformAccessToken } from '../lib/authSession';
|
import { getPlatformAccessToken } from '../lib/authSession';
|
||||||
@ -561,7 +562,7 @@ export const ChatControl = ({ profiles, onApplyProfile }: ChatControlProps) => {
|
|||||||
<div className="text-[10px] text-[var(--muted-foreground)] uppercase tracking-wider font-bold">Edit Parameters Before Apply</div>
|
<div className="text-[10px] text-[var(--muted-foreground)] uppercase tracking-wider font-bold">Edit Parameters Before Apply</div>
|
||||||
<Input
|
<Input
|
||||||
value={activeProfileData?.name || ''}
|
value={activeProfileData?.name || ''}
|
||||||
onChange={(e) => updateDraftField(msg.id, 'name', e.target.value)}
|
onChange={(e: ChangeEvent<HTMLInputElement>) => updateDraftField(msg.id, 'name', e.target.value)}
|
||||||
placeholder="Profile Name"
|
placeholder="Profile Name"
|
||||||
className="w-full rounded-lg px-2.5 py-1.5 text-[11px] outline-none"
|
className="w-full rounded-lg px-2.5 py-1.5 text-[11px] outline-none"
|
||||||
style={inputStyle}
|
style={inputStyle}
|
||||||
@ -572,7 +573,7 @@ export const ChatControl = ({ profiles, onApplyProfile }: ChatControlProps) => {
|
|||||||
min="0"
|
min="0"
|
||||||
step="1"
|
step="1"
|
||||||
value={activeProfileData?.allocated_capital ?? ''}
|
value={activeProfileData?.allocated_capital ?? ''}
|
||||||
onChange={(e) => updateDraftField(msg.id, 'allocated_capital', e.target.value)}
|
onChange={(e: ChangeEvent<HTMLInputElement>) => updateDraftField(msg.id, 'allocated_capital', e.target.value)}
|
||||||
placeholder="Capital"
|
placeholder="Capital"
|
||||||
className="w-full rounded-lg px-2.5 py-1.5 text-[11px] outline-none"
|
className="w-full rounded-lg px-2.5 py-1.5 text-[11px] outline-none"
|
||||||
style={inputStyle}
|
style={inputStyle}
|
||||||
@ -582,7 +583,7 @@ export const ChatControl = ({ profiles, onApplyProfile }: ChatControlProps) => {
|
|||||||
min="0"
|
min="0"
|
||||||
step="0.1"
|
step="0.1"
|
||||||
value={activeProfileData?.risk_per_trade_percent ?? ''}
|
value={activeProfileData?.risk_per_trade_percent ?? ''}
|
||||||
onChange={(e) => updateDraftField(msg.id, 'risk_per_trade_percent', e.target.value)}
|
onChange={(e: ChangeEvent<HTMLInputElement>) => updateDraftField(msg.id, 'risk_per_trade_percent', e.target.value)}
|
||||||
placeholder="Risk %"
|
placeholder="Risk %"
|
||||||
className="w-full rounded-lg px-2.5 py-1.5 text-[11px] outline-none"
|
className="w-full rounded-lg px-2.5 py-1.5 text-[11px] outline-none"
|
||||||
style={inputStyle}
|
style={inputStyle}
|
||||||
@ -590,7 +591,7 @@ export const ChatControl = ({ profiles, onApplyProfile }: ChatControlProps) => {
|
|||||||
</div>
|
</div>
|
||||||
<Input
|
<Input
|
||||||
value={activeProfileData?.symbols || ''}
|
value={activeProfileData?.symbols || ''}
|
||||||
onChange={(e) => updateDraftField(msg.id, 'symbols', e.target.value)}
|
onChange={(e: ChangeEvent<HTMLInputElement>) => updateDraftField(msg.id, 'symbols', e.target.value)}
|
||||||
placeholder="Symbols (e.g. BTC/USDT,ETH/USDT)"
|
placeholder="Symbols (e.g. BTC/USDT,ETH/USDT)"
|
||||||
className="w-full rounded-lg px-2.5 py-1.5 text-[11px] outline-none"
|
className="w-full rounded-lg px-2.5 py-1.5 text-[11px] outline-none"
|
||||||
style={inputStyle}
|
style={inputStyle}
|
||||||
@ -599,7 +600,7 @@ export const ChatControl = ({ profiles, onApplyProfile }: ChatControlProps) => {
|
|||||||
<span className="text-[10px] text-[var(--muted-foreground)] uppercase tracking-wider">Auto Trading</span>
|
<span className="text-[10px] text-[var(--muted-foreground)] uppercase tracking-wider">Auto Trading</span>
|
||||||
<Select
|
<Select
|
||||||
value={activeProfileData?.is_active === false ? 'false' : 'true'}
|
value={activeProfileData?.is_active === false ? 'false' : 'true'}
|
||||||
onChange={(e) => updateDraftField(msg.id, 'is_active', e.target.value === 'true')}
|
onChange={(e: ChangeEvent<HTMLSelectElement>) => updateDraftField(msg.id, 'is_active', e.target.value === 'true')}
|
||||||
className="rounded px-2 py-1 text-[10px] outline-none"
|
className="rounded px-2 py-1 text-[10px] outline-none"
|
||||||
style={inputStyle}
|
style={inputStyle}
|
||||||
options={[
|
options={[
|
||||||
@ -709,11 +710,11 @@ export const ChatControl = ({ profiles, onApplyProfile }: ChatControlProps) => {
|
|||||||
border: '1px solid var(--border)',
|
border: '1px solid var(--border)',
|
||||||
cursor: 'pointer',
|
cursor: 'pointer',
|
||||||
}}
|
}}
|
||||||
onMouseEnter={e => {
|
onMouseEnter={(e: React.MouseEvent<HTMLButtonElement>) => {
|
||||||
e.currentTarget.style.borderColor = 'var(--ring)';
|
e.currentTarget.style.borderColor = 'var(--ring)';
|
||||||
e.currentTarget.style.background = 'var(--accent-soft)';
|
e.currentTarget.style.background = 'var(--accent-soft)';
|
||||||
}}
|
}}
|
||||||
onMouseLeave={e => {
|
onMouseLeave={(e: React.MouseEvent<HTMLButtonElement>) => {
|
||||||
e.currentTarget.style.borderColor = 'var(--border)';
|
e.currentTarget.style.borderColor = 'var(--border)';
|
||||||
e.currentTarget.style.background = 'var(--card)';
|
e.currentTarget.style.background = 'var(--card)';
|
||||||
}}
|
}}
|
||||||
@ -755,7 +756,7 @@ export const ChatControl = ({ profiles, onApplyProfile }: ChatControlProps) => {
|
|||||||
<Textarea
|
<Textarea
|
||||||
ref={inputRef}
|
ref={inputRef}
|
||||||
value={input}
|
value={input}
|
||||||
onChange={e => setInput(e.target.value)}
|
onChange={(e: ChangeEvent<HTMLTextAreaElement>) => setInput(e.target.value)}
|
||||||
onKeyDown={handleKeyDown}
|
onKeyDown={handleKeyDown}
|
||||||
placeholder="Describe a strategy profile..."
|
placeholder="Describe a strategy profile..."
|
||||||
disabled={isLoading}
|
disabled={isLoading}
|
||||||
|
|||||||
@ -56,7 +56,7 @@ export function Login() {
|
|||||||
label="Email"
|
label="Email"
|
||||||
type="email"
|
type="email"
|
||||||
value={email}
|
value={email}
|
||||||
onChange={(e) => setEmail(e.target.value)}
|
onChange={(e: React.ChangeEvent<HTMLInputElement>) => setEmail(e.target.value)}
|
||||||
placeholder="trader@example.com"
|
placeholder="trader@example.com"
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
@ -68,7 +68,7 @@ export function Login() {
|
|||||||
label="Password"
|
label="Password"
|
||||||
type="password"
|
type="password"
|
||||||
value={password}
|
value={password}
|
||||||
onChange={(e) => setPassword(e.target.value)}
|
onChange={(e: React.ChangeEvent<HTMLInputElement>) => setPassword(e.target.value)}
|
||||||
placeholder="••••••••"
|
placeholder="••••••••"
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import { useState, useEffect } from 'react';
|
import { useState, useEffect } from 'react';
|
||||||
|
import type { ChangeEvent } from 'react';
|
||||||
import { resetPlatformPassword } from '../lib/authSession';
|
import { resetPlatformPassword } from '../lib/authSession';
|
||||||
import { Button, Input } from './ui/Primitives';
|
import { Button, Input } from './ui/Primitives';
|
||||||
|
|
||||||
@ -50,7 +51,7 @@ export function ResetPassword() {
|
|||||||
label="New Password"
|
label="New Password"
|
||||||
type="password"
|
type="password"
|
||||||
value={password}
|
value={password}
|
||||||
onChange={(e) => setPassword(e.target.value)}
|
onChange={(e: ChangeEvent<HTMLInputElement>) => setPassword(e.target.value)}
|
||||||
placeholder="New password"
|
placeholder="New password"
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
|
|||||||
@ -3,6 +3,7 @@
|
|||||||
* Lets users compose IF/THEN trading rules without writing code.
|
* Lets users compose IF/THEN trading rules without writing code.
|
||||||
*/
|
*/
|
||||||
import { useState, useCallback, useEffect, useRef } from 'react';
|
import { useState, useCallback, useEffect, useRef } from 'react';
|
||||||
|
import type { ChangeEvent } from 'react';
|
||||||
import {
|
import {
|
||||||
DndContext,
|
DndContext,
|
||||||
closestCenter,
|
closestCenter,
|
||||||
@ -136,7 +137,7 @@ function RuleCard({
|
|||||||
controlSize="sm"
|
controlSize="sm"
|
||||||
variant="surface"
|
variant="surface"
|
||||||
options={(Object.keys(INDICATOR_LABELS) as Indicator[]).map(k => ({ value: k, label: INDICATOR_LABELS[k] }))}
|
options={(Object.keys(INDICATOR_LABELS) as Indicator[]).map(k => ({ value: k, label: INDICATOR_LABELS[k] }))}
|
||||||
onChange={e => onChange(rule.id, {
|
onChange={(e: ChangeEvent<HTMLSelectElement>) => onChange(rule.id, {
|
||||||
indicator: e.target.value as Indicator,
|
indicator: e.target.value as Indicator,
|
||||||
value: INDICATOR_DEFAULTS[e.target.value as Indicator],
|
value: INDICATOR_DEFAULTS[e.target.value as Indicator],
|
||||||
})}
|
})}
|
||||||
@ -149,7 +150,7 @@ function RuleCard({
|
|||||||
controlSize="sm"
|
controlSize="sm"
|
||||||
variant="surface"
|
variant="surface"
|
||||||
options={(Object.keys(CONDITION_LABELS) as Condition[]).map(k => ({ value: k, label: CONDITION_LABELS[k] }))}
|
options={(Object.keys(CONDITION_LABELS) as Condition[]).map(k => ({ value: k, label: CONDITION_LABELS[k] }))}
|
||||||
onChange={e => onChange(rule.id, { condition: e.target.value as Condition })}
|
onChange={(e: ChangeEvent<HTMLSelectElement>) => onChange(rule.id, { condition: e.target.value as Condition })}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Value */}
|
{/* Value */}
|
||||||
@ -159,7 +160,7 @@ function RuleCard({
|
|||||||
style={numInp}
|
style={numInp}
|
||||||
controlSize="sm"
|
controlSize="sm"
|
||||||
variant="surface"
|
variant="surface"
|
||||||
onChange={e => onChange(rule.id, { value: parseFloat(e.target.value) || 0 })}
|
onChange={(e: ChangeEvent<HTMLInputElement>) => onChange(rule.id, { value: parseFloat(e.target.value) || 0 })}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* THEN */}
|
{/* THEN */}
|
||||||
@ -179,7 +180,7 @@ function RuleCard({
|
|||||||
{ value: 'BUY', label: 'BUY' },
|
{ value: 'BUY', label: 'BUY' },
|
||||||
{ value: 'SELL', label: 'SELL' },
|
{ value: 'SELL', label: 'SELL' },
|
||||||
]}
|
]}
|
||||||
onChange={e => onChange(rule.id, { action: e.target.value as TradeAction })}
|
onChange={(e: ChangeEvent<HTMLSelectElement>) => onChange(rule.id, { action: e.target.value as TradeAction })}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Quantity */}
|
{/* Quantity */}
|
||||||
@ -190,7 +191,7 @@ function RuleCard({
|
|||||||
min={1}
|
min={1}
|
||||||
controlSize="sm"
|
controlSize="sm"
|
||||||
variant="surface"
|
variant="surface"
|
||||||
onChange={e => onChange(rule.id, { quantity: parseFloat(e.target.value) || 1 })}
|
onChange={(e: ChangeEvent<HTMLInputElement>) => onChange(rule.id, { quantity: parseFloat(e.target.value) || 1 })}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Qty type */}
|
{/* Qty type */}
|
||||||
@ -203,7 +204,7 @@ function RuleCard({
|
|||||||
{ value: 'shares', label: 'shares' },
|
{ value: 'shares', label: 'shares' },
|
||||||
{ value: 'percent', label: '% of capital' },
|
{ value: 'percent', label: '% of capital' },
|
||||||
]}
|
]}
|
||||||
onChange={e => onChange(rule.id, { quantityType: e.target.value as QtyType })}
|
onChange={(e: ChangeEvent<HTMLSelectElement>) => onChange(rule.id, { quantityType: e.target.value as QtyType })}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Delete */}
|
{/* Delete */}
|
||||||
@ -315,7 +316,7 @@ export function VisualRuleBuilder({ symbol, onSave, onBacktest }: Props) {
|
|||||||
<div style={{ fontSize: 11, color: 'var(--muted-foreground)', fontWeight: 500, marginBottom: 3 }}>Strategy name</div>
|
<div style={{ fontSize: 11, color: 'var(--muted-foreground)', fontWeight: 500, marginBottom: 3 }}>Strategy name</div>
|
||||||
<Input
|
<Input
|
||||||
value={name}
|
value={name}
|
||||||
onChange={e => setName(e.target.value)}
|
onChange={(e: ChangeEvent<HTMLInputElement>) => setName(e.target.value)}
|
||||||
controlSize="sm"
|
controlSize="sm"
|
||||||
variant="surface"
|
variant="surface"
|
||||||
style={{
|
style={{
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import { useEffect, useMemo, useState } from 'react';
|
import { useEffect, useMemo, useState } from 'react';
|
||||||
|
import type { ChangeEvent } from 'react';
|
||||||
import type { BotState } from '../hooks/useWebSocket';
|
import type { BotState } from '../hooks/useWebSocket';
|
||||||
import { getPlatformAccessToken } from '../lib/authSession';
|
import { getPlatformAccessToken } from '../lib/authSession';
|
||||||
import { tradingRuntime } from '../lib/runtime';
|
import { tradingRuntime } from '../lib/runtime';
|
||||||
@ -1596,7 +1597,7 @@ export const PositionsTab = ({ botState, onManageHolding }: PositionsTabProps) =
|
|||||||
<th className="px-4 py-2">
|
<th className="px-4 py-2">
|
||||||
<Select
|
<Select
|
||||||
value={selectedProfileId}
|
value={selectedProfileId}
|
||||||
onChange={(e) => setSelectedProfileId(e.target.value)}
|
onChange={(e: ChangeEvent<HTMLSelectElement>) => setSelectedProfileId(e.target.value)}
|
||||||
options={[
|
options={[
|
||||||
{ value: 'all', label: 'All Profiles' },
|
{ value: 'all', label: 'All Profiles' },
|
||||||
...profiles.map((profileOption) => ({
|
...profiles.map((profileOption) => ({
|
||||||
@ -1614,7 +1615,7 @@ export const PositionsTab = ({ botState, onManageHolding }: PositionsTabProps) =
|
|||||||
<Input
|
<Input
|
||||||
type="date"
|
type="date"
|
||||||
value={ordersDateFrom}
|
value={ordersDateFrom}
|
||||||
onChange={(e) => setOrdersDateFrom(e.target.value)}
|
onChange={(e: ChangeEvent<HTMLInputElement>) => setOrdersDateFrom(e.target.value)}
|
||||||
controlSize="sm"
|
controlSize="sm"
|
||||||
variant="muted"
|
variant="muted"
|
||||||
className="bg-white/5 border border-white/10 rounded px-2 py-1 text-[10px] text-gray-200 focus:outline-none focus:ring-2 focus:ring-orange-500/40"
|
className="bg-white/5 border border-white/10 rounded px-2 py-1 text-[10px] text-gray-200 focus:outline-none focus:ring-2 focus:ring-orange-500/40"
|
||||||
@ -1622,7 +1623,7 @@ export const PositionsTab = ({ botState, onManageHolding }: PositionsTabProps) =
|
|||||||
<Input
|
<Input
|
||||||
type="date"
|
type="date"
|
||||||
value={ordersDateTo}
|
value={ordersDateTo}
|
||||||
onChange={(e) => setOrdersDateTo(e.target.value)}
|
onChange={(e: ChangeEvent<HTMLInputElement>) => setOrdersDateTo(e.target.value)}
|
||||||
controlSize="sm"
|
controlSize="sm"
|
||||||
variant="muted"
|
variant="muted"
|
||||||
className="bg-white/5 border border-white/10 rounded px-2 py-1 text-[10px] text-gray-200 focus:outline-none focus:ring-2 focus:ring-orange-500/40"
|
className="bg-white/5 border border-white/10 rounded px-2 py-1 text-[10px] text-gray-200 focus:outline-none focus:ring-2 focus:ring-orange-500/40"
|
||||||
@ -1863,7 +1864,7 @@ export const PositionsTab = ({ botState, onManageHolding }: PositionsTabProps) =
|
|||||||
<th className="px-4 py-2">
|
<th className="px-4 py-2">
|
||||||
<Select
|
<Select
|
||||||
value={selectedProfileId}
|
value={selectedProfileId}
|
||||||
onChange={(e) => setSelectedProfileId(e.target.value)}
|
onChange={(e: ChangeEvent<HTMLSelectElement>) => setSelectedProfileId(e.target.value)}
|
||||||
options={[
|
options={[
|
||||||
{ value: 'all', label: 'All Profiles' },
|
{ value: 'all', label: 'All Profiles' },
|
||||||
...profiles.map((profileOption) => ({
|
...profiles.map((profileOption) => ({
|
||||||
@ -1884,7 +1885,7 @@ export const PositionsTab = ({ botState, onManageHolding }: PositionsTabProps) =
|
|||||||
<Input
|
<Input
|
||||||
type="date"
|
type="date"
|
||||||
value={lifecycleDateFrom}
|
value={lifecycleDateFrom}
|
||||||
onChange={(e) => setLifecycleDateFrom(e.target.value)}
|
onChange={(e: ChangeEvent<HTMLInputElement>) => setLifecycleDateFrom(e.target.value)}
|
||||||
controlSize="sm"
|
controlSize="sm"
|
||||||
variant="muted"
|
variant="muted"
|
||||||
className="bg-white/5 border border-white/10 rounded px-2 py-1 text-[10px] text-gray-200 focus:outline-none focus:ring-2 focus:ring-cyan-500/40"
|
className="bg-white/5 border border-white/10 rounded px-2 py-1 text-[10px] text-gray-200 focus:outline-none focus:ring-2 focus:ring-cyan-500/40"
|
||||||
@ -1892,7 +1893,7 @@ export const PositionsTab = ({ botState, onManageHolding }: PositionsTabProps) =
|
|||||||
<Input
|
<Input
|
||||||
type="date"
|
type="date"
|
||||||
value={lifecycleDateTo}
|
value={lifecycleDateTo}
|
||||||
onChange={(e) => setLifecycleDateTo(e.target.value)}
|
onChange={(e: ChangeEvent<HTMLInputElement>) => setLifecycleDateTo(e.target.value)}
|
||||||
controlSize="sm"
|
controlSize="sm"
|
||||||
variant="muted"
|
variant="muted"
|
||||||
className="bg-white/5 border border-white/10 rounded px-2 py-1 text-[10px] text-gray-200 focus:outline-none focus:ring-2 focus:ring-cyan-500/40"
|
className="bg-white/5 border border-white/10 rounded px-2 py-1 text-[10px] text-gray-200 focus:outline-none focus:ring-2 focus:ring-cyan-500/40"
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import { useState, useEffect, useCallback } from 'react';
|
import { useState, useEffect, useCallback } from 'react';
|
||||||
|
import type { ChangeEvent } from 'react';
|
||||||
import { SlidersHorizontal, Search, RefreshCw } from 'lucide-react';
|
import { SlidersHorizontal, Search, RefreshCw } from 'lucide-react';
|
||||||
import { useAppContext } from '../context/AppContext';
|
import { useAppContext } from '../context/AppContext';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
@ -187,14 +188,14 @@ export function ScreenerView() {
|
|||||||
type="text"
|
type="text"
|
||||||
placeholder="Filter by name or ticker…"
|
placeholder="Filter by name or ticker…"
|
||||||
value={query}
|
value={query}
|
||||||
onChange={e => setQuery(e.target.value)}
|
onChange={(e: ChangeEvent<HTMLInputElement>) => setQuery(e.target.value)}
|
||||||
style={{ paddingLeft: 32 }}
|
style={{ paddingLeft: 32 }}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Select
|
<Select
|
||||||
value={String(capIdx)}
|
value={String(capIdx)}
|
||||||
onChange={e => setCapIdx(Number(e.target.value))}
|
onChange={(e: ChangeEvent<HTMLSelectElement>) => setCapIdx(Number(e.target.value))}
|
||||||
style={{ width: 180 }}
|
style={{ width: 180 }}
|
||||||
options={CAP_OPTIONS.map((c, i) => ({ value: String(i), label: c.label }))}
|
options={CAP_OPTIONS.map((c, i) => ({ value: String(i), label: c.label }))}
|
||||||
/>
|
/>
|
||||||
@ -222,7 +223,7 @@ export function ScreenerView() {
|
|||||||
<Select
|
<Select
|
||||||
aria-label="More sectors"
|
aria-label="More sectors"
|
||||||
value={SECTORS.indexOf(sector) >= 6 ? sector : ''}
|
value={SECTORS.indexOf(sector) >= 6 ? sector : ''}
|
||||||
onChange={e => e.target.value && setSector(e.target.value)}
|
onChange={(e: ChangeEvent<HTMLSelectElement>) => e.target.value && setSector(e.target.value)}
|
||||||
options={[
|
options={[
|
||||||
{ value: '', label: 'More sectors…' },
|
{ value: '', label: 'More sectors…' },
|
||||||
...SECTORS.slice(6).map(s => ({ value: s, label: s })),
|
...SECTORS.slice(6).map(s => ({ value: s, label: s })),
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { useEffect, useMemo, useReducer, useRef, useState } from 'react';
|
import { useEffect, useMemo, useReducer, useRef, useState } from 'react';
|
||||||
import type { FormEvent } from 'react';
|
import type { ChangeEvent, FormEvent } from 'react';
|
||||||
import { Pencil, RefreshCw, Trash2 } from 'lucide-react';
|
import { Pencil, RefreshCw, Trash2 } from 'lucide-react';
|
||||||
import { useSearchParams } from 'react-router-dom';
|
import { useSearchParams } from 'react-router-dom';
|
||||||
import { useAppContext } from '../context/AppContext';
|
import { useAppContext } from '../context/AppContext';
|
||||||
@ -1044,7 +1044,7 @@ export function SimpleView() {
|
|||||||
<span className="text-[11px] font-black uppercase tracking-[0.24em] text-zinc-700">Existing holding</span>
|
<span className="text-[11px] font-black uppercase tracking-[0.24em] text-zinc-700">Existing holding</span>
|
||||||
<Select
|
<Select
|
||||||
value={selectedHoldingTradeId || ''}
|
value={selectedHoldingTradeId || ''}
|
||||||
onChange={(e) => {
|
onChange={(e: ChangeEvent<HTMLSelectElement>) => {
|
||||||
const selected = availableSellHoldings.find((holding) => (holding.tradeId || '') === e.target.value);
|
const selected = availableSellHoldings.find((holding) => (holding.tradeId || '') === e.target.value);
|
||||||
if (selected) applyHoldingToDraft(selected);
|
if (selected) applyHoldingToDraft(selected);
|
||||||
}}
|
}}
|
||||||
@ -1067,7 +1067,7 @@ export function SimpleView() {
|
|||||||
<span className="text-[11px] font-black uppercase tracking-[0.24em] text-zinc-700">Symbol</span>
|
<span className="text-[11px] font-black uppercase tracking-[0.24em] text-zinc-700">Symbol</span>
|
||||||
<Input
|
<Input
|
||||||
value={draft.symbol}
|
value={draft.symbol}
|
||||||
onChange={(e) => {
|
onChange={(e: ChangeEvent<HTMLInputElement>) => {
|
||||||
dispatch({ type: 'set-market-price-source', value: null });
|
dispatch({ type: 'set-market-price-source', value: null });
|
||||||
if (draft.side === 'sell') {
|
if (draft.side === 'sell') {
|
||||||
dispatch({ type: 'set-selected-holding-trade-id', value: null });
|
dispatch({ type: 'set-selected-holding-trade-id', value: null });
|
||||||
@ -1136,7 +1136,7 @@ export function SimpleView() {
|
|||||||
<span className="text-[11px] font-black uppercase tracking-[0.24em] text-zinc-700">Setup type</span>
|
<span className="text-[11px] font-black uppercase tracking-[0.24em] text-zinc-700">Setup type</span>
|
||||||
<Select
|
<Select
|
||||||
value={draft.side}
|
value={draft.side}
|
||||||
onChange={(e) => updateDraft('side', e.target.value as SimpleSide)}
|
onChange={(e: ChangeEvent<HTMLSelectElement>) => updateDraft('side', e.target.value as SimpleSide)}
|
||||||
options={[
|
options={[
|
||||||
{ value: 'buy', label: 'Buy the dip + profit exit' },
|
{ value: 'buy', label: 'Buy the dip + profit exit' },
|
||||||
{ value: 'sell', label: 'Manage existing holding at profit' },
|
{ value: 'sell', label: 'Manage existing holding at profit' },
|
||||||
@ -1192,7 +1192,7 @@ export function SimpleView() {
|
|||||||
<span className="text-[11px] font-black uppercase tracking-[0.24em] text-zinc-700">Sizing method</span>
|
<span className="text-[11px] font-black uppercase tracking-[0.24em] text-zinc-700">Sizing method</span>
|
||||||
<Select
|
<Select
|
||||||
value={draft.sizingMode}
|
value={draft.sizingMode}
|
||||||
onChange={(e) => updateDraft('sizingMode', e.target.value as 'quantity' | 'amount')}
|
onChange={(e: ChangeEvent<HTMLSelectElement>) => updateDraft('sizingMode', e.target.value as 'quantity' | 'amount')}
|
||||||
options={[
|
options={[
|
||||||
{ value: 'quantity', label: 'Quantity / fractional shares' },
|
{ value: 'quantity', label: 'Quantity / fractional shares' },
|
||||||
{ value: 'amount', label: 'USD amount' },
|
{ value: 'amount', label: 'USD amount' },
|
||||||
@ -1206,7 +1206,7 @@ export function SimpleView() {
|
|||||||
</span>
|
</span>
|
||||||
<Input
|
<Input
|
||||||
value={draft.sizingMode === 'amount' ? draft.amountUsd : draft.quantity}
|
value={draft.sizingMode === 'amount' ? draft.amountUsd : draft.quantity}
|
||||||
onChange={(e) => {
|
onChange={(e: ChangeEvent<HTMLInputElement>) => {
|
||||||
if (draft.sizingMode === 'amount') {
|
if (draft.sizingMode === 'amount') {
|
||||||
updateDraft('amountUsd', e.target.value);
|
updateDraft('amountUsd', e.target.value);
|
||||||
} else {
|
} else {
|
||||||
@ -1230,7 +1230,7 @@ export function SimpleView() {
|
|||||||
</span>
|
</span>
|
||||||
<Input
|
<Input
|
||||||
value={draft.side === 'sell' && selectedSellHolding ? String(selectedSellHolding.size) : draft.quantity}
|
value={draft.side === 'sell' && selectedSellHolding ? String(selectedSellHolding.size) : draft.quantity}
|
||||||
onChange={(e) => updateDraft('quantity', e.target.value)}
|
onChange={(e: ChangeEvent<HTMLInputElement>) => updateDraft('quantity', e.target.value)}
|
||||||
readOnly={draft.side === 'sell' && !!selectedSellHolding}
|
readOnly={draft.side === 'sell' && !!selectedSellHolding}
|
||||||
className="read-only:bg-[var(--muted)]"
|
className="read-only:bg-[var(--muted)]"
|
||||||
placeholder="10"
|
placeholder="10"
|
||||||
@ -1242,7 +1242,7 @@ export function SimpleView() {
|
|||||||
<span className="text-[11px] font-black uppercase tracking-[0.24em] text-zinc-700">Notes</span>
|
<span className="text-[11px] font-black uppercase tracking-[0.24em] text-zinc-700">Notes</span>
|
||||||
<Input
|
<Input
|
||||||
value={draft.notes}
|
value={draft.notes}
|
||||||
onChange={(e) => updateDraft('notes', e.target.value)}
|
onChange={(e: ChangeEvent<HTMLInputElement>) => updateDraft('notes', e.target.value)}
|
||||||
placeholder="Optional context"
|
placeholder="Optional context"
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
@ -1254,7 +1254,7 @@ export function SimpleView() {
|
|||||||
<p className="text-[11px] font-black uppercase tracking-[0.24em] text-zinc-700">Drop trigger</p>
|
<p className="text-[11px] font-black uppercase tracking-[0.24em] text-zinc-700">Drop trigger</p>
|
||||||
<Select
|
<Select
|
||||||
value={draft.dropMode}
|
value={draft.dropMode}
|
||||||
onChange={(e) => updateDraft('dropMode', e.target.value as TriggerMode)}
|
onChange={(e: ChangeEvent<HTMLSelectElement>) => updateDraft('dropMode', e.target.value as TriggerMode)}
|
||||||
options={[
|
options={[
|
||||||
{ value: 'dollar', label: 'Dollar drop from current market' },
|
{ value: 'dollar', label: 'Dollar drop from current market' },
|
||||||
{ value: 'percent', label: 'Percent drop from current market' },
|
{ value: 'percent', label: 'Percent drop from current market' },
|
||||||
@ -1267,7 +1267,7 @@ export function SimpleView() {
|
|||||||
</span>
|
</span>
|
||||||
<Input
|
<Input
|
||||||
value={draft.dropValue}
|
value={draft.dropValue}
|
||||||
onChange={(e) => updateDraft('dropValue', e.target.value)}
|
onChange={(e: ChangeEvent<HTMLInputElement>) => updateDraft('dropValue', e.target.value)}
|
||||||
placeholder={draft.dropMode === 'dollar' ? '0.00' : '0'}
|
placeholder={draft.dropMode === 'dollar' ? '0.00' : '0'}
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
@ -1279,7 +1279,7 @@ export function SimpleView() {
|
|||||||
<p className="text-[11px] font-black uppercase tracking-[0.24em] text-zinc-700">Profit exit</p>
|
<p className="text-[11px] font-black uppercase tracking-[0.24em] text-zinc-700">Profit exit</p>
|
||||||
<Select
|
<Select
|
||||||
value={draft.profitMode}
|
value={draft.profitMode}
|
||||||
onChange={(e) => updateDraft('profitMode', e.target.value as TriggerMode)}
|
onChange={(e: ChangeEvent<HTMLSelectElement>) => updateDraft('profitMode', e.target.value as TriggerMode)}
|
||||||
options={[
|
options={[
|
||||||
{ value: 'dollar', label: 'Dollar gain from purchase' },
|
{ value: 'dollar', label: 'Dollar gain from purchase' },
|
||||||
{ value: 'percent', label: 'Percent gain from purchase' },
|
{ value: 'percent', label: 'Percent gain from purchase' },
|
||||||
@ -1292,7 +1292,7 @@ export function SimpleView() {
|
|||||||
</span>
|
</span>
|
||||||
<Input
|
<Input
|
||||||
value={draft.profitValue}
|
value={draft.profitValue}
|
||||||
onChange={(e) => updateDraft('profitValue', e.target.value)}
|
onChange={(e: ChangeEvent<HTMLInputElement>) => updateDraft('profitValue', e.target.value)}
|
||||||
placeholder={draft.profitMode === 'dollar' ? '7.50' : '10'}
|
placeholder={draft.profitMode === 'dollar' ? '7.50' : '10'}
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user