// ======================================== // Route Guard Components // ======================================== // Protected route wrappers that check user permissions import React, { useEffect, useState, ReactNode } from 'react'; import { Navigate } from 'react-router-dom'; import { usePezkuwi } from '@/contexts/PezkuwiContext'; import { useAuth } from '@/contexts/AuthContext'; import { checkCitizenStatus, checkValidatorStatus, checkEducatorRole, checkModeratorRole, } from '@pezkuwi/lib/guards'; import { Card, CardContent } from '@/components/ui/card'; import { Alert, AlertDescription } from '@/components/ui/alert'; import { Loader2, AlertCircle, Users, GraduationCap, Shield } from 'lucide-react'; import { Button } from '@/components/ui/button'; interface RouteGuardProps { children: ReactNode; fallbackPath?: string; } // ======================================== // LOADING COMPONENT // ======================================== const LoadingGuard: React.FC = () => { return (

Checking permissions...

); }; // ======================================== // CITIZEN ROUTE GUARD // ======================================== /** * CitizenRoute - Requires approved KYC (citizenship) * Use for: Voting, Education, Elections, etc. * * @example * * * * } /> */ export const CitizenRoute: React.FC = ({ children, fallbackPath = '/be-citizen', }) => { const { api, isApiReady, selectedAccount } = usePezkuwi(); const {} = useAuth(); const [isCitizen, setIsCitizen] = useState(null); const [loading, setLoading] = useState(true); useEffect(() => { const checkPermission = async () => { if (!isApiReady || !api) { setLoading(true); return; } if (!selectedAccount?.address) { setIsCitizen(false); setLoading(false); return; } try { const citizenStatus = await checkCitizenStatus(api, selectedAccount.address); setIsCitizen(citizenStatus); } catch (error) { if (import.meta.env.DEV) console.error('Citizen check failed:', error); setIsCitizen(false); } finally { setLoading(false); } }; checkPermission(); }, [api, isApiReady, selectedAccount]); // Loading state if (loading || !isApiReady) { return ; } // Not connected to wallet if (!selectedAccount) { return (

Wallet Not Connected

Please connect your Pezkuwi wallet to access this feature.

); } // Not a citizen if (isCitizen === false) { return ; } // Authorized return <>{children}; }; // ======================================== // VALIDATOR ROUTE GUARD // ======================================== /** * ValidatorRoute - Requires validator pool membership * Use for: Validator pool dashboard, validator settings * * @example * * * * } /> */ export const ValidatorRoute: React.FC = ({ children, fallbackPath = '/staking', }) => { const { api, isApiReady, selectedAccount } = usePezkuwi(); const [isValidator, setIsValidator] = useState(null); const [loading, setLoading] = useState(true); useEffect(() => { const checkPermission = async () => { if (!isApiReady || !api) { setLoading(true); return; } if (!selectedAccount?.address) { setIsValidator(false); setLoading(false); return; } try { const validatorStatus = await checkValidatorStatus(api, selectedAccount.address); setIsValidator(validatorStatus); } catch (error) { if (import.meta.env.DEV) console.error('Validator check failed:', error); setIsValidator(false); } finally { setLoading(false); } }; checkPermission(); }, [api, isApiReady, selectedAccount]); // Loading state if (loading || !isApiReady) { return ; } // Not connected to wallet if (!selectedAccount) { return ; } // Not in validator pool if (isValidator === false) { return (
Validator Access Required You must be registered in the Validator Pool to access this feature.
); } // Authorized return <>{children}; }; // ======================================== // EDUCATOR ROUTE GUARD // ======================================== /** * EducatorRoute - Requires educator Tiki role * Use for: Creating courses in Perwerde (Education platform) * * @example * * * * } /> */ export const EducatorRoute: React.FC = ({ children, fallbackPath = '/education', }) => { const { api, isApiReady, selectedAccount } = usePezkuwi(); const [isEducator, setIsEducator] = useState(null); const [loading, setLoading] = useState(true); useEffect(() => { const checkPermission = async () => { if (!isApiReady || !api) { setLoading(true); return; } if (!selectedAccount?.address) { setIsEducator(false); setLoading(false); return; } try { const educatorStatus = await checkEducatorRole(api, selectedAccount.address); setIsEducator(educatorStatus); } catch (error) { if (import.meta.env.DEV) console.error('Educator check failed:', error); setIsEducator(false); } finally { setLoading(false); } }; checkPermission(); }, [api, isApiReady, selectedAccount]); // Loading state if (loading || !isApiReady) { return ; } // Not connected to wallet if (!selectedAccount) { return ; } // Not an educator if (isEducator === false) { return (
Educator Role Required You need one of these Tiki roles to create courses:
  • Perwerdekar (Educator)
  • Mamoste (Teacher)
  • WezireCand (Education Minister)
  • RewsenbĂ®r (Intellectual)
); } // Authorized return <>{children}; }; // ======================================== // MODERATOR ROUTE GUARD // ======================================== /** * ModeratorRoute - Requires moderator Tiki role * Use for: Forum moderation, governance moderation * * @example * * * * } /> */ export const ModeratorRoute: React.FC = ({ children, fallbackPath = '/', }) => { const { api, isApiReady, selectedAccount } = usePezkuwi(); const [isModerator, setIsModerator] = useState(null); const [loading, setLoading] = useState(true); useEffect(() => { const checkPermission = async () => { if (!isApiReady || !api) { setLoading(true); return; } if (!selectedAccount?.address) { setIsModerator(false); setLoading(false); return; } try { const moderatorStatus = await checkModeratorRole(api, selectedAccount.address); setIsModerator(moderatorStatus); } catch (error) { if (import.meta.env.DEV) console.error('Moderator check failed:', error); setIsModerator(false); } finally { setLoading(false); } }; checkPermission(); }, [api, isApiReady, selectedAccount]); // Loading state if (loading || !isApiReady) { return ; } // Not connected to wallet if (!selectedAccount) { return ; } // Not a moderator if (isModerator === false) { return (
Moderator Access Required You need moderator privileges to access this feature.
); } // Authorized return <>{children}; }; // ======================================== // ADMIN ROUTE GUARD (Supabase-based) // ======================================== /** * AdminRoute - Requires Supabase admin role * Use for: Admin panel, system settings * Note: This is separate from blockchain permissions */ export const AdminRoute: React.FC = ({ children, fallbackPath = '/', }) => { const { user, isAdmin, loading } = useAuth(); // Loading state if (loading) { return ; } // Not logged in if (!user) { return ; } // Not admin if (!isAdmin) { return (
Admin Access Required You do not have permission to access the admin panel.
); } // Authorized return <>{children}; };