import React, { useMemo } from 'react' import { useTripStore } from '../../store/tripStore' import { useSettingsStore } from '../../store/settingsStore' import { useTranslation } from '../../i18n' import { MapPin, Clock, Calendar, Users, Sparkles } from 'lucide-react' function formatTime(timeStr, is12h) { if (!timeStr) return '' const [h, m] = timeStr.split(':').map(Number) if (is12h) { const period = h >= 12 ? 'PM' : 'AM' const h12 = h === 0 ? 12 : h > 12 ? h - 12 : h return `${h12}:${String(m).padStart(2, '0')} ${period}` } return `${String(h).padStart(2, '0')}:${String(m).padStart(2, '0')}` } function formatDayLabel(date, t, locale) { const d = new Date(date + 'T00:00:00') const now = new Date() const tomorrow = new Date(); tomorrow.setDate(now.getDate() + 1) if (d.toDateString() === now.toDateString()) return t('collab.whatsNext.today') || 'Today' if (d.toDateString() === tomorrow.toDateString()) return t('collab.whatsNext.tomorrow') || 'Tomorrow' return d.toLocaleDateString(locale || undefined, { weekday: 'short', day: 'numeric', month: 'short' }) } interface TripMember { id: number username: string avatar_url?: string | null } interface WhatsNextWidgetProps { tripMembers?: TripMember[] } export default function WhatsNextWidget({ tripMembers = [] }: WhatsNextWidgetProps) { const { days, assignments } = useTripStore() const { t, locale } = useTranslation() const is12h = useSettingsStore(s => s.settings.time_format) === '12h' const upcoming = useMemo(() => { const now = new Date() const nowDate = now.toISOString().split('T')[0] const nowTime = `${String(now.getHours()).padStart(2, '0')}:${String(now.getMinutes()).padStart(2, '0')}` const items = [] for (const day of (days || [])) { if (!day.date) continue const dayAssignments = assignments[String(day.id)] || [] for (const a of dayAssignments) { if (!a.place) continue // Include: today (future times) + all future days const isFutureDay = day.date > nowDate const isTodayFuture = day.date === nowDate && (!a.place.place_time || a.place.place_time >= nowTime) if (isFutureDay || isTodayFuture) { items.push({ id: a.id, name: a.place.name, time: a.place.place_time, endTime: a.place.end_time, date: day.date, dayTitle: day.title, category: a.place.category, participants: (a.participants && a.participants.length > 0) ? a.participants : tripMembers.map(m => ({ user_id: m.id, username: m.username, avatar: m.avatar })), address: a.place.address, }) } } } items.sort((a, b) => { const da = a.date + (a.time || '99:99') const db = b.date + (b.time || '99:99') return da.localeCompare(db) }) return items.slice(0, 8) }, [days, assignments, tripMembers]) return (
{/* Header */}
{t('collab.whatsNext.title') || "What's Next"}
{/* List */}
{upcoming.length === 0 ? (
{t('collab.whatsNext.empty')}
{t('collab.whatsNext.emptyHint')}
) : (
{upcoming.map((item, idx) => { const prevItem = upcoming[idx - 1] const showDayHeader = !prevItem || prevItem.date !== item.date return ( {showDayHeader && (
{formatDayLabel(item.date, t, locale)} {item.dayTitle ? ` — ${item.dayTitle}` : ''}
)}
e.currentTarget.style.background = 'var(--bg-hover)'} onMouseLeave={e => e.currentTarget.style.background = 'var(--bg-secondary)'} > {/* Time column */}
{item.time ? formatTime(item.time, is12h) : 'TBD'} {item.endTime && ( <> {t('collab.whatsNext.until') || 'bis'} {formatTime(item.endTime, is12h)} )}
{/* Divider */}
{/* Details */}
{item.name}
{item.address && (
{item.address}
)} {/* Participants */} {item.participants.length > 0 && (
{item.participants.map(p => (
{p.avatar ? : p.username?.[0]?.toUpperCase() }
{p.username}
))}
)}
) })}
)}
) }