import { useCallback, useEffect, useRef, useState } from "react";
import type { ExchangeId, PublicConfig } from "../types";
import { Card } from "./Card";
import { patchConfig } from "../config-api";
import { clsx, pct, btc } from "../format";
interface Props {
config: PublicConfig;
}
const EXCHANGES: { id: ExchangeId; label: string }[] = [
{ id: "kraken", label: "Kraken" },
{ id: "bybit", label: "Bybit" },
{ id: "okx", label: "OKX" },
{ id: "binance", label: "Binance" },
];
const MIN_PROFIT = 0.0001;
const MAX_PROFIT = 0.01;
const MIN_TRADE = 0.01;
const MAX_TRADE = 1.0;
const DEBOUNCE_MS = 200;
function Toggle({
label,
on,
modified,
onChange,
}: {
label: string;
on: boolean;
modified: boolean;
onChange: (v: boolean) => void;
}): JSX.Element {
return (
);
}
function SliderRow({
label,
valueLabel,
min,
max,
step,
value,
modified,
onChange,
}: {
label: string;
valueLabel: string;
min: number;
max: number;
step: number;
value: number;
modified: boolean;
onChange: (v: number) => void;
}): JSX.Element {
return (
);
}
export function ConfigPanel({ config }: Props): JSX.Element {
const [minProfit, setMinProfit] = useState(config.minNetProfitPct);
const [maxTrade, setMaxTrade] = useState(config.maxTradeBtc);
const [flickerMs, setFlickerMs] = useState(config.flickerConfirmMs);
const [active, setActive] = useState(config.activeExchanges);
const debounceRef = useRef | null>(null);
useEffect(() => {
setMinProfit(config.minNetProfitPct);
setMaxTrade(config.maxTradeBtc);
setFlickerMs(config.flickerConfirmMs);
setActive(config.activeExchanges);
}, [config]);
const sendPatch = useCallback((patch: Parameters[0]) => {
patchConfig(patch).catch(() => {
/* SSE will resync on next snapshot */
});
}, []);
const debouncedPatch = useCallback(
(patch: Parameters[0]) => {
if (debounceRef.current) clearTimeout(debounceRef.current);
debounceRef.current = setTimeout(() => sendPatch(patch), DEBOUNCE_MS);
},
[sendPatch],
);
useEffect(() => {
return () => {
if (debounceRef.current) clearTimeout(debounceRef.current);
};
}, []);
const defaults = config.defaults;
return (
{
setMinProfit(v);
debouncedPatch({ minNetProfitPct: v });
}}
/>
{
setMaxTrade(v);
debouncedPatch({ maxTradeBtc: v });
}}
/>
{
setFlickerMs(v);
debouncedPatch({ flickerConfirmMs: v });
}}
/>
Active exchanges
{EXCHANGES.map(({ id, label }) => (
{
const next = { ...active, [id]: enabled };
setActive(next);
sendPatch({ activeExchanges: { [id]: enabled } });
}}
/>
))}
);
}