MotorSignal-App/website/app/clubs/[clubId]/manage/page.tsx

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>
);
}