fix: resolve frontend lint errors and cleanup types
This commit is contained in:
@@ -12,7 +12,7 @@ export default function ProtectedLayout({
|
|||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
}) {
|
}) {
|
||||||
const { data } = useSession();
|
const { data } = useSession();
|
||||||
const isAdmin = (data?.user as any)?.isAdmin;
|
const isAdmin = data?.user?.isAdmin;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AuthGuard>
|
<AuthGuard>
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import { Button } from '@/components/ui/button';
|
|||||||
import { Progress } from '@/components/ui/progress';
|
import { Progress } from '@/components/ui/progress';
|
||||||
import { Badge } from '@/components/ui/badge';
|
import { Badge } from '@/components/ui/badge';
|
||||||
import { useRouter } from 'next/navigation';
|
import { useRouter } from 'next/navigation';
|
||||||
import { useSession } from 'next-auth/react';
|
|
||||||
|
|
||||||
export default function ShiftDetailPage({ params }: { params: Promise<{ id: string }> }) {
|
export default function ShiftDetailPage({ params }: { params: Promise<{ id: string }> }) {
|
||||||
const resolvedParams = use(params);
|
const resolvedParams = use(params);
|
||||||
@@ -15,7 +14,6 @@ export default function ShiftDetailPage({ params }: { params: Promise<{ id: stri
|
|||||||
const signUpMutation = useSignUpShift();
|
const signUpMutation = useSignUpShift();
|
||||||
const cancelMutation = useCancelSignUp();
|
const cancelMutation = useCancelSignUp();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { data: session } = useSession();
|
|
||||||
|
|
||||||
if (isLoading) return <div>Loading shift...</div>;
|
if (isLoading) return <div>Loading shift...</div>;
|
||||||
if (!shift) return <div>Shift not found</div>;
|
if (!shift) return <div>Shift not found</div>;
|
||||||
|
|||||||
@@ -47,14 +47,14 @@ export const { handlers, signIn, signOut, auth } = NextAuth({
|
|||||||
async jwt({ token, account }) {
|
async jwt({ token, account }) {
|
||||||
if (account && account.access_token) {
|
if (account && account.access_token) {
|
||||||
// Add clubs claim from Keycloak access token
|
// Add clubs claim from Keycloak access token
|
||||||
token.clubs = (account as any).clubs as Record<string, string> || {}
|
token.clubs = (account as { clubs?: Record<string, string> }).clubs || {}
|
||||||
token.accessToken = account.access_token as string
|
token.accessToken = account.access_token
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const payload = JSON.parse(Buffer.from((token.accessToken as string).split('.')[1], 'base64').toString());
|
const payload = JSON.parse(Buffer.from((token.accessToken as string).split('.')[1], 'base64').toString());
|
||||||
const roles = payload.realm_access?.roles || [];
|
const roles = (payload.realm_access?.roles as string[]) || [];
|
||||||
token.isAdmin = roles.includes('admin');
|
token.isAdmin = roles.includes('admin');
|
||||||
} catch (e) {
|
} catch {
|
||||||
token.isAdmin = false;
|
token.isAdmin = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -63,10 +63,10 @@ export const { handlers, signIn, signOut, auth } = NextAuth({
|
|||||||
async session({ session, token }) {
|
async session({ session, token }) {
|
||||||
// Expose clubs to client
|
// Expose clubs to client
|
||||||
if (session.user) {
|
if (session.user) {
|
||||||
session.user.clubs = (token as any).clubs as Record<string, string> | undefined
|
session.user.clubs = token.clubs as Record<string, string> | undefined
|
||||||
session.user.isAdmin = (token as any).isAdmin as boolean | undefined
|
session.user.isAdmin = token.isAdmin as boolean | undefined
|
||||||
}
|
}
|
||||||
session.accessToken = (token as any).accessToken as string | undefined
|
session.accessToken = token.accessToken as string | undefined
|
||||||
return session
|
return session
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,10 +17,11 @@ export function ClubManagement() {
|
|||||||
const [isCreating, setIsCreating] = useState(false);
|
const [isCreating, setIsCreating] = useState(false);
|
||||||
const [newClub, setNewClub] = useState({ name: '', sportType: 'Tennis', description: '' });
|
const [newClub, setNewClub] = useState({ name: '', sportType: 'Tennis', description: '' });
|
||||||
|
|
||||||
const fetchClubs = async () => {
|
useEffect(() => {
|
||||||
|
const fetchClubsLocally = async () => {
|
||||||
try {
|
try {
|
||||||
const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/api/admin/clubs`, {
|
const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/api/admin/clubs`, {
|
||||||
headers: { Authorization: `Bearer ${(session as any)?.accessToken}` },
|
headers: { Authorization: `Bearer ${session?.accessToken}` },
|
||||||
});
|
});
|
||||||
if (res.ok) {
|
if (res.ok) {
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
@@ -33,10 +34,25 @@ export function ClubManagement() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
if (session) fetchClubsLocally();
|
||||||
if (session) fetchClubs();
|
|
||||||
}, [session]);
|
}, [session]);
|
||||||
|
|
||||||
|
const fetchClubs = async () => {
|
||||||
|
try {
|
||||||
|
const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/api/admin/clubs`, {
|
||||||
|
headers: { Authorization: `Bearer ${session?.accessToken}` },
|
||||||
|
});
|
||||||
|
if (res.ok) {
|
||||||
|
const data = await res.json();
|
||||||
|
setClubs(data);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to fetch clubs', error);
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const handleCreate = async (e: React.FormEvent) => {
|
const handleCreate = async (e: React.FormEvent) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
try {
|
try {
|
||||||
@@ -44,7 +60,7 @@ export function ClubManagement() {
|
|||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
Authorization: `Bearer ${(session as any)?.accessToken}`,
|
Authorization: `Bearer ${session?.accessToken}`,
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
name: newClub.name,
|
name: newClub.name,
|
||||||
@@ -67,7 +83,7 @@ export function ClubManagement() {
|
|||||||
try {
|
try {
|
||||||
const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/api/admin/clubs/${id}`, {
|
const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/api/admin/clubs/${id}`, {
|
||||||
method: 'DELETE',
|
method: 'DELETE',
|
||||||
headers: { Authorization: `Bearer ${(session as any)?.accessToken}` },
|
headers: { Authorization: `Bearer ${session?.accessToken}` },
|
||||||
});
|
});
|
||||||
if (res.ok) {
|
if (res.ok) {
|
||||||
fetchClubs();
|
fetchClubs();
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ export function AuthGuard({ children }: { children: ReactNode }) {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (status === 'authenticated') {
|
if (status === 'authenticated') {
|
||||||
const isAdmin = (data?.user as any)?.isAdmin;
|
const isAdmin = data?.user?.isAdmin;
|
||||||
|
|
||||||
// Admin routing
|
// Admin routing
|
||||||
if (isAdmin) {
|
if (isAdmin) {
|
||||||
@@ -59,7 +59,7 @@ export function AuthGuard({ children }: { children: ReactNode }) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const isAdmin = (data?.user as any)?.isAdmin;
|
const isAdmin = data?.user?.isAdmin;
|
||||||
if (clubs.length === 0 && status === 'authenticated' && !isAdmin) {
|
if (clubs.length === 0 && status === 'authenticated' && !isAdmin) {
|
||||||
const handleSwitchAccount = () => {
|
const handleSwitchAccount = () => {
|
||||||
const keycloakLogoutUrl = `${process.env.NEXT_PUBLIC_KEYCLOAK_ISSUER || 'http://localhost:8080/realms/workclub'}/protocol/openid-connect/logout?redirect_uri=${encodeURIComponent(window.location.origin + '/login')}`;
|
const keycloakLogoutUrl = `${process.env.NEXT_PUBLIC_KEYCLOAK_ISSUER || 'http://localhost:8080/realms/workclub'}/protocol/openid-connect/logout?redirect_uri=${encodeURIComponent(window.location.origin + '/login')}`;
|
||||||
|
|||||||
Reference in New Issue
Block a user