Boring changes
This commit is contained in:
parent
cfaf58dfba
commit
920119ff48
32 changed files with 912 additions and 88 deletions
|
|
@ -2,6 +2,7 @@ import { useState, useEffect, useCallback } from 'react';
|
|||
import { useTranslation } from 'react-i18next';
|
||||
import pb from '../lib/pocketbase';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import { resolveAuthError, type AuthErrorAction } from '../lib/auth-errors';
|
||||
|
||||
export interface AuthUser {
|
||||
id: string;
|
||||
|
|
@ -41,6 +42,7 @@ export function useAuth() {
|
|||
});
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [errorAction, setErrorAction] = useState<AuthErrorAction>(null);
|
||||
|
||||
// Sync with authStore changes (cross-tab, external updates)
|
||||
useEffect(() => {
|
||||
|
|
@ -58,13 +60,15 @@ export function useAuth() {
|
|||
async (email: string, password: string) => {
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
setErrorAction(null);
|
||||
try {
|
||||
const result = await pb.collection('users').authWithPassword(email, password);
|
||||
setUser(recordToUser(result.record));
|
||||
trackEvent('Login', { method: 'email' });
|
||||
} catch (err) {
|
||||
const msg = err instanceof Error ? err.message : t('auth.loginFailed');
|
||||
setError(msg);
|
||||
const { message, action } = resolveAuthError(err, 'login', t);
|
||||
setError(message);
|
||||
setErrorAction(action);
|
||||
throw err;
|
||||
} finally {
|
||||
setLoading(false);
|
||||
|
|
@ -77,21 +81,41 @@ export function useAuth() {
|
|||
async (email: string, password: string) => {
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
setErrorAction(null);
|
||||
try {
|
||||
await pb.collection('users').create({
|
||||
email,
|
||||
password,
|
||||
passwordConfirm: password,
|
||||
newsletter: true,
|
||||
});
|
||||
// Auto-login after registration
|
||||
const result = await pb.collection('users').authWithPassword(email, password);
|
||||
setUser(recordToUser(result.record));
|
||||
trackEvent('Register');
|
||||
} catch (err) {
|
||||
const msg = err instanceof Error ? err.message : t('auth.registrationFailed');
|
||||
setError(msg);
|
||||
throw err;
|
||||
// Step 1: create the account. A failure here means nothing was created,
|
||||
// so surface a friendly, field-aware message (e.g. "email already exists").
|
||||
try {
|
||||
await pb.collection('users').create({
|
||||
email,
|
||||
password,
|
||||
passwordConfirm: password,
|
||||
newsletter: true,
|
||||
});
|
||||
} catch (err) {
|
||||
const { message, action } = resolveAuthError(err, 'register', t);
|
||||
setError(message);
|
||||
setErrorAction(action);
|
||||
throw err;
|
||||
}
|
||||
// Step 2: the account now EXISTS. If auto-login fails (commonly a 429
|
||||
// rate limit from the two back-to-back writes) the account is NOT
|
||||
// orphaned: tell the user it was created and let them log in with the
|
||||
// same credentials, instead of a misleading "registration failed".
|
||||
try {
|
||||
const result = await pb.collection('users').authWithPassword(email, password);
|
||||
setUser(recordToUser(result.record));
|
||||
trackEvent('Register');
|
||||
} catch (err) {
|
||||
const status = (err as { status?: number } | null)?.status;
|
||||
setError(
|
||||
status === 429
|
||||
? t('auth.accountCreatedRateLimited')
|
||||
: t('auth.accountCreatedPleaseLogIn')
|
||||
);
|
||||
setErrorAction('switchToLogin');
|
||||
throw err;
|
||||
}
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
|
|
@ -103,6 +127,7 @@ export function useAuth() {
|
|||
async (provider: string) => {
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
setErrorAction(null);
|
||||
try {
|
||||
const result = await pb.collection('users').authWithOAuth2({
|
||||
provider,
|
||||
|
|
@ -111,8 +136,9 @@ export function useAuth() {
|
|||
setUser(recordToUser(result.record));
|
||||
trackEvent('Login', { method: provider });
|
||||
} catch (err) {
|
||||
const msg = err instanceof Error ? err.message : t('auth.oauthFailed');
|
||||
setError(msg);
|
||||
const { message, action } = resolveAuthError(err, 'oauth', t);
|
||||
setError(message);
|
||||
setErrorAction(action);
|
||||
throw err;
|
||||
} finally {
|
||||
setLoading(false);
|
||||
|
|
@ -131,11 +157,13 @@ export function useAuth() {
|
|||
async (email: string) => {
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
setErrorAction(null);
|
||||
try {
|
||||
await pb.collection('users').requestPasswordReset(email);
|
||||
} catch (err) {
|
||||
const msg = err instanceof Error ? err.message : t('auth.passwordResetFailed');
|
||||
setError(msg);
|
||||
const { message, action } = resolveAuthError(err, 'reset', t);
|
||||
setError(message);
|
||||
setErrorAction(action);
|
||||
throw err;
|
||||
} finally {
|
||||
setLoading(false);
|
||||
|
|
@ -167,12 +195,14 @@ export function useAuth() {
|
|||
|
||||
const clearError = useCallback(() => {
|
||||
setError(null);
|
||||
setErrorAction(null);
|
||||
}, []);
|
||||
|
||||
return {
|
||||
user,
|
||||
loading,
|
||||
error,
|
||||
errorAction,
|
||||
login,
|
||||
register,
|
||||
loginWithOAuth,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue