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
package/LICENSE
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
|
23
|
+
|
package/README.md
ADDED
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
# Customized Calendar Component
|
|
2
|
+
|
|
3
|
+
A modern, elegant, and highly customizable calendar component built with React, TypeScript, and FullCalendar. Perfect for any application that needs a beautiful, flexible calendar interface.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
✨ **Modern Design**
|
|
8
|
+
- Clean, elegant UI with gradient accents
|
|
9
|
+
- Responsive layout for all screen sizes
|
|
10
|
+
- Customizable theme colors
|
|
11
|
+
- Smooth animations and transitions
|
|
12
|
+
|
|
13
|
+
📅 **Multiple Views**
|
|
14
|
+
- Month view
|
|
15
|
+
- Week view
|
|
16
|
+
- Day view
|
|
17
|
+
|
|
18
|
+
🎯 **Event Management**
|
|
19
|
+
- Color-coded events by type (SESSION, EVENT, EXAM, HOLIDAY)
|
|
20
|
+
- Batch information display
|
|
21
|
+
- Drag & drop support
|
|
22
|
+
- Event resizing
|
|
23
|
+
- Click to view/edit events
|
|
24
|
+
|
|
25
|
+
📚 **Batch Support**
|
|
26
|
+
- Display batch information for each event
|
|
27
|
+
- Group events by batch
|
|
28
|
+
- Batch-specific filtering
|
|
29
|
+
|
|
30
|
+
🎨 **Customizable**
|
|
31
|
+
- Theme color support
|
|
32
|
+
- Custom event colors
|
|
33
|
+
- Flexible styling with Tailwind CSS
|
|
34
|
+
|
|
35
|
+
## Installation
|
|
36
|
+
|
|
37
|
+
### NPM Package (Recommended)
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
npm install customized-calendar
|
|
41
|
+
# or
|
|
42
|
+
yarn add customized-calendar
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
**Note:** This component uses Tailwind CSS classes. Make sure Tailwind CSS is configured in your project. See [Styling](#styling) section below for setup instructions.
|
|
46
|
+
|
|
47
|
+
### Manual Installation
|
|
48
|
+
|
|
49
|
+
If you prefer to copy the component files directly:
|
|
50
|
+
|
|
51
|
+
1. Copy the `components/classroom-calendar` folder to your project
|
|
52
|
+
2. Install peer dependencies:
|
|
53
|
+
```bash
|
|
54
|
+
npm install @fullcalendar/react @fullcalendar/core @fullcalendar/daygrid @fullcalendar/timegrid @fullcalendar/interaction react react-dom
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Quick Start
|
|
58
|
+
|
|
59
|
+
### Using NPM Package
|
|
60
|
+
|
|
61
|
+
```tsx
|
|
62
|
+
import { CustomizedCalendar, CalendarEvent, EventType } from 'customized-calendar';
|
|
63
|
+
|
|
64
|
+
function MyCalendar() {
|
|
65
|
+
const events: CalendarEvent[] = [
|
|
66
|
+
{
|
|
67
|
+
id: '1',
|
|
68
|
+
title: 'Mathematics Session',
|
|
69
|
+
start: new Date(),
|
|
70
|
+
end: new Date(Date.now() + 90 * 60 * 1000),
|
|
71
|
+
batchId: 'batch-001',
|
|
72
|
+
batchName: 'Batch A - Morning',
|
|
73
|
+
type: EventType.SESSION,
|
|
74
|
+
},
|
|
75
|
+
];
|
|
76
|
+
|
|
77
|
+
return (
|
|
78
|
+
<CustomizedCalendar
|
|
79
|
+
events={events}
|
|
80
|
+
onDateClick={(date) => console.log('Date:', date)}
|
|
81
|
+
onEventClick={(event) => console.log('Event:', event)}
|
|
82
|
+
themeColor="#3b82f6"
|
|
83
|
+
/>
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Using Copied Component Files
|
|
89
|
+
|
|
90
|
+
```tsx
|
|
91
|
+
import { CustomizedCalendar, CalendarEvent, EventType } from '@/components/classroom-calendar';
|
|
92
|
+
|
|
93
|
+
function MyCalendar() {
|
|
94
|
+
const events: CalendarEvent[] = [
|
|
95
|
+
{
|
|
96
|
+
id: '1',
|
|
97
|
+
title: 'Mathematics Session',
|
|
98
|
+
start: new Date(),
|
|
99
|
+
end: new Date(Date.now() + 90 * 60 * 1000),
|
|
100
|
+
batchId: 'batch-001',
|
|
101
|
+
batchName: 'Batch A - Morning',
|
|
102
|
+
type: EventType.SESSION,
|
|
103
|
+
},
|
|
104
|
+
];
|
|
105
|
+
|
|
106
|
+
return (
|
|
107
|
+
<CustomizedCalendar
|
|
108
|
+
events={events}
|
|
109
|
+
onDateClick={(date) => console.log('Date:', date)}
|
|
110
|
+
onEventClick={(event) => console.log('Event:', event)}
|
|
111
|
+
themeColor="#3b82f6"
|
|
112
|
+
/>
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Documentation
|
|
118
|
+
|
|
119
|
+
- **[NPM Publish Guide](./NPM_PUBLISH_GUIDE.md)** - How to publish to NPM
|
|
120
|
+
- **[Quick Integration Guide](./QUICK_INTEGRATION.md)** - 5-minute setup guide
|
|
121
|
+
- **[Reusable Package Guide](./REUSABLE_PACKAGE_GUIDE.md)** - Use in other projects & backend integration
|
|
122
|
+
- **[Quick Start Guide](./QUICK_START.md)** - Get started in 5 minutes
|
|
123
|
+
- **[Integration Guide](./INTEGRATION_GUIDE.md)** - Complete integration documentation
|
|
124
|
+
- **[API Contract](./API_CONTRACT.md)** - Backend API requirements
|
|
125
|
+
- **[Data Structure](./data/README.md)** - Data models and types
|
|
126
|
+
|
|
127
|
+
## Component Structure
|
|
128
|
+
|
|
129
|
+
```
|
|
130
|
+
components/classroom-calendar/
|
|
131
|
+
├── CustomizedCalendar.tsx # Main calendar component
|
|
132
|
+
├── AddEventModal.tsx # Add event modal
|
|
133
|
+
├── EventDetailsModal.tsx # Event details modal
|
|
134
|
+
├── DateEventsList.tsx # Date events list modal
|
|
135
|
+
├── calendar.types.ts # TypeScript types
|
|
136
|
+
├── calendar.utils.ts # Utility functions
|
|
137
|
+
└── index.ts # Exports
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## Props
|
|
141
|
+
|
|
142
|
+
### CustomizedCalendar
|
|
143
|
+
|
|
144
|
+
| Prop | Type | Required | Default | Description |
|
|
145
|
+
|------|------|----------|---------|-------------|
|
|
146
|
+
| `events` | `CalendarEvent[]` | ✅ | - | Array of calendar events |
|
|
147
|
+
| `onDateClick` | `(date: string) => void` | ✅ | - | Callback when date is clicked |
|
|
148
|
+
| `onEventClick` | `(event: CalendarEvent) => void` | ✅ | - | Callback when event is clicked |
|
|
149
|
+
| `height` | `string \| number` | ❌ | `'auto'` | Calendar height |
|
|
150
|
+
| `initialView` | `'dayGridMonth' \| 'timeGridWeek' \| 'timeGridDay'` | ❌ | `'dayGridMonth'` | Initial view |
|
|
151
|
+
| `themeColor` | `string` | ❌ | `'#3b82f6'` | Primary theme color (hex) |
|
|
152
|
+
| `editable` | `boolean` | ❌ | `true` | Enable drag & drop |
|
|
153
|
+
| `selectable` | `boolean` | ❌ | `true` | Enable date selection |
|
|
154
|
+
|
|
155
|
+
## Event Types
|
|
156
|
+
|
|
157
|
+
- **SESSION**: Regular class sessions (Blue: `#4f46e5`)
|
|
158
|
+
- **EVENT**: Special events, labs, workshops (Green: `#059669`)
|
|
159
|
+
- **EXAM**: Examinations (Red: `#dc2626`)
|
|
160
|
+
- **HOLIDAY**: Holidays (Amber: `#d97706`)
|
|
161
|
+
|
|
162
|
+
## Examples
|
|
163
|
+
|
|
164
|
+
See `components/classroom-calendar/example-usage.tsx` for complete examples.
|
|
165
|
+
|
|
166
|
+
## Backend Integration
|
|
167
|
+
|
|
168
|
+
The component can work with any backend that provides calendar events. It's flexible and can be adapted to different API structures.
|
|
169
|
+
|
|
170
|
+
### Quick Setup
|
|
171
|
+
1. Copy component files to your project (see [QUICK_INTEGRATION.md](./QUICK_INTEGRATION.md))
|
|
172
|
+
2. Configure API service (see `services/calendarApi.configurable.ts`)
|
|
173
|
+
3. Connect to your backend
|
|
174
|
+
|
|
175
|
+
### Backend Options
|
|
176
|
+
- **REST API** - Standard REST endpoints (see [INTEGRATION_GUIDE.md](./INTEGRATION_GUIDE.md))
|
|
177
|
+
- **GraphQL** - Use GraphQL queries (see [REUSABLE_PACKAGE_GUIDE.md](./REUSABLE_PACKAGE_GUIDE.md))
|
|
178
|
+
- **Firebase/Supabase** - Direct database integration (examples included)
|
|
179
|
+
- **Custom Format** - Adapt to any API structure (see `examples/api-config-examples.ts`)
|
|
180
|
+
|
|
181
|
+
### Required Endpoints
|
|
182
|
+
- `GET /api/calendar/events` - Get events with date range
|
|
183
|
+
- `POST /api/calendar/events` - Create event
|
|
184
|
+
- `PUT /api/calendar/events/:id` - Update event
|
|
185
|
+
- `DELETE /api/calendar/events/:id` - Delete event
|
|
186
|
+
|
|
187
|
+
See [API_CONTRACT.md](./API_CONTRACT.md) for detailed API documentation and [REUSABLE_PACKAGE_GUIDE.md](./REUSABLE_PACKAGE_GUIDE.md) for backend integration strategies.
|
|
188
|
+
|
|
189
|
+
## Styling
|
|
190
|
+
|
|
191
|
+
The component uses Tailwind CSS. Ensure Tailwind is configured in your project:
|
|
192
|
+
|
|
193
|
+
```js
|
|
194
|
+
// tailwind.config.js
|
|
195
|
+
module.exports = {
|
|
196
|
+
content: [
|
|
197
|
+
'./components/**/*.{js,ts,jsx,tsx}',
|
|
198
|
+
'./node_modules/customized-calendar/dist/**/*.{js,jsx}', // Include package files
|
|
199
|
+
'./app/**/*.{js,ts,jsx,tsx}', // Your app files
|
|
200
|
+
],
|
|
201
|
+
// ... rest of config
|
|
202
|
+
};
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
**Important:** The component includes inline styles for FullCalendar customization, but Tailwind CSS classes are used for layout and responsive design. Make sure your Tailwind configuration includes the package files in the `content` array.
|
|
206
|
+
|
|
207
|
+
## Browser Support
|
|
208
|
+
|
|
209
|
+
- Chrome (latest)
|
|
210
|
+
- Firefox (latest)
|
|
211
|
+
- Safari (latest)
|
|
212
|
+
- Edge (latest)
|
|
213
|
+
|
|
214
|
+
## License
|
|
215
|
+
|
|
216
|
+
MIT
|
|
217
|
+
|
|
218
|
+
## Using in Other Projects
|
|
219
|
+
|
|
220
|
+
Want to use this calendar in another project? See the comprehensive guide:
|
|
221
|
+
|
|
222
|
+
- **[REUSABLE_PACKAGE_GUIDE.md](./REUSABLE_PACKAGE_GUIDE.md)** - Complete guide for using in other projects
|
|
223
|
+
- Copy component files
|
|
224
|
+
- Configure for different backends
|
|
225
|
+
- API service examples
|
|
226
|
+
- Firebase/GraphQL/Custom backend examples
|
|
227
|
+
|
|
228
|
+
Quick start: Copy `components/classroom-calendar` folder and install dependencies.
|
|
229
|
+
|
|
230
|
+
## Support
|
|
231
|
+
|
|
232
|
+
For issues or questions:
|
|
233
|
+
1. Check the [Quick Integration Guide](./QUICK_INTEGRATION.md) for fast setup
|
|
234
|
+
2. See [Reusable Package Guide](./REUSABLE_PACKAGE_GUIDE.md) for backend integration
|
|
235
|
+
3. Review [Integration Guide](./INTEGRATION_GUIDE.md) for complete documentation
|
|
236
|
+
4. Check [API Contract](./API_CONTRACT.md) for backend requirements
|
|
237
|
+
5. See example implementations in `examples/` folder
|
|
238
|
+
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Batch, Room, Subject, CalendarEventExtended } from '@/data/mock-calendar-data';
|
|
3
|
+
interface AddEventModalProps {
|
|
4
|
+
isOpen: boolean;
|
|
5
|
+
onClose: () => void;
|
|
6
|
+
onSave: (event: CalendarEventExtended) => void;
|
|
7
|
+
initialDate?: string;
|
|
8
|
+
batches: Batch[];
|
|
9
|
+
rooms: Room[];
|
|
10
|
+
subjects: Subject[];
|
|
11
|
+
}
|
|
12
|
+
declare const AddEventModal: React.FC<AddEventModalProps>;
|
|
13
|
+
export default AddEventModal;
|
|
14
|
+
//# sourceMappingURL=AddEventModal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AddEventModal.d.ts","sourceRoot":"","sources":["../../../components/classroom-calendar/AddEventModal.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAmB,MAAM,OAAO,CAAC;AAExC,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAExF,UAAU,kBAAkB;IAC1B,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,MAAM,EAAE,CAAC,KAAK,EAAE,qBAAqB,KAAK,IAAI,CAAC;IAC/C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,KAAK,EAAE,CAAC;IACjB,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,QAAQ,EAAE,OAAO,EAAE,CAAC;CACrB;AAED,QAAA,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CAyZ/C,CAAC;AAEF,eAAe,aAAa,CAAC"}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useState } from 'react';
|
|
4
|
+
import { EventType } from './calendar.types';
|
|
5
|
+
const AddEventModal = ({ isOpen, onClose, onSave, initialDate, batches, rooms, subjects, }) => {
|
|
6
|
+
const [formData, setFormData] = useState({
|
|
7
|
+
title: '',
|
|
8
|
+
description: '',
|
|
9
|
+
date: initialDate || new Date().toISOString().split('T')[0],
|
|
10
|
+
startTime: '10:00',
|
|
11
|
+
endTime: '11:30',
|
|
12
|
+
batchId: batches[0]?.id || '',
|
|
13
|
+
type: EventType.SESSION,
|
|
14
|
+
roomId: '',
|
|
15
|
+
subjectId: '',
|
|
16
|
+
color: '',
|
|
17
|
+
isAllDay: false,
|
|
18
|
+
});
|
|
19
|
+
const [errors, setErrors] = useState({});
|
|
20
|
+
if (!isOpen)
|
|
21
|
+
return null;
|
|
22
|
+
const handleChange = (e) => {
|
|
23
|
+
const { name, value, type } = e.target;
|
|
24
|
+
const checked = e.target.checked;
|
|
25
|
+
setFormData((prev) => ({
|
|
26
|
+
...prev,
|
|
27
|
+
[name]: type === 'checkbox' ? checked : value,
|
|
28
|
+
}));
|
|
29
|
+
// Clear error when user starts typing
|
|
30
|
+
if (errors[name]) {
|
|
31
|
+
setErrors((prev) => {
|
|
32
|
+
const newErrors = { ...prev };
|
|
33
|
+
delete newErrors[name];
|
|
34
|
+
return newErrors;
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
const validateForm = () => {
|
|
39
|
+
const newErrors = {};
|
|
40
|
+
if (!formData.title.trim()) {
|
|
41
|
+
newErrors.title = 'Title is required';
|
|
42
|
+
}
|
|
43
|
+
if (!formData.batchId) {
|
|
44
|
+
newErrors.batchId = 'Batch is required';
|
|
45
|
+
}
|
|
46
|
+
if (!formData.isAllDay) {
|
|
47
|
+
if (!formData.startTime) {
|
|
48
|
+
newErrors.startTime = 'Start time is required';
|
|
49
|
+
}
|
|
50
|
+
if (!formData.endTime) {
|
|
51
|
+
newErrors.endTime = 'End time is required';
|
|
52
|
+
}
|
|
53
|
+
// Validate end time is after start time
|
|
54
|
+
if (formData.startTime && formData.endTime) {
|
|
55
|
+
const [startHour, startMin] = formData.startTime.split(':').map(Number);
|
|
56
|
+
const [endHour, endMin] = formData.endTime.split(':').map(Number);
|
|
57
|
+
const startMinutes = startHour * 60 + startMin;
|
|
58
|
+
const endMinutes = endHour * 60 + endMin;
|
|
59
|
+
if (endMinutes <= startMinutes) {
|
|
60
|
+
newErrors.endTime = 'End time must be after start time';
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
setErrors(newErrors);
|
|
65
|
+
return Object.keys(newErrors).length === 0;
|
|
66
|
+
};
|
|
67
|
+
const handleSubmit = (e) => {
|
|
68
|
+
e.preventDefault();
|
|
69
|
+
if (!validateForm()) {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
const selectedBatch = batches.find((b) => b.id === formData.batchId);
|
|
73
|
+
const selectedRoom = formData.roomId ? rooms.find((r) => r.id === formData.roomId) : null;
|
|
74
|
+
const selectedSubject = formData.subjectId ? subjects.find((s) => s.id === formData.subjectId) : null;
|
|
75
|
+
// Create event dates
|
|
76
|
+
let start;
|
|
77
|
+
let end;
|
|
78
|
+
if (formData.isAllDay) {
|
|
79
|
+
start = formData.date;
|
|
80
|
+
end = formData.date;
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
start = `${formData.date}T${formData.startTime}:00`;
|
|
84
|
+
end = `${formData.date}T${formData.endTime}:00`;
|
|
85
|
+
}
|
|
86
|
+
const newEvent = {
|
|
87
|
+
id: `event-${Date.now()}`,
|
|
88
|
+
title: formData.title,
|
|
89
|
+
description: formData.description || undefined,
|
|
90
|
+
start,
|
|
91
|
+
end,
|
|
92
|
+
batchId: formData.batchId,
|
|
93
|
+
batchName: selectedBatch?.name || '',
|
|
94
|
+
type: formData.type,
|
|
95
|
+
color: formData.color || undefined,
|
|
96
|
+
room: selectedRoom || null,
|
|
97
|
+
instructor: selectedBatch?.instructor || null,
|
|
98
|
+
subject: selectedSubject || null,
|
|
99
|
+
status: 'SCHEDULED',
|
|
100
|
+
createdAt: new Date().toISOString(),
|
|
101
|
+
updatedAt: new Date().toISOString(),
|
|
102
|
+
};
|
|
103
|
+
onSave(newEvent);
|
|
104
|
+
// Reset form
|
|
105
|
+
setFormData({
|
|
106
|
+
title: '',
|
|
107
|
+
description: '',
|
|
108
|
+
date: initialDate || new Date().toISOString().split('T')[0],
|
|
109
|
+
startTime: '10:00',
|
|
110
|
+
endTime: '11:30',
|
|
111
|
+
batchId: batches[0]?.id || '',
|
|
112
|
+
type: EventType.SESSION,
|
|
113
|
+
roomId: '',
|
|
114
|
+
subjectId: '',
|
|
115
|
+
color: '',
|
|
116
|
+
isAllDay: false,
|
|
117
|
+
});
|
|
118
|
+
onClose();
|
|
119
|
+
};
|
|
120
|
+
const getEventTypeColor = (type) => {
|
|
121
|
+
const colorMap = {
|
|
122
|
+
[EventType.SESSION]: '#4f46e5',
|
|
123
|
+
[EventType.EVENT]: '#059669',
|
|
124
|
+
[EventType.EXAM]: '#dc2626',
|
|
125
|
+
[EventType.HOLIDAY]: '#d97706',
|
|
126
|
+
};
|
|
127
|
+
return colorMap[type] || '#6366f1';
|
|
128
|
+
};
|
|
129
|
+
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-center", children: [_jsx("h2", { className: "text-2xl font-bold", children: "Add New Event" }), _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("form", { onSubmit: handleSubmit, className: "p-6 space-y-6", children: [_jsxs("div", { children: [_jsxs("label", { className: "block text-sm font-semibold text-gray-700 mb-2", children: ["Event Title ", _jsx("span", { className: "text-red-500", children: "*" })] }), _jsx("input", { type: "text", name: "title", value: formData.title, onChange: handleChange, className: `w-full px-4 py-2 border rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent ${errors.title ? 'border-red-500' : 'border-gray-300'}`, placeholder: "e.g., Mathematics Session" }), errors.title && _jsx("p", { className: "text-red-500 text-sm mt-1", children: errors.title })] }), _jsxs("div", { children: [_jsx("label", { className: "block text-sm font-semibold text-gray-700 mb-2", children: "Description" }), _jsx("textarea", { name: "description", value: formData.description, onChange: handleChange, rows: 3, className: "w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent", placeholder: "Event description..." })] }), _jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4", children: [_jsxs("div", { children: [_jsxs("label", { className: "block text-sm font-semibold text-gray-700 mb-2", children: ["Date ", _jsx("span", { className: "text-red-500", children: "*" })] }), _jsx("input", { type: "date", name: "date", value: formData.date, onChange: handleChange, className: "w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent" })] }), _jsx("div", { className: "flex items-end", children: _jsxs("label", { className: "flex items-center space-x-2 cursor-pointer", children: [_jsx("input", { type: "checkbox", name: "isAllDay", checked: formData.isAllDay, onChange: handleChange, className: "w-5 h-5 text-blue-600 rounded focus:ring-blue-500" }), _jsx("span", { className: "text-sm font-semibold text-gray-700", children: "All Day Event" })] }) })] }), !formData.isAllDay && (_jsxs("div", { className: "grid grid-cols-2 gap-4", children: [_jsxs("div", { children: [_jsxs("label", { className: "block text-sm font-semibold text-gray-700 mb-2", children: ["Start Time ", _jsx("span", { className: "text-red-500", children: "*" })] }), _jsx("input", { type: "time", name: "startTime", value: formData.startTime, onChange: handleChange, className: `w-full px-4 py-2 border rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent ${errors.startTime ? 'border-red-500' : 'border-gray-300'}` }), errors.startTime && _jsx("p", { className: "text-red-500 text-sm mt-1", children: errors.startTime })] }), _jsxs("div", { children: [_jsxs("label", { className: "block text-sm font-semibold text-gray-700 mb-2", children: ["End Time ", _jsx("span", { className: "text-red-500", children: "*" })] }), _jsx("input", { type: "time", name: "endTime", value: formData.endTime, onChange: handleChange, className: `w-full px-4 py-2 border rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent ${errors.endTime ? 'border-red-500' : 'border-gray-300'}` }), errors.endTime && _jsx("p", { className: "text-red-500 text-sm mt-1", children: errors.endTime })] })] })), _jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4", children: [_jsxs("div", { children: [_jsxs("label", { className: "block text-sm font-semibold text-gray-700 mb-2", children: ["Batch ", _jsx("span", { className: "text-red-500", children: "*" })] }), _jsxs("select", { name: "batchId", value: formData.batchId, onChange: handleChange, className: `w-full px-4 py-2 border rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent ${errors.batchId ? 'border-red-500' : 'border-gray-300'}`, children: [_jsx("option", { value: "", children: "Select a batch" }), batches.map((batch) => (_jsxs("option", { value: batch.id, children: [batch.name, " (", batch.code, ")"] }, batch.id)))] }), errors.batchId && _jsx("p", { className: "text-red-500 text-sm mt-1", children: errors.batchId })] }), _jsxs("div", { children: [_jsxs("label", { className: "block text-sm font-semibold text-gray-700 mb-2", children: ["Event Type ", _jsx("span", { className: "text-red-500", children: "*" })] }), _jsx("select", { name: "type", value: formData.type, onChange: handleChange, className: "w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent", children: Object.values(EventType).map((type) => (_jsx("option", { value: type, children: type }, type))) })] })] }), _jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4", children: [_jsxs("div", { children: [_jsx("label", { className: "block text-sm font-semibold text-gray-700 mb-2", children: "Room" }), _jsxs("select", { name: "roomId", value: formData.roomId, onChange: handleChange, className: "w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent", children: [_jsx("option", { value: "", children: "Select a room (optional)" }), rooms.map((room) => (_jsxs("option", { value: room.id, children: [room.name, " - ", room.building, " (Floor ", room.floor, ")"] }, room.id)))] })] }), _jsxs("div", { children: [_jsx("label", { className: "block text-sm font-semibold text-gray-700 mb-2", children: "Subject" }), _jsxs("select", { name: "subjectId", value: formData.subjectId, onChange: handleChange, className: "w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent", children: [_jsx("option", { value: "", children: "Select a subject (optional)" }), subjects.map((subject) => (_jsxs("option", { value: subject.id, children: [subject.name, " (", subject.code, ")"] }, subject.id)))] })] })] }), _jsxs("div", { children: [_jsx("label", { className: "block text-sm font-semibold text-gray-700 mb-2", children: "Custom Color (optional)" }), _jsxs("div", { className: "flex items-center gap-4", children: [_jsx("input", { type: "color", name: "color", value: formData.color || getEventTypeColor(formData.type), onChange: handleChange, className: "w-16 h-10 border border-gray-300 rounded-lg cursor-pointer" }), _jsx("input", { type: "text", name: "color", value: formData.color, onChange: handleChange, placeholder: "#4f46e5", className: "flex-1 px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent" }), _jsx("button", { type: "button", onClick: () => setFormData((prev) => ({ ...prev, color: '' })), className: "px-4 py-2 text-sm text-gray-600 hover:text-gray-800 border border-gray-300 rounded-lg hover:bg-gray-50", children: "Use Default" })] }), _jsxs("p", { className: "text-xs text-gray-500 mt-1", children: ["Default: ", getEventTypeColor(formData.type), " for ", formData.type] })] }), _jsxs("div", { className: "flex justify-end gap-3 pt-4 border-t", children: [_jsx("button", { type: "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: "Cancel" }), _jsx("button", { type: "submit", 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 shadow-lg", children: "Add Event" })] })] })] }) }));
|
|
130
|
+
};
|
|
131
|
+
export default AddEventModal;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { CustomizedCalendarProps } from './calendar.types';
|
|
3
|
+
/**
|
|
4
|
+
* CustomizedCalendar Component
|
|
5
|
+
*
|
|
6
|
+
* A modern, reusable calendar component with customizable theme
|
|
7
|
+
* and support for multiple views, event management, and advanced interactions.
|
|
8
|
+
*/
|
|
9
|
+
declare const CustomizedCalendar: React.FC<CustomizedCalendarProps>;
|
|
10
|
+
export default CustomizedCalendar;
|
|
11
|
+
//# sourceMappingURL=CustomizedCalendar.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CustomizedCalendar.d.ts","sourceRoot":"","sources":["../../../components/classroom-calendar/CustomizedCalendar.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAsC,MAAM,OAAO,CAAC;AAK3D,OAAO,EACL,uBAAuB,EAExB,MAAM,kBAAkB,CAAC;AAY1B;;;;;GAKG;AACH,QAAA,MAAM,kBAAkB,EAAE,KAAK,CAAC,EAAE,CAAC,uBAAuB,CAshBzD,CAAC;AAEF,eAAe,kBAAkB,CAAC"}
|