Spaces:
Sleeping
Sleeping
gpt-engineer-app[bot]
commited on
Commit
·
b2510cd
1
Parent(s):
2782f86
Enhance calendar display
Browse filesDisplay all events for a given month below the calendar by default. Color entire days for conferences and deadlines.
- src/pages/Calendar.tsx +71 -30
src/pages/Calendar.tsx
CHANGED
|
@@ -4,7 +4,7 @@ import conferencesData from "@/data/conferences.yml";
|
|
| 4 |
import { Conference } from "@/types/conference";
|
| 5 |
import { Calendar as CalendarIcon, Tag, CircleDot } from "lucide-react";
|
| 6 |
import { Calendar } from "@/components/ui/calendar";
|
| 7 |
-
import { parseISO, format, isValid } from "date-fns";
|
| 8 |
|
| 9 |
const CalendarPage = () => {
|
| 10 |
const [selectedDate, setSelectedDate] = useState<Date | undefined>(new Date());
|
|
@@ -29,6 +29,17 @@ const CalendarPage = () => {
|
|
| 29 |
}
|
| 30 |
};
|
| 31 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 32 |
// Get all unique dates (deadlines and conference dates)
|
| 33 |
const getDatesWithEvents = () => {
|
| 34 |
const dates = {
|
|
@@ -39,11 +50,21 @@ const CalendarPage = () => {
|
|
| 39 |
conferencesData.forEach((conf: Conference) => {
|
| 40 |
const deadlineDate = safeParseISO(conf.deadline);
|
| 41 |
const startDate = safeParseISO(conf.start);
|
|
|
|
| 42 |
|
| 43 |
if (deadlineDate) {
|
| 44 |
dates.deadlines.add(format(deadlineDate, 'yyyy-MM-dd'));
|
| 45 |
}
|
| 46 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 47 |
dates.conferences.add(format(startDate, 'yyyy-MM-dd'));
|
| 48 |
}
|
| 49 |
});
|
|
@@ -60,15 +81,24 @@ const CalendarPage = () => {
|
|
| 60 |
return conferencesData.filter((conf: Conference) => {
|
| 61 |
const deadlineDate = safeParseISO(conf.deadline);
|
| 62 |
const startDate = safeParseISO(conf.start);
|
|
|
|
| 63 |
|
| 64 |
const deadlineDateStr = deadlineDate ? format(deadlineDate, 'yyyy-MM-dd') : null;
|
| 65 |
-
const
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 66 |
|
| 67 |
-
return
|
| 68 |
});
|
| 69 |
};
|
| 70 |
|
| 71 |
-
const
|
| 72 |
const datesWithEvents = getDatesWithEvents();
|
| 73 |
|
| 74 |
return (
|
|
@@ -108,10 +138,12 @@ const CalendarPage = () => {
|
|
| 108 |
}}
|
| 109 |
modifiersStyles={{
|
| 110 |
conference: {
|
|
|
|
| 111 |
color: '#7C3AED', // purple-600
|
| 112 |
fontWeight: 'bold'
|
| 113 |
},
|
| 114 |
deadline: {
|
|
|
|
| 115 |
color: '#EF4444', // red-500
|
| 116 |
fontWeight: 'bold'
|
| 117 |
}
|
|
@@ -119,36 +151,45 @@ const CalendarPage = () => {
|
|
| 119 |
/>
|
| 120 |
</div>
|
| 121 |
|
| 122 |
-
{/*
|
| 123 |
-
{selectedDate &&
|
| 124 |
<div className="mx-auto w-full max-w-3xl space-y-4">
|
| 125 |
<h2 className="text-xl font-semibold flex items-center gap-2">
|
| 126 |
<CalendarIcon className="h-5 w-5" />
|
| 127 |
-
Events
|
| 128 |
</h2>
|
| 129 |
-
|
| 130 |
-
|
| 131 |
-
|
| 132 |
-
|
| 133 |
-
|
| 134 |
-
|
| 135 |
-
<
|
| 136 |
-
|
| 137 |
-
|
| 138 |
-
|
| 139 |
-
|
| 140 |
-
|
| 141 |
-
|
| 142 |
-
|
| 143 |
-
|
| 144 |
-
|
| 145 |
-
|
| 146 |
-
|
| 147 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 148 |
</div>
|
| 149 |
-
|
| 150 |
-
|
| 151 |
-
|
| 152 |
</div>
|
| 153 |
)}
|
| 154 |
</div>
|
|
|
|
| 4 |
import { Conference } from "@/types/conference";
|
| 5 |
import { Calendar as CalendarIcon, Tag, CircleDot } from "lucide-react";
|
| 6 |
import { Calendar } from "@/components/ui/calendar";
|
| 7 |
+
import { parseISO, format, isValid, startOfMonth, endOfMonth, isSameMonth } from "date-fns";
|
| 8 |
|
| 9 |
const CalendarPage = () => {
|
| 10 |
const [selectedDate, setSelectedDate] = useState<Date | undefined>(new Date());
|
|
|
|
| 29 |
}
|
| 30 |
};
|
| 31 |
|
| 32 |
+
// Get all events (conferences and deadlines) for a given month
|
| 33 |
+
const getMonthEvents = (date: Date) => {
|
| 34 |
+
return conferencesData.filter((conf: Conference) => {
|
| 35 |
+
const deadlineDate = safeParseISO(conf.deadline);
|
| 36 |
+
const startDate = safeParseISO(conf.start);
|
| 37 |
+
|
| 38 |
+
return (deadlineDate && isSameMonth(deadlineDate, date)) ||
|
| 39 |
+
(startDate && isSameMonth(startDate, date));
|
| 40 |
+
});
|
| 41 |
+
};
|
| 42 |
+
|
| 43 |
// Get all unique dates (deadlines and conference dates)
|
| 44 |
const getDatesWithEvents = () => {
|
| 45 |
const dates = {
|
|
|
|
| 50 |
conferencesData.forEach((conf: Conference) => {
|
| 51 |
const deadlineDate = safeParseISO(conf.deadline);
|
| 52 |
const startDate = safeParseISO(conf.start);
|
| 53 |
+
const endDate = safeParseISO(conf.end);
|
| 54 |
|
| 55 |
if (deadlineDate) {
|
| 56 |
dates.deadlines.add(format(deadlineDate, 'yyyy-MM-dd'));
|
| 57 |
}
|
| 58 |
+
|
| 59 |
+
// If conference has both start and end dates, add all dates in between
|
| 60 |
+
if (startDate && endDate) {
|
| 61 |
+
let currentDate = startDate;
|
| 62 |
+
while (currentDate <= endDate) {
|
| 63 |
+
dates.conferences.add(format(currentDate, 'yyyy-MM-dd'));
|
| 64 |
+
currentDate = new Date(currentDate.setDate(currentDate.getDate() + 1));
|
| 65 |
+
}
|
| 66 |
+
} else if (startDate) {
|
| 67 |
+
// If only start date is available, add just that date
|
| 68 |
dates.conferences.add(format(startDate, 'yyyy-MM-dd'));
|
| 69 |
}
|
| 70 |
});
|
|
|
|
| 81 |
return conferencesData.filter((conf: Conference) => {
|
| 82 |
const deadlineDate = safeParseISO(conf.deadline);
|
| 83 |
const startDate = safeParseISO(conf.start);
|
| 84 |
+
const endDate = safeParseISO(conf.end);
|
| 85 |
|
| 86 |
const deadlineDateStr = deadlineDate ? format(deadlineDate, 'yyyy-MM-dd') : null;
|
| 87 |
+
const isDeadlineMatch = deadlineDateStr === formattedDate;
|
| 88 |
+
|
| 89 |
+
// Check if the date falls within the conference duration
|
| 90 |
+
let isConferenceDate = false;
|
| 91 |
+
if (startDate && endDate) {
|
| 92 |
+
isConferenceDate = date >= startDate && date <= endDate;
|
| 93 |
+
} else if (startDate) {
|
| 94 |
+
isConferenceDate = format(startDate, 'yyyy-MM-dd') === formattedDate;
|
| 95 |
+
}
|
| 96 |
|
| 97 |
+
return isDeadlineMatch || isConferenceDate;
|
| 98 |
});
|
| 99 |
};
|
| 100 |
|
| 101 |
+
const monthEvents = selectedDate ? getMonthEvents(selectedDate) : [];
|
| 102 |
const datesWithEvents = getDatesWithEvents();
|
| 103 |
|
| 104 |
return (
|
|
|
|
| 138 |
}}
|
| 139 |
modifiersStyles={{
|
| 140 |
conference: {
|
| 141 |
+
backgroundColor: '#DDD6FE', // purple-200
|
| 142 |
color: '#7C3AED', // purple-600
|
| 143 |
fontWeight: 'bold'
|
| 144 |
},
|
| 145 |
deadline: {
|
| 146 |
+
backgroundColor: '#FEE2E2', // red-100
|
| 147 |
color: '#EF4444', // red-500
|
| 148 |
fontWeight: 'bold'
|
| 149 |
}
|
|
|
|
| 151 |
/>
|
| 152 |
</div>
|
| 153 |
|
| 154 |
+
{/* Month Events */}
|
| 155 |
+
{selectedDate && (
|
| 156 |
<div className="mx-auto w-full max-w-3xl space-y-4">
|
| 157 |
<h2 className="text-xl font-semibold flex items-center gap-2">
|
| 158 |
<CalendarIcon className="h-5 w-5" />
|
| 159 |
+
Events in {format(selectedDate, 'MMMM yyyy')}
|
| 160 |
</h2>
|
| 161 |
+
{monthEvents.length === 0 ? (
|
| 162 |
+
<p className="text-neutral-600">No events this month.</p>
|
| 163 |
+
) : (
|
| 164 |
+
<div className="space-y-4">
|
| 165 |
+
{monthEvents.map((conf: Conference) => (
|
| 166 |
+
<div key={conf.id} className="bg-white p-4 rounded-lg shadow-sm">
|
| 167 |
+
<h3 className="font-semibold text-lg">{conf.title}</h3>
|
| 168 |
+
<div className="space-y-1">
|
| 169 |
+
{conf.deadline && safeParseISO(conf.deadline) && isSameMonth(safeParseISO(conf.deadline)!, selectedDate) && (
|
| 170 |
+
<p className="text-red-500">
|
| 171 |
+
Submission Deadline: {format(safeParseISO(conf.deadline)!, 'MMMM d, yyyy')}
|
| 172 |
+
</p>
|
| 173 |
+
)}
|
| 174 |
+
{conf.start && (
|
| 175 |
+
<p className="text-purple-600">
|
| 176 |
+
Conference Date: {format(safeParseISO(conf.start)!, 'MMMM d')}
|
| 177 |
+
{conf.end ? ` - ${format(safeParseISO(conf.end)!, 'MMMM d, yyyy')}` : `, ${format(safeParseISO(conf.start)!, 'yyyy')}`}
|
| 178 |
+
</p>
|
| 179 |
+
)}
|
| 180 |
+
</div>
|
| 181 |
+
<div className="mt-2 flex flex-wrap gap-2">
|
| 182 |
+
{conf.tags.map((tag) => (
|
| 183 |
+
<span key={tag} className="tag text-sm">
|
| 184 |
+
<Tag className="h-3 w-3 mr-1" />
|
| 185 |
+
{tag}
|
| 186 |
+
</span>
|
| 187 |
+
))}
|
| 188 |
+
</div>
|
| 189 |
</div>
|
| 190 |
+
))}
|
| 191 |
+
</div>
|
| 192 |
+
)}
|
| 193 |
</div>
|
| 194 |
)}
|
| 195 |
</div>
|