Adding features
This commit is contained in:
parent
600fef2b7c
commit
2b55ca4104
75 changed files with 9796 additions and 2759 deletions
|
|
@ -1,4 +1,4 @@
|
|||
import mongoose from 'mongoose'
|
||||
import mongoose from "mongoose";
|
||||
|
||||
const eventSchema = new mongoose.Schema({
|
||||
title: { type: String, required: true },
|
||||
|
|
@ -9,14 +9,14 @@ const eventSchema = new mongoose.Schema({
|
|||
featureImage: {
|
||||
url: String, // Cloudinary URL
|
||||
publicId: String, // Cloudinary public ID for transformations
|
||||
alt: String // Alt text for accessibility
|
||||
alt: String, // Alt text for accessibility
|
||||
},
|
||||
startDate: { type: Date, required: true },
|
||||
endDate: { type: Date, required: true },
|
||||
eventType: {
|
||||
type: String,
|
||||
enum: ['community', 'workshop', 'social', 'showcase'],
|
||||
default: 'community'
|
||||
enum: ["community", "workshop", "social", "showcase"],
|
||||
default: "community",
|
||||
},
|
||||
// Online-first location handling
|
||||
location: {
|
||||
|
|
@ -24,14 +24,15 @@ const eventSchema = new mongoose.Schema({
|
|||
required: true,
|
||||
// This will typically be a Slack channel or video conference link
|
||||
validate: {
|
||||
validator: function(v) {
|
||||
validator: function (v) {
|
||||
// Must be either a valid URL or a Slack channel reference
|
||||
const urlPattern = /^https?:\/\/.+/;
|
||||
const slackPattern = /^#[a-zA-Z0-9-_]+$/;
|
||||
return urlPattern.test(v) || slackPattern.test(v);
|
||||
},
|
||||
message: 'Location must be a valid URL (video conference link) or Slack channel (starting with #)'
|
||||
}
|
||||
message:
|
||||
"Location must be a valid URL (video conference link) or Slack channel (starting with #)",
|
||||
},
|
||||
},
|
||||
isOnline: { type: Boolean, default: true }, // Default to online-first
|
||||
// Visibility and status controls
|
||||
|
|
@ -46,97 +47,110 @@ const eventSchema = new mongoose.Schema({
|
|||
description: String, // Series description
|
||||
type: {
|
||||
type: String,
|
||||
enum: ['workshop_series', 'recurring_meetup', 'multi_day', 'course', 'tournament'],
|
||||
default: 'workshop_series'
|
||||
enum: [
|
||||
"workshop_series",
|
||||
"recurring_meetup",
|
||||
"multi_day",
|
||||
"course",
|
||||
"tournament",
|
||||
],
|
||||
default: "workshop_series",
|
||||
},
|
||||
position: Number, // Order within the series (e.g., 1 = first event, 2 = second, etc.)
|
||||
totalEvents: Number, // Total planned events in the series
|
||||
isSeriesEvent: { type: Boolean, default: false } // Flag to identify series events
|
||||
isSeriesEvent: { type: Boolean, default: false }, // Flag to identify series events
|
||||
},
|
||||
// Event pricing for public attendees (deprecated - use tickets instead)
|
||||
pricing: {
|
||||
isFree: { type: Boolean, default: true },
|
||||
publicPrice: { type: Number, default: 0 }, // Price for non-members
|
||||
currency: { type: String, default: 'CAD' },
|
||||
paymentRequired: { type: Boolean, default: false }
|
||||
currency: { type: String, default: "CAD" },
|
||||
paymentRequired: { type: Boolean, default: false },
|
||||
},
|
||||
// Ticket configuration
|
||||
tickets: {
|
||||
enabled: { type: Boolean, default: false },
|
||||
public: {
|
||||
available: { type: Boolean, default: false },
|
||||
name: { type: String, default: 'Public Ticket' },
|
||||
name: { type: String, default: "Public Ticket" },
|
||||
description: String,
|
||||
price: { type: Number, default: 0 },
|
||||
quantity: Number, // null = unlimited
|
||||
sold: { type: Number, default: 0 },
|
||||
earlyBirdPrice: Number,
|
||||
earlyBirdDeadline: Date
|
||||
}
|
||||
earlyBirdDeadline: Date,
|
||||
},
|
||||
},
|
||||
// Circle targeting
|
||||
targetCircles: [{
|
||||
type: String,
|
||||
enum: ['community', 'founder', 'practitioner'],
|
||||
required: false
|
||||
}],
|
||||
targetCircles: [
|
||||
{
|
||||
type: String,
|
||||
enum: ["community", "founder", "practitioner"],
|
||||
required: false,
|
||||
},
|
||||
],
|
||||
maxAttendees: Number,
|
||||
registrationRequired: { type: Boolean, default: false },
|
||||
registrationDeadline: Date,
|
||||
agenda: [String],
|
||||
speakers: [{
|
||||
name: String,
|
||||
role: String,
|
||||
bio: String
|
||||
}],
|
||||
registrations: [{
|
||||
name: String,
|
||||
email: String,
|
||||
membershipLevel: String,
|
||||
isMember: { type: Boolean, default: false },
|
||||
paymentStatus: {
|
||||
type: String,
|
||||
enum: ['pending', 'completed', 'failed', 'not_required'],
|
||||
default: 'not_required'
|
||||
speakers: [
|
||||
{
|
||||
name: String,
|
||||
role: String,
|
||||
bio: String,
|
||||
},
|
||||
paymentId: String, // Helcim transaction ID
|
||||
amountPaid: { type: Number, default: 0 },
|
||||
registeredAt: { type: Date, default: Date.now }
|
||||
}],
|
||||
],
|
||||
registrations: [
|
||||
{
|
||||
memberId: { type: mongoose.Schema.Types.ObjectId, ref: "Member" }, // Reference to Member model
|
||||
name: String,
|
||||
email: String,
|
||||
membershipLevel: String,
|
||||
isMember: { type: Boolean, default: false },
|
||||
paymentStatus: {
|
||||
type: String,
|
||||
enum: ["pending", "completed", "failed", "not_required"],
|
||||
default: "not_required",
|
||||
},
|
||||
paymentId: String, // Helcim transaction ID
|
||||
amountPaid: { type: Number, default: 0 },
|
||||
registeredAt: { type: Date, default: Date.now },
|
||||
},
|
||||
],
|
||||
createdBy: { type: String, required: true },
|
||||
createdAt: { type: Date, default: Date.now },
|
||||
updatedAt: { type: Date, default: Date.now }
|
||||
})
|
||||
updatedAt: { type: Date, default: Date.now },
|
||||
});
|
||||
|
||||
// Generate slug from title
|
||||
function generateSlug(title) {
|
||||
return title
|
||||
.toLowerCase()
|
||||
.replace(/[^a-z0-9]+/g, '-')
|
||||
.replace(/^-+|-+$/g, '')
|
||||
.replace(/[^a-z0-9]+/g, "-")
|
||||
.replace(/^-+|-+$/g, "");
|
||||
}
|
||||
|
||||
// Pre-save hook to generate slug
|
||||
eventSchema.pre('save', async function(next) {
|
||||
eventSchema.pre("save", async function (next) {
|
||||
try {
|
||||
if (this.isNew || this.isModified('title')) {
|
||||
let baseSlug = generateSlug(this.title)
|
||||
let slug = baseSlug
|
||||
let counter = 1
|
||||
|
||||
if (this.isNew || this.isModified("title")) {
|
||||
let baseSlug = generateSlug(this.title);
|
||||
let slug = baseSlug;
|
||||
let counter = 1;
|
||||
|
||||
// Ensure slug is unique
|
||||
while (await this.constructor.findOne({ slug, _id: { $ne: this._id } })) {
|
||||
slug = `${baseSlug}-${counter}`
|
||||
counter++
|
||||
slug = `${baseSlug}-${counter}`;
|
||||
counter++;
|
||||
}
|
||||
|
||||
this.slug = slug
|
||||
}
|
||||
next()
|
||||
} catch (error) {
|
||||
console.error('Error in pre-save hook:', error)
|
||||
next(error)
|
||||
}
|
||||
})
|
||||
|
||||
export default mongoose.models.Event || mongoose.model('Event', eventSchema)
|
||||
this.slug = slug;
|
||||
}
|
||||
next();
|
||||
} catch (error) {
|
||||
console.error("Error in pre-save hook:", error);
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
export default mongoose.models.Event || mongoose.model("Event", eventSchema);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue