invy/frontend/src/components/EventList.jsx

189 lines
5.9 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { useState, useEffect } from 'react'
import { getEvents, deleteEvent, getEventStats } from '../api/api'
import './EventList.css'
const he = {
myEvents: 'האירועים שלי',
newEvent: '+ אירוע חדש',
noEvents: 'אין לך אירועים עדיין.',
createFirstEvent: 'צור את האירוע הראשון',
manage: 'ניהול',
deleteEvent: 'מחוק אירוע',
sure: 'האם אתה בטוח שברצונך למחוק אירוע זה? פעולה זו לא ניתן לבטל.',
guests: 'אורחים',
confirmed: 'אישרו',
rate: 'אחוז אישור',
loadingEvents: 'טוען אירועים...',
failedLoadEvents: 'נכשל בטעינת אירועים',
failedDeleteEvent: 'נכשל במחיקת אירוע'
}
function EventList({ onEventSelect, onCreateEvent, onManageTemplates }) {
const [events, setEvents] = useState([])
const [loading, setLoading] = useState(true)
const [error, setError] = useState('')
const [stats, setStats] = useState({})
const [refreshTrigger, setRefreshTrigger] = useState(0)
useEffect(() => {
loadEvents()
// Set up page visibility listener to refresh when returning to this page
const handleVisibilityChange = () => {
if (!document.hidden) {
loadEvents()
}
}
document.addEventListener('visibilitychange', handleVisibilityChange)
return () => document.removeEventListener('visibilitychange', handleVisibilityChange)
}, [refreshTrigger])
const loadEvents = async () => {
try {
setLoading(true)
const data = await getEvents()
setEvents(data)
// Load stats for each event
const statsData = {}
for (const event of data) {
try {
statsData[event.id] = await getEventStats(event.id)
} catch (err) {
console.error(`Failed to load stats for event ${event.id}:`, err)
}
}
setStats(statsData)
setError('')
} catch (err) {
setError(he.failedLoadEvents)
console.error(err)
} finally {
setLoading(false)
}
}
const handleDelete = async (eventId, e) => {
e.stopPropagation()
if (!window.confirm(he.sure)) {
return
}
try {
await deleteEvent(eventId)
setEvents(events.filter(e => e.id !== eventId))
} catch (err) {
setError(he.failedDeleteEvent)
console.error(err)
}
}
const formatDate = (dateString) => {
if (!dateString) return 'לא קבוע תאריך'
const date = new Date(dateString)
return date.toLocaleDateString('he-IL', {
year: 'numeric',
month: 'short',
day: 'numeric',
hour: '2-digit',
minute: '2-digit'
})
}
if (loading) {
return <div className="event-list-loading">{he.loadingEvents}</div>
}
return (
<div className="event-list-container">
<div className="event-list-header">
<h1>{he.myEvents}</h1>
<div className="event-list-header-actions">
{onManageTemplates && (
<button onClick={onManageTemplates} className="btn-templates">
📋 תבניות WhatsApp
</button>
)}
<button onClick={onCreateEvent} className="btn-create-event">
{he.newEvent}
</button>
</div>
</div>
{error && <div className="error-message">{error}</div>}
{events.length === 0 ? (
<div className="empty-state">
<p>{he.noEvents}</p>
<button onClick={onCreateEvent} className="btn-create-event-large">
{he.createFirstEvent}
</button>
</div>
) : (
<div className="events-grid">
{events.map(event => {
const eventStats = stats[event.id] || { stats: { total: 0, confirmed: 0 } }
const guestStats = eventStats.stats || { total: 0, confirmed: 0 }
return (
<div
key={event.id}
className="event-card"
onClick={() => onEventSelect(event.id)}
>
<div className="event-card-content">
<h3>{event.name}</h3>
{event.location && (
<p className="event-location">📍 {event.location}</p>
)}
<p className="event-date">📅 {formatDate(event.date)}</p>
<div className="event-stats">
<div className="stat">
<span className="stat-label">{he.guests}</span>
<span className="stat-value">{guestStats.total}</span>
</div>
<div className="stat">
<span className="stat-label">{he.confirmed}</span>
<span className="stat-value">{guestStats.confirmed}</span>
</div>
{guestStats.total > 0 && (
<div className="stat">
<span className="stat-label">{he.rate}</span>
<span className="stat-value">
{Math.round((guestStats.confirmed / guestStats.total) * 100)}%
</span>
</div>
)}
</div>
</div>
<div className="event-card-actions">
<button
className="btn-manage"
onClick={(e) => {
e.stopPropagation()
onEventSelect(event.id)
}}
>
{he.manage}
</button>
<button
className="btn-delete"
onClick={(e) => handleDelete(event.id, e)}
title={he.deleteEvent}
>
🗑
</button>
</div>
</div>
)
})}
</div>
)}
</div>
)
}
export default EventList