83 lines
2.1 KiB
TypeScript
83 lines
2.1 KiB
TypeScript
import { createContext, use, type PropsWithChildren } from 'react';
|
|
import { createTanstackApi, createApi } from '../lib/api';
|
|
import axios from 'axios';
|
|
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
|
import { useNavigate } from 'react-router';
|
|
|
|
type ApiProviderProps = PropsWithChildren<object>;
|
|
type ApiContextType = {
|
|
apiClient: ReturnType<typeof createApi>;
|
|
tanstackApiClient: ReturnType<typeof createTanstackApi>;
|
|
};
|
|
|
|
const ApiContext = createContext<ApiContextType | null>(null);
|
|
|
|
const queryClient = new QueryClient();
|
|
|
|
/**
|
|
* Example usage:
|
|
* ```ts
|
|
* const { tanstackApiClient } = useApi();
|
|
* const { queryOptions } = tanstackApiClient.get('/api/health/info');
|
|
* useQuery({
|
|
* ...queryOptions,
|
|
* queryFn: async (...args) => {
|
|
* console.log('Fetching health info...');
|
|
* const data = await queryOptions.queryFn!(...args);
|
|
* console.log('Health Info:', data);
|
|
* return data;
|
|
* },
|
|
* });
|
|
* ```
|
|
*/
|
|
|
|
export const ApiProvider: React.FC<ApiProviderProps> = ({ children }) => {
|
|
const navigate = useNavigate();
|
|
const axiosInstance = axios.create({
|
|
withCredentials: true,
|
|
});
|
|
|
|
const internalAxiosInstance = axios.create({
|
|
withCredentials: true,
|
|
});
|
|
|
|
internalAxiosInstance.interceptors.response.use(
|
|
(response) => response,
|
|
(error) => {
|
|
// only handle 403 errors
|
|
if (!error.response) return Promise.reject(error);
|
|
|
|
if (error.response.status === 401) {
|
|
// redirect to login page
|
|
return navigate('/login', {});
|
|
}
|
|
|
|
return Promise.reject(error);
|
|
}
|
|
);
|
|
|
|
const apiClient = createApi(axiosInstance);
|
|
const tanstackApiClient = createTanstackApi(internalAxiosInstance);
|
|
|
|
return (
|
|
<QueryClientProvider client={queryClient}>
|
|
<ApiContext
|
|
value={{
|
|
apiClient,
|
|
tanstackApiClient,
|
|
}}
|
|
>
|
|
{children}
|
|
</ApiContext>
|
|
</QueryClientProvider>
|
|
);
|
|
};
|
|
|
|
export function useApi() {
|
|
const context = use(ApiContext);
|
|
if (!context) {
|
|
throw new Error('useApi must be used within an ApiProvider');
|
|
}
|
|
return context;
|
|
}
|