| // src/components/networking/EventCard.tsx | |
| import { Calendar, Clock, MapPin, Video, Users, Tag, ExternalLink, Play, Bell, BellOff } from "lucide-react"; | |
| import type { Event } from "@/types/networking"; | |
| import { useNavigate } from "react-router-dom"; | |
| import { useState } from "react"; | |
| interface EventCardProps { | |
| event: Event; | |
| onRSVP?: (eventId: string, status: "yes" | "maybe" | "no") => void; | |
| } | |
| export function EventCard({ event, onRSVP }: EventCardProps) { | |
| const navigate = useNavigate(); | |
| const [rsvp, setRsvp] = useState<"yes" | "maybe" | "no" | null>(null); | |
| const handleRSVP = (status: "yes" | "maybe" | "no") => { | |
| setRsvp(status); | |
| onRSVP?.(event.id, status); | |
| }; | |
| const isPast = new Date(event.scheduledEnd) < new Date(); | |
| return ( | |
| <div className={`glass rounded-2xl border border-white/20 dark:border-white/10 p-4 transition ${event.isLive ? "ring-2 ring-red-500 animate-pulse" : ""}`}> | |
| <div className="flex items-start justify-between"> | |
| <div className="flex-1"> | |
| <div className="flex items-center gap-2 mb-1"> | |
| <span className="text-[10px] px-2 py-0.5 rounded-full bg-primary/10 text-primary capitalize">{event.type.replace(/_/g, " ")}</span> | |
| {event.isLive && <span className="text-[10px] px-2 py-0.5 rounded-full bg-red-500 text-white animate-pulse">LIVE</span>} | |
| </div> | |
| <h3 className="font-bold text-lg cursor-pointer hover:text-primary" onClick={() => navigate(`/events/${event.id}`)}>{event.title}</h3> | |
| <p className="text-sm text-gray-500 mt-1">{event.hostName}</p> | |
| <div className="flex flex-wrap items-center gap-3 mt-2 text-xs text-gray-500"> | |
| <span className="flex items-center gap-1"><Calendar className="w-3.5 h-3.5"/> {new Date(event.scheduledStart).toLocaleDateString()}</span> | |
| <span className="flex items-center gap-1"><Clock className="w-3.5 h-3.5"/> {new Date(event.scheduledStart).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" })}</span> | |
| {event.isOnline ? <span className="flex items-center gap-1"><Video className="w-3.5 h-3.5"/> Online</span> : <span className="flex items-center gap-1"><MapPin className="w-3.5 h-3.5"/> {event.location}</span>} | |
| <span className="flex items-center gap-1"><Users className="w-3.5 h-3.5"/> {event.attendanceCount}</span> | |
| </div> | |
| </div> | |
| <div className="flex flex-col gap-2"> | |
| {!isPast && ( | |
| <> | |
| <button onClick={() => handleRSVP("yes")} className={`btn btn-xs ${rsvp === "yes" ? "btn-primary" : "btn-ghost"}`}>Going</button> | |
| <button onClick={() => handleRSVP("maybe")} className={`btn btn-xs ${rsvp === "maybe" ? "btn-primary" : "btn-ghost"}`}>Maybe</button> | |
| </> | |
| )} | |
| {event.streamUrl && <a href={event.streamUrl} target="_blank" className="btn btn-ghost btn-xs gap-1"><ExternalLink className="w-3 h-3"/> Join</a>} | |
| {event.recordingUrl && <a href={event.recordingUrl} target="_blank" className="btn btn-ghost btn-xs gap-1"><Play className="w-3 h-3"/> Recording</a>} | |
| </div> | |
| </div> | |
| {event.tags.length > 0 && <div className="flex flex-wrap gap-1 mt-3">{event.tags.map(t => <span key={t} className="text-[9px] bg-white/10 px-2 py-0.5 rounded-full">{t}</span>)}</div>} | |
| </div> | |
| ); | |
| } |
Xet Storage Details
- Size:
- 3.34 kB
- Xet hash:
- 57e4ae34b39df479deb7706e52258a0ab8ee2e00de74c0ed0539e3eaaa382b29
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.