This commit is contained in:
Andras Schmelczer 2026-05-13 12:11:54 +01:00
parent a08b5d2ae0
commit b98f0e3904
38 changed files with 3732 additions and 483 deletions

View file

@ -23,6 +23,11 @@ function recordToUser(record: { id: string; [key: string]: unknown }): AuthUser
};
}
function authRefreshInvalidated(error: unknown): boolean {
const status = (error as { status?: unknown })?.status;
return status === 401 || status === 403;
}
export function useAuth() {
const [user, setUser] = useState<AuthUser | null>(() => {
if (pb.authStore.isValid && pb.authStore.record) {
@ -128,12 +133,16 @@ export function useAuth() {
setError(null);
try {
const result = await pb.collection('users').authRefresh();
setUser(recordToUser(result.record));
const refreshedUser = recordToUser(result.record);
setUser(refreshedUser);
return refreshedUser;
} catch (err) {
// Token is invalid/expired — clear auth state but don't set error,
// since this is a background refresh, not a user-initiated action
pb.authStore.clear();
setUser(null);
// Only clear auth on explicit token rejection. Network and 5xx failures
// should not log users out during background refresh.
if (authRefreshInvalidated(err)) {
pb.authStore.clear();
setUser(null);
}
throw err;
} finally {
setLoading(false);

View file

@ -134,8 +134,10 @@ describe('useHexagonSelection', () => {
});
});
expect(result.current.areaStats?.count).toBe(4);
expect(result.current.unfilteredAreaCount).toBeNull();
await waitFor(() => {
expect(result.current.areaStats?.count).toBe(4);
expect(result.current.unfilteredAreaCount).toBeNull();
});
expect(requests.some((url) => url.startsWith('/api/hexagon-stats'))).toBe(false);
});

View file

@ -6,7 +6,7 @@ export function useLicense() {
const [checkingOut, setCheckingOut] = useState(false);
const [error, setError] = useState<string | null>(null);
const startCheckout = useCallback(async () => {
const startCheckout = useCallback(async (returnPath?: string) => {
trackEvent('Checkout Start', { has_referral: 'false' });
setCheckingOut(true);
setError(null);
@ -15,7 +15,7 @@ export function useLicense() {
method: 'POST',
...authHeaders({
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({}),
body: JSON.stringify(returnPath ? { return_path: returnPath } : {}),
}),
});
assertOk(res, 'Checkout');