/* 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.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;