import Header from "@/components/Header"; import FilterBar from "@/components/FilterBar"; import ConferenceCard from "@/components/ConferenceCard"; import conferencesData from "@/data/conferences.yml"; import { Conference } from "@/types/conference"; import { useState, useMemo, useEffect } from "react"; import { Switch } from "@/components/ui/switch" import { parseISO, isValid, isPast } from "date-fns"; const Index = () => { const [selectedTags, setSelectedTags] = useState>(new Set()); const [searchQuery, setSearchQuery] = useState(""); const [showPastConferences, setShowPastConferences] = useState(false); const filteredConferences = useMemo(() => { if (!Array.isArray(conferencesData)) { console.error("Conferences data is not an array:", conferencesData); return []; } return conferencesData .filter((conf: Conference) => { // Filter by deadline (past/future) const deadlineDate = conf.deadline && conf.deadline !== 'TBD' ? parseISO(conf.deadline) : null; const isUpcoming = !deadlineDate || !isValid(deadlineDate) || !isPast(deadlineDate); if (!showPastConferences && !isUpcoming) return false; // Filter by tags and search query const matchesTags = selectedTags.size === 0 || (Array.isArray(conf.tags) && conf.tags.some(tag => selectedTags.has(tag))); const matchesSearch = searchQuery === "" || conf.title.toLowerCase().includes(searchQuery.toLowerCase()) || (conf.full_name && conf.full_name.toLowerCase().includes(searchQuery.toLowerCase())); return matchesTags && matchesSearch; }) .sort((a: Conference, b: Conference) => { const dateA = a.deadline && a.deadline !== 'TBD' ? parseISO(a.deadline).getTime() : Infinity; const dateB = b.deadline && b.deadline !== 'TBD' ? parseISO(b.deadline).getTime() : Infinity; return dateA - dateB; }); }, [selectedTags, searchQuery, showPastConferences]); // Update handleTagsChange to handle multiple tags const handleTagsChange = (newTags: Set) => { setSelectedTags(newTags); const searchParams = new URLSearchParams(window.location.search); if (newTags.size > 0) { searchParams.set('tags', Array.from(newTags).join(',')); } else { searchParams.delete('tags'); } const newUrl = `${window.location.pathname}${searchParams.toString() ? `?${searchParams.toString()}` : ''}`; window.history.pushState({}, '', newUrl); }; useEffect(() => { const handleUrlChange = (event: CustomEvent) => { const { tag } = event.detail; // Create new Set with existing tags plus the new one const newTags = new Set(selectedTags); if (newTags.has(tag)) { newTags.delete(tag); } else { newTags.add(tag); } handleTagsChange(newTags); }; window.addEventListener('urlchange', handleUrlChange as EventListener); // Check URL params on mount const params = new URLSearchParams(window.location.search); const tagsParam = params.get('tags'); if (tagsParam) { setSelectedTags(new Set(tagsParam.split(','))); } return () => { window.removeEventListener('urlchange', handleUrlChange as EventListener); }; }, [selectedTags]); // Add selectedTags as dependency if (!Array.isArray(conferencesData)) { return
Loading conferences...
; } return (
{filteredConferences.map((conference: Conference) => ( ))}
); }; export default Index;