import { createContext, useContext, useEffect, useMemo, useState, type ReactNode } from "react" type FlowName = "login" | "signup" | "forgotPassword" export type CooldownKey = | "loginOtpSend" | "signupOtpSend" | "forgotPasswordOtpSend" | "loginPassword" | "loginOtpVerify" interface FlowBranchState { mobile: string code: string } interface CooldownState { loginOtpSend: number signupOtpSend: number forgotPasswordOtpSend: number loginPassword: number loginOtpVerify: number } interface AuthFlowState { login: FlowBranchState signup: FlowBranchState forgotPassword: FlowBranchState cooldowns: CooldownState } interface AuthFlowContextValue { state: AuthFlowState setMobile: (flow: FlowName, mobile: string) => void setCode: (flow: FlowName, code: string) => void setCooldown: (key: CooldownKey, seconds: number) => void clearCooldown: (key: CooldownKey) => void resetFlow: (flow: FlowName) => void } const STORAGE_KEY = "auth_flow_state:v1" const defaultState: AuthFlowState = { login: { mobile: "", code: "", }, signup: { mobile: "", code: "", }, forgotPassword: { mobile: "", code: "", }, cooldowns: { loginOtpSend: 0, signupOtpSend: 0, forgotPasswordOtpSend: 0, loginPassword: 0, loginOtpVerify: 0, }, } const AuthFlowContext = createContext(null) const parseStoredState = (): AuthFlowState => { if (typeof window === "undefined") { return defaultState } const raw = window.sessionStorage.getItem(STORAGE_KEY) if (!raw) { return defaultState } try { const parsed = JSON.parse(raw) as Partial return { login: { mobile: parsed.login?.mobile ?? "", code: parsed.login?.code ?? "", }, signup: { mobile: parsed.signup?.mobile ?? "", code: parsed.signup?.code ?? "", }, forgotPassword: { mobile: parsed.forgotPassword?.mobile ?? "", code: parsed.forgotPassword?.code ?? "", }, cooldowns: { loginOtpSend: parsed.cooldowns?.loginOtpSend ?? 0, signupOtpSend: parsed.cooldowns?.signupOtpSend ?? 0, forgotPasswordOtpSend: parsed.cooldowns?.forgotPasswordOtpSend ?? 0, loginPassword: parsed.cooldowns?.loginPassword ?? 0, loginOtpVerify: parsed.cooldowns?.loginOtpVerify ?? 0, }, } } catch { return defaultState } } export function AuthFlowProvider({ children }: { children: ReactNode }) { const [state, setState] = useState(parseStoredState) useEffect(() => { window.sessionStorage.setItem(STORAGE_KEY, JSON.stringify(state)) }, [state]) useEffect(() => { if (!Object.values(state.cooldowns).some((value) => value > 0)) { return } const timer = window.setInterval(() => { setState((current) => ({ ...current, cooldowns: { loginOtpSend: Math.max(0, current.cooldowns.loginOtpSend - 1), signupOtpSend: Math.max(0, current.cooldowns.signupOtpSend - 1), forgotPasswordOtpSend: Math.max(0, current.cooldowns.forgotPasswordOtpSend - 1), loginPassword: Math.max(0, current.cooldowns.loginPassword - 1), loginOtpVerify: Math.max(0, current.cooldowns.loginOtpVerify - 1), }, })) }, 1000) return () => window.clearInterval(timer) }, [state.cooldowns]) const value = useMemo( () => ({ state, setMobile: (flow, mobile) => { setState((current) => ({ ...current, [flow]: { ...current[flow], mobile, }, })) }, setCode: (flow, code) => { setState((current) => ({ ...current, [flow]: { ...current[flow], code, }, })) }, setCooldown: (key, seconds) => { setState((current) => ({ ...current, cooldowns: { ...current.cooldowns, [key]: Math.max(current.cooldowns[key], seconds), }, })) }, clearCooldown: (key) => { setState((current) => ({ ...current, cooldowns: { ...current.cooldowns, [key]: 0, }, })) }, resetFlow: (flow) => { setState((current) => ({ ...current, [flow]: { mobile: "", code: "", }, })) }, }), [state], ) return {children} } export function useAuthFlow() { const context = useContext(AuthFlowContext) if (!context) { throw new Error("useAuthFlow must be used within an AuthFlowProvider") } return context }