- Refactored Calendar.tsx into modular component structure - Added glassmorphism theming with CSS custom properties - Implemented reusable calendar subcomponents: - CalendarGrid: Month view with improved day/event display - CalendarHeader: Navigation and view controls - EventList: List view for events - TrendingEvents: Location-based trending events - UpcomingEvents: Quick upcoming events preview - Enhanced responsive design for mobile devices - Added Playwright testing framework for automated testing - Updated Docker development commands in CLAUDE.md - Improved accessibility and user experience 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
78 lines
2.9 KiB
TypeScript
78 lines
2.9 KiB
TypeScript
import React from 'react';
|
|
import { EventListProps } from './types';
|
|
import { groupEventsByDate, sortEventsByDate, getFutureEvents, getRelativeDateText } from './utils';
|
|
import { EventCard } from './EventCard';
|
|
|
|
/**
|
|
* Event list component showing events grouped by date
|
|
*/
|
|
export const EventList: React.FC<EventListProps> = ({
|
|
events,
|
|
onEventClick,
|
|
showDistance = false
|
|
}) => {
|
|
const futureEvents = getFutureEvents(events);
|
|
const sortedEvents = sortEventsByDate(futureEvents);
|
|
const groupedEvents = groupEventsByDate(sortedEvents);
|
|
const sortedDates = Object.keys(groupedEvents).sort((a, b) => new Date(a).getTime() - new Date(b).getTime());
|
|
|
|
if (sortedEvents.length === 0) {
|
|
return (
|
|
<div className="p-3 md:p-6">
|
|
<div className="text-center py-16">
|
|
<div className="w-24 h-24 mx-auto mb-6 rounded-full flex items-center justify-center"
|
|
style={{ background: 'linear-gradient(to bottom right, var(--ui-bg-secondary), var(--ui-bg-elevated))' }}>
|
|
<svg className="w-12 h-12" style={{ color: 'var(--ui-text-muted)' }} fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="1.5" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"></path>
|
|
</svg>
|
|
</div>
|
|
<h3 className="text-xl font-semibold mb-2" style={{ color: 'var(--ui-text-primary)' }}>
|
|
No Upcoming Events
|
|
</h3>
|
|
<p style={{ color: 'var(--ui-text-secondary)' }}>
|
|
Check back later for new events or adjust your filters.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div className="p-3 md:p-6">
|
|
<div className="space-y-6">
|
|
{sortedDates.map(dateKey => {
|
|
const date = new Date(dateKey);
|
|
const dateEvents = groupedEvents[dateKey];
|
|
const dateText = getRelativeDateText(date);
|
|
|
|
return (
|
|
<div key={dateKey} className="animate-fade-in-up">
|
|
{/* Date Header */}
|
|
<div className="mb-4">
|
|
<h3 className="text-lg font-semibold mb-1" style={{ color: 'var(--ui-text-primary)' }}>
|
|
{dateText}
|
|
</h3>
|
|
<div className="w-16 h-1 rounded-full"
|
|
style={{ background: 'linear-gradient(to right, rgb(37, 99, 235), rgb(147, 51, 234))' }}>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Events for this date */}
|
|
<div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
|
|
{dateEvents.map(event => (
|
|
<EventCard
|
|
key={event.id}
|
|
event={event}
|
|
onClick={onEventClick}
|
|
variant="list"
|
|
showDistance={showDistance}
|
|
/>
|
|
))}
|
|
</div>
|
|
</div>
|
|
);
|
|
})}
|
|
</div>
|
|
</div>
|
|
);
|
|
}; |