File size: 4,638 Bytes
2906af3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
import { useState } from "react";
import { Calendar } from "@/components/ui/calendar";
import { Conference } from "@/types/conference";
import { parseISO, format, parse, startOfMonth } from "date-fns";

interface ConferenceCalendarProps {
  conferences: Conference[];
}

const ConferenceCalendar = ({ conferences }: ConferenceCalendarProps) => {
  const [selectedDate, setSelectedDate] = useState<Date | undefined>(undefined);
  const [currentMonth, setCurrentMonth] = useState<Date>(new Date());

  // Handle month change
  const handleMonthChange = (month: Date) => {
    setCurrentMonth(month);
    setSelectedDate(undefined); // Clear selected date when changing months
  };

  // Convert conference dates to calendar events
  const conferenceEvents = conferences.map(conf => {
    let startDate: Date | null = null;
    
    try {
      // First try to use the start field if it exists
      if (conf.start) {
        startDate = parseISO(conf.start);
      } 
      // If no start field or it failed, try to parse the date field
      else if (conf.date) {
        // Handle various date formats
        const dateStr = conf.date.split('–')[0].split('-')[0].trim(); // Get first date in range
        
        // Try different date formats
        try {
          // Try "MMM d, yyyy" format (e.g., "Feb 28, 2025")
          startDate = parse(dateStr, 'MMM d, yyyy', new Date());
        } catch {
          try {
            // Try "MMMM d, yyyy" format (e.g., "February 28, 2025")
            startDate = parse(dateStr, 'MMMM d, yyyy', new Date());
          } catch {
            // If all else fails, try ISO format
            startDate = parseISO(dateStr);
          }
        }
      }

      // Only return event if we successfully parsed a date
      if (startDate && isValidDate(startDate)) {
        return {
          date: startDate,
          title: conf.title,
          conference: conf
        };
      }
      return null;
    } catch (error) {
      console.warn(`Failed to parse date for conference ${conf.title}:`, error);
      return null;
    }
  }).filter(event => event !== null); // Remove any null events

  // Helper function to check if date is valid
  function isValidDate(date: Date) {
    return date instanceof Date && !isNaN(date.getTime());
  }

  // Get events for the selected date
  const getEventsForDate = (date: Date) => {
    if (!date || !isValidDate(date)) return [];
    return conferenceEvents.filter(event => 
      event && event.date && 
      format(event.date, 'yyyy-MM-dd') === format(date, 'yyyy-MM-dd')
    );
  };

  // Get events for the current month
  const getEventsForMonth = (date: Date) => {
    return conferenceEvents.filter(event => 
      event && event.date && 
      format(event.date, 'yyyy-MM') === format(date, 'yyyy-MM')
    );
  };

  // Create footer content
  const footer = (
    <div className="mt-3">
      <h3 className="font-medium">
        Events in {format(currentMonth, 'MMMM yyyy')}:
      </h3>
      {getEventsForMonth(currentMonth).length > 0 ? (
        <ul className="mt-2 space-y-1">
          {getEventsForMonth(currentMonth).map((event, index) => (
            <li key={index} className="text-sm">
              {event.title} ({format(event.date, 'MMM d')}) - {event.conference.place}
            </li>
          ))}
        </ul>
      ) : (
        <p className="text-sm text-muted-foreground">No events this month</p>
      )}
      {selectedDate && (
        <div className="mt-4">
          <h3 className="font-medium">
            Events on {format(selectedDate, 'MMMM d, yyyy')}:
          </h3>
          {getEventsForDate(selectedDate).length > 0 ? (
            <ul className="mt-2 space-y-1">
              {getEventsForDate(selectedDate).map((event, index) => (
                <li key={index} className="text-sm">
                  {event.title} - {event.conference.place}
                </li>
              ))}
            </ul>
          ) : (
            <p className="text-sm text-muted-foreground">No events on this date</p>
          )}
        </div>
      )}
    </div>
  );

  return (
    <div className="flex flex-col items-center space-y-4 p-4">
      <Calendar
        mode="single"
        selected={selectedDate}
        onSelect={setSelectedDate}
        footer={footer}
        month={currentMonth}
        onMonthChange={handleMonthChange}
        modifiers={{
          event: (date) => getEventsForDate(date).length > 0
        }}
        modifiersStyles={{
          event: { fontWeight: 'bold', textDecoration: 'underline' }
        }}
      />
    </div>
  );
};

export default ConferenceCalendar;