← back to Bertha
kalshi-dash/src/setup/SetupWizard.jsx
120 lines
import React, { useState, useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
import { checkSession, post, api } from '../api';
import Welcome from './steps/Welcome';
import ConnectKalshi from './steps/ConnectKalshi';
import TestConnection from './steps/TestConnection';
import BrowseMarkets from './steps/BrowseMarkets';
import FetchWeather from './steps/FetchWeather';
import RunPredictions from './steps/RunPredictions';
import RiskProfile from './steps/RiskProfile';
import GoLive from './steps/GoLive';
const STEPS = [
{ label: 'Shalom', icon: '1' },
{ label: 'Keys', icon: '2' },
{ label: 'Test It', icon: '3' },
{ label: 'Snoop', icon: '4' },
{ label: 'Weather', icon: '5' },
{ label: 'Predict', icon: '6' },
{ label: 'Limits', icon: '7' },
{ label: 'Mazel Tov', icon: '8' },
];
const COMPS = [Welcome, ConnectKalshi, TestConnection, BrowseMarkets, FetchWeather, RunPredictions, RiskProfile, GoLive];
export default function SetupWizard() {
const nav = useNavigate();
const [authed, setAuthed] = useState(false);
const [step, setStep] = useState(0);
const [data, setData] = useState({
keys: null,
connectionOk: false,
marketsLoaded: 0,
weatherFetched: false,
predictionsRun: false,
riskProfile: null,
});
useEffect(() => {
checkSession().then(ok => {
if (!ok) { nav('/login'); return; }
setAuthed(true);
api('/setup').then(r => {
if (r.setup_complete) { nav('/'); return; }
if (r.setup_progress) {
setStep(r.setup_progress.step || 0);
setData(d => ({ ...d, ...r.setup_progress.data }));
}
}).catch(() => {});
});
}, []);
useEffect(() => {
if (authed && step > 0) {
post('/setup', { action: 'save_progress', progress: { step, data } }).catch(() => {});
}
}, [step]);
function next() { if (step < STEPS.length - 1) setStep(s => s + 1); }
function back() { if (step > 0) setStep(s => s - 1); }
function goTo(i) { if (i <= step) setStep(i); }
function update(partial) { setData(d => ({ ...d, ...partial })); }
async function complete() {
await post('/setup', { action: 'complete', progress: { step: STEPS.length - 1, data } });
nav('/');
}
if (!authed) return <div className="flex items-center justify-center min-h-screen"><div className="animate-spin w-8 h-8 border-2 border-amber-500 border-t-transparent rounded-full" /></div>;
const StepComponent = COMPS[step];
return (
<div className="min-h-screen flex flex-col" style={{ background: 'var(--bg)' }}>
{/* Header */}
<div className="flex items-center gap-3 px-6 py-4 border-b border-gray-800">
<div className="w-8 h-8 rounded-lg flex items-center justify-center flex-shrink-0" style={{ background: 'linear-gradient(135deg,#f59e0b,#f97316)' }}>
<span className="text-black font-bold text-sm">K</span>
</div>
<span className="font-bold text-sm kalshi-gradient">KEN SETUP — SIT, WE'LL TALK</span>
</div>
{/* Stepper */}
<div className="px-6 py-5">
<div className="max-w-3xl mx-auto flex items-center">
{STEPS.map((s, i) => (
<React.Fragment key={i}>
<button onClick={() => goTo(i)} disabled={i > step} className="flex flex-col items-center gap-1.5 group" style={{ minWidth: 56 }}>
<div className={`w-8 h-8 rounded-full flex items-center justify-center text-xs font-bold transition-all ${
i < step ? 'bg-green-500 text-white' :
i === step ? 'bg-amber-500 text-black' :
'bg-gray-800 text-gray-500'
} ${i <= step ? 'cursor-pointer' : 'cursor-default'}`}
style={i === step ? { animation: 'pg 2s infinite' } : {}}
>
{i < step ? (
<svg className="w-4 h-4" fill="none" stroke="currentColor" strokeWidth="2.5" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" d="M5 13l4 4L19 7" /></svg>
) : s.icon}
</div>
<span className={`text-[10px] font-medium ${
i < step ? 'text-green-400' : i === step ? 'text-amber-400' : 'text-gray-600'
}`}>{s.label}</span>
</button>
{i < STEPS.length - 1 && (
<div className={`h-0.5 flex-1 transition-colors ${i < step ? 'bg-green-500' : 'bg-gray-800'}`} />
)}
</React.Fragment>
))}
</div>
</div>
{/* Content */}
<div className="flex-1 flex items-start justify-center px-6 pb-10">
<div className="w-full max-w-2xl" key={step}>
<StepComponent data={data} update={update} next={next} back={back} complete={complete} step={step} />
</div>
</div>
</div>
);
}