nielsr HF staff commited on
Commit
2e6eb2a
·
1 Parent(s): b45eb38

Add ability to switch year

Browse files
Files changed (1) hide show
  1. src/pages/Calendar.tsx +74 -48
src/pages/Calendar.tsx CHANGED
@@ -53,6 +53,7 @@ const CalendarPage = () => {
53
  new Set(Object.keys(categoryColors))
54
  );
55
  const [showDeadlines, setShowDeadlines] = useState(true);
 
56
 
57
  const safeParseISO = (dateString: string | undefined | number): Date | null => {
58
  if (!dateString) return null;
@@ -95,55 +96,43 @@ const CalendarPage = () => {
95
  const startDate = safeParseISO(conf.start);
96
  const endDate = safeParseISO(conf.end);
97
 
98
- const dateMatches = isYearView ? isSameYear : isSameMonth;
 
 
 
99
 
100
  // If showing deadlines and no categories selected, only show deadlines
101
  if (showDeadlines && selectedCategories.size === 0) {
102
- return deadlineDate && dateMatches(deadlineDate, date) && matchesSearch;
103
  }
104
 
105
- // Otherwise, check for category matches and show both deadlines and conference dates
106
  const matchesCategory = Array.isArray(conf.tags) &&
107
  conf.tags.some(tag => selectedCategories.has(tag));
108
 
109
- if (!matchesSearch || !matchesCategory) return false;
110
 
111
- const deadlineInPeriod = showDeadlines && deadlineDate && dateMatches(deadlineDate, date);
112
-
113
- let conferenceInPeriod = false;
114
- if (startDate && endDate) {
115
- let currentDate = new Date(startDate);
116
- while (currentDate <= endDate) {
117
- if (dateMatches(currentDate, date)) {
118
- conferenceInPeriod = true;
119
- break;
120
- }
121
- currentDate.setDate(currentDate.getDate() + 1);
122
- }
123
- } else if (startDate) {
124
- conferenceInPeriod = dateMatches(startDate, date);
125
- }
126
 
127
- return deadlineInPeriod || conferenceInPeriod;
128
  });
129
  };
130
 
131
  const getDayEvents = (date: Date) => {
132
  const deadlines = showDeadlines ? conferencesData.filter(conf => {
133
  const deadlineDate = safeParseISO(conf.deadline);
134
- const matchesSearch = searchQuery === "" ||
135
- conf.title.toLowerCase().includes(searchQuery.toLowerCase()) ||
136
- (conf.full_name && conf.full_name.toLowerCase().includes(searchQuery.toLowerCase()));
137
-
138
- // If no categories selected, show all deadlines
139
- if (selectedCategories.size === 0) {
140
- return deadlineDate && isSameDay(deadlineDate, date) && matchesSearch;
141
- }
142
-
143
- // Otherwise, filter by selected categories
144
- const matchesCategory = Array.isArray(conf.tags) &&
145
- conf.tags.some(tag => selectedCategories.has(tag));
146
- return deadlineDate && isSameDay(deadlineDate, date) && matchesCategory && matchesSearch;
147
  }) : [];
148
 
149
  const conferences = selectedCategories.size > 0 ? conferencesData.filter(conf => {
@@ -151,29 +140,30 @@ const CalendarPage = () => {
151
  const endDate = safeParseISO(conf.end);
152
  const matchesCategory = Array.isArray(conf.tags) &&
153
  conf.tags.some(tag => selectedCategories.has(tag));
154
- const matchesSearch = searchQuery === "" ||
155
- conf.title.toLowerCase().includes(searchQuery.toLowerCase()) ||
156
- (conf.full_name && conf.full_name.toLowerCase().includes(searchQuery.toLowerCase()));
157
 
158
- if (!matchesCategory || !matchesSearch) return false;
159
 
160
  if (startDate && endDate) {
161
- let currentDate = new Date(startDate);
162
- while (currentDate <= endDate) {
163
- if (isSameDay(currentDate, date)) {
164
- return true;
165
- }
166
- currentDate.setDate(currentDate.getDate() + 1);
167
- }
168
  } else if (startDate) {
169
- return isSameDay(startDate, date);
170
  }
171
  return false;
172
  }) : [];
173
 
174
  return {
175
- deadlines: deadlines,
176
- conferences: conferences
 
 
 
 
 
 
 
 
177
  };
178
  };
179
 
@@ -472,7 +462,7 @@ const CalendarPage = () => {
472
 
473
  const renderViewToggle = () => {
474
  return (
475
- <div className="flex justify-center mb-6">
476
  <div className="bg-neutral-100 rounded-lg p-1 inline-flex">
477
  <button
478
  onClick={() => setIsYearView(false)}
@@ -495,6 +485,38 @@ const CalendarPage = () => {
495
  Year View
496
  </button>
497
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
498
  </div>
499
  );
500
  };
@@ -582,6 +604,10 @@ const CalendarPage = () => {
582
  onSelect={setSelectedDate}
583
  numberOfMonths={isYearView ? 12 : 1}
584
  showOutsideDays={false}
 
 
 
 
585
  className="bg-white rounded-lg p-6 shadow-sm mx-auto w-full"
586
  components={{
587
  Day: ({ date, displayMonth, ...props }) => {
 
53
  new Set(Object.keys(categoryColors))
54
  );
55
  const [showDeadlines, setShowDeadlines] = useState(true);
56
+ const [currentYear, setCurrentYear] = useState(new Date().getFullYear());
57
 
58
  const safeParseISO = (dateString: string | undefined | number): Date | null => {
59
  if (!dateString) return null;
 
96
  const startDate = safeParseISO(conf.start);
97
  const endDate = safeParseISO(conf.end);
98
 
99
+ // Check if a date is in the current year
100
+ const isInCurrentYear = (date: Date | null) => {
101
+ return date && date.getFullYear() === currentYear;
102
+ };
103
 
104
  // If showing deadlines and no categories selected, only show deadlines
105
  if (showDeadlines && selectedCategories.size === 0) {
106
+ return deadlineDate && isInCurrentYear(deadlineDate) && matchesSearch;
107
  }
108
 
109
+ // Check for category matches
110
  const matchesCategory = Array.isArray(conf.tags) &&
111
  conf.tags.some(tag => selectedCategories.has(tag));
112
 
113
+ if (!matchesSearch || (!matchesCategory && selectedCategories.size > 0)) return false;
114
 
115
+ // Check if either deadline or conference dates are in the current year
116
+ const deadlineInYear = showDeadlines && deadlineDate && isInCurrentYear(deadlineDate);
117
+ const conferenceInYear = (startDate && isInCurrentYear(startDate)) ||
118
+ (endDate && isInCurrentYear(endDate)) ||
119
+ (startDate && endDate &&
120
+ startDate.getFullYear() <= currentYear &&
121
+ endDate.getFullYear() >= currentYear);
 
 
 
 
 
 
 
 
122
 
123
+ return deadlineInYear || (selectedCategories.size > 0 && conferenceInYear);
124
  });
125
  };
126
 
127
  const getDayEvents = (date: Date) => {
128
  const deadlines = showDeadlines ? conferencesData.filter(conf => {
129
  const deadlineDate = safeParseISO(conf.deadline);
130
+ const matchesCategory = selectedCategories.size === 0 ? true :
131
+ (Array.isArray(conf.tags) && conf.tags.some(tag => selectedCategories.has(tag)));
132
+ return deadlineDate &&
133
+ isSameDay(deadlineDate, date) &&
134
+ deadlineDate.getFullYear() === currentYear &&
135
+ matchesCategory;
 
 
 
 
 
 
 
136
  }) : [];
137
 
138
  const conferences = selectedCategories.size > 0 ? conferencesData.filter(conf => {
 
140
  const endDate = safeParseISO(conf.end);
141
  const matchesCategory = Array.isArray(conf.tags) &&
142
  conf.tags.some(tag => selectedCategories.has(tag));
 
 
 
143
 
144
+ if (!matchesCategory) return false;
145
 
146
  if (startDate && endDate) {
147
+ return startDate.getFullYear() <= currentYear &&
148
+ endDate.getFullYear() >= currentYear &&
149
+ date >= startDate && date <= endDate;
 
 
 
 
150
  } else if (startDate) {
151
+ return startDate.getFullYear() === currentYear && isSameDay(startDate, date);
152
  }
153
  return false;
154
  }) : [];
155
 
156
  return {
157
+ deadlines: deadlines.filter(conf =>
158
+ searchQuery === "" ||
159
+ conf.title.toLowerCase().includes(searchQuery.toLowerCase()) ||
160
+ (conf.full_name && conf.full_name.toLowerCase().includes(searchQuery.toLowerCase()))
161
+ ),
162
+ conferences: conferences.filter(conf =>
163
+ searchQuery === "" ||
164
+ conf.title.toLowerCase().includes(searchQuery.toLowerCase()) ||
165
+ (conf.full_name && conf.full_name.toLowerCase().includes(searchQuery.toLowerCase()))
166
+ )
167
  };
168
  };
169
 
 
462
 
463
  const renderViewToggle = () => {
464
  return (
465
+ <div className="flex flex-col items-center gap-4 mb-6">
466
  <div className="bg-neutral-100 rounded-lg p-1 inline-flex">
467
  <button
468
  onClick={() => setIsYearView(false)}
 
485
  Year View
486
  </button>
487
  </div>
488
+
489
+ {isYearView && (
490
+ <div className="flex items-center gap-4">
491
+ <button
492
+ onClick={() => {
493
+ const newYear = currentYear - 1;
494
+ setCurrentYear(newYear);
495
+ setSelectedDate(new Date(newYear, 0, 1)); // Set to January 1st of the new year
496
+ }}
497
+ className="p-2 hover:bg-neutral-100 rounded-full transition-colors"
498
+ aria-label="Previous year"
499
+ >
500
+ <svg className="w-5 h-5" viewBox="0 0 24 24" fill="none" stroke="currentColor">
501
+ <path d="M15 18l-6-6 6-6" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
502
+ </svg>
503
+ </button>
504
+ <span className="text-lg font-semibold">{currentYear}</span>
505
+ <button
506
+ onClick={() => {
507
+ const newYear = currentYear + 1;
508
+ setCurrentYear(newYear);
509
+ setSelectedDate(new Date(newYear, 0, 1)); // Set to January 1st of the new year
510
+ }}
511
+ className="p-2 hover:bg-neutral-100 rounded-full transition-colors"
512
+ aria-label="Next year"
513
+ >
514
+ <svg className="w-5 h-5" viewBox="0 0 24 24" fill="none" stroke="currentColor">
515
+ <path d="M9 18l6-6-6-6" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
516
+ </svg>
517
+ </button>
518
+ </div>
519
+ )}
520
  </div>
521
  );
522
  };
 
604
  onSelect={setSelectedDate}
605
  numberOfMonths={isYearView ? 12 : 1}
606
  showOutsideDays={false}
607
+ defaultMonth={new Date(currentYear, 0)}
608
+ month={new Date(currentYear, 0)}
609
+ fromMonth={isYearView ? new Date(currentYear, 0) : undefined}
610
+ toMonth={isYearView ? new Date(currentYear, 11) : undefined}
611
  className="bg-white rounded-lg p-6 shadow-sm mx-auto w-full"
612
  components={{
613
  Day: ({ date, displayMonth, ...props }) => {