'use client';
import React from 'react';
import Link from 'next/link';
import { useParams } from 'next/navigation';
import { ClubUpcomingRide, UserPortalPermissions } from './types';
import { EmptyState } from './empty-state';
interface UpcomingRidesSectionProps {
rides: ClubUpcomingRide[];
permissions: UserPortalPermissions;
clubId?: string;
onPlanRide?: () => void;
onManageRide?: (rideId: string) => void;
onViewRoster?: (rideId: string) => void;
onViewRoute?: (routeId?: string) => void;
}
export function ClubRideCard({
ride,
permissions,
clubId,
onManageRide,
onViewRoster,
onViewRoute,
}: {
ride: ClubUpcomingRide;
permissions: UserPortalPermissions;
clubId?: string;
onManageRide?: (rideId: string) => void;
onViewRoster?: (rideId: string) => void;
onViewRoute?: (routeId?: string) => void;
}) {
const params = useParams();
const targetClubId = clubId || (typeof params?.clubId === 'string' ? params.clubId : '');
const capacityPercent = ride.capacity ? Math.min(100, Math.round((ride.confirmedCount / ride.capacity) * 100)) : 75;
return (
{/* Top Metadata Row */}
{ride.scheduledStartAt}
•
Ride ID: {ride.rideIdentifier}
{ride.title}
{ride.paceClassification}
{/* Attributes Row */}
Distance
{ride.distanceMiles ? `${ride.distanceMiles} mi` : '--'}
Duration
{ride.durationString ?? '--'}
Pace Classification
{ride.paceClassification}
{/* Roster & Road Captain Details */}
Riders: {ride.confirmedCount} going
{ride.pendingCount > 0 ? (
{ride.pendingCount} requests pending
) : ride.capacity ? (
{Math.max(0, ride.capacity - ride.confirmedCount)} open spots
) : null}
0 ? 'bg-amber-400' : 'bg-brand-cyan'
}`}
style={{ width: `${capacityPercent}%` }}
/>
Road Captain:
{ride.roadCaptainName}
{ride.roadCaptainMotorcycle && (
({ride.roadCaptainMotorcycle})
)}
{ride.sweepStatus === 'needs_assignment' ? (
Sweep: Needs Assignment
) : ride.briefingTime ? (
Briefing: {ride.briefingTime}
) : null}
{/* Section 15: Verbatim Live Location Privacy Policy Notice */}
info
Live location is shared only with eligible ride participants while sharing is enabled. Club membership alone never grants access to rider location.
{/* Actions */}
{permissions.canPlanRides ? (
onManageRide?.(ride.id)}
className="h-9 px-3.5 rounded-xl bg-primary-container text-on-primary-container font-body text-xs font-bold hover:brightness-110 shadow-sm transition-all cursor-pointer"
>
Manage Ride
) : (
onViewRoster?.(ride.id)}
className="h-9 px-3.5 rounded-xl bg-surface-container border border-brand-border/60 text-slate-200 font-body text-xs font-medium hover:bg-surface-container-high transition-colors cursor-pointer"
>
View Ride
)}
View Roster ({ride.confirmedCount})
onViewRoute?.(ride.routeId ?? undefined)}
className="h-9 px-3.5 rounded-xl bg-surface-container border border-brand-border/60 text-slate-300 hover:text-white font-body text-xs flex items-center gap-1.5 transition-colors cursor-pointer"
>
map
View Route
);
}
export function UpcomingRidesSection({
rides,
permissions,
clubId,
onPlanRide,
onManageRide,
onViewRoster,
onViewRoute,
}: UpcomingRidesSectionProps) {
const params = useParams();
const targetClubId = clubId || (typeof params?.clubId === 'string' ? params.clubId : '');
return (
Upcoming Club Rides
Scheduled Club Rides, routes, participants, and ride assignments.
{rides.length > 0 && (
Full Ride Schedule
schedule
)}
{rides.length === 0 ? (
) : (
{rides.map((ride) => (
))}
)}
);
}