Auto-redirect to login on 401 API responses
When a session token expires, API calls return 401 but nothing caught it — errors were shown as generic dialogs or swallowed. Now both apiClient and streamingService detect 401 responses and clear auth state, which causes App.tsx to render the login modal automatically.
This commit is contained in:
parent
3acf8db7af
commit
a1829957c1
4 changed files with 29 additions and 1 deletions
|
|
@ -18,6 +18,8 @@ import { Button } from './components/ui/button';
|
|||
import { Filter } from 'lucide-react';
|
||||
import type { GeoJSONFeatureCollection, PropertyProperties, PropertyFeature, POI, POITravelFilter } from '@/types';
|
||||
import { refreshListings, streamListingGeoJSON, fetchUserPOIs, type StreamingProgress } from '@/services';
|
||||
import { setOnUnauthorized } from '@/services/apiClient';
|
||||
import { clearPasskeyUser } from './auth/passkeyService';
|
||||
import { poiMetricPropertyName, injectPoiMetricProperty } from '@/utils/poiUtils';
|
||||
import { useTaskProgress } from '@/hooks/useTaskProgress';
|
||||
|
||||
|
|
@ -94,6 +96,13 @@ function App() {
|
|||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
setOnUnauthorized(() => {
|
||||
clearPasskeyUser();
|
||||
setUser(null);
|
||||
});
|
||||
}, []);
|
||||
|
||||
const handlePasskeyLogin = (passkeyUser: AuthUser) => {
|
||||
setUser(passkeyUser);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -3,6 +3,18 @@
|
|||
import type { AuthUser } from '@/auth/types';
|
||||
import { ApiError } from '@/types';
|
||||
|
||||
let onUnauthorized: (() => void) | null = null;
|
||||
|
||||
export function setOnUnauthorized(handler: () => void): void {
|
||||
onUnauthorized = handler;
|
||||
}
|
||||
|
||||
export function fireUnauthorized(): void {
|
||||
if (onUnauthorized) {
|
||||
onUnauthorized();
|
||||
}
|
||||
}
|
||||
|
||||
export interface RequestOptions {
|
||||
method?: 'GET' | 'POST' | 'PUT' | 'DELETE';
|
||||
params?: Record<string, string | number | boolean | Date | undefined>;
|
||||
|
|
@ -61,6 +73,9 @@ export async function apiRequest<T>(
|
|||
const response = await fetch(url, fetchOptions);
|
||||
|
||||
if (!response.ok) {
|
||||
if (response.status === 401) {
|
||||
fireUnauthorized();
|
||||
}
|
||||
throw new ApiError(`Error: ${response.status}`, response.status);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import type { PropertyFeature } from '@/types';
|
|||
import type { ParameterValues } from '@/components/FilterPanel';
|
||||
import { ApiError } from '@/types';
|
||||
import { API_ENDPOINTS } from '@/constants';
|
||||
import { fireUnauthorized } from './apiClient';
|
||||
|
||||
/**
|
||||
* Build query string from parameters object
|
||||
|
|
@ -87,6 +88,9 @@ export async function* streamListingGeoJSON(
|
|||
});
|
||||
|
||||
if (!response.ok) {
|
||||
if (response.status === 401) {
|
||||
fireUnauthorized();
|
||||
}
|
||||
throw new ApiError(`Error: ${response.status}`, response.status);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
{"root":["./src/App.tsx","./src/AppSidebar.tsx","./src/main.tsx","./src/vite-env.d.ts","./src/auth/authService.ts","./src/auth/config.ts","./src/auth/errors.ts","./src/auth/passkeyService.ts","./src/auth/types.ts","./src/components/ActiveQuery.tsx","./src/components/AlertError.tsx","./src/components/AuthCallback.tsx","./src/components/FilterPanel.tsx","./src/components/Header.tsx","./src/components/HealthIndicator.tsx","./src/components/ListView.tsx","./src/components/LoginModal.tsx","./src/components/Map.tsx","./src/components/POIManager.tsx","./src/components/PropertyCard.tsx","./src/components/Spinner.tsx","./src/components/StatsBar.tsx","./src/components/StreamingProgressBar.tsx","./src/components/TaskIndicator.tsx","./src/components/TaskProgressDrawer.tsx","./src/components/VisualizationCard.tsx","./src/components/ui/DatePicker.tsx","./src/components/ui/accordion.tsx","./src/components/ui/alert-dialog.tsx","./src/components/ui/breadcrumb.tsx","./src/components/ui/button.tsx","./src/components/ui/calendar.tsx","./src/components/ui/checkbox.tsx","./src/components/ui/dialog.tsx","./src/components/ui/form.tsx","./src/components/ui/hover-card.tsx","./src/components/ui/input.tsx","./src/components/ui/label.tsx","./src/components/ui/popover.tsx","./src/components/ui/progress.tsx","./src/components/ui/range-slider-field.tsx","./src/components/ui/scroll-area.tsx","./src/components/ui/select.tsx","./src/components/ui/separator.tsx","./src/components/ui/sheet.tsx","./src/components/ui/sidebar.tsx","./src/components/ui/skeleton.tsx","./src/components/ui/slider.tsx","./src/components/ui/tabs.tsx","./src/components/ui/tooltip.tsx","./src/constants/colorSchemes.ts","./src/constants/index.ts","./src/hooks/use-mobile.ts","./src/lib/utils.ts","./src/services/apiClient.ts","./src/services/healthService.ts","./src/services/index.ts","./src/services/listingService.ts","./src/services/poiService.ts","./src/services/streamingService.ts","./src/services/taskService.ts","./src/types/index.ts","./src/utils/mapUtils.ts","./src/utils/poiUtils.ts"],"version":"5.8.3"}
|
||||
{"root":["./src/app.tsx","./src/appsidebar.tsx","./src/main.tsx","./src/vite-env.d.ts","./src/auth/authservice.ts","./src/auth/config.ts","./src/auth/errors.ts","./src/auth/passkeyservice.ts","./src/auth/types.ts","./src/components/activequery.tsx","./src/components/alerterror.tsx","./src/components/authcallback.tsx","./src/components/filterpanel.tsx","./src/components/header.tsx","./src/components/healthindicator.tsx","./src/components/listview.tsx","./src/components/loginmodal.tsx","./src/components/map.tsx","./src/components/poimanager.tsx","./src/components/propertycard.tsx","./src/components/spinner.tsx","./src/components/statsbar.tsx","./src/components/streamingprogressbar.tsx","./src/components/taskindicator.tsx","./src/components/taskprogressdrawer.tsx","./src/components/visualizationcard.tsx","./src/components/ui/datepicker.tsx","./src/components/ui/accordion.tsx","./src/components/ui/alert-dialog.tsx","./src/components/ui/breadcrumb.tsx","./src/components/ui/button.tsx","./src/components/ui/calendar.tsx","./src/components/ui/checkbox.tsx","./src/components/ui/dialog.tsx","./src/components/ui/form.tsx","./src/components/ui/hover-card.tsx","./src/components/ui/input.tsx","./src/components/ui/label.tsx","./src/components/ui/popover.tsx","./src/components/ui/progress.tsx","./src/components/ui/range-slider-field.tsx","./src/components/ui/scroll-area.tsx","./src/components/ui/select.tsx","./src/components/ui/separator.tsx","./src/components/ui/sheet.tsx","./src/components/ui/sidebar.tsx","./src/components/ui/skeleton.tsx","./src/components/ui/slider.tsx","./src/components/ui/tabs.tsx","./src/components/ui/tooltip.tsx","./src/constants/colorschemes.ts","./src/constants/index.ts","./src/hooks/use-mobile.ts","./src/hooks/usetaskprogress.ts","./src/lib/utils.ts","./src/services/apiclient.ts","./src/services/healthservice.ts","./src/services/index.ts","./src/services/listingservice.ts","./src/services/poiservice.ts","./src/services/streamingservice.ts","./src/services/taskservice.ts","./src/types/index.ts","./src/utils/maputils.ts","./src/utils/poiutils.ts"],"version":"5.8.3"}
|
||||
Loading…
Add table
Add a link
Reference in a new issue