152 lines
5.1 KiB
TypeScript
152 lines
5.1 KiB
TypeScript
'use client';
|
|
|
|
import React, { useEffect, useState, use } from 'react';
|
|
import { useRouter, useSearchParams } from 'next/navigation';
|
|
import {
|
|
Club,
|
|
ClubMetrics,
|
|
ClubUpcomingRide,
|
|
ClubMember,
|
|
ClubActivityItem,
|
|
ClubRole,
|
|
UserPortalPermissions,
|
|
} from '../../../../components/founder-portal/types';
|
|
import {
|
|
fetchClubData,
|
|
getPortalPermissions,
|
|
sanitizePortalError,
|
|
} from '../../../../lib/club-data';
|
|
import { FounderPortalShell } from '../../../../components/founder-portal/founder-portal-shell';
|
|
import { FounderOverview } from '../../../../components/founder-portal/founder-overview';
|
|
import { OverviewSkeleton } from '../../../../components/founder-portal/skeleton-state';
|
|
import { SafeErrorState } from '../../../../components/founder-portal/safe-error-state';
|
|
import { firebaseAuth } from '../../../../lib/firebase-client';
|
|
|
|
interface PageProps {
|
|
params: Promise<{ clubId: string }>;
|
|
}
|
|
|
|
export default function ClubFounderPortalPage({ params }: PageProps) {
|
|
const { clubId } = use(params);
|
|
const router = useRouter();
|
|
const searchParams = useSearchParams();
|
|
|
|
const [club, setClub] = useState<Club | null>(null);
|
|
const [metrics, setMetrics] = useState<ClubMetrics | null>(null);
|
|
const [upcomingRides, setUpcomingRides] = useState<ClubUpcomingRide[]>([]);
|
|
const [pendingApplications, setPendingApplications] = useState<ClubMember[]>([]);
|
|
const [activities, setActivities] = useState<ClubActivityItem[]>([]);
|
|
const [userRole, setUserRole] = useState<ClubRole>('owner');
|
|
const [userRank, setUserRank] = useState('President');
|
|
|
|
const [loading, setLoading] = useState(true);
|
|
const [error, setError] = useState<string | null>(null);
|
|
const [activeNav, setActiveNav] = useState('overview');
|
|
|
|
async function loadData() {
|
|
setLoading(true);
|
|
setError(null);
|
|
try {
|
|
await firebaseAuth.authStateReady();
|
|
const currentUser = firebaseAuth.currentUser;
|
|
const isDemoPreview = searchParams?.get('preview') === 'demo';
|
|
const data = await fetchClubData(clubId, currentUser?.uid, {
|
|
allowDemoPreview: isDemoPreview,
|
|
});
|
|
setClub(data.club);
|
|
setMetrics(data.metrics);
|
|
setUpcomingRides(data.upcomingRides);
|
|
setPendingApplications(data.pendingApplications);
|
|
setActivities(data.activities);
|
|
setUserRole(data.userRole);
|
|
setUserRank(data.userRank);
|
|
} catch (err) {
|
|
setError(sanitizePortalError(err, "Club information couldn't be loaded."));
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
}
|
|
|
|
useEffect(() => {
|
|
void loadData();
|
|
}, [clubId]);
|
|
|
|
const permissions: UserPortalPermissions = getPortalPermissions(userRole, true);
|
|
|
|
if (loading) {
|
|
return (
|
|
<div className="min-h-screen bg-brand-bg telemetry-grid-bg p-6 flex items-center justify-center">
|
|
<div className="w-full max-w-5xl">
|
|
<OverviewSkeleton />
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
// Unauthenticated Guard
|
|
const isDemo = searchParams?.get('preview') === 'demo';
|
|
if (!firebaseAuth.currentUser && !isDemo) {
|
|
return (
|
|
<div className="min-h-screen bg-brand-bg telemetry-grid-bg flex items-center justify-center p-4 sm:p-6">
|
|
<SafeErrorState
|
|
title="Authentication Required"
|
|
message="Sign in with your rider account to access this club's management portal."
|
|
actionLabel="Sign In"
|
|
onAction={() => router.push(`/login?returnUrl=/clubs/${clubId}/manage`)}
|
|
/>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
if (error || !club || !metrics) {
|
|
return (
|
|
<div className="min-h-screen bg-brand-bg telemetry-grid-bg flex items-center justify-center p-4 sm:p-6">
|
|
<SafeErrorState
|
|
title="Club Unavailable"
|
|
message={error ?? "Club information couldn't be loaded."}
|
|
actionLabel="Return to Clubs"
|
|
onAction={() => router.push('/clubs')}
|
|
onRetry={loadData}
|
|
/>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
// Member Access Guard: Non-admin members are forbidden from administrative portal
|
|
const isDev = process.env.NODE_ENV === 'development';
|
|
if (!isDev && userRole !== 'owner' && userRole !== 'admin') {
|
|
return (
|
|
<div className="min-h-screen bg-brand-bg telemetry-grid-bg flex items-center justify-center p-4 sm:p-6">
|
|
<SafeErrorState
|
|
title="Management Access Restricted"
|
|
message="You must be an Owner or Admin of this Club to access the Founder Portal."
|
|
actionLabel="Return to Clubs"
|
|
onAction={() => router.push('/clubs')}
|
|
/>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<FounderPortalShell
|
|
club={club}
|
|
permissions={permissions}
|
|
activeNav={activeNav}
|
|
onNavSelect={(nav: string) => setActiveNav(nav)}
|
|
onSwitchRole={(newRole: ClubRole) => setUserRole(newRole)}
|
|
pendingApplicationsCount={pendingApplications.length}
|
|
upcomingRidesCount={upcomingRides.length}
|
|
>
|
|
<FounderOverview
|
|
club={club}
|
|
metrics={metrics}
|
|
upcomingRides={upcomingRides}
|
|
pendingApplications={pendingApplications}
|
|
activities={activities}
|
|
permissions={permissions}
|
|
onRefresh={loadData}
|
|
/>
|
|
</FounderPortalShell>
|
|
);
|
|
}
|