import { Schema, model, Document, Types } from 'mongoose'; // Field types supported in forms type FieldType = | 'short_text' | 'long_text' | 'multiple_choice' | 'checkboxes' | 'dropdown' | 'linear_scale' | 'date' | 'time' | 'email' | 'phone' | 'number' | 'file_upload'; interface IFormField { id: string; // Unique field ID type: FieldType; label: string; description?: string; required: boolean; options?: string[]; // For multiple_choice, checkboxes, dropdown validation?: { min?: number; // For number, linear_scale max?: number; pattern?: string; // For text fields (regex) maxLength?: number; minLength?: number; fileTypes?: string[]; // For file uploads maxFileSize?: number; // In bytes }; order: number; // Display order } export interface IForm extends Document { // Basic Info title: string; description?: string; // Association event?: Types.ObjectId; // If attached to an event organization: Types.ObjectId; // Template forms belong to organization createdBy: Types.ObjectId; // Trainer who created it // Form Structure fields: IFormField[]; // Access Control accessType: 'event_attendees' | 'verified_users' | 'public'; // Who can submit restrictToAttendees: boolean; // Only event participants can submit oneResponsePerUser: boolean; // Enforce single response // Sharing shortCode: string; // Short join code (e.g., FORM-ABC123) shareToken: string; // Secret token for share links qrCode?: string; // QR code image URL/data // Settings acceptingResponses: boolean; showResponseSummary: boolean; // Show summary to respondents allowEditing: boolean; // Allow users to edit their responses // Metadata responseCount: number; status: 'draft' | 'active' | 'closed'; createdAt: Date; updatedAt: Date; } const FormSchema = new Schema({ title: { type: String, required: true, trim: true, index: 'text' }, description: { type: String, trim: true }, event: { type: Schema.Types.ObjectId, ref: 'Event', index: true }, organization: { type: Schema.Types.ObjectId, ref: 'User', required: false, index: true }, createdBy: { type: Schema.Types.ObjectId, ref: 'User', required: true, index: true }, fields: [{ id: { type: String, required: true }, type: { type: String, enum: [ 'short_text', 'long_text', 'multiple_choice', 'checkboxes', 'dropdown', 'linear_scale', 'date', 'time', 'email', 'phone', 'number', 'file_upload' ], required: true }, label: { type: String, required: true }, description: String, required: { type: Boolean, default: false }, options: [String], validation: { min: Number, max: Number, pattern: String, maxLength: Number, minLength: Number, fileTypes: [String], maxFileSize: Number }, order: { type: Number, required: true } }], accessType: { type: String, enum: ['event_attendees', 'verified_users', 'public'], default: 'verified_users' }, restrictToAttendees: { type: Boolean, default: false }, oneResponsePerUser: { type: Boolean, default: true }, shortCode: { type: String, required: true, unique: true, uppercase: true, trim: true, index: true }, shareToken: { type: String, required: true, index: true }, qrCode: String, acceptingResponses: { type: Boolean, default: true }, showResponseSummary: { type: Boolean, default: false }, allowEditing: { type: Boolean, default: false }, responseCount: { type: Number, default: 0 }, status: { type: String, enum: ['draft', 'active', 'closed'], default: 'draft', index: true } }, { timestamps: true }); // Indexes FormSchema.index({ event: 1, status: 1 }); FormSchema.index({ organization: 1, createdBy: 1 }); FormSchema.index({ shortCode: 1, shareToken: 1 }); export default model('Form', FormSchema);