import { useApp } from '../context/AppContext.js'; import { startMfaSetup, confirmMfaSetup, disableMfa, changePassword, updateProfile, } from '../syncService.js'; export default function SettingsPage() { const { authUser, setAuthUser, authStatus, goHome, mfaSetup, setMfaSetup, mfaSetupCode, setMfaSetupCode, mfaSetupError, setMfaSetupError, mfaSetupBusy, setMfaSetupBusy, mfaBackupCodes, setMfaBackupCodes, mfaDisablePassword, setMfaDisablePassword, mfaDisableError, setMfaDisableError, podcastNameInput, setPodcastNameInput, podcastNameSaving, setPodcastNameSaving, podcastNameSaved, setPodcastNameSaved, changePasswordForm, setChangePasswordForm, changePasswordBusy, setChangePasswordBusy, changePasswordError, setChangePasswordError, changePasswordSaved, setChangePasswordSaved, } = useApp(); const startSetup = async () => { setMfaSetupError(''); setMfaSetupBusy(true); const result = await startMfaSetup(); setMfaSetupBusy(false); if (!result.ok) { setMfaSetupError(result.error ?? 'Could not start 2FA setup.'); return; } setMfaSetup(result.data); setMfaSetupCode(''); }; const confirmSetup = async (e) => { e.preventDefault(); setMfaSetupError(''); setMfaSetupBusy(true); const result = await confirmMfaSetup(mfaSetupCode.trim()); setMfaSetupBusy(false); if (!result.ok) { setMfaSetupError(result.error ?? 'Invalid code.'); return; } setMfaSetup(null); setMfaSetupCode(''); setMfaBackupCodes(result.data.backupCodes); setAuthUser((u) => ({ ...u, totpEnabled: true })); }; const cancelSetup = () => { setMfaSetup(null); setMfaSetupCode(''); setMfaSetupError(''); }; const submitDisable = async (e) => { e.preventDefault(); setMfaDisableError(''); const result = await disableMfa(mfaDisablePassword); if (!result.ok) { setMfaDisableError(result.error ?? 'Incorrect password.'); return; } setMfaDisablePassword(''); setAuthUser((u) => ({ ...u, totpEnabled: false })); }; const submitChangePassword = async (e) => { e.preventDefault(); setChangePasswordError(''); if (changePasswordForm.next !== changePasswordForm.confirm) { setChangePasswordError("New passwords don't match."); return; } setChangePasswordBusy(true); const result = await changePassword(changePasswordForm.current, changePasswordForm.next); setChangePasswordBusy(false); if (!result.ok) { setChangePasswordError(result.error ?? 'Failed to change password.'); return; } setChangePasswordForm({ current: '', next: '', confirm: '' }); setChangePasswordSaved(true); window.setTimeout(() => setChangePasswordSaved(false), 3000); }; const submitPodcastName = async (e) => { e.preventDefault(); setPodcastNameSaving(true); setPodcastNameSaved(false); const result = await updateProfile({ podcastName: podcastNameInput.trim() }); setPodcastNameSaving(false); if (!result.ok) return; setAuthUser((u) => ({ ...u, podcastName: result.data.podcastName })); setPodcastNameSaved(true); window.setTimeout(() => setPodcastNameSaved(false), 2500); }; return (

Bible Study Project

Account Settings

{authStatus}

Account

Signed in as {authUser.email}

Change password

Changing your password signs you out of every other device — this one stays signed in.

{changePasswordError &&

{changePasswordError}

} {changePasswordSaved &&

Password changed.

}

Podcast / show name

Only needed if you use "🎙 Prepare for Podcast" on the study page — it fills in your show's name when asking Claude to write an episode script. Leave blank if you're just doing personal study; that button still works, it just won't name a specific show.

setPodcastNameInput(e.target.value)} placeholder="e.g. Verse by Verse with Nate: A Journey Through Scripture" className="w-full flex-1 rounded-xl border border-slate-300 px-3 py-2 text-sm shadow-sm focus:border-sky-500 focus:outline-none focus:ring-2 focus:ring-sky-200" />
{podcastNameSaved &&

Saved.

}

Two-factor authentication

{authUser.totpEnabled ? "Enabled — you'll need a code from your authenticator app to sign in." : 'Add a 6-digit code from an authenticator app (Google Authenticator, Authy, 1Password, etc.) as a second step at sign-in.'}

{mfaBackupCodes ? (

Save these backup codes now — each works once if you ever lose your device. They won't be shown again.

{mfaBackupCodes.map((code) => (
{code}
))}
) : authUser.totpEnabled ? (
{mfaDisableError &&

{mfaDisableError}

}
) : mfaSetup ? (
2FA QR code

Scan this with your authenticator app, or enter the code manually:

{mfaSetup.secret}

{mfaSetupError &&

{mfaSetupError}

}
) : (
{mfaSetupError &&

{mfaSetupError}

}
)}
); }