import { useEffect, useState, useMemo, useCallback } from 'react'; import { Helmet } from 'react-helmet-async'; import { Link } from 'react-router-dom'; import { api } from '@/lib/api'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; import { Badge } from '@/components/ui/badge'; import { Input } from '@/components/ui/input'; import { Button } from '@/components/ui/button'; import type * as Types from '@/lib/types'; import { formatJalali, formatNumberPersian, formatToman, getThumbUrl } from '@/lib/utils'; function labelPrice(event: Types.EventListItemSchema) { const price = Number(event?.price ?? 0); return price <= 0 ? "رایگان" : formatToman(price); } function modeFa(event_type: Types.EventListItemSchema["event_type"]) { return event_type === "online" ? "آنلاین" : "حضوری"; } function spotsLeft(event: Types.EventListItemSchema) { const cap = Number(event.capacity); const used = Number(event.registration_count); const left = cap - used; return left; } function isAvailable(event: Types.EventListItemSchema) { const now = new Date(); const end = new Date(event.registration_end_date); const timeOk = end.getTime() > now.getTime(); const left = spotsLeft(event); return timeOk && left > 0; } function notAvailableReasonFa(event: Types.EventListItemSchema) { const now = new Date(); const end = new Date(event.registration_end_date); if (end.getTime() <= now.getTime()) return "ثبت‌نام پایان‌یافته"; const left = spotsLeft(event); if (left <= 0) return "ظرفیت تکمیل"; return "غیرقابل ثبت‌نام"; } export default function Events() { const [events, setEvents] = useState([]); const [search, setSearch] = useState(''); const [loading, setLoading] = useState(true); const siteUrl = 'https://east-guilan-ce.ir'; const siteName = 'East Guilan CE'; const pageTitle = `Events | ${siteName}`; const pageDescription = 'Discover upcoming and past events organized by the East Guilan Computer Engineering Association, including workshops, competitions, and community programs.'; const canonicalUrl = `${siteUrl}/events`; const toAbsoluteUrl = (url?: string | null) => { if (!url) return undefined; if (url.startsWith('http')) return url; const normalizedSite = siteUrl.endsWith('/') ? siteUrl.slice(0, -1) : siteUrl; const normalizedPath = url.startsWith('/') ? url.slice(1) : url; return `${normalizedSite}/${normalizedPath}`; }; const ogImage = useMemo(() => { if (!events.length) return `${siteUrl}/favicon.ico`; return toAbsoluteUrl(getThumbUrl(events[0])) ?? `${siteUrl}/favicon.ico`; }, [events]); const listStructuredData = useMemo(() => { if (!events.length) return null; const itemListElement = events.map((eventItem, index) => { const listItem: Record = { '@type': 'ListItem', position: index + 1, url: `${siteUrl}/events/${eventItem.slug}`, name: eventItem.title, description: eventItem.description, startDate: eventItem.start_time, }; if (eventItem.end_time) { listItem.endDate = eventItem.end_time; } const imageUrl = toAbsoluteUrl(getThumbUrl(eventItem)); if (imageUrl) { listItem.image = imageUrl; } const placeName = eventItem.location || eventItem.address; if (placeName) { const place: Record = { '@type': 'Place', name: placeName, }; if (eventItem.address) { place.address = eventItem.address; } listItem.location = place; } return listItem; }); return { '@context': 'https://schema.org', '@type': 'ItemList', name: pageTitle, description: pageDescription, url: canonicalUrl, numberOfItems: events.length, itemListElement, }; }, [events, canonicalUrl, pageDescription, pageTitle]); const loadEvents = useCallback(async () => { try { setLoading(true); const data = await api.getEvents({ search: search || undefined, statuses: ['published', 'completed'], limit: 30, }); setEvents(data); } catch (error) { console.error('Error loading events:', error); } finally { setLoading(false); } }, [search]); useEffect(() => { loadEvents(); }, [loadEvents]); return ( <> {pageTitle} {listStructuredData && ( )}

رویدادها

setSearch(e.target.value)} className="max-w-md" />
{loading ? (

در حال بارگذاری...

) : events.length === 0 ? (

رویدادی یافت نشد

) : (
{events.map((event) => (
{event.title}
{/* این رپر حالا قدِ باقی‌مانده رو می‌گیره */}
{event.title} {modeFa(event.event_type)}
{formatJalali(event.start_time, false)}
ظرفیت رویداد {formatNumberPersian(Number(event?.capacity ?? 0) - Number(event?.registration_count ?? 0))}/{formatNumberPersian(Number(event?.capacity ?? 0))} نفر
هزینه‌ی ثبت‌نام {labelPrice(event)}
{isAvailable(event) ? ( ) : ( )}
))}
)}
); }