Prashikshak / API /src /model /eventDay.model.ts
Abhisingh-18's picture
Initial commit: Prashikshak - disaster management training platform
9a92a42
Raw
History Blame Contribute Delete
5.18 kB
import { Schema, model, Document, Types } from 'mongoose';
interface IGeoPoint {
type: "Point";
coordinates: [number, number]; // [lng, lat]
}
interface IEventDayPhoto {
url: string;
publicId: string; // Cloudinary public ID for deletion
caption?: string;
uploadedBy: Types.ObjectId;
uploadedAt: Date;
}
interface IEventDayAttendance {
user: Types.ObjectId;
checkInTime: Date;
checkInMethod: 'gps' | 'qr' | 'manual' | 'hotspot';
checkInLocation?: IGeoPoint;
verifiedBy?: Types.ObjectId; // Trainer who verified (for manual)
}
export interface IEventDay extends Document {
// Reference to parent event
event: Types.ObjectId;
// Date information
date: Date; // Specific date (YYYY-MM-DD)
dayNumber: number; // Day 1, Day 2, etc.
// Time slots
startTime: Date; // Planned start time for this day's session
endTime: Date; // Planned end time for this day's session
// Photos
photos: IEventDayPhoto[];
// Attendance
attendance: IEventDayAttendance[];
// Optional metadata for disaster management training
notes?: string; // Trainer's notes for the day
weatherCondition?: string; // e.g., "Sunny", "Rainy", "Cloudy"
activitiesConducted?: string[]; // List of activities/drills conducted
incidentsReported?: string; // Any incidents/issues during the day
equipmentUsed?: string[]; // Equipment/resources used
cvDetectedCount?: number; // Number of people detected in photos via CV (optional)
// Status
hasStarted: boolean; // Event day has been started by trainer
isCompleted: boolean; // Mark day as completed
completedAt?: Date;
// Metadata
createdAt: Date;
updatedAt: Date;
}
const EventDaySchema = new Schema<IEventDay>({
event: {
type: Schema.Types.ObjectId,
ref: 'Event',
required: true,
index: true
},
date: {
type: Date,
required: true,
index: true
},
dayNumber: {
type: Number,
required: true,
min: 1
},
startTime: {
type: Date,
required: true
},
endTime: {
type: Date,
required: true
},
photos: [{
url: {
type: String,
required: true
},
publicId: {
type: String,
required: true
},
caption: {
type: String,
trim: true
},
uploadedBy: {
type: Schema.Types.ObjectId,
ref: 'User',
required: true
},
uploadedAt: {
type: Date,
default: Date.now
}
}],
attendance: [{
user: {
type: Schema.Types.ObjectId,
ref: 'User',
required: true
},
checkInTime: {
type: Date,
default: Date.now
},
checkInMethod: {
type: String,
enum: ['gps', 'qr', 'manual', 'hotspot'],
required: true
},
checkInLocation: {
type: {
type: String,
enum: ['Point']
},
coordinates: {
type: [Number]
}
},
verifiedBy: {
type: Schema.Types.ObjectId,
ref: 'User'
}
}],
notes: {
type: String,
trim: true
},
weatherCondition: {
type: String,
trim: true
},
activitiesConducted: [{
type: String,
trim: true
}],
incidentsReported: {
type: String,
trim: true
},
equipmentUsed: [{
type: String,
trim: true
}],
cvDetectedCount: {
type: Number,
min: 0
},
hasStarted: {
type: Boolean,
default: false
},
isCompleted: {
type: Boolean,
default: false
},
completedAt: {
type: Date
}
}, {
timestamps: true
});
// Indexes
EventDaySchema.index({ event: 1, date: 1 }, { unique: true }); // Unique day per event
EventDaySchema.index({ event: 1, dayNumber: 1 }); // Sequential access
EventDaySchema.index({ 'attendance.user': 1 }); // User attendance queries
EventDaySchema.index({ date: 1 }); // Date-based queries
// Pre-save hook to validate and set completion status
EventDaySchema.pre('save', function (this: IEventDay) {
// Validate time slots
if (this.endTime <= this.startTime) {
throw new Error('End time must be after start time');
}
// Validate completion requirements
if (this.isModified('isCompleted') && this.isCompleted) {
// Ensure photos and attendance exist
if (this.photos.length === 0) {
throw new Error('Cannot mark as completed: No photos uploaded');
}
if (this.attendance.length === 0) {
throw new Error('Cannot mark as completed: No attendance recorded');
}
// Set completedAt timestamp
if (!this.completedAt) {
this.completedAt = new Date();
}
}
});
export default model<IEventDay>('EventDay', EventDaySchema);