import { useState, useEffect, useRef, useMemo } from "react";
import { isValidLimit, computeMaxDailyExposure, computeExposurePctOfBalance } from "../lib/automatedLimits.js";
/**
* AutomatedSetupModal.jsx
*
* Replaces the prompt()/alert() placeholder that used to sit inline in
* Dashboard.jsx's handleTierChange. This is the one moment in the whole
* app where a human hands off standing permission to trade without a
* per-trade tap -- tradeGate.js already refuses to enable that tier
* without finite, positive limits (no "unlimited" option, checked on
* every signal, not just here); this form is the honest UI for setting
* them, not just a barrier to get past.
*
* SIGNATURE ELEMENT: the two numbers a person types here (max per trade,
* max trades per day) don't mean anything on their own -- their PRODUCT
* is the real question ("how much could this commit in a single day if
* every trade hit the cap"). That's computed live below the inputs, and
* related to the actual USD balance when known, rather than left as an
* exercise for the reader. Framed explicitly as a ceiling, not a loss
* estimate -- each trade is a grid buy, not a guaranteed loss, and
* overstating this as "money you will lose" would be its own kind of
* dishonesty this project has consistently tried to avoid elsewhere
* (see tradeGate.js and covenant_unified_v8.py's own HONESTY NOTEs).
*
* Validation lives in two places on purpose, not by accident: the fast
* inline check here (so the submit button reflects reality as you type,
* and you never even attempt a bad submission) AND tradeGate.js's own
* enableAutomated() (the actual authority -- see its own comment: "no
* unlimited option"). If those two ever disagreed, the gate wins; this
* form's job is to never let that disagreement surface as a raw
* exception, not to be a second source of truth.
*/
const FIELD_STYLE = {
width: "100%", padding: "10px 12px", background: "#0d0f12",
border: "1px solid #2a2d33", borderRadius: 8, color: "#e8e6e1",
fontSize: 15, fontFamily: "ui-monospace, monospace",
};
function Field({ label, hint, value, onChange, inputRef, autoFocus, invalidMessage }) {
const [touched, setTouched] = useState(false);
const showError = touched && value !== "" && !isValidLimit(value);
return (
The gate runs the strategy on a timer within the limits below. A Ledger
confirmation is still required for every trade — this cannot be
switched off at any tier.
{bothValid
? exposurePctOfBalance !== null
? `If every trade hits the per-trade cap, ${exposurePctOfBalance.toFixed(0)}% of your current $${usdBalance.toFixed(2)} balance in one day.`
: "If every trade hits the per-trade cap. Not a loss estimate — each trade is a grid buy, not a guaranteed loss."
: "Fill in both fields to see the ceiling this sets."}