/* eslint-disable @next/next/no-img-element */ import React, { useState } from 'react'; import { DateTime } from 'luxon'; import { cn } from "@/lib/utils"; import { Button } from '@/components/ui/button'; import { Badge } from '@/components/ui/badge'; import { Card } from '@/components/ui/card'; import { MapPin, Star, ExternalLink, Navigation, Globe, Phone, ChevronDown, ChevronUp, Clock } from 'lucide-react'; interface Location { lat: number; lng: number; } interface Photo { thumbnail: string; small: string; medium: string; large: string; original: string; caption?: string; } interface Place { name: string; location: Location; place_id: string; vicinity: string; rating?: number; reviews_count?: number; price_level?: string; description?: string; photos?: Photo[]; is_closed?: boolean; next_open_close?: string; type?: string; cuisine?: string; source?: string; phone?: string; website?: string; hours?: string[]; distance?: number; bearing?: string; timezone?: string; } interface PlaceCardProps { place: Place; onClick: () => void; isSelected?: boolean; variant?: 'overlay' | 'list'; } const HoursSection: React.FC<{ hours: string[]; timezone?: string }> = ({ hours, timezone }) => { const [isOpen, setIsOpen] = useState(false); const now = timezone ? DateTime.now().setZone(timezone) : DateTime.now(); const currentDay = now.weekdayLong; if (!hours?.length) return null; // Find today's hours const todayHours = hours.find(h => h.startsWith(currentDay!))?.split(': ')[1] || 'Closed'; return (
{ e.stopPropagation(); setIsOpen(!isOpen); }} className={cn( "mt-4 flex items-center gap-2 cursor-pointer transition-colors", "text-neutral-600 dark:text-neutral-400 hover:text-neutral-900 dark:hover:text-neutral-200" )} >
Today: {todayHours}
{hours.map((timeSlot, idx) => { const [day, hours] = timeSlot.split(': '); const isToday = day === currentDay; return (
{day} {hours}
); })}
); }; const PlaceCard: React.FC = ({ place, onClick, isSelected = false, variant = 'list' }) => { const [showHours, setShowHours] = useState(false); const isOverlay = variant === 'overlay'; const formatTime = (timeStr: string | undefined, timezone: string | undefined): string => { if (!timeStr || !timezone) return ''; const hours = Math.floor(parseInt(timeStr) / 100); const minutes = parseInt(timeStr) % 100; return DateTime.now() .setZone(timezone) .set({ hour: hours, minute: minutes }) .toFormat('h:mm a'); }; const getStatusDisplay = (): { text: string; color: string } | null => { if (!place.timezone || place.is_closed === undefined || !place.next_open_close) { return null; } const timeStr = formatTime(place.next_open_close, place.timezone); if (place.is_closed) { return { text: `Closed · Opens ${timeStr}`, color: 'red-600 dark:text-red-400' }; } return { text: `Open · Closes ${timeStr}`, color: 'green-600 dark:text-green-400' }; }; const statusDisplay = getStatusDisplay(); const cardContent = ( <>
{/* Image with Price Badge */} {place.photos?.[0]?.medium && (
{place.name} {place.price_level && (
{place.price_level}
)}
)}

{place.name}

{/* Rating & Reviews */} {place.rating && (
{place.rating.toFixed(1)} {place.reviews_count && ( ({place.reviews_count}) )}
)} {/* Status */} {statusDisplay && (
{statusDisplay.text}
)} {/* Address */} {place.vicinity && (
{place.vicinity}
)}
{/* Action Buttons */}
{place.phone && ( )} {place.website && ( )} {place.place_id && !isOverlay && ( )}
{/* Hours Section - Only show if has hours */} {place.hours && place.hours.length > 0 && ( )} ); if (isOverlay) { return (
{cardContent}
); } return ( {cardContent} ); }; export default PlaceCard;