Various Fixes and QoL enhancements.
This commit is contained in:
@@ -21,15 +21,36 @@ api.interceptors.request.use((config) => {
|
||||
return config;
|
||||
});
|
||||
|
||||
// Global auth failure handler - can be set by AuthContext
|
||||
let globalAuthFailureHandler: (() => void) | null = null;
|
||||
|
||||
export const setGlobalAuthFailureHandler = (handler: () => void) => {
|
||||
globalAuthFailureHandler = handler;
|
||||
};
|
||||
|
||||
// Response interceptor to handle auth errors
|
||||
api.interceptors.response.use(
|
||||
(response) => response,
|
||||
(error) => {
|
||||
if (error.response?.status === 401) {
|
||||
// Clear invalid token and redirect to login
|
||||
// Handle authentication failures
|
||||
if (error.response?.status === 401 || error.response?.status === 403) {
|
||||
console.warn('Authentication failed, token may be expired or invalid');
|
||||
|
||||
// Clear invalid token
|
||||
localStorage.removeItem('auth-token');
|
||||
window.location.href = '/login';
|
||||
|
||||
// Use global handler if available (from AuthContext), otherwise fallback to direct redirect
|
||||
if (globalAuthFailureHandler) {
|
||||
globalAuthFailureHandler();
|
||||
} else {
|
||||
// Fallback for cases where AuthContext isn't available
|
||||
window.location.href = '/login';
|
||||
}
|
||||
|
||||
// Return a more specific error for components to handle gracefully
|
||||
return Promise.reject(new Error('Authentication required'));
|
||||
}
|
||||
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
@@ -150,6 +171,22 @@ export const storyApi = {
|
||||
const response = await api.post('/stories/recreate-typesense-collection');
|
||||
return response.data;
|
||||
},
|
||||
|
||||
checkDuplicate: async (title: string, authorName: string): Promise<{
|
||||
hasDuplicates: boolean;
|
||||
count: number;
|
||||
duplicates: Array<{
|
||||
id: string;
|
||||
title: string;
|
||||
authorName: string;
|
||||
createdAt: string;
|
||||
}>;
|
||||
}> => {
|
||||
const response = await api.get('/stories/check-duplicate', {
|
||||
params: { title, authorName }
|
||||
});
|
||||
return response.data;
|
||||
},
|
||||
};
|
||||
|
||||
// Author endpoints
|
||||
@@ -240,6 +277,11 @@ export const tagApi = {
|
||||
// Backend returns TagDto[], extract just the names
|
||||
return response.data.map((tag: Tag) => tag.name);
|
||||
},
|
||||
|
||||
getCollectionTags: async (): Promise<Tag[]> => {
|
||||
const response = await api.get('/tags/collections');
|
||||
return response.data;
|
||||
},
|
||||
};
|
||||
|
||||
// Series endpoints
|
||||
|
||||
Reference in New Issue
Block a user