Add LoadingSpinner and API client with auth interceptors

This commit is contained in:
Lukas Bauer 2026-02-04 11:00:00 +00:00
parent 416b331703
commit 9f19912bdd
2 changed files with 37 additions and 0 deletions

23
src/api/client.ts Normal file
View file

@ -0,0 +1,23 @@
import axios from 'axios';
export const apiClient = axios.create({
baseURL: import.meta.env.VITE_API_BASE_URL ?? '/api',
headers: { 'Content-Type': 'application/json' },
});
apiClient.interceptors.request.use((config) => {
const token = localStorage.getItem('access_token');
if (token) config.headers.Authorization = `Bearer ${token}`;
return config;
});
apiClient.interceptors.response.use(
(r) => r,
(err) => {
if (err.response?.status === 401) {
localStorage.removeItem('access_token');
window.location.href = '/login';
}
return Promise.reject(err);
},
);

View file

@ -0,0 +1,14 @@
import React from 'react';
interface Props { size?: number; }
export const LoadingSpinner: React.FC<Props> = ({ size = 32 }) => (
<div role="status" aria-label="Loading" style={{ width: size, height: size }}>
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={2}>
<circle cx={12} cy={12} r={10} strokeOpacity={0.25} />
<path d="M12 2 a10 10 0 0 1 10 10" strokeLinecap="round">
<animateTransform attributeName="transform" type="rotate" from="0 12 12" to="360 12 12" dur="0.8s" repeatCount="indefinite" />
</path>
</svg>
</div>
);