| import EventDay from '../model/eventDay.model'; |
| import { IEvent } from '../model/event.model'; |
| import cloudinary from './cloudinary.util'; |
|
|
| |
| |
| |
| export const generateEventDays = async (event: IEvent): Promise<void> => { |
| const startDate = new Date(event.startDate); |
| const endDate = new Date(event.endDate); |
|
|
| |
| startDate.setHours(0, 0, 0, 0); |
| endDate.setHours(0, 0, 0, 0); |
|
|
| const days: any[] = []; |
| let currentDate = new Date(startDate); |
| let dayNumber = 1; |
|
|
| |
| const [startHour, startMinute] = event.defaultStartTime.split(':').map(Number); |
| const [endHour, endMinute] = event.defaultEndTime.split(':').map(Number); |
|
|
| while (currentDate <= endDate) { |
| |
| const dayStartTime = new Date(currentDate); |
| dayStartTime.setHours(startHour, startMinute, 0, 0); |
|
|
| const dayEndTime = new Date(currentDate); |
| dayEndTime.setHours(endHour, endMinute, 0, 0); |
|
|
| days.push({ |
| event: event._id, |
| date: new Date(currentDate), |
| dayNumber: dayNumber, |
| startTime: dayStartTime, |
| endTime: dayEndTime, |
| photos: [], |
| attendance: [], |
| hasStarted: false, |
| isCompleted: false |
| }); |
|
|
| currentDate.setDate(currentDate.getDate() + 1); |
| dayNumber++; |
| } |
|
|
| |
| if (days.length > 0) { |
| await EventDay.insertMany(days); |
| } |
| }; |
|
|
| |
| |
| |
| |
| export const uploadEventPhoto = async ( |
| file: any, |
| eventId: string, |
| dayNumber: number |
| ): Promise<{ url: string; publicId: string }> => { |
| return new Promise((resolve, reject) => { |
| const timestamp = Date.now(); |
| const random = Math.random().toString(36).substring(7); |
| const folder = `events/${eventId}/day-${dayNumber}`; |
| const publicId = `${folder}/${timestamp}-${random}`; |
|
|
| const uploadStream = cloudinary.uploader.upload_stream( |
| { |
| folder: folder, |
| public_id: `${timestamp}-${random}`, |
| resource_type: 'auto' |
| }, |
| (error, result) => { |
| if (error || !result) { |
| reject(error || new Error('Upload failed')); |
| } else { |
| resolve({ |
| url: result.secure_url, |
| publicId: result.public_id |
| }); |
| } |
| } |
| ); |
|
|
| uploadStream.end(file.buffer); |
| }); |
| }; |
|
|
| |
| |
| |
| export const deleteEventPhoto = async (publicId: string): Promise<void> => { |
| await cloudinary.uploader.destroy(publicId); |
| }; |
|
|
| |
| |
| |
| export const calculateAttendanceStats = async (eventId: string): Promise<{ |
| totalDays: number; |
| completedDays: number; |
| averageAttendance: number; |
| dailyStats: Array<{ |
| date: Date; |
| dayNumber: number; |
| attendanceCount: number; |
| isCompleted: boolean; |
| }>; |
| }> => { |
| const eventDays = await EventDay.find({ event: eventId }).sort({ dayNumber: 1 }); |
|
|
| const totalDays = eventDays.length; |
| const completedDays = eventDays.filter(day => day.isCompleted).length; |
|
|
| const dailyStats = eventDays.map(day => ({ |
| date: day.date, |
| dayNumber: day.dayNumber, |
| attendanceCount: day.attendance.length, |
| isCompleted: day.isCompleted |
| })); |
|
|
| const totalAttendance = dailyStats.reduce((sum, day) => sum + day.attendanceCount, 0); |
| const averageAttendance = totalDays > 0 ? totalAttendance / totalDays : 0; |
|
|
| return { |
| totalDays, |
| completedDays, |
| averageAttendance: Math.round(averageAttendance * 100) / 100, |
| dailyStats |
| }; |
| }; |
|
|
| |
| |
| |
| export const deleteEventDays = async (eventId: string): Promise<void> => { |
| |
| const eventDays = await EventDay.find({ event: eventId }); |
|
|
| |
| for (const day of eventDays) { |
| for (const photo of day.photos) { |
| try { |
| await deleteEventPhoto(photo.publicId); |
| } catch (err) { |
| console.error(`Failed to delete photo ${photo.publicId}:`, err); |
| } |
| } |
| } |
|
|
| |
| await EventDay.deleteMany({ event: eventId }); |
| }; |
|
|
| |
| |
| |
| export const regenerateEventDays = async (event: IEvent): Promise<void> => { |
| |
| const existingDays = await EventDay.find({ event: event._id }).sort({ date: 1 }); |
|
|
| |
| await EventDay.deleteMany({ event: event._id }); |
|
|
| |
| await generateEventDays(event); |
|
|
| |
| const newDays = await EventDay.find({ event: event._id }).sort({ date: 1 }); |
|
|
| for (const existingDay of existingDays) { |
| const matchingNewDay = newDays.find( |
| newDay => newDay.date.toISOString().split('T')[0] === existingDay.date.toISOString().split('T')[0] |
| ); |
|
|
| if (matchingNewDay) { |
| matchingNewDay.photos = existingDay.photos; |
| matchingNewDay.attendance = existingDay.attendance; |
| matchingNewDay.notes = existingDay.notes; |
| matchingNewDay.weatherCondition = existingDay.weatherCondition; |
| matchingNewDay.activitiesConducted = existingDay.activitiesConducted; |
| matchingNewDay.incidentsReported = existingDay.incidentsReported; |
| matchingNewDay.equipmentUsed = existingDay.equipmentUsed; |
| matchingNewDay.isCompleted = existingDay.isCompleted; |
| matchingNewDay.completedAt = existingDay.completedAt; |
|
|
| await matchingNewDay.save(); |
| } |
| } |
| }; |
|
|