diff --git a/packages/web/src/components/auth/RegisterPage.tsx b/packages/web/src/components/auth/RegisterPage.tsx index c9eb04ac..8a2146f1 100644 --- a/packages/web/src/components/auth/RegisterPage.tsx +++ b/packages/web/src/components/auth/RegisterPage.tsx @@ -40,8 +40,7 @@ export function RegisterPage() { const [isRegistering, setIsRegistering] = useState(false); const [retryAfter, setRetryAfter] = useState(0); - const register = useAuthStore((s) => s.register); - const updateProfile = useAuthStore((s) => s.updateProfile); + const initSession = useAuthStore((s) => s.initSession); const navigate = useNavigate(); const [searchParams] = useSearchParams(); const redirect = searchParams.get('redirect'); @@ -192,18 +191,28 @@ export function RegisterPage() { try { const dn = skip ? undefined : displayName.trim() || undefined; const ac = skip ? undefined : avatarColor; - await register(username.trim(), password, dn, ac); - // Upload avatar if chosen (non-fatal — account already created) + // Step 1: Register via API — store token in localStorage for API auth, + // but NOT in Zustand yet so AuthRedirect doesn't fire prematurely + const response = await api.auth.register({ + username: username.trim(), password, displayName: dn, avatarColor: ac, + }); + localStorage.setItem('backspace_token', response.token); + + // Step 2: Upload avatar while still on the register page + let finalUser = response.user; if (!skip && avatarFile) { try { const attachment = await api.uploads.upload(avatarFile); - await updateProfile({ avatar: attachment.filename }); + finalUser = await api.users.update({ avatar: attachment.filename }); } catch { // Avatar upload failed — user can set it later in settings } } + // Step 3: Activate session — sets Zustand token, triggers AuthRedirect + initSession(response.token, finalUser); + if (redirect && redirect.startsWith('/') && !redirect.startsWith('//')) { navigate(redirect); } else { diff --git a/packages/web/src/stores/authStore.ts b/packages/web/src/stores/authStore.ts index f2471c78..2c2a1788 100644 --- a/packages/web/src/stores/authStore.ts +++ b/packages/web/src/stores/authStore.ts @@ -15,6 +15,7 @@ interface AuthState { user: User | null; isLoading: boolean; error: string | null; + initSession: (token: string, user: User) => void; login: (username: string, password: string) => Promise; register: (username: string, password: string, displayName?: string, avatarColor?: string) => Promise; logout: () => void; @@ -42,15 +43,18 @@ export const useAuthStore = create((set, get) => ({ isLoading: false, error: null, + initSession: (token: string, user: User) => { + resetUserStores(); + localStorage.setItem('backspace_token', token); + set({ token, user, isLoading: false }); + useInstanceStore.getState().autoConnectAll().catch(() => {}); + }, + login: async (username: string, password: string) => { set({ isLoading: true, error: null }); try { const response = await api.auth.login({ username, password }); - resetUserStores(); - localStorage.setItem('backspace_token', response.token); - set({ token: response.token, user: response.user, isLoading: false }); - // Auto-connect to remote instances (fire-and-forget) - useInstanceStore.getState().autoConnectAll().catch(() => {}); + get().initSession(response.token, response.user); } catch (err) { set({ isLoading: false, error: err instanceof Error ? err.message : 'Login failed' }); throw err; @@ -61,11 +65,7 @@ export const useAuthStore = create((set, get) => ({ set({ isLoading: true, error: null }); try { const response = await api.auth.register({ username, password, displayName, avatarColor }); - resetUserStores(); - localStorage.setItem('backspace_token', response.token); - set({ token: response.token, user: response.user, isLoading: false }); - // Auto-connect to remote instances (fire-and-forget) - useInstanceStore.getState().autoConnectAll().catch(() => {}); + get().initSession(response.token, response.user); } catch (err) { set({ isLoading: false, error: err instanceof Error ? err.message : 'Registration failed' }); throw err;