f072ed0115
Fundament migracji z useState(view) na prawdziwy routing: - react-router-dom 7 w zaleznosciach - BrowserRouter w main.tsx (nginx ma juz try_files, wiec czyste sciezki dzialaja) - routes.ts: centralna mapa adresow + helpery listingPath/mapPath/adminTabPath - ProtectedRoute z obsluga stanu loading z AuthProvider Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
38 lines
1.3 KiB
TypeScript
38 lines
1.3 KiB
TypeScript
import { Navigate, Outlet, useLocation } from 'react-router-dom';
|
|
import { useAuth } from './auth';
|
|
import { ROUTES } from './routes';
|
|
|
|
/**
|
|
* Bramka dostępu dla tras wymagających zalogowania (i opcjonalnie roli ADMIN).
|
|
*
|
|
* Uwaga na `loading`: po odświeżeniu strony token jest w localStorage, ale profil
|
|
* dociąga się asynchronicznie z /auth/me. Bez tego warunku bezpośrednie wejście na
|
|
* /konto wyrzucałoby zalogowanego użytkownika na logowanie, zanim profil dotrze.
|
|
*
|
|
* To zabezpieczenie interfejsu, nie kontrola dostępu do danych — autoryzację
|
|
* egzekwuje backend przy każdym endpoincie.
|
|
*/
|
|
export function ProtectedRoute({ requireAdmin = false }: { requireAdmin?: boolean }) {
|
|
const { user, loading } = useAuth();
|
|
const location = useLocation();
|
|
|
|
if (loading) {
|
|
return (
|
|
<div className="route-loading" role="status" aria-live="polite">
|
|
Wczytywanie…
|
|
</div>
|
|
);
|
|
}
|
|
|
|
if (!user) {
|
|
// Zapamiętujemy cel, żeby po zalogowaniu wrócić dokładnie tam, gdzie użytkownik zmierzał.
|
|
return <Navigate to={ROUTES.login} state={{ from: `${location.pathname}${location.search}` }} replace />;
|
|
}
|
|
|
|
if (requireAdmin && user.role !== 'ADMIN') {
|
|
return <Navigate to={ROUTES.account} replace />;
|
|
}
|
|
|
|
return <Outlet />;
|
|
}
|