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 type { ChangeEvent } from 'react';
|
||||
import { createPortal } from 'react-dom';
|
||||
import { tradingRuntime } from '../lib/runtime';
|
||||
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>
|
||||
<Input
|
||||
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"
|
||||
className="w-full rounded-lg px-2.5 py-1.5 text-[11px] outline-none"
|
||||
style={inputStyle}
|
||||
@ -572,7 +573,7 @@ export const ChatControl = ({ profiles, onApplyProfile }: ChatControlProps) => {
|
||||
min="0"
|
||||
step="1"
|
||||
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"
|
||||
className="w-full rounded-lg px-2.5 py-1.5 text-[11px] outline-none"
|
||||
style={inputStyle}
|
||||
@ -582,7 +583,7 @@ export const ChatControl = ({ profiles, onApplyProfile }: ChatControlProps) => {
|
||||
min="0"
|
||||
step="0.1"
|
||||
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 %"
|
||||
className="w-full rounded-lg px-2.5 py-1.5 text-[11px] outline-none"
|
||||
style={inputStyle}
|
||||
@ -590,7 +591,7 @@ export const ChatControl = ({ profiles, onApplyProfile }: ChatControlProps) => {
|
||||
</div>
|
||||
<Input
|
||||
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)"
|
||||
className="w-full rounded-lg px-2.5 py-1.5 text-[11px] outline-none"
|
||||
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>
|
||||
<Select
|
||||
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"
|
||||
style={inputStyle}
|
||||
options={[
|
||||
@ -709,11 +710,11 @@ export const ChatControl = ({ profiles, onApplyProfile }: ChatControlProps) => {
|
||||
border: '1px solid var(--border)',
|
||||
cursor: 'pointer',
|
||||
}}
|
||||
onMouseEnter={e => {
|
||||
onMouseEnter={(e: React.MouseEvent<HTMLButtonElement>) => {
|
||||
e.currentTarget.style.borderColor = 'var(--ring)';
|
||||
e.currentTarget.style.background = 'var(--accent-soft)';
|
||||
}}
|
||||
onMouseLeave={e => {
|
||||
onMouseLeave={(e: React.MouseEvent<HTMLButtonElement>) => {
|
||||
e.currentTarget.style.borderColor = 'var(--border)';
|
||||
e.currentTarget.style.background = 'var(--card)';
|
||||
}}
|
||||
@ -755,7 +756,7 @@ export const ChatControl = ({ profiles, onApplyProfile }: ChatControlProps) => {
|
||||
<Textarea
|
||||
ref={inputRef}
|
||||
value={input}
|
||||
onChange={e => setInput(e.target.value)}
|
||||
onChange={(e: ChangeEvent<HTMLTextAreaElement>) => setInput(e.target.value)}
|
||||
onKeyDown={handleKeyDown}
|
||||
placeholder="Describe a strategy profile..."
|
||||
disabled={isLoading}
|
||||
|
||||
@ -56,7 +56,7 @@ export function Login() {
|
||||
label="Email"
|
||||
type="email"
|
||||
value={email}
|
||||
onChange={(e) => setEmail(e.target.value)}
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => setEmail(e.target.value)}
|
||||
placeholder="trader@example.com"
|
||||
required
|
||||
/>
|
||||
@ -68,7 +68,7 @@ export function Login() {
|
||||
label="Password"
|
||||
type="password"
|
||||
value={password}
|
||||
onChange={(e) => setPassword(e.target.value)}
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => setPassword(e.target.value)}
|
||||
placeholder="••••••••"
|
||||
required
|
||||
/>
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import type { ChangeEvent } from 'react';
|
||||
import { resetPlatformPassword } from '../lib/authSession';
|
||||
import { Button, Input } from './ui/Primitives';
|
||||
|
||||
@ -50,7 +51,7 @@ export function ResetPassword() {
|
||||
label="New Password"
|
||||
type="password"
|
||||
value={password}
|
||||
onChange={(e) => setPassword(e.target.value)}
|
||||
onChange={(e: ChangeEvent<HTMLInputElement>) => setPassword(e.target.value)}
|
||||
placeholder="New password"
|
||||
required
|
||||
/>
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
* Lets users compose IF/THEN trading rules without writing code.
|
||||
*/
|
||||
import { useState, useCallback, useEffect, useRef } from 'react';
|
||||
import type { ChangeEvent } from 'react';
|
||||
import {
|
||||
DndContext,
|
||||
closestCenter,
|
||||
@ -136,7 +137,7 @@ function RuleCard({
|
||||
controlSize="sm"
|
||||
variant="surface"
|
||||
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,
|
||||
value: INDICATOR_DEFAULTS[e.target.value as Indicator],
|
||||
})}
|
||||
@ -149,7 +150,7 @@ function RuleCard({
|
||||
controlSize="sm"
|
||||
variant="surface"
|
||||
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 */}
|
||||
@ -159,7 +160,7 @@ function RuleCard({
|
||||
style={numInp}
|
||||
controlSize="sm"
|
||||
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 */}
|
||||
@ -179,7 +180,7 @@ function RuleCard({
|
||||
{ value: 'BUY', label: 'BUY' },
|
||||
{ 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 */}
|
||||
@ -190,7 +191,7 @@ function RuleCard({
|
||||
min={1}
|
||||
controlSize="sm"
|
||||
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 */}
|
||||
@ -203,7 +204,7 @@ function RuleCard({
|
||||
{ value: 'shares', label: 'shares' },
|
||||
{ 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 */}
|
||||
@ -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>
|
||||
<Input
|
||||
value={name}
|
||||
onChange={e => setName(e.target.value)}
|
||||
onChange={(e: ChangeEvent<HTMLInputElement>) => setName(e.target.value)}
|
||||
controlSize="sm"
|
||||
variant="surface"
|
||||
style={{
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import type { ChangeEvent } from 'react';
|
||||
import type { BotState } from '../hooks/useWebSocket';
|
||||
import { getPlatformAccessToken } from '../lib/authSession';
|
||||
import { tradingRuntime } from '../lib/runtime';
|
||||
@ -1596,7 +1597,7 @@ export const PositionsTab = ({ botState, onManageHolding }: PositionsTabProps) =
|
||||
<th className="px-4 py-2">
|
||||
<Select
|
||||
value={selectedProfileId}
|
||||
onChange={(e) => setSelectedProfileId(e.target.value)}
|
||||
onChange={(e: ChangeEvent<HTMLSelectElement>) => setSelectedProfileId(e.target.value)}
|
||||
options={[
|
||||
{ value: 'all', label: 'All Profiles' },
|
||||
...profiles.map((profileOption) => ({
|
||||
@ -1614,7 +1615,7 @@ export const PositionsTab = ({ botState, onManageHolding }: PositionsTabProps) =
|
||||
<Input
|
||||
type="date"
|
||||
value={ordersDateFrom}
|
||||
onChange={(e) => setOrdersDateFrom(e.target.value)}
|
||||
onChange={(e: ChangeEvent<HTMLInputElement>) => setOrdersDateFrom(e.target.value)}
|
||||
controlSize="sm"
|
||||
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"
|
||||
@ -1622,7 +1623,7 @@ export const PositionsTab = ({ botState, onManageHolding }: PositionsTabProps) =
|
||||
<Input
|
||||
type="date"
|
||||
value={ordersDateTo}
|
||||
onChange={(e) => setOrdersDateTo(e.target.value)}
|
||||
onChange={(e: ChangeEvent<HTMLInputElement>) => setOrdersDateTo(e.target.value)}
|
||||
controlSize="sm"
|
||||
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"
|
||||
@ -1863,7 +1864,7 @@ export const PositionsTab = ({ botState, onManageHolding }: PositionsTabProps) =
|
||||
<th className="px-4 py-2">
|
||||
<Select
|
||||
value={selectedProfileId}
|
||||
onChange={(e) => setSelectedProfileId(e.target.value)}
|
||||
onChange={(e: ChangeEvent<HTMLSelectElement>) => setSelectedProfileId(e.target.value)}
|
||||
options={[
|
||||
{ value: 'all', label: 'All Profiles' },
|
||||
...profiles.map((profileOption) => ({
|
||||
@ -1884,7 +1885,7 @@ export const PositionsTab = ({ botState, onManageHolding }: PositionsTabProps) =
|
||||
<Input
|
||||
type="date"
|
||||
value={lifecycleDateFrom}
|
||||
onChange={(e) => setLifecycleDateFrom(e.target.value)}
|
||||
onChange={(e: ChangeEvent<HTMLInputElement>) => setLifecycleDateFrom(e.target.value)}
|
||||
controlSize="sm"
|
||||
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"
|
||||
@ -1892,7 +1893,7 @@ export const PositionsTab = ({ botState, onManageHolding }: PositionsTabProps) =
|
||||
<Input
|
||||
type="date"
|
||||
value={lifecycleDateTo}
|
||||
onChange={(e) => setLifecycleDateTo(e.target.value)}
|
||||
onChange={(e: ChangeEvent<HTMLInputElement>) => setLifecycleDateTo(e.target.value)}
|
||||
controlSize="sm"
|
||||
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"
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import { useState, useEffect, useCallback } from 'react';
|
||||
import type { ChangeEvent } from 'react';
|
||||
import { SlidersHorizontal, Search, RefreshCw } from 'lucide-react';
|
||||
import { useAppContext } from '../context/AppContext';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
@ -187,14 +188,14 @@ export function ScreenerView() {
|
||||
type="text"
|
||||
placeholder="Filter by name or ticker…"
|
||||
value={query}
|
||||
onChange={e => setQuery(e.target.value)}
|
||||
onChange={(e: ChangeEvent<HTMLInputElement>) => setQuery(e.target.value)}
|
||||
style={{ paddingLeft: 32 }}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Select
|
||||
value={String(capIdx)}
|
||||
onChange={e => setCapIdx(Number(e.target.value))}
|
||||
onChange={(e: ChangeEvent<HTMLSelectElement>) => setCapIdx(Number(e.target.value))}
|
||||
style={{ width: 180 }}
|
||||
options={CAP_OPTIONS.map((c, i) => ({ value: String(i), label: c.label }))}
|
||||
/>
|
||||
@ -222,7 +223,7 @@ export function ScreenerView() {
|
||||
<Select
|
||||
aria-label="More sectors"
|
||||
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={[
|
||||
{ value: '', label: 'More sectors…' },
|
||||
...SECTORS.slice(6).map(s => ({ value: s, label: s })),
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
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 { useSearchParams } from 'react-router-dom';
|
||||
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>
|
||||
<Select
|
||||
value={selectedHoldingTradeId || ''}
|
||||
onChange={(e) => {
|
||||
onChange={(e: ChangeEvent<HTMLSelectElement>) => {
|
||||
const selected = availableSellHoldings.find((holding) => (holding.tradeId || '') === e.target.value);
|
||||
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>
|
||||
<Input
|
||||
value={draft.symbol}
|
||||
onChange={(e) => {
|
||||
onChange={(e: ChangeEvent<HTMLInputElement>) => {
|
||||
dispatch({ type: 'set-market-price-source', value: null });
|
||||
if (draft.side === 'sell') {
|
||||
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>
|
||||
<Select
|
||||
value={draft.side}
|
||||
onChange={(e) => updateDraft('side', e.target.value as SimpleSide)}
|
||||
onChange={(e: ChangeEvent<HTMLSelectElement>) => updateDraft('side', e.target.value as SimpleSide)}
|
||||
options={[
|
||||
{ value: 'buy', label: 'Buy the dip + profit exit' },
|
||||
{ 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>
|
||||
<Select
|
||||
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={[
|
||||
{ value: 'quantity', label: 'Quantity / fractional shares' },
|
||||
{ value: 'amount', label: 'USD amount' },
|
||||
@ -1206,7 +1206,7 @@ export function SimpleView() {
|
||||
</span>
|
||||
<Input
|
||||
value={draft.sizingMode === 'amount' ? draft.amountUsd : draft.quantity}
|
||||
onChange={(e) => {
|
||||
onChange={(e: ChangeEvent<HTMLInputElement>) => {
|
||||
if (draft.sizingMode === 'amount') {
|
||||
updateDraft('amountUsd', e.target.value);
|
||||
} else {
|
||||
@ -1230,7 +1230,7 @@ export function SimpleView() {
|
||||
</span>
|
||||
<Input
|
||||
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}
|
||||
className="read-only:bg-[var(--muted)]"
|
||||
placeholder="10"
|
||||
@ -1242,7 +1242,7 @@ export function SimpleView() {
|
||||
<span className="text-[11px] font-black uppercase tracking-[0.24em] text-zinc-700">Notes</span>
|
||||
<Input
|
||||
value={draft.notes}
|
||||
onChange={(e) => updateDraft('notes', e.target.value)}
|
||||
onChange={(e: ChangeEvent<HTMLInputElement>) => updateDraft('notes', e.target.value)}
|
||||
placeholder="Optional context"
|
||||
/>
|
||||
</label>
|
||||
@ -1254,7 +1254,7 @@ export function SimpleView() {
|
||||
<p className="text-[11px] font-black uppercase tracking-[0.24em] text-zinc-700">Drop trigger</p>
|
||||
<Select
|
||||
value={draft.dropMode}
|
||||
onChange={(e) => updateDraft('dropMode', e.target.value as TriggerMode)}
|
||||
onChange={(e: ChangeEvent<HTMLSelectElement>) => updateDraft('dropMode', e.target.value as TriggerMode)}
|
||||
options={[
|
||||
{ value: 'dollar', label: 'Dollar drop from current market' },
|
||||
{ value: 'percent', label: 'Percent drop from current market' },
|
||||
@ -1267,7 +1267,7 @@ export function SimpleView() {
|
||||
</span>
|
||||
<Input
|
||||
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'}
|
||||
/>
|
||||
</label>
|
||||
@ -1279,7 +1279,7 @@ export function SimpleView() {
|
||||
<p className="text-[11px] font-black uppercase tracking-[0.24em] text-zinc-700">Profit exit</p>
|
||||
<Select
|
||||
value={draft.profitMode}
|
||||
onChange={(e) => updateDraft('profitMode', e.target.value as TriggerMode)}
|
||||
onChange={(e: ChangeEvent<HTMLSelectElement>) => updateDraft('profitMode', e.target.value as TriggerMode)}
|
||||
options={[
|
||||
{ value: 'dollar', label: 'Dollar gain from purchase' },
|
||||
{ value: 'percent', label: 'Percent gain from purchase' },
|
||||
@ -1292,7 +1292,7 @@ export function SimpleView() {
|
||||
</span>
|
||||
<Input
|
||||
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'}
|
||||
/>
|
||||
</label>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user