customized-calendar 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +23 -0
- package/README.md +238 -0
- package/dist/components/classroom-calendar/AddEventModal.d.ts +14 -0
- package/dist/components/classroom-calendar/AddEventModal.d.ts.map +1 -0
- package/dist/components/classroom-calendar/AddEventModal.js +131 -0
- package/dist/components/classroom-calendar/CustomizedCalendar.d.ts +11 -0
- package/dist/components/classroom-calendar/CustomizedCalendar.d.ts.map +1 -0
- package/dist/components/classroom-calendar/CustomizedCalendar.js +442 -0
- package/dist/components/classroom-calendar/DateEventsList.d.ts +14 -0
- package/dist/components/classroom-calendar/DateEventsList.d.ts.map +1 -0
- package/dist/components/classroom-calendar/DateEventsList.js +56 -0
- package/dist/components/classroom-calendar/EventDetailsModal.d.ts +11 -0
- package/dist/components/classroom-calendar/EventDetailsModal.d.ts.map +1 -0
- package/dist/components/classroom-calendar/EventDetailsModal.js +37 -0
- package/dist/components/classroom-calendar/calendar.types.d.ts +57 -0
- package/dist/components/classroom-calendar/calendar.types.d.ts.map +1 -0
- package/dist/components/classroom-calendar/calendar.types.js +10 -0
- package/dist/components/classroom-calendar/calendar.utils.d.ts +64 -0
- package/dist/components/classroom-calendar/calendar.utils.d.ts.map +1 -0
- package/dist/components/classroom-calendar/calendar.utils.js +119 -0
- package/dist/components/classroom-calendar/index.d.ts +7 -0
- package/dist/components/classroom-calendar/index.d.ts.map +1 -0
- package/dist/components/classroom-calendar/index.js +6 -0
- package/dist/src/index.d.ts +11 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +9 -0
- package/package.json +74 -0
|
@@ -0,0 +1,442 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useRef, useEffect, useState } from 'react';
|
|
3
|
+
import FullCalendar from '@fullcalendar/react';
|
|
4
|
+
import dayGridPlugin from '@fullcalendar/daygrid';
|
|
5
|
+
import timeGridPlugin from '@fullcalendar/timegrid';
|
|
6
|
+
import interactionPlugin from '@fullcalendar/interaction';
|
|
7
|
+
import { formatEventForFullCalendar, convertFullCalendarEventToCalendarEvent, formatDateToString, hexToRgbString, lightenColor, darkenColor, } from './calendar.utils';
|
|
8
|
+
/**
|
|
9
|
+
* CustomizedCalendar Component
|
|
10
|
+
*
|
|
11
|
+
* A modern, reusable calendar component with customizable theme
|
|
12
|
+
* and support for multiple views, event management, and advanced interactions.
|
|
13
|
+
*/
|
|
14
|
+
const CustomizedCalendar = ({ events, onDateClick, onEventClick, height = 'auto', initialView = 'dayGridMonth', editable = true, selectable = true, selectMirror = true, droppable = true, eventResizableFromStart = true, eventStartEditable = true, eventDurationEditable = true, themeColor = '#3b82f6', // Default blue
|
|
15
|
+
}) => {
|
|
16
|
+
const calendarRef = useRef(null);
|
|
17
|
+
const [mounted, setMounted] = useState(false);
|
|
18
|
+
// Generate color variations from theme color
|
|
19
|
+
const primaryRgb = hexToRgbString(themeColor);
|
|
20
|
+
const primaryLight = lightenColor(themeColor, 0.15);
|
|
21
|
+
const primaryDark = darkenColor(themeColor, 0.15);
|
|
22
|
+
const primaryDarker = darkenColor(themeColor, 0.25);
|
|
23
|
+
// Handle client-side mounting
|
|
24
|
+
useEffect(() => {
|
|
25
|
+
setMounted(true);
|
|
26
|
+
}, []);
|
|
27
|
+
// Format events for FullCalendar
|
|
28
|
+
const formattedEvents = events.map(formatEventForFullCalendar);
|
|
29
|
+
// Custom event content renderer to show batch information
|
|
30
|
+
const renderEventContent = (eventInfo) => {
|
|
31
|
+
const batchName = eventInfo.event.extendedProps?.batchName || '';
|
|
32
|
+
const eventType = eventInfo.event.extendedProps?.type || '';
|
|
33
|
+
const isAllDay = eventInfo.event.allDay;
|
|
34
|
+
return (_jsxs("div", { className: "fc-event-main-frame", children: [!isAllDay && eventInfo.timeText && (_jsx("div", { className: "fc-event-time", children: eventInfo.timeText })), _jsxs("div", { className: "fc-event-title-container", children: [_jsx("div", { className: "fc-event-title fc-sticky", children: eventInfo.event.title }), batchName && batchName !== 'All Batches' && (_jsxs("div", { className: "fc-event-batch", children: [_jsx("span", { style: { marginRight: '4px' }, children: "\uD83D\uDCDA" }), batchName] })), eventType && (_jsx("div", { className: "fc-event-type", children: eventType }))] })] }));
|
|
35
|
+
};
|
|
36
|
+
// Handle date click
|
|
37
|
+
const handleDateClick = (info) => {
|
|
38
|
+
const dateStr = info.dateStr || formatDateToString(info.date);
|
|
39
|
+
onDateClick(dateStr);
|
|
40
|
+
};
|
|
41
|
+
// Handle event click
|
|
42
|
+
const handleEventClick = (info) => {
|
|
43
|
+
const calendarEvent = convertFullCalendarEventToCalendarEvent(info.event);
|
|
44
|
+
onEventClick(calendarEvent);
|
|
45
|
+
};
|
|
46
|
+
// Handle event drop (drag & drop)
|
|
47
|
+
const handleEventDrop = (info) => {
|
|
48
|
+
const calendarEvent = convertFullCalendarEventToCalendarEvent(info.event);
|
|
49
|
+
onEventClick(calendarEvent);
|
|
50
|
+
};
|
|
51
|
+
// Handle event resize
|
|
52
|
+
const handleEventResize = (info) => {
|
|
53
|
+
const calendarEvent = convertFullCalendarEventToCalendarEvent(info.event);
|
|
54
|
+
onEventClick(calendarEvent);
|
|
55
|
+
};
|
|
56
|
+
// Calendar header toolbar configuration
|
|
57
|
+
const headerToolbar = {
|
|
58
|
+
left: 'prev,next today',
|
|
59
|
+
center: 'title',
|
|
60
|
+
right: 'dayGridMonth,timeGridWeek,timeGridDay',
|
|
61
|
+
};
|
|
62
|
+
// Button text configuration
|
|
63
|
+
const buttonText = {
|
|
64
|
+
today: 'Today',
|
|
65
|
+
month: 'Month',
|
|
66
|
+
week: 'Week',
|
|
67
|
+
day: 'Day',
|
|
68
|
+
};
|
|
69
|
+
// If not mounted, return placeholder (for SSR)
|
|
70
|
+
if (!mounted) {
|
|
71
|
+
return (_jsx("div", { className: "w-full h-96 bg-gradient-to-br from-gray-50 to-gray-100 rounded-2xl flex items-center justify-center border border-gray-200", children: _jsxs("div", { className: "flex flex-col items-center gap-3", children: [_jsx("div", { className: "w-8 h-8 border-4 border-t-transparent rounded-full animate-spin", style: { borderColor: `${themeColor} transparent transparent transparent` } }), _jsx("div", { className: "text-gray-500 font-medium", children: "Loading calendar..." })] }) }));
|
|
72
|
+
}
|
|
73
|
+
return (_jsxs("div", { className: "w-full rounded-2xl shadow-2xl border border-gray-200/50 p-4 md:p-6 backdrop-blur-sm", style: {
|
|
74
|
+
background: `linear-gradient(to bottom right, white, rgba(${primaryRgb}, 0.1), rgba(${primaryRgb}, 0.05))`,
|
|
75
|
+
}, children: [_jsx("div", { className: "calendar-container", style: {
|
|
76
|
+
'--theme-color': themeColor,
|
|
77
|
+
'--theme-rgb': primaryRgb,
|
|
78
|
+
'--theme-light': primaryLight,
|
|
79
|
+
'--theme-dark': primaryDark,
|
|
80
|
+
'--theme-darker': primaryDarker,
|
|
81
|
+
}, children: _jsx(FullCalendar, { ref: calendarRef, plugins: [dayGridPlugin, timeGridPlugin, interactionPlugin], initialView: initialView, headerToolbar: headerToolbar, buttonText: buttonText, height: height, events: formattedEvents, editable: editable, selectable: selectable, selectMirror: selectMirror, droppable: droppable, eventResizableFromStart: eventResizableFromStart, eventStartEditable: eventStartEditable, eventDurationEditable: eventDurationEditable, dateClick: handleDateClick, eventClick: handleEventClick, eventDrop: handleEventDrop, eventResize: handleEventResize, eventContent: renderEventContent, dayMaxEvents: true, moreLinkClick: "popover", eventDisplay: "block", eventTimeFormat: {
|
|
82
|
+
hour: 'numeric',
|
|
83
|
+
minute: '2-digit',
|
|
84
|
+
meridiem: 'short',
|
|
85
|
+
}, slotMinTime: "06:00:00", slotMaxTime: "22:00:00", allDaySlot: true, nowIndicator: true, weekends: true, firstDay: 1, locale: "en",
|
|
86
|
+
// Custom styling classes
|
|
87
|
+
eventClassNames: "rounded-lg shadow-sm cursor-pointer hover:shadow-md transition-shadow duration-200", dayHeaderClassNames: "font-semibold text-gray-700", dayCellClassNames: "hover:bg-gray-50 transition-colors duration-150",
|
|
88
|
+
// Responsive breakpoints
|
|
89
|
+
views: {
|
|
90
|
+
dayGridMonth: {
|
|
91
|
+
dayMaxEvents: 5,
|
|
92
|
+
moreLinkClick: 'popover',
|
|
93
|
+
eventMinHeight: 20,
|
|
94
|
+
},
|
|
95
|
+
timeGridWeek: {
|
|
96
|
+
slotDuration: '00:30:00',
|
|
97
|
+
slotLabelInterval: '01:00:00',
|
|
98
|
+
},
|
|
99
|
+
timeGridDay: {
|
|
100
|
+
slotDuration: '00:30:00',
|
|
101
|
+
slotLabelInterval: '01:00:00',
|
|
102
|
+
},
|
|
103
|
+
} }) }), _jsx("style", { children: `
|
|
104
|
+
.calendar-container {
|
|
105
|
+
width: 100%;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/* FullCalendar custom styles */
|
|
109
|
+
.fc {
|
|
110
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
|
111
|
+
color: #1f2937;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
.fc-toolbar {
|
|
115
|
+
margin-bottom: 2rem;
|
|
116
|
+
padding: 1rem 0;
|
|
117
|
+
border-bottom: 2px solid rgba(var(--theme-rgb, 59, 130, 246), 0.1);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
.fc-toolbar-title {
|
|
121
|
+
font-size: 1.75rem;
|
|
122
|
+
font-weight: 700;
|
|
123
|
+
background: linear-gradient(135deg, var(--theme-color, #3b82f6) 0%, var(--theme-light, #8b5cf6) 100%);
|
|
124
|
+
-webkit-background-clip: text;
|
|
125
|
+
-webkit-text-fill-color: transparent;
|
|
126
|
+
background-clip: text;
|
|
127
|
+
letter-spacing: -0.025em;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
.fc-button {
|
|
131
|
+
background: linear-gradient(135deg, var(--theme-color, #3b82f6) 0%, var(--theme-dark, #2563eb) 100%);
|
|
132
|
+
border: none;
|
|
133
|
+
color: white;
|
|
134
|
+
padding: 0.625rem 1.25rem;
|
|
135
|
+
border-radius: 0.75rem;
|
|
136
|
+
font-weight: 600;
|
|
137
|
+
font-size: 0.875rem;
|
|
138
|
+
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
|
139
|
+
box-shadow: 0 2px 4px rgba(var(--theme-rgb, 59, 130, 246), 0.2);
|
|
140
|
+
text-transform: none;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
.fc-button:hover {
|
|
144
|
+
background: linear-gradient(135deg, var(--theme-dark, #2563eb) 0%, var(--theme-darker, #1d4ed8) 100%);
|
|
145
|
+
transform: translateY(-2px);
|
|
146
|
+
box-shadow: 0 4px 12px rgba(var(--theme-rgb, 59, 130, 246), 0.4);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
.fc-button:active {
|
|
150
|
+
transform: translateY(0);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
.fc-button-active {
|
|
154
|
+
background: linear-gradient(135deg, var(--theme-darker, #1d4ed8) 0%, var(--theme-darker, #1e40af) 100%);
|
|
155
|
+
box-shadow: 0 4px 12px rgba(var(--theme-rgb, 59, 130, 246), 0.5);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
.fc-button:focus {
|
|
159
|
+
outline: none;
|
|
160
|
+
box-shadow: 0 0 0 4px rgba(var(--theme-rgb, 59, 130, 246), 0.3), 0 4px 12px rgba(var(--theme-rgb, 59, 130, 246), 0.4);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
.fc-button-primary:not(:disabled):active,
|
|
164
|
+
.fc-button-primary:not(:disabled).fc-button-active {
|
|
165
|
+
background: linear-gradient(135deg, var(--theme-darker, #1d4ed8) 0%, var(--theme-darker, #1e40af) 100%);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
.fc-event {
|
|
169
|
+
border-radius: 0.75rem;
|
|
170
|
+
padding: 0.375rem 0.5rem;
|
|
171
|
+
font-size: 0.875rem;
|
|
172
|
+
font-weight: 600;
|
|
173
|
+
border: none;
|
|
174
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15), 0 1px 3px rgba(0, 0, 0, 0.1);
|
|
175
|
+
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
|
176
|
+
cursor: pointer;
|
|
177
|
+
backdrop-filter: blur(10px);
|
|
178
|
+
border-left: 4px solid rgba(255, 255, 255, 0.5);
|
|
179
|
+
min-height: auto;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
.fc-event:hover {
|
|
183
|
+
transform: translateY(-2px) scale(1.02);
|
|
184
|
+
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.2), 0 4px 8px rgba(0, 0, 0, 0.15);
|
|
185
|
+
z-index: 10;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
.fc-event-title {
|
|
189
|
+
font-weight: 600;
|
|
190
|
+
line-height: 1.3;
|
|
191
|
+
font-size: 0.8rem;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
.fc-event-batch {
|
|
195
|
+
font-weight: 500;
|
|
196
|
+
line-height: 1.2;
|
|
197
|
+
white-space: nowrap;
|
|
198
|
+
overflow: hidden;
|
|
199
|
+
text-overflow: ellipsis;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
.fc-event-type {
|
|
203
|
+
font-weight: 500;
|
|
204
|
+
line-height: 1.2;
|
|
205
|
+
text-transform: uppercase;
|
|
206
|
+
letter-spacing: 0.5px;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
.fc-event-main-frame {
|
|
210
|
+
display: flex;
|
|
211
|
+
flex-direction: column;
|
|
212
|
+
width: 100%;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
.fc-event-title-container {
|
|
216
|
+
display: flex;
|
|
217
|
+
flex-direction: column;
|
|
218
|
+
flex: 1;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
.fc-event-time {
|
|
222
|
+
font-size: 0.7rem;
|
|
223
|
+
opacity: 0.95;
|
|
224
|
+
margin-bottom: 2px;
|
|
225
|
+
font-weight: 600;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
.fc-daygrid-day {
|
|
229
|
+
border-radius: 0.5rem;
|
|
230
|
+
transition: all 0.2s ease;
|
|
231
|
+
border: 1px solid transparent;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
.fc-daygrid-day:hover {
|
|
235
|
+
background: linear-gradient(135deg, rgba(var(--theme-rgb, 59, 130, 246), 0.05) 0%, rgba(var(--theme-rgb, 59, 130, 246), 0.05) 100%);
|
|
236
|
+
border-color: rgba(var(--theme-rgb, 59, 130, 246), 0.2);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
.fc-day-today {
|
|
240
|
+
background: linear-gradient(135deg, rgba(var(--theme-rgb, 59, 130, 246), 0.1) 0%, rgba(var(--theme-rgb, 59, 130, 246), 0.1) 100%) !important;
|
|
241
|
+
border: 2px solid rgba(var(--theme-rgb, 59, 130, 246), 0.3) !important;
|
|
242
|
+
border-radius: 0.5rem;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
.fc-day-today .fc-daygrid-day-number {
|
|
246
|
+
background: linear-gradient(135deg, var(--theme-color, #3b82f6) 0%, var(--theme-light, #8b5cf6) 100%);
|
|
247
|
+
color: white;
|
|
248
|
+
width: 2rem;
|
|
249
|
+
height: 2rem;
|
|
250
|
+
border-radius: 50%;
|
|
251
|
+
display: flex;
|
|
252
|
+
align-items: center;
|
|
253
|
+
justify-content: center;
|
|
254
|
+
font-weight: 700;
|
|
255
|
+
margin: 0.25rem;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
.fc-daygrid-day-number {
|
|
259
|
+
padding: 0.5rem;
|
|
260
|
+
font-weight: 600;
|
|
261
|
+
color: #4b5563;
|
|
262
|
+
transition: all 0.2s ease;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
.fc-daygrid-day:hover .fc-daygrid-day-number {
|
|
266
|
+
color: var(--theme-color, #3b82f6);
|
|
267
|
+
transform: scale(1.1);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
.fc-col-header-cell {
|
|
271
|
+
padding: 1rem 0.5rem;
|
|
272
|
+
background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);
|
|
273
|
+
border-radius: 0.75rem 0.75rem 0 0;
|
|
274
|
+
border-bottom: 2px solid rgba(var(--theme-rgb, 59, 130, 246), 0.1);
|
|
275
|
+
font-weight: 700;
|
|
276
|
+
font-size: 0.875rem;
|
|
277
|
+
text-transform: uppercase;
|
|
278
|
+
letter-spacing: 0.05em;
|
|
279
|
+
color: #475569;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
.fc-timegrid-slot {
|
|
283
|
+
height: 2.5rem;
|
|
284
|
+
border-color: rgba(226, 232, 240, 0.8);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
.fc-timegrid-slot-label {
|
|
288
|
+
border-color: rgba(226, 232, 240, 0.8);
|
|
289
|
+
color: #64748b;
|
|
290
|
+
font-weight: 600;
|
|
291
|
+
font-size: 0.75rem;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
.fc-timegrid-now-indicator-line {
|
|
295
|
+
border-color: #ef4444;
|
|
296
|
+
border-width: 3px;
|
|
297
|
+
box-shadow: 0 0 8px rgba(239, 68, 68, 0.5);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
.fc-timegrid-now-indicator-arrow {
|
|
301
|
+
border-color: #ef4444;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
.fc-popover {
|
|
305
|
+
border-radius: 1rem;
|
|
306
|
+
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
|
|
307
|
+
border: 1px solid rgba(226, 232, 240, 0.8);
|
|
308
|
+
backdrop-filter: blur(10px);
|
|
309
|
+
background: rgba(255, 255, 255, 0.95);
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
.fc-popover-header {
|
|
313
|
+
background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);
|
|
314
|
+
border-radius: 1rem 1rem 0 0;
|
|
315
|
+
padding: 1rem 1.25rem;
|
|
316
|
+
font-weight: 700;
|
|
317
|
+
font-size: 0.875rem;
|
|
318
|
+
text-transform: uppercase;
|
|
319
|
+
letter-spacing: 0.05em;
|
|
320
|
+
color: #475569;
|
|
321
|
+
border-bottom: 2px solid rgba(var(--theme-rgb, 59, 130, 246), 0.1);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
.fc-popover-body {
|
|
325
|
+
padding: 1rem;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
.fc-more-link {
|
|
329
|
+
color: var(--theme-color, #3b82f6);
|
|
330
|
+
font-weight: 600;
|
|
331
|
+
padding: 0.25rem 0.5rem;
|
|
332
|
+
border-radius: 0.5rem;
|
|
333
|
+
transition: all 0.2s ease;
|
|
334
|
+
background: rgba(var(--theme-rgb, 59, 130, 246), 0.1);
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
.fc-more-link:hover {
|
|
338
|
+
color: var(--theme-dark, #2563eb);
|
|
339
|
+
background: rgba(var(--theme-rgb, 59, 130, 246), 0.2);
|
|
340
|
+
transform: translateX(2px);
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
.fc-scrollgrid {
|
|
344
|
+
border-color: rgba(226, 232, 240, 0.5);
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
.fc-scrollgrid-section-header > td {
|
|
348
|
+
border-color: rgba(226, 232, 240, 0.5);
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
.fc-scrollgrid-sync-inner {
|
|
352
|
+
border-color: rgba(226, 232, 240, 0.3);
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
.fc-daygrid-event {
|
|
356
|
+
margin: 0.125rem 0.25rem;
|
|
357
|
+
min-height: 24px;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
.fc-daygrid-day-events {
|
|
361
|
+
margin-top: 0.25rem;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
.fc-daygrid-day-frame {
|
|
365
|
+
min-height: 100px;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
.fc-timegrid-event {
|
|
369
|
+
border-radius: 0.5rem;
|
|
370
|
+
margin: 0.125rem;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
.fc-event-main {
|
|
374
|
+
padding: 0.25rem;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
/* Smooth animations */
|
|
378
|
+
@keyframes fadeIn {
|
|
379
|
+
from {
|
|
380
|
+
opacity: 0;
|
|
381
|
+
transform: translateY(-10px);
|
|
382
|
+
}
|
|
383
|
+
to {
|
|
384
|
+
opacity: 1;
|
|
385
|
+
transform: translateY(0);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
.fc-view-harness {
|
|
390
|
+
animation: fadeIn 0.3s ease-out;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
/* Responsive adjustments */
|
|
394
|
+
@media (max-width: 768px) {
|
|
395
|
+
.fc-toolbar {
|
|
396
|
+
flex-direction: column;
|
|
397
|
+
gap: 1rem;
|
|
398
|
+
padding: 0.75rem 0;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
.fc-toolbar-title {
|
|
402
|
+
font-size: 1.5rem;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
.fc-button {
|
|
406
|
+
padding: 0.5rem 1rem;
|
|
407
|
+
font-size: 0.8125rem;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
.fc-event {
|
|
411
|
+
font-size: 0.75rem;
|
|
412
|
+
padding: 0.25rem 0.5rem;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
.fc-col-header-cell {
|
|
416
|
+
padding: 0.75rem 0.25rem;
|
|
417
|
+
font-size: 0.75rem;
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
/* Custom scrollbar */
|
|
422
|
+
.fc-scroller::-webkit-scrollbar {
|
|
423
|
+
width: 8px;
|
|
424
|
+
height: 8px;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
.fc-scroller::-webkit-scrollbar-track {
|
|
428
|
+
background: #f1f5f9;
|
|
429
|
+
border-radius: 4px;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
.fc-scroller::-webkit-scrollbar-thumb {
|
|
433
|
+
background: linear-gradient(135deg, var(--theme-color, #3b82f6) 0%, var(--theme-light, #8b5cf6) 100%);
|
|
434
|
+
border-radius: 4px;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
.fc-scroller::-webkit-scrollbar-thumb:hover {
|
|
438
|
+
background: linear-gradient(135deg, var(--theme-dark, #2563eb) 0%, var(--theme-light, #7c3aed) 100%);
|
|
439
|
+
}
|
|
440
|
+
` })] }));
|
|
441
|
+
};
|
|
442
|
+
export default CustomizedCalendar;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { CalendarEventExtended, Batch } from '@/data/mock-calendar-data';
|
|
3
|
+
interface DateEventsListProps {
|
|
4
|
+
date: string;
|
|
5
|
+
events: CalendarEventExtended[];
|
|
6
|
+
batches: Batch[];
|
|
7
|
+
isOpen: boolean;
|
|
8
|
+
onClose: () => void;
|
|
9
|
+
onEventClick: (event: CalendarEventExtended) => void;
|
|
10
|
+
onAddEvent?: () => void;
|
|
11
|
+
}
|
|
12
|
+
declare const DateEventsList: React.FC<DateEventsListProps>;
|
|
13
|
+
export default DateEventsList;
|
|
14
|
+
//# sourceMappingURL=DateEventsList.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DateEventsList.d.ts","sourceRoot":"","sources":["../../../components/classroom-calendar/DateEventsList.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,qBAAqB,EAAE,KAAK,EAAiC,MAAM,2BAA2B,CAAC;AAGxG,UAAU,mBAAmB;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,qBAAqB,EAAE,CAAC;IAChC,OAAO,EAAE,KAAK,EAAE,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,YAAY,EAAE,CAAC,KAAK,EAAE,qBAAqB,KAAK,IAAI,CAAC;IACrD,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;CACzB;AAED,QAAA,MAAM,cAAc,EAAE,KAAK,CAAC,EAAE,CAAC,mBAAmB,CAgNjD,CAAC;AAEF,eAAe,cAAc,CAAC"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { getEventsByDate, getBatchById } from '@/data/mock-calendar-data';
|
|
4
|
+
import { EventType } from './calendar.types';
|
|
5
|
+
const DateEventsList = ({ date, events, batches, isOpen, onClose, onEventClick, onAddEvent, }) => {
|
|
6
|
+
if (!isOpen)
|
|
7
|
+
return null;
|
|
8
|
+
const dateEvents = getEventsByDate(date, events);
|
|
9
|
+
const formattedDate = new Date(date).toLocaleDateString('en-US', {
|
|
10
|
+
weekday: 'long',
|
|
11
|
+
year: 'numeric',
|
|
12
|
+
month: 'long',
|
|
13
|
+
day: 'numeric',
|
|
14
|
+
});
|
|
15
|
+
const getEventTypeColor = (type) => {
|
|
16
|
+
switch (type) {
|
|
17
|
+
case EventType.SESSION:
|
|
18
|
+
return 'bg-blue-500';
|
|
19
|
+
case EventType.EVENT:
|
|
20
|
+
return 'bg-green-500';
|
|
21
|
+
case EventType.EXAM:
|
|
22
|
+
return 'bg-red-500';
|
|
23
|
+
case EventType.HOLIDAY:
|
|
24
|
+
return 'bg-amber-500';
|
|
25
|
+
default:
|
|
26
|
+
return 'bg-gray-500';
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
const formatTime = (date) => {
|
|
30
|
+
const d = new Date(date);
|
|
31
|
+
return d.toLocaleTimeString('en-US', { hour: 'numeric', minute: '2-digit', hour12: true });
|
|
32
|
+
};
|
|
33
|
+
// Group events by batch
|
|
34
|
+
const eventsByBatch = dateEvents.reduce((acc, event) => {
|
|
35
|
+
const batchId = event.batchId;
|
|
36
|
+
if (!acc[batchId]) {
|
|
37
|
+
acc[batchId] = [];
|
|
38
|
+
}
|
|
39
|
+
acc[batchId].push(event);
|
|
40
|
+
return acc;
|
|
41
|
+
}, {});
|
|
42
|
+
return (_jsx("div", { className: "fixed inset-0 z-50 flex items-center justify-center bg-black bg-opacity-50 backdrop-blur-sm", children: _jsxs("div", { className: "bg-white rounded-2xl shadow-2xl max-w-3xl w-full mx-4 max-h-[90vh] overflow-y-auto", children: [_jsx("div", { className: "sticky top-0 bg-gradient-to-r from-blue-600 to-purple-600 text-white p-6 rounded-t-2xl", children: _jsxs("div", { className: "flex justify-between items-center", children: [_jsxs("div", { children: [_jsxs("h2", { className: "text-2xl font-bold mb-1", children: ["Events on ", formattedDate] }), _jsxs("p", { className: "text-blue-100 text-sm", children: [dateEvents.length, " ", dateEvents.length === 1 ? 'event' : 'events', " scheduled"] })] }), _jsx("button", { onClick: onClose, className: "text-white hover:text-gray-200 transition-colors p-2 hover:bg-white/20 rounded-lg", children: _jsx("svg", { className: "w-6 h-6", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) }) })] }) }), _jsx("div", { className: "p-6", children: dateEvents.length === 0 ? (_jsxs("div", { className: "text-center py-12", children: [_jsx("svg", { className: "w-16 h-16 text-gray-300 mx-auto mb-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" }) }), _jsx("p", { className: "text-gray-500 text-lg", children: "No events scheduled for this date" }), _jsx("button", { onClick: () => {
|
|
43
|
+
onClose();
|
|
44
|
+
onAddEvent?.();
|
|
45
|
+
}, className: "mt-4 px-6 py-2 bg-gradient-to-r from-blue-600 to-purple-600 text-white rounded-lg font-semibold hover:from-blue-700 hover:to-purple-700 transition-all", children: "Add Event" })] })) : (_jsx("div", { className: "space-y-6", children: Object.entries(eventsByBatch).map(([batchId, batchEvents]) => {
|
|
46
|
+
const batch = getBatchById(batchId, batches);
|
|
47
|
+
return (_jsxs("div", { className: "border border-gray-200 rounded-lg overflow-hidden", children: [_jsx("div", { className: "bg-gradient-to-r from-blue-50 to-purple-50 p-4 border-b border-gray-200", children: _jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("div", { children: [_jsx("h3", { className: "font-bold text-gray-900 text-lg", children: batch?.name || 'All Batches' }), batch && (_jsxs("p", { className: "text-sm text-gray-600 mt-1", children: [batch.code, " \u2022 ", batch.startTime, " - ", batch.endTime, " \u2022 ", batch.currentEnrollment, "/", batch.capacity, " students"] }))] }), batch?.instructor && (_jsxs("div", { className: "text-right", children: [_jsx("p", { className: "text-sm text-gray-600", children: "Instructor" }), _jsx("p", { className: "font-semibold text-gray-900", children: batch.instructor.name })] }))] }) }), _jsx("div", { className: "divide-y divide-gray-100", children: batchEvents.map((event) => (_jsx("div", { className: "p-4 hover:bg-gray-50 transition-colors cursor-pointer", onClick: () => onEventClick(event), children: _jsxs("div", { className: "flex items-start gap-4", children: [_jsx("div", { className: `w-1 h-full min-h-[60px] ${getEventTypeColor(event.type)} rounded` }), _jsxs("div", { className: "flex-1", children: [_jsxs("div", { className: "flex items-center gap-2 mb-2", children: [_jsx("h4", { className: "font-semibold text-gray-900", children: event.title }), _jsx("span", { className: `px-2 py-0.5 rounded text-xs font-semibold ${event.type === EventType.SESSION ? 'bg-blue-100 text-blue-800' :
|
|
48
|
+
event.type === EventType.EVENT ? 'bg-green-100 text-green-800' :
|
|
49
|
+
event.type === EventType.EXAM ? 'bg-red-100 text-red-800' :
|
|
50
|
+
'bg-amber-100 text-amber-800'}`, children: event.type })] }), _jsxs("div", { className: "grid grid-cols-2 gap-2 text-sm text-gray-600", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" }) }), formatTime(event.start), " - ", formatTime(event.end)] }), event.room && (_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6" }) }), event.room.name, " (", event.room.building, ")"] })), event.subject && (_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.747 0 3.332.477 4.5 1.253v13C19.832 18.477 18.247 18 16.5 18c-1.746 0-3.332.477-4.5 1.253" }) }), event.subject.name, " (", event.subject.code, ")"] })), event.instructor && (_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z" }) }), event.instructor.name] }))] }), event.description && (_jsx("p", { className: "text-sm text-gray-500 mt-2 line-clamp-2", children: event.description }))] })] }) }, event.id))) })] }, batchId));
|
|
51
|
+
}) })) }), _jsxs("div", { className: "sticky bottom-0 bg-gray-50 p-4 rounded-b-2xl flex justify-end gap-3", children: [_jsx("button", { onClick: onClose, className: "px-6 py-2 bg-gray-200 text-gray-700 rounded-lg font-semibold hover:bg-gray-300 transition-colors", children: "Close" }), dateEvents.length > 0 && (_jsx("button", { onClick: () => {
|
|
52
|
+
onClose();
|
|
53
|
+
onAddEvent?.();
|
|
54
|
+
}, className: "px-6 py-2 bg-gradient-to-r from-blue-600 to-purple-600 text-white rounded-lg font-semibold hover:from-blue-700 hover:to-purple-700 transition-all", children: "Add New Event" }))] })] }) }));
|
|
55
|
+
};
|
|
56
|
+
export default DateEventsList;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { CalendarEventExtended, Batch } from '@/data/mock-calendar-data';
|
|
3
|
+
interface EventDetailsModalProps {
|
|
4
|
+
event: CalendarEventExtended;
|
|
5
|
+
batch?: Batch;
|
|
6
|
+
isOpen: boolean;
|
|
7
|
+
onClose: () => void;
|
|
8
|
+
}
|
|
9
|
+
declare const EventDetailsModal: React.FC<EventDetailsModalProps>;
|
|
10
|
+
export default EventDetailsModal;
|
|
11
|
+
//# sourceMappingURL=EventDetailsModal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EventDetailsModal.d.ts","sourceRoot":"","sources":["../../../components/classroom-calendar/EventDetailsModal.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EAAE,qBAAqB,EAAE,KAAK,EAA4B,MAAM,2BAA2B,CAAC;AAEnG,UAAU,sBAAsB;IAC9B,KAAK,EAAE,qBAAqB,CAAC;IAC7B,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,QAAA,MAAM,iBAAiB,EAAE,KAAK,CAAC,EAAE,CAAC,sBAAsB,CAwMvD,CAAC;AAEF,eAAe,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { EventType } from './calendar.types';
|
|
4
|
+
const EventDetailsModal = ({ event, batch, isOpen, onClose }) => {
|
|
5
|
+
if (!isOpen)
|
|
6
|
+
return null;
|
|
7
|
+
const getEventTypeBadgeColor = (type) => {
|
|
8
|
+
switch (type) {
|
|
9
|
+
case EventType.SESSION:
|
|
10
|
+
return 'bg-blue-100 text-blue-800';
|
|
11
|
+
case EventType.EVENT:
|
|
12
|
+
return 'bg-green-100 text-green-800';
|
|
13
|
+
case EventType.EXAM:
|
|
14
|
+
return 'bg-red-100 text-red-800';
|
|
15
|
+
case EventType.HOLIDAY:
|
|
16
|
+
return 'bg-amber-100 text-amber-800';
|
|
17
|
+
default:
|
|
18
|
+
return 'bg-gray-100 text-gray-800';
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
const formatTime = (date) => {
|
|
22
|
+
const d = new Date(date);
|
|
23
|
+
return d.toLocaleTimeString('en-US', { hour: 'numeric', minute: '2-digit', hour12: true });
|
|
24
|
+
};
|
|
25
|
+
const formatDate = (date) => {
|
|
26
|
+
const d = new Date(date);
|
|
27
|
+
return d.toLocaleDateString('en-US', { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' });
|
|
28
|
+
};
|
|
29
|
+
return (_jsx("div", { className: "fixed inset-0 z-50 flex items-center justify-center bg-black bg-opacity-50 backdrop-blur-sm", children: _jsxs("div", { className: "bg-white rounded-2xl shadow-2xl max-w-2xl w-full mx-4 max-h-[90vh] overflow-y-auto", children: [_jsx("div", { className: "sticky top-0 bg-gradient-to-r from-blue-600 to-purple-600 text-white p-6 rounded-t-2xl", children: _jsxs("div", { className: "flex justify-between items-start", children: [_jsxs("div", { children: [_jsx("h2", { className: "text-2xl font-bold mb-2", children: event.title }), _jsx("span", { className: `inline-block px-3 py-1 rounded-full text-sm font-semibold ${getEventTypeBadgeColor(event.type)}`, children: event.type })] }), _jsx("button", { onClick: onClose, className: "text-white hover:text-gray-200 transition-colors p-2 hover:bg-white/20 rounded-lg", children: _jsx("svg", { className: "w-6 h-6", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) }) })] }) }), _jsxs("div", { className: "p-6 space-y-6", children: [_jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4", children: [_jsxs("div", { className: "bg-gray-50 p-4 rounded-lg", children: [_jsx("p", { className: "text-sm text-gray-600 mb-1", children: "Date" }), _jsx("p", { className: "font-semibold text-gray-900", children: formatDate(event.start) })] }), _jsxs("div", { className: "bg-gray-50 p-4 rounded-lg", children: [_jsx("p", { className: "text-sm text-gray-600 mb-1", children: "Time" }), _jsxs("p", { className: "font-semibold text-gray-900", children: [formatTime(event.start), " - ", formatTime(event.end)] })] })] }), batch && (_jsxs("div", { className: "bg-blue-50 border-l-4 border-blue-500 p-4 rounded-lg", children: [_jsxs("h3", { className: "font-bold text-gray-900 mb-3 flex items-center gap-2", children: [_jsx("svg", { className: "w-5 h-5 text-blue-600", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M17 20h5v-2a3 3 0 00-3-3H5a3 3 0 00-3 3v2h5m0 0v-2a2 2 0 012-2h6a2 2 0 012 2v2m-7 0h6" }) }), "Batch Information"] }), _jsxs("div", { className: "grid grid-cols-2 gap-3 text-sm", children: [_jsxs("div", { children: [_jsx("p", { className: "text-gray-600", children: "Batch Name" }), _jsx("p", { className: "font-semibold text-gray-900", children: batch.name })] }), _jsxs("div", { children: [_jsx("p", { className: "text-gray-600", children: "Batch Code" }), _jsx("p", { className: "font-semibold text-gray-900", children: batch.code })] }), _jsxs("div", { children: [_jsx("p", { className: "text-gray-600", children: "Timing" }), _jsxs("p", { className: "font-semibold text-gray-900", children: [batch.startTime, " - ", batch.endTime] })] }), _jsxs("div", { children: [_jsx("p", { className: "text-gray-600", children: "Enrollment" }), _jsxs("p", { className: "font-semibold text-gray-900", children: [batch.currentEnrollment, " / ", batch.capacity] })] })] }), batch.instructor && (_jsxs("div", { className: "mt-3 pt-3 border-t border-blue-200", children: [_jsx("p", { className: "text-gray-600 text-sm", children: "Instructor" }), _jsx("p", { className: "font-semibold text-gray-900", children: batch.instructor.name }), _jsx("p", { className: "text-gray-500 text-sm", children: batch.instructor.email })] }))] })), event.description && (_jsxs("div", { children: [_jsx("h3", { className: "font-bold text-gray-900 mb-2", children: "Description" }), _jsx("p", { className: "text-gray-700", children: event.description })] })), event.room && (_jsxs("div", { className: "bg-gray-50 p-4 rounded-lg", children: [_jsxs("h3", { className: "font-bold text-gray-900 mb-3 flex items-center gap-2", children: [_jsx("svg", { className: "w-5 h-5 text-gray-600", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6" }) }), "Room Information"] }), _jsxs("div", { className: "grid grid-cols-2 gap-3 text-sm", children: [_jsxs("div", { children: [_jsx("p", { className: "text-gray-600", children: "Room" }), _jsx("p", { className: "font-semibold text-gray-900", children: event.room.name })] }), _jsxs("div", { children: [_jsx("p", { className: "text-gray-600", children: "Building" }), _jsx("p", { className: "font-semibold text-gray-900", children: event.room.building })] }), _jsxs("div", { children: [_jsx("p", { className: "text-gray-600", children: "Floor" }), _jsxs("p", { className: "font-semibold text-gray-900", children: ["Floor ", event.room.floor] })] }), _jsxs("div", { children: [_jsx("p", { className: "text-gray-600", children: "Capacity" }), _jsxs("p", { className: "font-semibold text-gray-900", children: [event.room.capacity, " seats"] })] })] }), event.room.facilities && event.room.facilities.length > 0 && (_jsxs("div", { className: "mt-3 pt-3 border-t border-gray-200", children: [_jsx("p", { className: "text-gray-600 text-sm mb-2", children: "Facilities" }), _jsx("div", { className: "flex flex-wrap gap-2", children: event.room.facilities.map((facility, index) => (_jsx("span", { className: "px-2 py-1 bg-white rounded text-xs font-medium text-gray-700", children: facility }, index))) })] }))] })), event.subject && (_jsxs("div", { className: "bg-purple-50 p-4 rounded-lg", children: [_jsx("h3", { className: "font-bold text-gray-900 mb-2", children: "Subject" }), _jsx("p", { className: "font-semibold text-gray-900", children: event.subject.name }), _jsxs("p", { className: "text-gray-600 text-sm", children: [event.subject.code, " \u2022 ", event.subject.credits, " Credits"] })] })), event.status && (_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("span", { className: "text-sm text-gray-600", children: "Status:" }), _jsx("span", { className: `px-3 py-1 rounded-full text-sm font-semibold ${event.status === 'CONFIRMED' ? 'bg-green-100 text-green-800' :
|
|
30
|
+
event.status === 'SCHEDULED' ? 'bg-blue-100 text-blue-800' :
|
|
31
|
+
event.status === 'CANCELLED' ? 'bg-red-100 text-red-800' :
|
|
32
|
+
'bg-gray-100 text-gray-800'}`, children: event.status })] }))] }), _jsxs("div", { className: "sticky bottom-0 bg-gray-50 p-4 rounded-b-2xl flex justify-end gap-3", children: [_jsx("button", { onClick: onClose, className: "px-6 py-2 bg-gray-200 text-gray-700 rounded-lg font-semibold hover:bg-gray-300 transition-colors", children: "Close" }), _jsx("button", { onClick: () => {
|
|
33
|
+
// Handle edit action
|
|
34
|
+
onClose();
|
|
35
|
+
}, className: "px-6 py-2 bg-gradient-to-r from-blue-600 to-purple-600 text-white rounded-lg font-semibold hover:from-blue-700 hover:to-purple-700 transition-all", children: "Edit Event" })] })] }) }));
|
|
36
|
+
};
|
|
37
|
+
export default EventDetailsModal;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Calendar Event Types
|
|
3
|
+
*/
|
|
4
|
+
export declare enum EventType {
|
|
5
|
+
SESSION = "SESSION",
|
|
6
|
+
EVENT = "EVENT",
|
|
7
|
+
EXAM = "EXAM",
|
|
8
|
+
HOLIDAY = "HOLIDAY"
|
|
9
|
+
}
|
|
10
|
+
export interface CalendarEvent {
|
|
11
|
+
id: string;
|
|
12
|
+
title: string;
|
|
13
|
+
start: string | Date;
|
|
14
|
+
end: string | Date;
|
|
15
|
+
batchId: string;
|
|
16
|
+
batchName: string;
|
|
17
|
+
type: EventType;
|
|
18
|
+
color?: string;
|
|
19
|
+
extendedProps?: {
|
|
20
|
+
[key: string]: any;
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
export interface CustomizedCalendarProps {
|
|
24
|
+
events: CalendarEvent[];
|
|
25
|
+
onDateClick: (date: string) => void;
|
|
26
|
+
onEventClick: (event: CalendarEvent) => void;
|
|
27
|
+
height?: string | number;
|
|
28
|
+
initialView?: 'dayGridMonth' | 'timeGridWeek' | 'timeGridDay';
|
|
29
|
+
editable?: boolean;
|
|
30
|
+
selectable?: boolean;
|
|
31
|
+
selectMirror?: boolean;
|
|
32
|
+
droppable?: boolean;
|
|
33
|
+
eventResizableFromStart?: boolean;
|
|
34
|
+
eventStartEditable?: boolean;
|
|
35
|
+
eventDurationEditable?: boolean;
|
|
36
|
+
themeColor?: string;
|
|
37
|
+
}
|
|
38
|
+
export interface EventClickInfo {
|
|
39
|
+
event: {
|
|
40
|
+
id: string;
|
|
41
|
+
title: string;
|
|
42
|
+
start: Date;
|
|
43
|
+
end: Date;
|
|
44
|
+
extendedProps: {
|
|
45
|
+
batchId: string;
|
|
46
|
+
batchName: string;
|
|
47
|
+
type: EventType;
|
|
48
|
+
color?: string;
|
|
49
|
+
};
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
export interface DateClickInfo {
|
|
53
|
+
date: Date;
|
|
54
|
+
dateStr: string;
|
|
55
|
+
allDay: boolean;
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=calendar.types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"calendar.types.d.ts","sourceRoot":"","sources":["../../../components/classroom-calendar/calendar.types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,oBAAY,SAAS;IACnB,OAAO,YAAY;IACnB,KAAK,UAAU;IACf,IAAI,SAAS;IACb,OAAO,YAAY;CACpB;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,SAAS,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,aAAa,CAAC,EAAE;QACd,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;KACpB,CAAC;CACH;AAED,MAAM,WAAW,uBAAuB;IACtC,MAAM,EAAE,aAAa,EAAE,CAAC;IACxB,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,YAAY,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IAC7C,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACzB,WAAW,CAAC,EAAE,cAAc,GAAG,cAAc,GAAG,aAAa,CAAC;IAC9D,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE;QACL,EAAE,EAAE,MAAM,CAAC;QACX,KAAK,EAAE,MAAM,CAAC;QACd,KAAK,EAAE,IAAI,CAAC;QACZ,GAAG,EAAE,IAAI,CAAC;QACV,aAAa,EAAE;YACb,OAAO,EAAE,MAAM,CAAC;YAChB,SAAS,EAAE,MAAM,CAAC;YAClB,IAAI,EAAE,SAAS,CAAC;YAChB,KAAK,CAAC,EAAE,MAAM,CAAC;SAChB,CAAC;KACH,CAAC;CACH;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,IAAI,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,OAAO,CAAC;CACjB"}
|