'use client'; import React, { useState, useMemo } from 'react'; import Link from 'next/link'; import { Club, ClubUpcomingRide, UserPortalPermissions } from './types'; import { EmptyState } from './empty-state'; import { ClubRideCard } from './club-ride-card'; interface FounderRidesProps { club: Club; permissions: UserPortalPermissions; upcomingRides: ClubUpcomingRide[]; pastRides: ClubUpcomingRide[]; isLoading?: boolean; error?: string | null; onPlanRide?: () => void; onManageRide?: (rideId: string) => void; onViewRoster?: (rideId: string) => void; onViewRoute?: (routeId?: string) => void; } type TabType = 'upcoming' | 'completed' | 'all'; export function FounderRides({ club, permissions, upcomingRides, pastRides, isLoading = false, error = null, onPlanRide, onManageRide, onViewRoster, onViewRoute, }: FounderRidesProps) { const [activeTab, setActiveTab] = useState('upcoming'); const [searchQuery, setSearchQuery] = useState(''); const [paceFilter, setPaceFilter] = useState('all'); const allRides = useMemo(() => { return [...upcomingRides, ...pastRides]; }, [upcomingRides, pastRides]); // Available pace options from actual data const paceOptions = useMemo(() => { const paces = new Set(); for (const r of allRides) { if (r.paceClassification) paces.add(r.paceClassification); } return Array.from(paces); }, [allRides]); // Tab-filtered rides const tabRides = useMemo(() => { if (activeTab === 'upcoming') return upcomingRides; if (activeTab === 'completed') return pastRides; return allRides; }, [activeTab, upcomingRides, pastRides, allRides]); // Search & pace filtered rides const filteredRides = useMemo(() => { const q = searchQuery.trim().toLowerCase(); return tabRides.filter((ride) => { const matchesSearch = !q || ride.title.toLowerCase().includes(q) || ride.rideIdentifier.toLowerCase().includes(q) || ride.roadCaptainName.toLowerCase().includes(q) || (ride.roadCaptainHandle && ride.roadCaptainHandle.toLowerCase().includes(q)) || (ride.description && ride.description.toLowerCase().includes(q)); const matchesPace = paceFilter === 'all' || ride.paceClassification === paceFilter; return matchesSearch && matchesPace; }); }, [tabRides, searchQuery, paceFilter]); // Metrics summary const upcomingCount = upcomingRides.length; const confirmedRidersTotal = upcomingRides.reduce((sum, r) => sum + r.confirmedCount, 0); const completedCount = pastRides.length; if (isLoading) { return (
{[1, 2, 3, 4].map((i) => (
))}
); } if (error) { return (
error

Unable to Load Club Rides

{error}

); } return (
{/* Header Section */}

Club Rides

{upcomingCount} Scheduled

Schedule, coordinate, and review group rides and road captain assignments.

groups Live Pack Radar & Hub
add_road Plan Club Ride SOON
{/* Architecture & Privacy Notice Banner */}
shield

Live location is shared only with eligible ride participants while sharing is enabled. Club membership alone never grants access to rider location.

Discovery Pending: GroupRide.clubId is live, but broad Founder Portal discovery remains disabled until mutual-block privacy can be preserved.

{/* Metrics Summary Strip (4 Cards) */}
{/* Card 1: Upcoming Rides */}
UPCOMING RIDES route
{upcomingCount}
Active & scheduled
{/* Card 2: Confirmed Riders */}
CONFIRMED RIDERS group
{confirmedRidersTotal}
Across upcoming rides
{/* Card 3: Completed Rides */}
COMPLETED RIDES task_alt
{completedCount}
Recorded club events
{/* Card 4: Club Miles */}
CLUB MILES lock
--
Completed Club Rides only
Calculated from eligible completed Club Rides. Private rider mileage is not automatically included.
{/* Tabs & Search Toolbar */}
{/* Navigation Tabs */}
{/* Search & Pace Filter */}
{/* Search Input */}
search setSearchQuery(e.target.value)} placeholder="Search rides or captains..." className="w-full h-8 pl-8 pr-3 rounded-lg bg-surface-container-low border border-brand-border/60 text-white placeholder:text-slate-500 font-body text-xs focus:outline-none focus:border-brand-cyan transition-colors" aria-label="Search rides or road captains" /> {searchQuery && ( )}
{/* Pace Filter Dropdown */} {paceOptions.length > 0 && ( )}
{/* Ride List */} {filteredRides.length === 0 ? ( ) : (
{filteredRides.map((ride) => ( ))}
)}
); }