import { useHttp } from '@inertiajs/react'; import { useCallback, useState } from 'react'; import { qrCode, recoveryCodes, secretKey } from '@/routes/two-factor'; export type UseTwoFactorAuthReturn = { qrCodeSvg: string | null; manualSetupKey: string | null; recoveryCodesList: string[]; hasSetupData: boolean; errors: string[]; clearErrors: () => void; clearSetupData: () => void; clearTwoFactorAuthData: () => void; fetchQrCode: () => Promise; fetchSetupKey: () => Promise; fetchSetupData: () => Promise; fetchRecoveryCodes: () => Promise; }; export const OTP_MAX_LENGTH = 6; export const useTwoFactorAuth = (): UseTwoFactorAuthReturn => { const { submit } = useHttp(); const [qrCodeSvg, setQrCodeSvg] = useState(null); const [manualSetupKey, setManualSetupKey] = useState(null); const [recoveryCodesList, setRecoveryCodesList] = useState([]); const [errors, setErrors] = useState([]); const hasSetupData = qrCodeSvg !== null && manualSetupKey !== null; const clearErrors = useCallback((): void => { setErrors([]); }, []); const clearSetupData = useCallback((): void => { setManualSetupKey(null); setQrCodeSvg(null); setErrors([]); }, []); const clearTwoFactorAuthData = useCallback((): void => { setManualSetupKey(null); setQrCodeSvg(null); setErrors([]); setRecoveryCodesList([]); }, []); const fetchQrCode = useCallback(async (): Promise => { try { const { svg } = (await submit(qrCode())) as { svg: string; url: string; }; setQrCodeSvg(svg); } catch { setErrors((prev) => [...prev, 'Failed to fetch QR code']); setQrCodeSvg(null); } }, [submit]); const fetchSetupKey = useCallback(async (): Promise => { try { const { secretKey: key } = (await submit(secretKey())) as { secretKey: string; }; setManualSetupKey(key); } catch { setErrors((prev) => [...prev, 'Failed to fetch a setup key']); setManualSetupKey(null); } }, [submit]); const fetchRecoveryCodes = useCallback(async (): Promise => { try { setErrors([]); const codes = (await submit(recoveryCodes())) as string[]; setRecoveryCodesList(codes); } catch { setErrors((prev) => [...prev, 'Failed to fetch recovery codes']); setRecoveryCodesList([]); } }, [submit]); const fetchSetupData = useCallback(async (): Promise => { try { setErrors([]); await Promise.all([fetchQrCode(), fetchSetupKey()]); } catch { setQrCodeSvg(null); setManualSetupKey(null); } }, [fetchQrCode, fetchSetupKey]); return { qrCodeSvg, manualSetupKey, recoveryCodesList, hasSetupData, errors, clearErrors, clearSetupData, clearTwoFactorAuthData, fetchQrCode, fetchSetupKey, fetchSetupData, fetchRecoveryCodes, }; };