All files / src/components/public/Event EventLogistics.tsx

100% Statements 6/6
86.36% Branches 19/22
100% Functions 1/1
100% Lines 6/6

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91                            1x 11x   11x     11x 11x   11x                                                                                                                                      
/**
 * EventLogistics Component (Story 4.1.3)
 * Displays event logistics information with icons
 */
 
import { Calendar, Clock, MapPin, Users, Tag } from 'lucide-react';
import { format } from 'date-fns';
import type { EventDetail } from '@/types/event.types';
import { useTranslation } from 'react-i18next';
 
interface EventLogisticsProps {
  event: EventDetail;
}
 
export const EventLogistics = ({ event }: EventLogisticsProps) => {
  const { t } = useTranslation('events');
  // Parse date string to Date object
  const eventDate = event.date ? new Date(event.date) : null;
 
  // Use typicalStartTime and typicalEndTime from event type (not event.date hour)
  const startTime = event.typicalStartTime || null;
  const endTime = event.typicalEndTime || null;
 
  return (
    <div className="grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-4">
      {/* Date */}
      {eventDate && (
        <div className="flex items-start gap-3">
          <Calendar className="h-5 w-5 text-primary mt-1 flex-shrink-0" />
          <div>
            <p className="text-sm text-zinc-400">{t('common:labels.date')}</p>
            <p className="text-lg font-light text-zinc-100">{format(eventDate, 'PPP')}</p>
          </div>
        </div>
      )}
 
      {/* Time */}
      {startTime && (
        <div className="flex items-start gap-3">
          <Clock className="h-5 w-5 text-primary mt-1 flex-shrink-0" />
          <div>
            <p className="text-sm text-zinc-400">{t('public.logistics.time')}</p>
            <p className="text-lg font-light text-zinc-100">
              {startTime}h - {endTime}h
            </p>
          </div>
        </div>
      )}
 
      {/* Location */}
      {event.venueName && (
        <div className="flex items-start gap-3">
          <MapPin className="h-5 w-5 text-primary mt-1 flex-shrink-0" />
          <div>
            <p className="text-sm text-zinc-400">{t('public.logistics.location')}</p>
            <p className="text-lg font-light text-zinc-100">{event.venueName}</p>
            {event.venueAddress && (
              <p className="text-sm text-zinc-500 mt-1">{event.venueAddress.split(',')[0]}</p>
            )}
          </div>
        </div>
      )}
 
      {/* Capacity — show registrationCapacity only (venueCapacity is organizer-internal) */}
      {event.registrationCapacity != null && (
        <div className="flex items-start gap-3">
          <Users className="h-5 w-5 text-primary mt-1 flex-shrink-0" />
          <div>
            <p className="text-sm text-zinc-400">{t('public.logistics.capacity')}</p>
            <p className="text-lg font-light text-zinc-100">
              {(event.confirmedCount || 0) + (event.waitlistCount || 0)} /{' '}
              {event.registrationCapacity}
            </p>
          </div>
        </div>
      )}
 
      {/* Topic */}
      {event.topic?.name && (
        <div className="flex items-start gap-3">
          <Tag className="h-5 w-5 text-primary mt-1 flex-shrink-0" />
          <div>
            <p className="text-sm text-zinc-400">{t('public.logistics.topic', 'Topic')}</p>
            <p className="text-lg font-light text-zinc-100">{event.topic.name}</p>
          </div>
        </div>
      )}
    </div>
  );
};