CoolFace
Apppublic

huggingface/ai-deadlines

sourceHugging Faceupdated 2d agoView on Hugging Face
781likes
ConferenceCalendar.tsx164 linesDownload Raw Back to components
1import { useState } from "react";2import { Calendar } from "@/components/ui/calendar";3import { Conference } from "@/types/conference";4import { parseISO, format, parse, startOfMonth } from "date-fns";5 6interface ConferenceCalendarProps {7  conferences: Conference[];8}9 10const ConferenceCalendar = ({ conferences }: ConferenceCalendarProps) => {11  const [selectedDate, setSelectedDate] = useState<Date | undefined>(undefined);12  const [currentMonth, setCurrentMonth] = useState<Date>(new Date());13 14  // Handle month change15  const handleMonthChange = (month: Date) => {16    setCurrentMonth(month);17    setSelectedDate(undefined); // Clear selected date when changing months18  };19 20  // Convert conference dates to calendar events21  const conferenceEvents = conferences.map(conf => {22    let startDate: Date | null = null;23    let endDate: Date | null = null;24    25    try {26      // Parse both start and end dates27      if (conf.start && conf.end) {28        startDate = parseISO(conf.start);29        endDate = parseISO(conf.end);30      } 31      // If no start/end fields, try to parse from date field32      else if (conf.date) {33        const [startStr, endStr] = conf.date.split(/[-–]/).map(d => d.trim());34        35        try {36          // Try parsing start date37          startDate = parse(startStr, 'MMM d, yyyy', new Date()) ||38                     parse(startStr, 'MMMM d, yyyy', new Date()) ||39                     parseISO(startStr);40          41          // Try parsing end date if it exists42          if (endStr) {43            endDate = parse(endStr, 'MMM d, yyyy', new Date()) ||44                     parse(endStr, 'MMMM d, yyyy', new Date()) ||45                     parseISO(endStr);46          } else {47            // If no end date, use start date48            endDate = startDate;49          }50        } catch (error) {51          console.warn(`Failed to parse date range for conference ${conf.title}:`, error);52        }53      }54 55      // Only return event if we successfully parsed both dates56      if (startDate && endDate && isValidDate(startDate) && isValidDate(endDate)) {57        return {58          startDate,59          endDate,60          title: conf.title,61          conference: conf62        };63      }64      return null;65    } catch (error) {66      console.warn(`Failed to parse dates for conference ${conf.title}:`, error);67      return null;68    }69  }).filter(event => event !== null);70 71  // Helper function to check if date is valid72  function isValidDate(date: Date) {73    return date instanceof Date && !isNaN(date.getTime());74  }75 76  // Get events for the selected date77  const getEventsForDate = (date: Date) => {78    if (!date || !isValidDate(date)) return [];79    return conferenceEvents.filter(event => 80      event && event.startDate && event.endDate && 81      date >= event.startDate && date <= event.endDate82    );83  };84 85  // Get events for the current month86  const getEventsForMonth = (date: Date) => {87    const monthStart = startOfMonth(date);88    const nextMonthStart = new Date(date.getFullYear(), date.getMonth() + 1, 1);89    90    return conferenceEvents.filter(event => 91      event && event.startDate && event.endDate &&92      ((event.startDate >= monthStart && event.startDate < nextMonthStart) ||93       (event.endDate >= monthStart && event.endDate < nextMonthStart) ||94       (event.startDate <= monthStart && event.endDate >= nextMonthStart))95    );96  };97 98  // Create footer content99  const footer = (100    <div className="mt-3">101      <h3 className="font-medium">102        Events in {format(currentMonth, 'MMMM yyyy')}:103      </h3>104      {getEventsForMonth(currentMonth).length > 0 ? (105        <ul className="mt-2 space-y-1">106          {getEventsForMonth(currentMonth).map((event, index) => (107            <li key={index} className="text-sm">108              {event.title} ({format(event.startDate, 'MMM d')}-{format(event.endDate, 'MMM d')}) - {109                event.conference.venue || 110                [event.conference.city, event.conference.country].filter(Boolean).join(", ") ||111                "Location TBD"112              }113            </li>114          ))}115        </ul>116      ) : (117        <p className="text-sm text-muted-foreground">No events this month</p>118      )}119      {selectedDate && (120        <div className="mt-4">121          <h3 className="font-medium">122            Events on {format(selectedDate, 'MMMM d, yyyy')}:123          </h3>124          {getEventsForDate(selectedDate).length > 0 ? (125            <ul className="mt-2 space-y-1">126              {getEventsForDate(selectedDate).map((event, index) => (127                <li key={index} className="text-sm">128                  {event.title} - {129                    event.conference.venue || 130                    [event.conference.city, event.conference.country].filter(Boolean).join(", ") ||131                    "Location TBD"132                  }133                </li>134              ))}135            </ul>136          ) : (137            <p className="text-sm text-muted-foreground">No events on this date</p>138          )}139        </div>140      )}141    </div>142  );143 144  return (145    <div className="flex flex-col items-center space-y-4 p-4">146      <Calendar147        mode="single"148        selected={selectedDate}149        onSelect={setSelectedDate}150        footer={footer}151        month={currentMonth}152        onMonthChange={handleMonthChange}153        modifiers={{154          event: (date) => getEventsForDate(date).length > 0155        }}156        modifiersStyles={{157          event: { fontWeight: 'bold', textDecoration: 'underline' }158        }}159      />160    </div>161  );162};163 164export default ConferenceCalendar;