File size: 5,136 Bytes
64b8b1b
 
 
 
 
 
 
 
 
 
 
67688f8
5251633
67688f8
 
5251633
 
67688f8
5251633
 
 
 
 
 
 
 
 
 
 
67688f8
 
64b8b1b
 
 
 
67688f8
 
 
 
 
64b8b1b
67688f8
 
64b8b1b
 
 
 
 
 
 
 
 
67688f8
 
 
 
 
 
 
64b8b1b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
67688f8
 
64b8b1b
 
67688f8
 
64b8b1b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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

import { useState } from "react";
import conferencesData from "@/data/conferences.yml";
import { Conference } from "@/types/conference";
import { Calendar as CalendarIcon, Tag } from "lucide-react";
import { Calendar } from "@/components/ui/calendar";
import { parseISO, format, isValid } from "date-fns";

const CalendarPage = () => {
  const [selectedDate, setSelectedDate] = useState<Date | undefined>(new Date());
  
  // Helper function to safely parse dates
  const safeParseISO = (dateString: string | undefined | number): Date | null => {
    if (!dateString || dateString === 'TBD') return null;
    
    // Convert to string if it's a number
    const dateStr = typeof dateString === 'number' ? dateString.toString() : dateString;
    
    try {
      // Try to parse the date, handling different formats
      const normalizedDate = dateStr.replace(/(\d{4})-(\d{1})-(\d{1,2})/, '$1-0$2-$3')
                                  .replace(/(\d{4})-(\d{2})-(\d{1})/, '$1-$2-0$3');
      
      const parsedDate = parseISO(normalizedDate);
      return isValid(parsedDate) ? parsedDate : null;
    } catch (error) {
      console.error("Error parsing date:", dateString);
      return null;
    }
  };

  // Get all unique dates (deadlines and conference dates)
  const getDatesWithEvents = () => {
    const dates = new Set<string>();
    conferencesData.forEach((conf: Conference) => {
      const deadlineDate = safeParseISO(conf.deadline);
      const startDate = safeParseISO(conf.start);

      if (deadlineDate) {
        dates.add(format(deadlineDate, 'yyyy-MM-dd'));
      }
      if (startDate) {
        dates.add(format(startDate, 'yyyy-MM-dd'));
      }
    });
    return Array.from(dates).map(date => parseISO(date));
  };

  // Get conferences for selected date
  const getConferencesForDate = (date: Date) => {
    const formattedDate = format(date, 'yyyy-MM-dd');
    return conferencesData.filter((conf: Conference) => {
      const deadlineDate = safeParseISO(conf.deadline);
      const startDate = safeParseISO(conf.start);

      const deadlineDateStr = deadlineDate ? format(deadlineDate, 'yyyy-MM-dd') : null;
      const startDateStr = startDate ? format(startDate, 'yyyy-MM-dd') : null;

      return deadlineDateStr === formattedDate || startDateStr === formattedDate;
    });
  };

  const selectedDateConferences = selectedDate ? getConferencesForDate(selectedDate) : [];

  return (
    <div className="min-h-screen bg-neutral-light p-6">
      <div className="max-w-7xl mx-auto">
        <h1 className="text-3xl font-bold mb-8">Calendar Overview</h1>
        <div className="grid md:grid-cols-2 gap-8">
          <div>
            <Calendar
              mode="single"
              selected={selectedDate}
              onSelect={setSelectedDate}
              className="bg-white rounded-lg p-4 shadow-sm"
              modifiers={{
                event: getDatesWithEvents()
              }}
              modifiersStyles={{
                event: {
                  fontWeight: 'bold',
                  color: '#0284C7',
                  textDecoration: 'underline'
                }
              }}
            />
          </div>
          <div className="space-y-4">
            {selectedDate && (
              <>
                <h2 className="text-xl font-semibold flex items-center gap-2">
                  <CalendarIcon className="h-5 w-5" />
                  Events on {format(selectedDate, 'MMMM d, yyyy')}
                </h2>
                {selectedDateConferences.length === 0 ? (
                  <p className="text-neutral-600">No events on this date.</p>
                ) : (
                  <div className="space-y-4">
                    {selectedDateConferences.map((conf: Conference) => (
                      <div key={conf.id} className="bg-white p-4 rounded-lg shadow-sm">
                        <h3 className="font-semibold text-lg">{conf.title}</h3>
                        {conf.deadline && safeParseISO(conf.deadline) && 
                          format(safeParseISO(conf.deadline)!, 'yyyy-MM-dd') === format(selectedDate, 'yyyy-MM-dd') && (
                          <p className="text-red-600">Submission Deadline</p>
                        )}
                        {conf.start && safeParseISO(conf.start) && 
                          format(safeParseISO(conf.start)!, 'yyyy-MM-dd') === format(selectedDate, 'yyyy-MM-dd') && (
                          <p className="text-green-600">Conference Start Date</p>
                        )}
                        <div className="mt-2 flex flex-wrap gap-2">
                          {conf.tags.map((tag) => (
                            <span key={tag} className="tag text-sm">
                              <Tag className="h-3 w-3 mr-1" />
                              {tag}
                            </span>
                          ))}
                        </div>
                      </div>
                    ))}
                  </div>
                )}
              </>
            )}
          </div>
        </div>
      </div>
    </div>
  );
};

export default CalendarPage;