refactor(web): normalize strategy profile theme surfaces
This commit is contained in:
parent
6b2ddeb837
commit
5d0f138cd1
@ -95,8 +95,8 @@ Current public bundle:
|
||||
|
||||
## Phase 4: Remaining legacy component cleanup
|
||||
|
||||
- [ ] Normalize `web/src/components/TradeProfileManager.tsx`
|
||||
- [ ] Normalize `web/src/components/StrategyWizard.tsx`
|
||||
- [x] Normalize `web/src/components/TradeProfileManager.tsx`
|
||||
- [x] Normalize `web/src/components/StrategyWizard.tsx`
|
||||
- [ ] Normalize `web/src/tabs/ReconciliationAuditPanel.tsx`
|
||||
- [ ] Normalize `web/src/components/GlobalConfigManager.tsx`
|
||||
- [ ] Normalize `web/src/components/EntryForm.tsx`
|
||||
|
||||
@ -21,6 +21,9 @@ import { useAuth } from './AuthContext';
|
||||
import { BacktestRunnerPanel } from '../backtest/components/BacktestRunnerPanel';
|
||||
import { useBacktestFeatureGate } from '../backtest/useBacktestFeatureGate';
|
||||
import { createTradeProfile, updateTradeProfile } from '../lib/profileApi';
|
||||
import { Button } from './ui/button';
|
||||
import { Card } from './ui/card';
|
||||
import { Input } from './ui/input';
|
||||
|
||||
interface WizardState {
|
||||
step: number;
|
||||
@ -43,6 +46,13 @@ const SESSION_MAP = {
|
||||
'Asia only': 'TOK,SYD'
|
||||
};
|
||||
|
||||
const sectionTitleClass = 'mb-2 text-2xl font-bold text-[var(--foreground)]';
|
||||
const sectionDescriptionClass = 'text-sm text-[var(--muted-foreground)]';
|
||||
const labelClass = 'text-xs font-bold uppercase tracking-widest text-[var(--muted-foreground)]';
|
||||
const optionBaseClass = 'w-full rounded-2xl border-2 p-5 text-left transition-all';
|
||||
const optionSelectedClass = 'border-[var(--accent)] bg-[var(--accent-soft)]';
|
||||
const optionIdleClass = 'border-[var(--border)] bg-[var(--card)] hover:border-[var(--border-strong)]';
|
||||
|
||||
const buildStrategyConfig = (state: WizardState) => ({
|
||||
rules: [
|
||||
{ ruleId: 'RiskManagementRule', enabled: true, ruleType: 'mandatory', params: {} },
|
||||
@ -148,16 +158,16 @@ export const StrategyWizard: React.FC<{
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="max-w-3xl mx-auto py-8 px-4">
|
||||
{/* Progress Bar */}
|
||||
<div className="flex justify-between mb-12 relative">
|
||||
<div className="absolute top-1/2 left-0 w-full h-0.5 bg-zinc-800 -translate-y-1/2 z-0" />
|
||||
{[1, 2, 3, 4, 5].map(i => (
|
||||
<div
|
||||
key={i}
|
||||
className={`relative z-10 w-10 h-10 rounded-full flex items-center justify-center font-bold text-sm transition-all duration-300 ${state.step >= i ? 'bg-[#00ff88] text-black scale-110' : 'bg-zinc-800 text-zinc-500 border border-zinc-700'
|
||||
}`}
|
||||
>
|
||||
<div className="mx-auto max-w-3xl px-4 py-8">
|
||||
{/* Progress Bar */}
|
||||
<div className="relative mb-12 flex justify-between">
|
||||
<div className="absolute left-0 top-1/2 z-0 h-0.5 w-full -translate-y-1/2 bg-[var(--border)]" />
|
||||
{[1, 2, 3, 4, 5].map(i => (
|
||||
<div
|
||||
key={i}
|
||||
className={`relative z-10 flex h-10 w-10 items-center justify-center rounded-full text-sm font-bold transition-all duration-300 ${state.step >= i ? 'scale-110 bg-[var(--primary)] text-[var(--primary-foreground)]' : 'border border-[var(--border)] bg-[var(--card)] text-[var(--muted-foreground)]'
|
||||
}`}
|
||||
>
|
||||
{state.step > i ? <CheckCircle2 size={18} /> : i}
|
||||
</div>
|
||||
))}
|
||||
@ -166,9 +176,9 @@ export const StrategyWizard: React.FC<{
|
||||
{/* Step 1: Risk Style */}
|
||||
{state.step === 1 && (
|
||||
<div className="space-y-6 animate-in fade-in slide-in-from-bottom-4 duration-500">
|
||||
<div className="text-center mb-8">
|
||||
<h2 className="text-2xl font-bold text-white mb-2">How should this bot behave?</h2>
|
||||
<p className="text-zinc-400 text-sm">Select a pre-configured risk style. High-frequency options seek more opportunities but require more flexibility.</p>
|
||||
<div className="mb-8 text-center">
|
||||
<h2 className={sectionTitleClass}>How should this bot behave?</h2>
|
||||
<p className={sectionDescriptionClass}>Select a pre-configured risk style. High-frequency options seek more opportunities but require more flexibility.</p>
|
||||
</div>
|
||||
<div className="grid grid-cols-1 gap-4">
|
||||
{RISK_STYLE_TEMPLATES.map(style => {
|
||||
@ -178,27 +188,27 @@ export const StrategyWizard: React.FC<{
|
||||
<button
|
||||
disabled={isLocked}
|
||||
onClick={() => setState({ ...state, riskStyle: style })}
|
||||
className={`w-full p-5 rounded-2xl border-2 text-left transition-all ${isLocked ? 'opacity-40 cursor-not-allowed grayscale' : 'hover:scale-[1.01] active:scale-[0.99]'
|
||||
} ${state.riskStyle?.id === style.id
|
||||
? 'border-[#00ff88] bg-[#00ff88]/5'
|
||||
: 'border-white/5 bg-zinc-900/50 hover:border-white/10'
|
||||
}`}
|
||||
className={`${optionBaseClass} ${isLocked ? 'cursor-not-allowed opacity-40 grayscale' : 'hover:scale-[1.01] active:scale-[0.99]'
|
||||
} ${state.riskStyle?.id === style.id
|
||||
? optionSelectedClass
|
||||
: optionIdleClass
|
||||
}`}
|
||||
>
|
||||
<div className="flex items-start gap-4">
|
||||
<div className={`w-12 h-12 rounded-xl flex items-center justify-center ${style.id === 'safe' ? 'bg-blue-500/10 text-blue-400' :
|
||||
style.id === 'balanced' ? 'bg-[#00ff88]/10 text-[#00ff88]' : 'bg-orange-500/10 text-orange-400'
|
||||
}`}>
|
||||
style.id === 'balanced' ? 'bg-[var(--accent-soft)] text-[var(--accent)]' : 'bg-orange-500/10 text-orange-400'
|
||||
}`}>
|
||||
{style.id === 'safe' ? <ShieldCheck size={24} /> : style.id === 'balanced' ? <Scale size={24} /> : <Zap size={24} />}
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<div className="flex justify-between items-center mb-1">
|
||||
<span className="text-lg font-bold text-white flex items-center gap-2">
|
||||
{style.label}
|
||||
{isLocked && <Lock size={14} className="text-zinc-500" />}
|
||||
</span>
|
||||
<span className="flex items-center gap-2 text-lg font-bold text-[var(--foreground)]">
|
||||
{style.label}
|
||||
{isLocked && <Lock size={14} className="text-[var(--muted-foreground)]" />}
|
||||
</span>
|
||||
<span className="text-[10px] uppercase tracking-widest font-black opacity-40">{style.tradeFrequency}</span>
|
||||
</div>
|
||||
<p className="text-sm text-zinc-400 leading-relaxed">{style.description}</p>
|
||||
<p className="text-sm leading-relaxed text-[var(--muted-foreground)]">{style.description}</p>
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
@ -212,13 +222,13 @@ export const StrategyWizard: React.FC<{
|
||||
})}
|
||||
</div>
|
||||
<div className="flex justify-end pt-4">
|
||||
<button
|
||||
disabled={!state.riskStyle}
|
||||
onClick={next}
|
||||
className="flex items-center gap-2 bg-[#00ff88] text-black px-8 py-3 rounded-xl font-bold hover:brightness-110 transition-all disabled:opacity-30"
|
||||
>
|
||||
Continue <ChevronRight size={18} />
|
||||
</button>
|
||||
<Button
|
||||
disabled={!state.riskStyle}
|
||||
onClick={next}
|
||||
className="px-8"
|
||||
>
|
||||
Continue <ChevronRight size={18} />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
@ -226,14 +236,14 @@ export const StrategyWizard: React.FC<{
|
||||
{/* Step 2: Assets & Capital */}
|
||||
{state.step === 2 && (
|
||||
<div className="space-y-8 animate-in fade-in slide-in-from-right-4 duration-500">
|
||||
<div className="text-center">
|
||||
<h2 className="text-2xl font-bold text-white mb-2">Assets & Capital</h2>
|
||||
<p className="text-zinc-400 text-sm">Define what to trade and how much capital to use.</p>
|
||||
<div className="text-center">
|
||||
<h2 className={sectionTitleClass}>Assets & Capital</h2>
|
||||
<p className={sectionDescriptionClass}>Define what to trade and how much capital to use.</p>
|
||||
</div>
|
||||
|
||||
<div className="space-y-6">
|
||||
<div className="space-y-3">
|
||||
<label className="text-xs font-bold text-zinc-500 uppercase tracking-widest">Select Trading Assets</label>
|
||||
<label className={labelClass}>Select Trading Assets</label>
|
||||
<div className="flex flex-wrap gap-3">
|
||||
{ASSETS.map(asset => (
|
||||
<button
|
||||
@ -244,10 +254,10 @@ export const StrategyWizard: React.FC<{
|
||||
: [...state.assets, asset.id];
|
||||
if (newAssets.length > 0) setState({ ...state, assets: newAssets });
|
||||
}}
|
||||
className={`px-5 py-3 rounded-xl border-2 font-bold text-sm transition-all ${state.assets.includes(asset.id)
|
||||
? 'border-[#00ff88] bg-[#00ff88]/10 text-white'
|
||||
: 'border-white/5 bg-zinc-900 text-zinc-500 hover:border-white/10'
|
||||
}`}
|
||||
className={`rounded-xl border-2 px-5 py-3 text-sm font-bold transition-all ${state.assets.includes(asset.id)
|
||||
? 'border-[var(--accent)] bg-[var(--accent-soft)] text-[var(--foreground)]'
|
||||
: 'border-[var(--border)] bg-[var(--card)] text-[var(--muted-foreground)] hover:border-[var(--border-strong)]'
|
||||
}`}
|
||||
>
|
||||
{asset.label}
|
||||
</button>
|
||||
@ -257,33 +267,33 @@ export const StrategyWizard: React.FC<{
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<div className="space-y-3">
|
||||
<label className="text-xs font-bold text-zinc-500 uppercase tracking-widest">Capital Allocation</label>
|
||||
<div className="relative">
|
||||
<div className="absolute inset-y-0 left-4 flex items-center pointer-events-none text-zinc-500">
|
||||
<DollarSign size={16} />
|
||||
</div>
|
||||
<input
|
||||
type="number"
|
||||
value={state.capital}
|
||||
onChange={e => setState({ ...state, capital: Number(e.target.value) })}
|
||||
className="w-full bg-zinc-900 border-2 border-white/5 rounded-xl py-4 pl-10 pr-4 text-white font-bold outline-none focus:border-[#00ff88]/50 transition-all"
|
||||
/>
|
||||
</div>
|
||||
<p className="text-[10px] text-zinc-500">Total USD balance this bot is allowed to manage.</p>
|
||||
<label className={labelClass}>Capital Allocation</label>
|
||||
<div className="relative">
|
||||
<div className="pointer-events-none absolute inset-y-0 left-4 flex items-center text-[var(--muted-foreground)]">
|
||||
<DollarSign size={16} />
|
||||
</div>
|
||||
<Input
|
||||
type="number"
|
||||
value={state.capital}
|
||||
onChange={e => setState({ ...state, capital: Number(e.target.value) })}
|
||||
className="h-14 pl-10 font-bold"
|
||||
/>
|
||||
</div>
|
||||
<p className="text-[10px] text-[var(--muted-foreground)]">Total USD balance this bot is allowed to manage.</p>
|
||||
</div>
|
||||
|
||||
<div className="space-y-3">
|
||||
<label className="text-xs font-bold text-zinc-500 uppercase tracking-widest flex items-center justify-between">
|
||||
<label className="flex items-center justify-between text-xs font-bold uppercase tracking-widest text-[var(--muted-foreground)]">
|
||||
Daily Profit Target
|
||||
{!isFeatureAllowed(tier, 'profit_target', policy.maxDailyProfitTargetUsd + 1) && (
|
||||
<span className="text-[9px] text-amber-500 flex items-center gap-1"><Lock size={10} /> Limited to ${policy.maxDailyProfitTargetUsd}</span>
|
||||
)}
|
||||
</label>
|
||||
<div className="relative">
|
||||
<div className="absolute inset-y-0 left-4 flex items-center pointer-events-none text-zinc-500">
|
||||
<div className="pointer-events-none absolute inset-y-0 left-4 flex items-center text-[var(--muted-foreground)]">
|
||||
<Target size={16} />
|
||||
</div>
|
||||
<input
|
||||
<Input
|
||||
type="number"
|
||||
disabled={tier === 'free'}
|
||||
value={state.profitTarget}
|
||||
@ -293,24 +303,24 @@ export const StrategyWizard: React.FC<{
|
||||
setState({ ...state, profitTarget: val });
|
||||
}
|
||||
}}
|
||||
className={`w-full bg-zinc-900 border-2 border-white/5 rounded-xl py-4 pl-10 pr-4 text-white font-bold outline-none focus:border-[#00ff88]/50 transition-all ${tier === 'free' ? 'opacity-50 cursor-not-allowed' : ''}`}
|
||||
/>
|
||||
className={`h-14 pl-10 font-bold ${tier === 'free' ? 'cursor-not-allowed opacity-50' : ''}`}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex gap-2 items-start mt-1">
|
||||
<Info size={12} className="text-[#00ff88] mt-0.5 shrink-0" />
|
||||
<p className="text-[10px] text-zinc-500 italic">Once this profit is reached, the bot automatically pauses for the day to lock in gains.</p>
|
||||
<Info size={12} className="mt-0.5 shrink-0 text-[var(--accent)]" />
|
||||
<p className="text-[10px] italic text-[var(--muted-foreground)]">Once this profit is reached, the bot automatically pauses for the day to lock in gains.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex justify-between pt-4">
|
||||
<button onClick={back} className="flex items-center gap-2 text-zinc-500 hover:text-white font-bold px-6 transition-all">
|
||||
<ChevronLeft size={18} /> Back
|
||||
</button>
|
||||
<button onClick={next} className="flex items-center gap-2 bg-[#00ff88] text-black px-8 py-3 rounded-xl font-bold hover:brightness-110 transition-all">
|
||||
Continue <ChevronRight size={18} />
|
||||
</button>
|
||||
<Button onClick={back} variant="ghost" className="px-6">
|
||||
<ChevronLeft size={18} /> Back
|
||||
</Button>
|
||||
<Button onClick={next} className="px-8">
|
||||
Continue <ChevronRight size={18} />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
@ -319,8 +329,8 @@ export const StrategyWizard: React.FC<{
|
||||
{state.step === 3 && (
|
||||
<div className="space-y-8 animate-in fade-in slide-in-from-right-4 duration-500">
|
||||
<div className="text-center">
|
||||
<h2 className="text-2xl font-bold text-white mb-2">Trading Hours</h2>
|
||||
<p className="text-zinc-400 text-sm">When should the bot look for signals?</p>
|
||||
<h2 className={sectionTitleClass}>Trading Hours</h2>
|
||||
<p className={sectionDescriptionClass}>When should the bot look for signals?</p>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 gap-4">
|
||||
@ -328,18 +338,18 @@ export const StrategyWizard: React.FC<{
|
||||
<button
|
||||
key={option}
|
||||
onClick={() => setState({ ...state, hours: option })}
|
||||
className={`p-6 rounded-2xl border-2 text-left transition-all ${state.hours === option
|
||||
? 'border-[#00ff88] bg-[#00ff88]/5'
|
||||
: 'border-white/5 bg-zinc-900/50 hover:border-white/10'
|
||||
}`}
|
||||
className={`rounded-2xl border-2 p-6 text-left transition-all ${state.hours === option
|
||||
? optionSelectedClass
|
||||
: optionIdleClass
|
||||
}`}
|
||||
>
|
||||
<div className="flex items-center gap-4">
|
||||
<div className={`w-10 h-10 rounded-lg flex items-center justify-center ${state.hours === option ? 'bg-[#00ff88]/10 text-[#00ff88]' : 'bg-zinc-800 text-zinc-500'}`}>
|
||||
<div className={`flex h-10 w-10 items-center justify-center rounded-lg ${state.hours === option ? 'bg-[var(--accent-soft)] text-[var(--accent)]' : 'bg-[var(--muted)] text-[var(--muted-foreground)]'}`}>
|
||||
<Clock size={20} />
|
||||
</div>
|
||||
<div>
|
||||
<span className="block font-bold text-white text-lg">{option}</span>
|
||||
<span className="text-xs text-zinc-500">
|
||||
<span className="block text-lg font-bold text-[var(--foreground)]">{option}</span>
|
||||
<span className="text-xs text-[var(--muted-foreground)]">
|
||||
{option === '24/7' ? 'Universal coverage, trades any time signals appear.' :
|
||||
option === 'London + New York' ? 'Focuses on the most liquid market overlap (07:00 - 21:00 UTC).' :
|
||||
'Optimized for Tokoyo and Sydney sessions.'}
|
||||
@ -351,12 +361,12 @@ export const StrategyWizard: React.FC<{
|
||||
</div>
|
||||
|
||||
<div className="flex justify-between pt-4">
|
||||
<button onClick={back} className="flex items-center gap-2 text-zinc-500 hover:text-white font-bold px-6 transition-all">
|
||||
<ChevronLeft size={18} /> Back
|
||||
</button>
|
||||
<button onClick={next} className="flex items-center gap-2 bg-[#00ff88] text-black px-8 py-3 rounded-xl font-bold hover:brightness-110 transition-all">
|
||||
Continue <ChevronRight size={18} />
|
||||
</button>
|
||||
<Button onClick={back} variant="ghost" className="px-6">
|
||||
<ChevronLeft size={18} /> Back
|
||||
</Button>
|
||||
<Button onClick={next} className="px-8">
|
||||
Continue <ChevronRight size={18} />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
@ -365,26 +375,26 @@ export const StrategyWizard: React.FC<{
|
||||
{state.step === 4 && (
|
||||
<div className="space-y-8 animate-in fade-in slide-in-from-right-4 duration-500">
|
||||
<div className="text-center">
|
||||
<h2 className="text-2xl font-bold text-white mb-2">Safety Confirmation</h2>
|
||||
<p className="text-zinc-400 text-sm">Review the built-in safeguards protecting your capital.</p>
|
||||
<h2 className={sectionTitleClass}>Safety Confirmation</h2>
|
||||
<p className={sectionDescriptionClass}>Review the built-in safeguards protecting your capital.</p>
|
||||
</div>
|
||||
|
||||
<div className="bg-zinc-900/80 rounded-2xl border border-white/5 overflow-hidden">
|
||||
<Card className="overflow-hidden rounded-2xl">
|
||||
<div className="p-6 space-y-4">
|
||||
<div className="flex items-center justify-between py-3 border-b border-white/5">
|
||||
<span className="text-zinc-500 text-sm font-medium">Auto-Protective Stop Loss</span>
|
||||
<span className="text-[#00ff88] text-sm font-bold">Enabled (Mandatory)</span>
|
||||
</div>
|
||||
<div className="flex items-center justify-between py-3 border-b border-white/5">
|
||||
<span className="text-zinc-500 text-sm font-medium">Position Sizing Limit</span>
|
||||
<span className="text-white text-sm font-bold font-mono">Max {state.riskStyle?.riskPerTrade}% per trade</span>
|
||||
</div>
|
||||
<div className="flex items-center justify-between py-3 border-b border-white/5">
|
||||
<span className="text-zinc-500 text-sm font-medium">Daily Recovery Halt</span>
|
||||
<div className="flex items-center justify-between border-b border-[var(--border)] py-3">
|
||||
<span className="text-sm font-medium text-[var(--muted-foreground)]">Auto-Protective Stop Loss</span>
|
||||
<span className="text-sm font-bold text-[var(--accent)]">Enabled (Mandatory)</span>
|
||||
</div>
|
||||
<div className="flex items-center justify-between border-b border-[var(--border)] py-3">
|
||||
<span className="text-sm font-medium text-[var(--muted-foreground)]">Position Sizing Limit</span>
|
||||
<span className="font-mono text-sm font-bold text-[var(--foreground)]">Max {state.riskStyle?.riskPerTrade}% per trade</span>
|
||||
</div>
|
||||
<div className="flex items-center justify-between border-b border-[var(--border)] py-3">
|
||||
<span className="text-sm font-medium text-[var(--muted-foreground)]">Daily Recovery Halt</span>
|
||||
<span className="text-rose-400 text-sm font-bold font-mono">-${Math.floor(state.capital * 0.05)} (5%)</span>
|
||||
</div>
|
||||
<div className="flex items-center justify-between py-3">
|
||||
<span className="text-zinc-500 text-sm font-medium">Market Volatility Guard</span>
|
||||
<span className="text-sm font-medium text-[var(--muted-foreground)]">Market Volatility Guard</span>
|
||||
<span className="text-blue-400 text-sm font-bold">Smart ATR Check</span>
|
||||
</div>
|
||||
</div>
|
||||
@ -392,17 +402,17 @@ export const StrategyWizard: React.FC<{
|
||||
<AlertTriangle className="text-amber-500 shrink-0" size={20} />
|
||||
<p className="text-xs text-amber-500/90 leading-relaxed font-medium">
|
||||
Risk management and safety rules are coded into the engine core. These cannot be disabled or bypassed, ensuring your bot always operates within safety boundaries.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</p>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
<div className="flex justify-between pt-4">
|
||||
<button onClick={back} className="flex items-center gap-2 text-zinc-500 hover:text-white font-bold px-6 transition-all">
|
||||
<ChevronLeft size={18} /> Back
|
||||
</button>
|
||||
<button onClick={next} className="flex items-center gap-2 bg-[#00ff88] text-black px-8 py-3 rounded-xl font-bold hover:brightness-110 transition-all">
|
||||
I Understand <ChevronRight size={18} />
|
||||
</button>
|
||||
<Button onClick={back} variant="ghost" className="px-6">
|
||||
<ChevronLeft size={18} /> Back
|
||||
</Button>
|
||||
<Button onClick={next} className="px-8">
|
||||
I Understand <ChevronRight size={18} />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
@ -411,79 +421,78 @@ export const StrategyWizard: React.FC<{
|
||||
{state.step === 5 && (
|
||||
<div className="space-y-8 animate-in fade-in zoom-in-95 duration-500">
|
||||
<div className="text-center">
|
||||
<h2 className="text-3xl font-bold text-white mb-2">Ready to Deploy</h2>
|
||||
<p className="text-zinc-400 text-sm">Verify your bot strategy one last time.</p>
|
||||
</div>
|
||||
|
||||
<div className="bg-[#00ff88]/5 rounded-3xl border-2 border-[#00ff88]/20 p-8 space-y-6 relative overflow-hidden">
|
||||
{/* Decorative background element */}
|
||||
<div className="absolute -top-24 -right-24 w-64 h-64 bg-[#00ff88]/10 blur-[100px] rounded-full pointer-events-none" />
|
||||
|
||||
<div className="flex items-center gap-6">
|
||||
<div className="w-20 h-20 rounded-2xl bg-[#00ff88] text-black flex items-center justify-center">
|
||||
{state.riskStyle?.id === 'safe' ? <ShieldCheck size={40} /> : state.riskStyle?.id === 'balanced' ? <Scale size={40} /> : <Zap size={40} />}
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="text-2xl font-bold text-white">{state.riskStyle?.label} Bot</h3>
|
||||
<div className="flex gap-2 mt-1">
|
||||
{state.assets.map(a => (
|
||||
<span key={a} className="bg-white/10 px-2 py-0.5 rounded text-[10px] font-black text-white/80">{a.split('/')[0]}</span>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<h2 className="mb-2 text-3xl font-bold text-[var(--foreground)]">Ready to Deploy</h2>
|
||||
<p className={sectionDescriptionClass}>Verify your bot strategy one last time.</p>
|
||||
</div>
|
||||
|
||||
<Card className="relative space-y-6 overflow-hidden rounded-3xl border-[var(--border-strong)] p-8">
|
||||
<div className="flex items-center gap-6">
|
||||
<div className="flex h-20 w-20 items-center justify-center rounded-2xl bg-[var(--primary)] text-[var(--primary-foreground)]">
|
||||
{state.riskStyle?.id === 'safe' ? <ShieldCheck size={40} /> : state.riskStyle?.id === 'balanced' ? <Scale size={40} /> : <Zap size={40} />}
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="text-2xl font-bold text-[var(--foreground)]">{state.riskStyle?.label} Bot</h3>
|
||||
<div className="flex gap-2 mt-1">
|
||||
{state.assets.map(a => (
|
||||
<span key={a} className="rounded border border-[var(--border)] bg-[var(--muted)] px-2 py-0.5 text-[10px] font-black text-[var(--muted-foreground)]">{a.split('/')[0]}</span>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-2 gap-8 pt-4">
|
||||
<div className="space-y-1">
|
||||
<span className="text-zinc-500 text-[10px] uppercase font-black tracking-widest">Target Capital</span>
|
||||
<div className="text-xl font-bold text-white flex items-baseline gap-1">
|
||||
<span className="text-[10px] font-black uppercase tracking-widest text-[var(--muted-foreground)]">Target Capital</span>
|
||||
<div className="flex items-baseline gap-1 text-xl font-bold text-[var(--foreground)]">
|
||||
<span className="text-sm opacity-50 opacity-40">$</span>{state.capital}
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<span className="text-zinc-500 text-[10px] uppercase font-black tracking-widest">Profit Threshold</span>
|
||||
<div className="text-xl font-bold text-[#00ff88] flex items-baseline gap-1">
|
||||
<span className="text-[10px] font-black uppercase tracking-widest text-[var(--muted-foreground)]">Profit Threshold</span>
|
||||
<div className="flex items-baseline gap-1 text-xl font-bold text-[var(--accent)]">
|
||||
<span className="text-sm opacity-40">$</span>{state.profitTarget}<span className="text-[10px] opacity-60 ml-1">/day</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<span className="text-zinc-500 text-[10px] uppercase font-black tracking-widest">Risk Level</span>
|
||||
<div className="text-xl font-bold text-white">{(state.riskStyle?.riskPerTrade || 0)}% <span className="text-xs opacity-50 font-normal">per trade</span></div>
|
||||
<span className="text-[10px] font-black uppercase tracking-widest text-[var(--muted-foreground)]">Risk Level</span>
|
||||
<div className="text-xl font-bold text-[var(--foreground)]">{(state.riskStyle?.riskPerTrade || 0)}% <span className="text-xs font-normal opacity-50">per trade</span></div>
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<span className="text-zinc-500 text-[10px] uppercase font-black tracking-widest">Active Schedule</span>
|
||||
<div className="text-xl font-bold text-white">{state.hours}</div>
|
||||
<span className="text-[10px] font-black uppercase tracking-widest text-[var(--muted-foreground)]">Active Schedule</span>
|
||||
<div className="text-xl font-bold text-[var(--foreground)]">{state.hours}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="pt-6 border-t border-white/5 flex gap-4 items-center">
|
||||
<div className="w-12 h-12 rounded-full border border-zinc-800 flex items-center justify-center text-zinc-600">
|
||||
<div className="flex items-center gap-4 border-t border-[var(--border)] pt-6">
|
||||
<div className="flex h-12 w-12 items-center justify-center rounded-full border border-[var(--border)] text-[var(--muted-foreground)]">
|
||||
<Wallet size={20} />
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<p className="text-sm text-zinc-400">Bots are created in <span className="text-white font-bold">PAUSED</span> mode by default. You must manually enable trading from your dashboard.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p className="text-sm text-[var(--muted-foreground)]">Bots are created in <span className="font-bold text-[var(--foreground)]">PAUSED</span> mode by default. You must manually enable trading from your dashboard.</p>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
<div className="flex justify-between pt-4">
|
||||
<button onClick={back} className="flex items-center gap-2 text-zinc-500 hover:text-white font-bold px-6 transition-all">
|
||||
<Button onClick={back} variant="ghost" className="px-6">
|
||||
<ChevronLeft size={18} /> Back
|
||||
</button>
|
||||
</Button>
|
||||
<div className="flex items-center gap-3">
|
||||
{!backtestGateLoading && backtestEnabled && (
|
||||
<button
|
||||
<Button
|
||||
type="button"
|
||||
onClick={() => setShowBacktest((prev) => !prev)}
|
||||
className="flex items-center gap-2 bg-white/10 text-white px-5 py-3 rounded-xl font-black text-xs uppercase tracking-wider hover:bg-white/20 transition-all"
|
||||
variant="outline"
|
||||
className="px-5 text-xs uppercase tracking-wider"
|
||||
>
|
||||
{showBacktest ? 'Hide Backtest' : 'Run Backtest'}
|
||||
</button>
|
||||
</Button>
|
||||
)}
|
||||
<button
|
||||
<Button
|
||||
disabled={loading}
|
||||
onClick={handleSave}
|
||||
className="group relative flex items-center gap-3 bg-[#00ff88] text-black px-12 py-4 rounded-2xl font-black text-lg hover:brightness-110 hover:scale-[1.02] active:scale-[0.98] transition-all shadow-2xl shadow-[#00ff88]/20 disabled:opacity-50"
|
||||
size="lg"
|
||||
className="group rounded-2xl px-12 text-lg font-black"
|
||||
>
|
||||
{loading ? 'Processing...' : (
|
||||
<>
|
||||
@ -491,7 +500,7 @@ export const StrategyWizard: React.FC<{
|
||||
<ChevronRight size={20} className="group-hover:translate-x-1 transition-transform" />
|
||||
</>
|
||||
)}
|
||||
</button>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user