feat(auth): improve otp delivery and verification flow
This commit is contained in:
@@ -11,6 +11,8 @@ export type CooldownKey =
|
||||
interface FlowBranchState {
|
||||
mobile: string
|
||||
code: string
|
||||
otpExpiresAt: number | null
|
||||
pendingOtpSend: boolean
|
||||
}
|
||||
|
||||
interface CooldownState {
|
||||
@@ -32,25 +34,34 @@ interface AuthFlowContextValue {
|
||||
state: AuthFlowState
|
||||
setMobile: (flow: FlowName, mobile: string) => void
|
||||
setCode: (flow: FlowName, code: string) => void
|
||||
markOtpSendPending: (flow: FlowName) => void
|
||||
setOtpDelivery: (flow: FlowName, expiresInSeconds: number) => void
|
||||
clearOtpDelivery: (flow: FlowName) => void
|
||||
setCooldown: (key: CooldownKey, seconds: number) => void
|
||||
clearCooldown: (key: CooldownKey) => void
|
||||
resetFlow: (flow: FlowName) => void
|
||||
}
|
||||
|
||||
const STORAGE_KEY = "auth_flow_state:v1"
|
||||
const STORAGE_KEY = "auth_flow_state:v2"
|
||||
|
||||
const defaultState: AuthFlowState = {
|
||||
login: {
|
||||
mobile: "",
|
||||
code: "",
|
||||
otpExpiresAt: null,
|
||||
pendingOtpSend: false,
|
||||
},
|
||||
signup: {
|
||||
mobile: "",
|
||||
code: "",
|
||||
otpExpiresAt: null,
|
||||
pendingOtpSend: false,
|
||||
},
|
||||
forgotPassword: {
|
||||
mobile: "",
|
||||
code: "",
|
||||
otpExpiresAt: null,
|
||||
pendingOtpSend: false,
|
||||
},
|
||||
cooldowns: {
|
||||
loginOtpSend: 0,
|
||||
@@ -80,14 +91,20 @@ const parseStoredState = (): AuthFlowState => {
|
||||
login: {
|
||||
mobile: parsed.login?.mobile ?? "",
|
||||
code: parsed.login?.code ?? "",
|
||||
otpExpiresAt: parsed.login?.otpExpiresAt ?? null,
|
||||
pendingOtpSend: parsed.login?.pendingOtpSend ?? false,
|
||||
},
|
||||
signup: {
|
||||
mobile: parsed.signup?.mobile ?? "",
|
||||
code: parsed.signup?.code ?? "",
|
||||
otpExpiresAt: parsed.signup?.otpExpiresAt ?? null,
|
||||
pendingOtpSend: parsed.signup?.pendingOtpSend ?? false,
|
||||
},
|
||||
forgotPassword: {
|
||||
mobile: parsed.forgotPassword?.mobile ?? "",
|
||||
code: parsed.forgotPassword?.code ?? "",
|
||||
otpExpiresAt: parsed.forgotPassword?.otpExpiresAt ?? null,
|
||||
pendingOtpSend: parsed.forgotPassword?.pendingOtpSend ?? false,
|
||||
},
|
||||
cooldowns: {
|
||||
loginOtpSend: parsed.cooldowns?.loginOtpSend ?? 0,
|
||||
@@ -151,6 +168,36 @@ export function AuthFlowProvider({ children }: { children: ReactNode }) {
|
||||
},
|
||||
}))
|
||||
},
|
||||
markOtpSendPending: (flow) => {
|
||||
setState((current) => ({
|
||||
...current,
|
||||
[flow]: {
|
||||
...current[flow],
|
||||
code: "",
|
||||
pendingOtpSend: true,
|
||||
},
|
||||
}))
|
||||
},
|
||||
setOtpDelivery: (flow, expiresInSeconds) => {
|
||||
setState((current) => ({
|
||||
...current,
|
||||
[flow]: {
|
||||
...current[flow],
|
||||
pendingOtpSend: false,
|
||||
otpExpiresAt: Date.now() + Math.max(0, expiresInSeconds) * 1000,
|
||||
},
|
||||
}))
|
||||
},
|
||||
clearOtpDelivery: (flow) => {
|
||||
setState((current) => ({
|
||||
...current,
|
||||
[flow]: {
|
||||
...current[flow],
|
||||
pendingOtpSend: false,
|
||||
otpExpiresAt: null,
|
||||
},
|
||||
}))
|
||||
},
|
||||
setCooldown: (key, seconds) => {
|
||||
setState((current) => ({
|
||||
...current,
|
||||
@@ -175,6 +222,8 @@ export function AuthFlowProvider({ children }: { children: ReactNode }) {
|
||||
[flow]: {
|
||||
mobile: "",
|
||||
code: "",
|
||||
otpExpiresAt: null,
|
||||
pendingOtpSend: false,
|
||||
},
|
||||
}))
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user