feat(frontend-auth): complete NextAuth.js Keycloak integration with middleware, hooks, and API utility
- Add middleware.ts for route protection (redirects unauthenticated users to /login) - Add useActiveClub() hook for managing active club context (localStorage + session) - Add apiClient() fetch wrapper with automatic Authorization + X-Tenant-Id headers - Configure vitest with jsdom environment and global test setup - Add comprehensive test coverage: 16/16 tests passing (hooks + API utility) - Install test dependencies: vitest, @testing-library/react, @vitejs/plugin-react, happy-dom Task 10 COMPLETE - all acceptance criteria met
This commit is contained in:
51
frontend/src/hooks/useActiveClub.ts
Normal file
51
frontend/src/hooks/useActiveClub.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
'use client';
|
||||
|
||||
import { useSession } from 'next-auth/react';
|
||||
import { useState, useEffect } from 'react';
|
||||
|
||||
const ACTIVE_CLUB_KEY = 'activeClubId';
|
||||
|
||||
export interface ActiveClubData {
|
||||
activeClubId: string | null;
|
||||
role: string | null;
|
||||
clubs: Record<string, string> | null;
|
||||
setActiveClub: (clubId: string) => void;
|
||||
}
|
||||
|
||||
export function useActiveClub(): ActiveClubData {
|
||||
const { data: session, status } = useSession();
|
||||
const [activeClubId, setActiveClubIdState] = useState<string | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (status === 'authenticated' && session?.user?.clubs) {
|
||||
const clubs = session.user.clubs;
|
||||
const storedClubId = localStorage.getItem(ACTIVE_CLUB_KEY);
|
||||
|
||||
if (storedClubId && clubs[storedClubId]) {
|
||||
setActiveClubIdState(storedClubId);
|
||||
} else {
|
||||
const firstClubId = Object.keys(clubs)[0];
|
||||
if (firstClubId) {
|
||||
setActiveClubIdState(firstClubId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}, [session, status]);
|
||||
|
||||
const setActiveClub = (clubId: string) => {
|
||||
if (session?.user?.clubs && session.user.clubs[clubId]) {
|
||||
localStorage.setItem(ACTIVE_CLUB_KEY, clubId);
|
||||
setActiveClubIdState(clubId);
|
||||
}
|
||||
};
|
||||
|
||||
const clubs = session?.user?.clubs || null;
|
||||
const role = activeClubId && clubs ? clubs[activeClubId] : null;
|
||||
|
||||
return {
|
||||
activeClubId,
|
||||
role,
|
||||
clubs,
|
||||
setActiveClub,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user