const mongoose = require("mongoose"); const activitySchema = new mongoose.Schema( { // Hero section for activity page header (supports Activities and Booking variants) hero: { titleActivities: { type: String, trim: true, default: "", maxlength: 80, }, titleBooking: { type: String, trim: true, default: "", maxlength: 80, }, bannerImageActivities: { type: String, trim: true, default: "", maxlength: 255, }, bannerImageBooking: { type: String, trim: true, default: "", maxlength: 255, }, }, name: { type: String, required: true, trim: true, maxlength: 120, }, price: { type: Number, required: true, min: 0, }, priceText: { type: String, trim: true, maxlength: 32, }, season: [ { type: String, enum: ["spring", "summer", "autumn", "winter"], }, ], age: { type: [Number], validate: { validator: function (v) { return v.length === 2 && v[0] <= v[1]; }, message: "Age must be an array of [minAge, maxAge]", }, }, locations: [ { type: String, trim: true, maxlength: 80, }, ], image: { type: String, trim: true, maxlength: 255, }, link: { type: String, trim: true, maxlength: 255, }, // Global filters document (single document in Activity collection) filters: [ { label: { type: String, required: true, trim: true, maxlength: 64 }, value: { type: String, required: true, trim: true, maxlength: 64 }, items: [ { value: { type: String, required: true, maxlength: 64 }, label: { type: String, required: true, maxlength: 64 }, }, ], order: { type: Number, default: 0 }, }, ], program: { type: String, trim: true, maxlength: 80, }, rating: { type: Number, min: 1, max: 5, default: 4, }, isActive: { type: Boolean, default: true, }, order: { type: Number, default: 0, }, // marker for the single document that stores global filters isFiltersDoc: { type: Boolean, default: false, }, // Rich camp details from camp-detail field in activities.json campDetail: { type: mongoose.Schema.Types.Mixed, default: {}, }, // Booking sessions - các đợt booking với thông số riêng bookingSessions: [ { sessionId: { type: String, required: true, maxlength: 80 }, startDate: { type: Date, required: true }, endDate: { type: Date, required: true }, overnightStays: { type: Number, required: true, default: 14 }, // Spots theo giới tính totalMaleSpots: { type: Number, default: 25 }, totalFemaleSpots: { type: Number, default: 25 }, bookedMaleSpots: { type: Number, default: 0 }, bookedFemaleSpots: { type: Number, default: 0 }, price: { type: Number }, isActive: { type: Boolean, default: true }, // Danh sách booking cho session này bookingList: [ { address: { type: String, required: true, maxlength: 255 }, agreeNewsletter: { type: Boolean, default: false }, agreeTerms: { type: Boolean, required: true }, city: { type: String, required: true, maxlength: 80 }, country: { type: String, required: true, maxlength: 80 }, dietaryRestrictions: { type: String, enum: ['none', 'vegetarian', 'vegan', 'halal', 'kosher', 'gluten-free', 'other'], default: 'none' }, email: { type: String, required: true, lowercase: true, trim: true, maxlength: 120 }, emergencyContact: { type: String, required: true, maxlength: 80 }, emergencyPhone: { type: String, required: true, maxlength: 40 }, medicalConditions: { type: String, default: '', maxlength: 500 }, numberOfParticipants: { type: Number, required: true, min: 1 }, parentFirstName: { type: String, required: true, trim: true, maxlength: 80 }, parentLastName: { type: String, required: true, trim: true, maxlength: 80 }, participantBirthDate: { type: Date, required: true }, participantFirstName: { type: String, required: true, trim: true, maxlength: 80 }, participantGender: { type: String, enum: ['male', 'female', 'other'], required: true }, participantLastName: { type: String, required: true, trim: true, maxlength: 80 }, phone: { type: String, required: true, maxlength: 40 }, postalCode: { type: String, required: true, maxlength: 20 }, sessionDate: { type: String, required: true, maxlength: 80 }, // sessionId reference specialRequests: { type: String, default: '', maxlength: 500 }, // Thêm các trường quản lý bookingStatus: { type: String, enum: ['pending', 'confirmed', 'cancelled', 'completed'], default: 'pending' }, paymentStatus: { type: String, enum: ['pending', 'partial', 'paid', 'refunded'], default: 'pending' }, totalAmount: { type: Number, default: 0 }, paidAmount: { type: Number, default: 0 }, bookingDate: { type: Date, default: Date.now }, confirmationCode: { type: String, unique: true, maxlength: 32 }, adminNotes: { type: String, default: '', maxlength: 1000 } } ] } ], }, {timestamps: true} ); // Add index for better query performance activitySchema.index({name: 1}); activitySchema.index({isActive: 1, order: 1}); activitySchema.index({season: 1}); activitySchema.index({locations: 1}); module.exports = mongoose.model("Activity", activitySchema);