MotorSignal-App/website/components/group-rides/ride-details-modal.tsx

193 lines
8.1 KiB
TypeScript

'use client';
import React, { useEffect } from 'react';
import { GroupRideSummary } from './types';
interface RideDetailsModalProps {
isOpen: boolean;
ride: GroupRideSummary | null;
onClose: () => void;
onEdit?: (ride: GroupRideSummary) => void;
onRequestSlot?: (rideId: string) => void;
}
export function RideDetailsModal({
isOpen,
ride,
onClose,
onEdit,
onRequestSlot,
}: RideDetailsModalProps) {
useEffect(() => {
function handleKeyDown(e: KeyboardEvent) {
if (e.key === 'Escape') onClose();
}
if (isOpen) {
document.addEventListener('keydown', handleKeyDown);
}
return () => document.removeEventListener('keydown', handleKeyDown);
}, [isOpen, onClose]);
if (!isOpen || !ride) return null;
const isFull = ride.participantCount >= ride.participantLimit;
const isJoined = ride.userStatus === 'joined' || ride.isOrganizer;
return (
<div
role="dialog"
aria-modal="true"
aria-labelledby="ride-details-title"
className="fixed inset-0 z-50 flex items-center justify-center p-4 bg-slate-950/80 backdrop-blur-md overflow-y-auto animate-in fade-in duration-200"
onClick={(e) => {
if (e.target === e.currentTarget) onClose();
}}
>
<div className="relative w-full max-w-lg bg-surface-container-low border border-outline-variant/40 rounded-2xl p-6 shadow-2xl space-y-5 my-8">
{/* Header */}
<div className="flex items-center justify-between pb-3 border-b border-outline-variant/20">
<div className="flex items-center gap-2.5">
<div className="w-10 h-10 rounded-xl bg-primary-container/20 text-primary-container flex items-center justify-center">
<span className="material-symbols-outlined text-[24px]">sports_motorsports</span>
</div>
<div>
<h2 id="ride-details-title" className="font-headline text-lg font-bold text-on-surface">
{ride.title}
</h2>
<span className="font-mono text-xs text-primary-container font-semibold">
{ride.discipline || 'Sport / Canyon'} • {ride.paceClassification}
</span>
</div>
</div>
<button
onClick={onClose}
className="w-8 h-8 rounded-lg bg-surface-container hover:bg-surface-container-high text-on-surface-variant flex items-center justify-center transition cursor-pointer"
aria-label="Close dialog"
>
<span className="material-symbols-outlined text-[18px]">close</span>
</button>
</div>
{/* Status & Code Row */}
<div className="flex items-center justify-between p-3 rounded-xl bg-surface-container border border-outline-variant/20 text-xs font-mono">
<div className="flex items-center gap-2">
<span className="text-on-surface-variant">Status:</span>
<span className="px-2 py-0.5 rounded bg-primary-container/20 text-primary-container font-bold uppercase text-[10px]">
{ride.status || 'scheduled'}
</span>
</div>
{ride.rideCode && (
<div className="flex items-center gap-1.5">
<span className="text-on-surface-variant">Code:</span>
<span className="px-2 py-0.5 rounded bg-surface-container-highest text-secondary-fixed font-bold">
{ride.rideCode}
</span>
</div>
)}
</div>
{/* Detailed Metadata Grid */}
<div className="space-y-3 text-xs font-mono">
<div className="p-3 rounded-xl bg-surface-container/60 border border-outline-variant/20 space-y-2">
<div className="flex items-center justify-between">
<span className="text-on-surface-variant">Date &amp; Time:</span>
<span className="text-on-surface font-semibold">
{ride.scheduledDate} • {ride.scheduledTime}
</span>
</div>
<div className="flex items-center justify-between">
<span className="text-on-surface-variant">Region:</span>
<span className="text-on-surface">{ride.region}</span>
</div>
<div className="flex items-center justify-between">
<span className="text-on-surface-variant">Total Distance:</span>
<span className="text-on-surface">{ride.distance}</span>
</div>
<div className="flex items-center justify-between">
<span className="text-on-surface-variant">Formation Profile:</span>
<span className="text-secondary-fixed">{ride.formationProfile}</span>
</div>
<div className="flex items-center justify-between">
<span className="text-on-surface-variant">Rider Roster:</span>
<span className="text-on-surface font-bold">
{ride.participantCount} / {ride.participantLimit} Riders
</span>
</div>
<div className="flex items-center justify-between">
<span className="text-on-surface-variant">Road Captain / Lead:</span>
<span className="text-primary-container font-bold">{ride.leadHandle}</span>
</div>
</div>
{/* Meeting Point */}
<div>
<span className="block text-[11px] text-outline font-semibold uppercase mb-1">
Meeting Point &amp; Rally Location
</span>
<div className="p-3 rounded-xl bg-surface-container/80 border border-outline-variant/20 text-on-surface">
{ride.meetingPoint}
</div>
</div>
{/* Route Preview Snippet */}
<div>
<span className="block text-[11px] text-outline font-semibold uppercase mb-1">
Route Preview Waypoints
</span>
<div className="p-3 rounded-xl bg-surface-container/80 border border-outline-variant/20 text-primary-fixed-dim">
{ride.routeSnippet || 'Waypoints synchronized via MotorSignal GNSS Multi-Band Mesh.'}
</div>
</div>
{/* Description & Safety Briefing */}
<div>
<span className="block text-[11px] text-outline font-semibold uppercase mb-1">
Briefing &amp; Safety Protocol
</span>
<p className="p-3 rounded-xl bg-surface-container/80 border border-outline-variant/20 font-body text-xs text-on-surface-variant leading-relaxed">
{ride.description}
</p>
</div>
</div>
{/* Footer Actions */}
<div className="flex items-center justify-end gap-3 pt-3 border-t border-outline-variant/20">
<button
type="button"
onClick={onClose}
className="px-4 py-2 rounded-xl bg-surface-container hover:bg-surface-container-high text-xs font-semibold text-on-surface transition cursor-pointer"
>
Close
</button>
{ride.isOrganizer && onEdit && (
<button
type="button"
onClick={() => {
onClose();
onEdit(ride);
}}
className="px-4 py-2 rounded-xl bg-primary-container text-on-primary-container text-xs font-bold hover:shadow-lg transition cursor-pointer flex items-center gap-1.5"
>
<span className="material-symbols-outlined text-[16px]">edit</span>
<span>Edit Ride</span>
</button>
)}
{!ride.isOrganizer && !isJoined && onRequestSlot && !isFull && (
<button
type="button"
onClick={() => {
onClose();
onRequestSlot(ride.id);
}}
className="px-4 py-2 rounded-xl bg-gradient-to-r from-primary-container to-primary-fixed text-on-primary-container text-xs font-bold hover:shadow-lg transition cursor-pointer flex items-center gap-1.5"
>
<span className="material-symbols-outlined text-[16px]">how_to_reg</span>
<span>Join Pack Run</span>
</button>
)}
</div>
</div>
</div>
);
}