91 lines
2.3 KiB
TypeScript
91 lines
2.3 KiB
TypeScript
|
|
import { useCallback, useMemo, useState } from 'react';
|
||
|
|
import {
|
||
|
|
advanceCapture,
|
||
|
|
buildSovereigntyReport,
|
||
|
|
computeOffRamp,
|
||
|
|
createInitialState,
|
||
|
|
persistToVault,
|
||
|
|
selectOutlaws,
|
||
|
|
setPhase,
|
||
|
|
transitionAfterShowdown,
|
||
|
|
type LoginMethod,
|
||
|
|
type PlayerJourneyState,
|
||
|
|
} from '@bigtech-sucks/core';
|
||
|
|
|
||
|
|
export function useGameState() {
|
||
|
|
const [state, setState] = useState<PlayerJourneyState>(() => createInitialState());
|
||
|
|
|
||
|
|
const report = useMemo(
|
||
|
|
() => buildSovereigntyReport(state.selectedOutlaws, state.loginMethod),
|
||
|
|
[state.selectedOutlaws, state.loginMethod],
|
||
|
|
);
|
||
|
|
|
||
|
|
const offRamp = useMemo(
|
||
|
|
() => (state.selectedOutlaws.length ? computeOffRamp(state.selectedOutlaws) : null),
|
||
|
|
[state.selectedOutlaws],
|
||
|
|
);
|
||
|
|
|
||
|
|
const vaultExport = useMemo(() => persistToVault(state), [state]);
|
||
|
|
|
||
|
|
const login = useCallback((method: LoginMethod) => {
|
||
|
|
setState((s) => ({ ...s, loginMethod: method }));
|
||
|
|
}, []);
|
||
|
|
|
||
|
|
const goToPhase = useCallback((phase: PlayerJourneyState['phase']) => {
|
||
|
|
setState((s) => setPhase(s, phase));
|
||
|
|
}, []);
|
||
|
|
|
||
|
|
const drawLine = useCallback((ids: string[]) => {
|
||
|
|
setState((s) => selectOutlaws(s, ids));
|
||
|
|
}, []);
|
||
|
|
|
||
|
|
const startShowdown = useCallback((outlawId: string) => {
|
||
|
|
setState((s) => setPhase({ ...s, activeOutlawId: outlawId }, 'showdown'));
|
||
|
|
}, []);
|
||
|
|
|
||
|
|
const showdownStep = useCallback(
|
||
|
|
(step: 'round_up' | 'validate' | 'cut') => {
|
||
|
|
setState((s) => {
|
||
|
|
if (!s.activeOutlawId) return s;
|
||
|
|
const advanced = advanceCapture(s, s.activeOutlawId, step);
|
||
|
|
if (step === 'cut') {
|
||
|
|
return transitionAfterShowdown(advanced);
|
||
|
|
}
|
||
|
|
return advanced;
|
||
|
|
});
|
||
|
|
},
|
||
|
|
[],
|
||
|
|
);
|
||
|
|
|
||
|
|
const submitWaitlist = useCallback(async (email: string, channel: string) => {
|
||
|
|
const payload = {
|
||
|
|
email,
|
||
|
|
channel,
|
||
|
|
settlerSince: state.settlerSince,
|
||
|
|
};
|
||
|
|
|
||
|
|
const res = await fetch('/api/waitlist', {
|
||
|
|
method: 'POST',
|
||
|
|
headers: { 'Content-Type': 'application/json' },
|
||
|
|
body: JSON.stringify(payload),
|
||
|
|
});
|
||
|
|
|
||
|
|
if (!res.ok) throw new Error('Waitlist submission failed');
|
||
|
|
|
||
|
|
setState((s) => ({ ...s, waitlistEmail: email, waitlistChannel: channel }));
|
||
|
|
return payload;
|
||
|
|
}, [state.settlerSince]);
|
||
|
|
|
||
|
|
return {
|
||
|
|
state,
|
||
|
|
report,
|
||
|
|
offRamp,
|
||
|
|
vaultExport,
|
||
|
|
login,
|
||
|
|
goToPhase,
|
||
|
|
drawLine,
|
||
|
|
startShowdown,
|
||
|
|
showdownStep,
|
||
|
|
submitWaitlist,
|
||
|
|
};
|
||
|
|
}
|