Enhance application structure: Add runtime configuration for environment variables, integrate new dependencies for Cloudinary and UI components, and refactor member management features including improved forms and member dashboard. Update styles and layout for better user experience.
This commit is contained in:
parent
6e7e27ac4e
commit
e4a0a9ab0f
61 changed files with 7902 additions and 950 deletions
99
server/models/event.js
Normal file
99
server/models/event.js
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
import mongoose from 'mongoose'
|
||||
|
||||
const eventSchema = new mongoose.Schema({
|
||||
title: { type: String, required: true },
|
||||
slug: { type: String, required: true, unique: true },
|
||||
tagline: String,
|
||||
description: { type: String, required: true },
|
||||
content: String,
|
||||
featureImage: {
|
||||
url: String, // Cloudinary URL
|
||||
publicId: String, // Cloudinary public ID for transformations
|
||||
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'
|
||||
},
|
||||
// Online-first location handling
|
||||
location: {
|
||||
type: String,
|
||||
required: true,
|
||||
// This will typically be a Slack channel or video conference link
|
||||
validate: {
|
||||
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 #)'
|
||||
}
|
||||
},
|
||||
isOnline: { type: Boolean, default: true }, // Default to online-first
|
||||
// Visibility and status controls
|
||||
isVisible: { type: Boolean, default: true }, // Hide from public calendar when false
|
||||
isCancelled: { type: Boolean, default: false },
|
||||
cancellationMessage: String, // Custom message for cancelled events
|
||||
membersOnly: { type: Boolean, default: false },
|
||||
// Circle targeting
|
||||
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,
|
||||
registeredAt: { type: Date, default: Date.now }
|
||||
}],
|
||||
createdBy: { type: String, required: true },
|
||||
createdAt: { 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, '')
|
||||
}
|
||||
|
||||
// Pre-save hook to generate slug
|
||||
eventSchema.pre('save', async function(next) {
|
||||
try {
|
||||
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++
|
||||
}
|
||||
|
||||
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