mirror of
https://github.com/openswarm-ai/openswarm.git
synced 2026-08-26 22:42:23 +02:00
[eric] onboarding: Get started shows busy state + finish double-fire guard
This commit is contained in:
@@ -52,6 +52,8 @@ const BeatCard: React.FC<{
|
||||
}> = ({ c, identity, onFinish, onBack }) => {
|
||||
const { accent, gradient } = useThemeAccent();
|
||||
const [name, setName] = useState(() => nameFromIdentity(identity));
|
||||
// finish() can legitimately wait up to PREP_WAIT_CAP_MS on prep; the button must say so, once.
|
||||
const [submitting, setSubmitting] = useState(false);
|
||||
const seed = useMemo(() => Math.floor(Math.random() * EPITHETS.length), []);
|
||||
const [roll, setRoll] = useState(0);
|
||||
const epithet = EPITHETS[(seed + roll) % EPITHETS.length];
|
||||
@@ -184,8 +186,9 @@ const BeatCard: React.FC<{
|
||||
c={c}
|
||||
title={name ? `Welcome to OpenSwarm, ${name}` : 'Welcome to OpenSwarm'}
|
||||
body={"Here's your Swarm Card. Show it off to the world or keep it to yourself.\n\nAnd with that, you're ready to run your new OS."}
|
||||
nextLabel="Get started"
|
||||
onNext={() => onFinish(name.trim() || null)}
|
||||
nextLabel={submitting ? 'Setting up...' : 'Get started'}
|
||||
nextDisabled={submitting}
|
||||
onNext={() => { if (submitting) return; setSubmitting(true); onFinish(name.trim() || null); }}
|
||||
onBack={onBack}
|
||||
stageDark
|
||||
>
|
||||
|
||||
@@ -29,6 +29,7 @@ export function useOnboardingV3Pipeline() {
|
||||
// greeting/starters the instant they're ready (the common case, prep finishes during the beats) without
|
||||
// awaiting, so the curtain never blocks behind a spinner.
|
||||
const prepReadyRef = useRef<PrepResponse | null>(null);
|
||||
const finishingRef = useRef(false);
|
||||
const scanResultRef = useRef<ScanResult | null>(null);
|
||||
const usageSummaryRef = useRef<string>('');
|
||||
const usageReadRef = useRef<Promise<void> | null>(null);
|
||||
@@ -72,6 +73,9 @@ export function useOnboardingV3Pipeline() {
|
||||
}, []);
|
||||
|
||||
const finish = useCallback(async (outcome: 'done' | 'skipped') => {
|
||||
// Double-fire guard: repeated Get-started clicks during the prep wait must not stage twice.
|
||||
if (finishingRef.current) return;
|
||||
finishingRef.current = true;
|
||||
if (outcome === 'skipped') {
|
||||
dispatch(setFlowActive(false));
|
||||
dispatch(updateSettingsPatch({ onboarding_v3: 'skipped', accent_color: accent, accent_gradient: gradient, theme: mode }));
|
||||
|
||||
Reference in New Issue
Block a user