#5CRSE Custom Event Creation Implementation Plan

#Overview

The custom event creation flow is a key differentiator for 5CRSE, allowing users to create personalized events with premium transportation, venue selection, and guest management. This document outlines the implementation plan for this feature, focusing on a premium user experience that showcases our luxury transportation options.

#User Journey & Flow

flowchart TD
    A[Dashboard] -->|"Click 'Create Custom Event'"| B[Event Type Selection]
    B -->|"Select category"| C[Date & Time Selection]
    C -->|"Select date/time"| D[Location Selection]
    D -->|"Choose venue"| E[Transportation Planning]
    E -->|"Select vehicle & logistics"| F[Guest Management]
    F -->|"Invite guests"| G[Add-on Services]
    G -->|"Select add-ons"| H[Review & Confirm]
    H -->|"Complete booking"| I[Confirmation]
    
    subgraph "Restaurant Preferences Form"
    D1[Restaurant Type] --> D2[Party Size]
    D2 --> D3[Special Requirements]
    end
    
    D -.->|"If dining event"| D1
    
    subgraph "Premium Transportation"
    E1[Premium Vehicle Selection] --> E2[Pickup Details]
    E2 --> E3[Dropoff Details]
    end
    
    E -.-> E1
    
    subgraph "Guest System"
    F1[Add Guest Details] --> F2[Send Invitations]
    F2 --> F3[Track RSVPs]
    end
    
    F -.-> F1

#Implementation Phases

gantt
    title Custom Event Creation Implementation Plan
    dateFormat  YYYY-MM-DD
    section Phase 1: Core Experience
    Event Type Selection            :2025-04-01, 5d
    Date & Time Selection           :2025-04-06, 4d
    Premium Transportation UI       :2025-04-10, 7d
    
    section Phase 2: Venue & Location
    Basic Venue Selection           :2025-04-17, 5d
    Restaurant Preferences Form     :2025-04-22, 4d
    Custom Location Input           :2025-04-26, 3d
    
    section Phase 3: Guest Experience
    Guest Management Interface      :2025-04-29, 5d
    Email Template System           :2025-05-04, 4d
    Basic RSVP Tracking             :2025-05-08, 3d
    
    section Phase 4: Finalization
    Add-on Services Selection       :2025-05-11, 4d
    Review & Summary UI             :2025-05-15, 3d
    Basic Payment Integration       :2025-05-18, 5d
    
    section Phase 5: Enhancements
    OpenTable API Integration       :future, 0d
    Advanced Guest Management       :future, 0d
    Advanced Payment Options        :future, 0d

#Detailed Component Implementations

#1. Event Type Selection

This is the entry point for the custom event creation flow, where users select the type of event they want to create.

User Interface

  • Large, visually appealing cards for each event type
  • Gold accents to highlight selected options
  • Clear descriptions of each event type
  • Subtle animations on hover/selection

Component Structure

// src/components/CreateEvent/EventTypeSelection.tsx
import React from 'react';
import Image from 'next/image';

const eventTypes = [
  { 
    id: 'birthday', 
    title: 'Birthday Party', 
    description: 'Celebrate with luxury transportation',
    icon: '/images/event-types/birthday.svg'
  },
  { 
    id: 'corporate', 
    title: 'Corporate Event', 
    description: 'Impress clients and colleagues',
    icon: '/images/event-types/corporate.svg'
  },
  { 
    id: 'dining', 
    title: 'Fine Dining', 
    description: 'Premium restaurant experience',
    icon: '/images/event-types/dining.svg'
  },
  { 
    id: 'concert', 
    title: 'Concert or Show', 
    description: 'Arrive in style to performances',
    icon: '/images/event-types/concert.svg'
  },
  { 
    id: 'sports', 
    title: 'Sporting Event', 
    description: 'Transportation to games and matches',
    icon: '/images/event-types/sports.svg'
  },
  { 
    id: 'other', 
    title: 'Custom Event', 
    description: 'Create your own unique experience',
    icon: '/images/event-types/custom.svg'
  }
];

interface EventTypeSelectionProps {
  selectedType: string | null;
  onSelect: (type: string) => void;
}

export const EventTypeSelection: React.FC<EventTypeSelectionProps> = ({
  selectedType,
  onSelect
}) => {
  return (
    <div className="space-y-6">
      <h2 className="text-2xl font-bold text-white">What type of event are you planning?</h2>
      <p className="text-gray-300">Select an event type to begin customizing your experience</p>
      
      <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
        {eventTypes.map((type) => (
          <div 
            key={type.id}
            className={`p-4 rounded-lg cursor-pointer transition-all ${
              selectedType === type.id 
                ? 'bg-gold bg-opacity-20 border-2 border-gold' 
                : 'bg-gray-900 hover:bg-gray-800 border-2 border-transparent'
            }`}
            onClick={() => onSelect(type.id)}
          >
            <div className="flex items-center space-x-4">
              <div className="w-12 h-12 relative">
                <Image
                  src={type.icon}
                  alt={type.title}
                  fill
                  className="object-contain"
                />
              </div>
              <div>
                <h3 className="font-bold text-white">{type.title}</h3>
                <p className="text-sm text-gray-300">{type.description}</p>
              </div>
            </div>
          </div>
        ))}
      </div>
    </div>
  );
};

Data Flow

  • User selects event type
  • Selection is stored in event creation context/state
  • Event type determines available options in subsequent steps
  • Backend validates event type against supported categories

#2. Premium Transportation Selection

This component is the centerpiece of our custom event creation flow, highlighting our luxury vehicles with rich visuals and detailed features.

User Interface

  • High-quality images of Cadillac Escalade and Tesla vehicles
  • Prominent brand logos and model specifications
  • Gold accents to highlight premium nature
  • Elegant animations for vehicle selection
  • Clear capacity and feature listings
  • Luxurious copy emphasizing the premium experience

Component Structure

// src/components/CreateEvent/PremiumTransportation.tsx
import React, { useState } from 'react';
import Image from 'next/image';
import { CheckIcon } from '@heroicons/react/24/outline';

interface PremiumTransportationProps {
  onSelect: (transportationDetails: any) => void;
  eventDateTime?: Date;
  eventLocation?: {
    address: string;
    coordinates: [number, number];
  };
}

export const PremiumTransportation: React.FC<PremiumTransportationProps> = ({
  onSelect,
  eventDateTime,
  eventLocation
}) => {
  const [vehicleType, setVehicleType] = useState<'escalade' | 'tesla'>('escalade');
  const [passengerCount, setPassengerCount] = useState(2);
  
  const [pickupDetails, setPickupDetails] = useState({
    location: '',
    time: eventDateTime ? new Date(eventDateTime.getTime() - 2 * 60 * 60 * 1000) : null
  });
  
  const [dropoffDetails, setDropoffDetails] = useState({
    location: eventLocation?.address || '',
    time: eventDateTime || null
  });
  
  const [specialInstructions, setSpecialInstructions] = useState('');
  
  // Vehicle feature lists
  const escaladeFeatures = [
    'Premium leather interior',
    'Seating for up to 7 passengers',
    'Complimentary chilled beverages',
    'Climate-controlled cabin',
    'Wi-Fi connectivity',
    'Premium sound system',
    'Privacy partition',
    'Professional chauffeur'
  ];
  
  const teslaFeatures = [
    'Modern luxury interior',
    'Seating for up to 5 passengers',
    'Eco-friendly all-electric vehicle',
    'Panoramic glass roof',
    'Wi-Fi connectivity',
    'Premium sound system',
    'Cutting-edge technology',
    'Professional chauffeur'
  ];
  
  const handleSubmit = () => {
    // Validation and submission logic
    onSelect({
      vehicleType,
      capacity: vehicleType === 'escalade' ? 7 : 5,
      passengerCount,
      pickupDetails,
      dropoffDetails,
      specialInstructions
    });
  };
  
  return (
    <div className="space-y-8">
      <div className="text-center">
        <h2 className="text-3xl font-bold text-white mb-2">Premium Transportation</h2>
        <p className="text-xl text-gold">The 5CRSE Experience</p>
        <p className="text-gray-300 mt-2 max-w-2xl mx-auto">
          Select your preferred luxury vehicle for an unforgettable transportation experience.
          Our professional chauffeurs ensure a seamless journey in ultimate comfort.
        </p>
      </div>
      
      <div className="grid grid-cols-1 lg:grid-cols-2 gap-8">
        {/* Cadillac Escalade Card */}
        <div
          className={`rounded-lg overflow-hidden transition-all ${
            vehicleType === 'escalade'
              ? 'ring-4 ring-gold'
              : 'ring-1 ring-gray-700 hover:ring-gray-500'
          }`}
        >
          <div className="relative h-64">
            <Image
              src="/images/vehicles/escalade-premium.jpg"
              alt="Cadillac Escalade"
              fill
              className="object-cover"
            />
            <div className="absolute top-4 left-4 bg-black bg-opacity-70 rounded-full px-4 py-1">
              <Image 
                src="/images/logos/cadillac-logo.svg" 
                alt="Cadillac" 
                width={80} 
                height={20} 
              />
            </div>
          </div>
          
          <div className="p-6 bg-black">
            <div className="flex justify-between items-center mb-4">
              <h3 className="text-2xl font-bold text-white">Cadillac Escalade</h3>
              <span className="text-gold text-lg font-medium">Premium SUV</span>
            </div>
            
            <div className="mb-6">
              <p className="text-gray-300">
                Experience the epitome of luxury with our Cadillac Escalade, combining
                elegant styling with spacious comfort for up to 7 passengers.
              </p>
            </div>
            
            <div className="mb-6">
              <h4 className="text-lg font-medium text-white mb-2">Vehicle Features</h4>
              <ul className="grid grid-cols-1 md:grid-cols-2 gap-2">
                {escaladeFeatures.map((feature) => (
                  <li key={feature} className="flex items-center text-gray-300">
                    <CheckIcon className="w-5 h-5 text-gold mr-2" />
                    <span>{feature}</span>
                  </li>
                ))}
              </ul>
            </div>
            
            <button
              onClick={() => setVehicleType('escalade')}
              className={`w-full py-3 rounded-md font-medium transition-colors ${
                vehicleType === 'escalade'
                  ? 'bg-gold text-black'
                  : 'bg-gray-800 text-white hover:bg-gray-700'
              }`}
            >
              {vehicleType === 'escalade' ? 'Selected' : 'Select Escalade'}
            </button>
          </div>
        </div>
        
        {/* Tesla Card */}
        <div
          className={`rounded-lg overflow-hidden transition-all ${
            vehicleType === 'tesla'
              ? 'ring-4 ring-gold'
              : 'ring-1 ring-gray-700 hover:ring-gray-500'
          }`}
        >
          <div className="relative h-64">
            <Image
              src="/images/vehicles/tesla-premium.jpg"
              alt="Tesla Model X"
              fill
              className="object-cover"
            />
            <div className="absolute top-4 left-4 bg-black bg-opacity-70 rounded-full px-4 py-1">
              <Image 
                src="/images/logos/tesla-logo.svg" 
                alt="Tesla" 
                width={80} 
                height={20} 
              />
            </div>
          </div>
          
          <div className="p-6 bg-black">
            <div className="flex justify-between items-center mb-4">
              <h3 className="text-2xl font-bold text-white">Tesla Model X</h3>
              <span className="text-gold text-lg font-medium">Electric Luxury</span>
            </div>
            
            <div className="mb-6">
              <p className="text-gray-300">
                Choose our Tesla Model X for a sophisticated, eco-friendly luxury experience
                with cutting-edge technology and seating for up to 5 passengers.
              </p>
            </div>
            
            <div className="mb-6">
              <h4 className="text-lg font-medium text-white mb-2">Vehicle Features</h4>
              <ul className="grid grid-cols-1 md:grid-cols-2 gap-2">
                {teslaFeatures.map((feature) => (
                  <li key={feature} className="flex items-center text-gray-300">
                    <CheckIcon className="w-5 h-5 text-gold mr-2" />
                    <span>{feature}</span>
                  </li>
                ))}
              </ul>
            </div>
            
            <button
              onClick={() => setVehicleType('tesla')}
              className={`w-full py-3 rounded-md font-medium transition-colors ${
                vehicleType === 'tesla'
                  ? 'bg-gold text-black'
                  : 'bg-gray-800 text-white hover:bg-gray-700'
              }`}
            >
              {vehicleType === 'tesla' ? 'Selected' : 'Select Tesla'}
            </button>
          </div>
        </div>
      </div>
      
      {/* Passenger Count Section */}
      <div className="bg-gray-900 p-6 rounded-lg">
        <h3 className="text-xl font-medium text-white mb-4">Passenger Details</h3>
        
        <div className="grid grid-cols-1 md:grid-cols-2 gap-6">
          <div>
            <label className="block text-sm font-medium text-gray-300 mb-2">
              Number of Passengers
            </label>
            <select
              value={passengerCount}
              onChange={(e) => setPassengerCount(parseInt(e.target.value))}
              className="w-full px-4 py-2 bg-gray-800 border border-gray-700 rounded-md text-white"
            >
              {[...Array(vehicleType === 'escalade' ? 7 : 5)].map((_, i) => (
                <option key={i} value={i + 1}>
                  {i + 1} {i === 0 ? 'Passenger' : 'Passengers'}
                </option>
              ))}
            </select>
            <p className="mt-2 text-sm text-gray-400">
              {vehicleType === 'escalade' 
                ? 'Escalade comfortably seats up to 7 passengers'
                : 'Tesla Model X comfortably seats up to 5 passengers'}
            </p>
          </div>
          
          <div>
            <label className="block text-sm font-medium text-gray-300 mb-2">
              Special Requirements
            </label>
            <textarea
              value={specialInstructions}
              onChange={(e) => setSpecialInstructions(e.target.value)}
              placeholder="Any special requests or accommodations?"
              className="w-full px-4 py-2 bg-gray-800 border border-gray-700 rounded-md text-white h-24"
            />
          </div>
        </div>
      </div>
      
      {/* Pickup & Dropoff Details */}
      <div className="grid grid-cols-1 md:grid-cols-2 gap-6">
        {/* Pickup details */}
        <div className="bg-gray-900 p-6 rounded-lg">
          <h3 className="text-xl font-medium text-white mb-4">Pickup Details</h3>
          
          <div className="space-y-4">
            <div>
              <label className="block text-sm font-medium text-gray-300 mb-2">
                Pickup Location
              </label>
              <input
                type="text"
                value={pickupDetails.location}
                onChange={(e) => setPickupDetails({...pickupDetails, location: e.target.value})}
                placeholder="Enter pickup address"
                className="w-full px-4 py-2 bg-gray-800 border border-gray-700 rounded-md text-white"
              />
            </div>
            
            <div>
              <label className="block text-sm font-medium text-gray-300 mb-2">
                Pickup Time
              </label>
              <input
                type="datetime-local"
                value={pickupDetails.time ? pickupDetails.time.toISOString().slice(0, 16) : ''}
                onChange={(e) => setPickupDetails({
                  ...pickupDetails, 
                  time: e.target.value ? new Date(e.target.value) : null
                })}
                className="w-full px-4 py-2 bg-gray-800 border border-gray-700 rounded-md text-white"
              />
            </div>
          </div>
        </div>
        
        {/* Dropoff details */}
        <div className="bg-gray-900 p-6 rounded-lg">
          <h3 className="text-xl font-medium text-white mb-4">Dropoff Details</h3>
          
          <div className="space-y-4">
            <div>
              <label className="block text-sm font-medium text-gray-300 mb-2">
                Dropoff Location
              </label>
              <input
                type="text"
                value={dropoffDetails.location}
                onChange={(e) => setDropoffDetails({...dropoffDetails, location: e.target.value})}
                placeholder="Enter dropoff address"
                className="w-full px-4 py-2 bg-gray-800 border border-gray-700 rounded-md text-white"
              />
            </div>
            
            <div>
              <label className="block text-sm font-medium text-gray-300 mb-2">
                Dropoff Time
              </label>
              <input
                type="datetime-local"
                value={dropoffDetails.time ? dropoffDetails.time.toISOString().slice(0, 16) : ''}
                onChange={(e) => setDropoffDetails({
                  ...dropoffDetails, 
                  time: e.target.value ? new Date(e.target.value) : null
                })}
                className="w-full px-4 py-2 bg-gray-800 border border-gray-700 rounded-md text-white"
              />
            </div>
          </div>
        </div>
      </div>
      
      <div className="flex justify-end mt-8">
        <button
          onClick={handleSubmit}
          className="px-8 py-3 bg-gold text-black rounded-md font-medium text-lg"
        >
          Continue to Next Step
        </button>
      </div>
    </div>
  );
};

#3. Restaurant Preferences Form (Simplified Approach)

Instead of direct OpenTable API integration, we'll start with a form that collects restaurant preferences for dining events.

User Interface

  • Restaurant type/cuisine selection
  • Party size input
  • Special dietary requirements
  • Preferred date/time
  • Price range selection
  • Special occasion notification

Component Structure

// src/components/CreateEvent/RestaurantPreferences.tsx
import React, { useState } from 'react';

interface RestaurantPreferencesProps {
  onComplete: (preferences: any) => void;
}

const cuisineTypes = [
  'American', 'Italian', 'French', 'Japanese', 'Chinese', 
  'Indian', 'Mexican', 'Mediterranean', 'Steakhouse', 'Seafood',
  'Vegetarian', 'Vegan', 'Fusion', 'Other'
];

const priceRanges = [
  { id: '$', label: 'Moderate ($30-50 per person)' },
  { id: '$$', label: 'Upscale ($50-100 per person)' },
  { id: '$$$', label: 'Fine Dining ($100-200 per person)' },
  { id: '$$$$', label: 'Premium Experience ($200+ per person)' }
];

export const RestaurantPreferences: React.FC<RestaurantPreferencesProps> = ({
  onComplete
}) => {
  const [preferences, setPreferences] = useState({
    cuisineType: '',
    partySize: 2,
    date: '',
    time: '19:00',
    priceRange: '$$',
    specialOccasion: false,
    occasionType: '',
    dietaryRequirements: '',
    additionalRequests: ''
  });
  
  const handleChange = (e) => {
    const { name, value, type, checked } = e.target;
    setPreferences({
      ...preferences,
      [name]: type === 'checkbox' ? checked : value
    });
  };
  
  const handleSubmit = (e) => {
    e.preventDefault();
    onComplete(preferences);
  };
  
  return (
    <div className="space-y-6">
      <div className="text-center">
        <h2 className="text-3xl font-bold text-white mb-2">Dining Preferences</h2>
        <p className="text-gray-300 mt-2 max-w-2xl mx-auto">
          Tell us about your dining preferences and we'll arrange the perfect restaurant experience.
        </p>
      </div>
      
      <form onSubmit={handleSubmit} className="space-y-8">
        <div className="bg-gray-900 p-6 rounded-lg">
          <h3 className="text-xl font-medium text-white mb-4">Restaurant Type</h3>
          
          <div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-3">
            {cuisineTypes.map((cuisine) => (
              <label 
                key={cuisine} 
                className={`flex items-center p-3 rounded-md cursor-pointer ${
                  preferences.cuisineType === cuisine 
                    ? 'bg-gold bg-opacity-20 border border-gold' 
                    : 'bg-gray-800 border border-gray-700 hover:border-gray-500'
                }`}
              >
                <input
                  type="radio"
                  name="cuisineType"
                  value={cuisine}
                  checked={preferences.cuisineType === cuisine}
                  onChange={handleChange}
                  className="sr-only"
                />
                <span className={`${
                  preferences.cuisineType === cuisine ? 'text-gold' : 'text-white'
                }`}>
                  {cuisine}
                </span>
              </label>
            ))}
          </div>
        </div>
        
        <div className="grid grid-cols-1 md:grid-cols-2 gap-6">
          <div className="bg-gray-900 p-6 rounded-lg">
            <h3 className="text-xl font-medium text-white mb-4">Party Details</h3>
            
            <div className="space-y-4">
              <div>
                <label className="block text-sm font-medium text-gray-300 mb-2">
                  Party Size
                </label>
                <select
                  name="partySize"
                  value={preferences.partySize}
                  onChange={handleChange}
                  className="w-full px-4 py-2 bg-gray-800 border border-gray-700 rounded-md text-white"
                >
                  {[...Array(20)].map((_, i) => (
                    <option key={i} value={i + 1}>
                      {i + 1} {i === 0 ? 'Person' : 'People'}
                    </option>
                  ))}
                </select>
              </div>
              
              <div>
                <label className="block text-sm font-medium text-gray-300 mb-2">
                  Price Range
                </label>
                <div className="space-y-2">
                  {priceRanges.map((range) => (
                    <label 
                      key={range.id} 
                      className="flex items-center cursor-pointer"
                    >
                      <input
                        type="radio"
                        name="priceRange"
                        value={range.id}
                        checked={preferences.priceRange === range.id}
                        onChange={handleChange}
                        className="mr-2 text-gold"
                      />
                      <span className="text-white">{range.label}</span>
                    </label>
                  ))}
                </div>
              </div>
            </div>
          </div>
          
          <div className="bg-gray-900 p-6 rounded-lg">
            <h3 className="text-xl font-medium text-white mb-4">Date & Time</h3>
            
            <div className="space-y-4">
              <div>
                <label className="block text-sm font-medium text-gray-300 mb-2">
                  Preferred Date
                </label>
                <input
                  type="date"
                  name="date"
                  value={preferences.date}
                  onChange={handleChange}
                  className="w-full px-4 py-2 bg-gray-800 border border-gray-700 rounded-md text-white"
                />
              </div>
              
              <div>
                <label className="block text-sm font-medium text-gray-300 mb-2">
                  Preferred Time
                </label>
                <input
                  type="time"
                  name="time"
                  value={preferences.time}
                  onChange={handleChange}
                  className="w-full px-4 py-2 bg-gray-800 border border-gray-700 rounded-md text-white"
                />
              </div>
              
              <div className="flex items-center">
                <input
                  type="checkbox"
                  id="specialOccasion"
                  name="specialOccasion"
                  checked={preferences.specialOccasion}
                  onChange={handleChange}
                  className="mr-2 text-gold"
                />
                <label htmlFor="specialOccasion" className="text-white">
                  This is a special occasion
                </label>
              </div>
              
              {preferences.specialOccasion && (
                <div>
                  <label className="block text-sm font-medium text-gray-300 mb-2">
                    Occasion Type
                  </label>
                  <select
                    name="occasionType"
                    value={preferences.occasionType}
                    onChange={handleChange}
                    className="w-full px-4 py-2 bg-gray-800 border border-gray-700 rounded-md text-white"
                  >
                    <option value="">Select Occasion</option>
                    <option value="birthday">Birthday</option>
                    <option value="anniversary">Anniversary</option>
                    <option value="business">Business Meeting</option>
                    <option value="engagement">Engagement</option>
                    <option value="other">Other</option>
                  </select>
                </div>
              )}
            </div>
          </div>
        </div>
        
        <div className="bg-gray-900 p-6 rounded-lg">
          <h3 className="text-xl font-medium text-white mb-4">Special Requirements</h3>
          
          <div className="space-y-4">
            <div>
              <label className="block text-sm font-medium text-gray-300 mb-2">
                Dietary Requirements
              </label>
              <textarea
                name="dietaryRequirements"
                value={preferences.dietaryRequirements}
                onChange={handleChange}
                placeholder="Vegetarian, vegan, gluten-free, allergies, etc."
                className="w-full px-4 py-2 bg-gray-800 border border-gray-700 rounded-md text-white h-20"
              />
            </div>
            
            <div>
              <label className="block text-sm font-medium text-gray-300 mb-2">
                Additional Requests
              </label>
              <textarea
                name="additionalRequests"
                value={preferences.additionalRequests}
                onChange={handleChange}
                placeholder="Private dining, specific table requests, etc."
                className="w-full px-4 py-2 bg-gray-800 border border-gray-700 rounded-md text-white h-20"
              />
            </div>
          </div>
        </div>
        
        <div className="flex justify-end">
          <button
            type="submit"
            className="px-8 py-3 bg-gold text-black rounded-md font-medium text-lg"
          >
            Submit Dining Preferences
          </button>
        </div>
      </form>
    </div>
  );
};

#4. Guest Management & Invitation System

The guest management system allows event creators to invite guests to their custom events.

User Interface

  • Clean guest list interface
  • Easy-to-use form for adding guests
  • Customizable invitation message
  • Real-time validation of email addresses
  • Elegant invitation templates

Backend Integration

For the initial phase, we'll implement a simplified email invitation system:

// src/pages/api/send-invitations.ts
import { NextApiRequest, NextApiResponse } from 'next';
import nodemailer from 'nodemailer';
import { getPayloadClient } from '../../payload/payloadClient';

export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse
) {
  if (req.method !== 'POST') {
    return res.status(405).json({ error: 'Method not allowed' });
  }
  
  const { eventId, guests, message } = req.body;
  
  if (!eventId || !guests || !Array.isArray(guests) || guests.length === 0) {
    return res.status(400).json({ error: 'Invalid request data' });
  }
  
  try {
    // Get event details from Payload
    const payload = await getPayloadClient();
    const event = await payload.findByID({
      collection: 'events',
      id: eventId
    });
    
    if (!event) {
      return res.status(404).json({ error: 'Event not found' });
    }
    
    // Configure email transporter
    const transporter = nodemailer.createTransport({
      // Email configuration
      host: process.env.SMTP_HOST,
      port: parseInt(process.env.SMTP_PORT || '587'),
      secure: process.env.SMTP_SECURE === 'true',
      auth: {
        user: process.env.SMTP_USER,
        pass: process.env.SMTP_PASS
      }
    });
    
    // Update event with invited guests
    await payload.update({
      collection: 'events',
      id: eventId,
      data: {
        invitedGuests: guests.map(guest => ({
          name: guest.name,
          email: guest.email,
          status: 'pending',
          invitedAt: new Date().toISOString()
        }))
      }
    });
    
    // Send invitations to all guests
    const emailPromises = guests.map(async (guest) => {
      const emailContent = generateInvitationEmail(event, guest, message);
      
      await transporter.sendMail({
        from: `"5CRSE Events" <${process.env.SMTP_FROM_EMAIL}>`,
        to: guest.email,
        subject: `You're Invited: ${event.event_name}`,
        html: emailContent
      });
    });
    
    await Promise.all(emailPromises);
    
    return res.status(200).json({ 
      success: true, 
      message: `Invitations sent to ${guests.length} guests` 
    });
  } catch (error) {
    console.error('Error sending invitations:', error);
    return res.status(500).json({ error: 'Failed to send invitations' });
  }
}

function generateInvitationEmail(event, guest, customMessage) {
  // Generate HTML email template with event details, custom message, etc.
  return `
    <!DOCTYPE html>
    <html>
      <head>
        <style>
          /* Email styles */
          body { font-family: Arial, sans-serif; color: #333; }
          .container { max-width: 600px; margin: 0 auto; }
          .header { background-color: #000; padding: 20px; text-align: center; }
          .logo { color: #D4AF37; font-size: 24px; font-weight: bold; }
          .content { padding: 20px; }
          .event-details { background-color: #f5f5f5; padding: 15px; margin: 20px 0; }
          .footer { font-size: 12px; text-align: center; margin-top: 30px; color: #999; }
          .button { display: inline-block; background-color: #D4AF37; color: #000; text-decoration: none; padding: 12px 30px; border-radius: 4px; font-weight: bold; }
        </style>
      </head>
      <body>
        <div class="container">
          <div class="header">
            <div class="logo">5CRSE</div>
          </div>
          <div class="content">
            <h2>You're Invited</h2>
            <p>Hello ${guest.name},</p>
            <p>${customMessage}</p>
            
            <div class="event-details">
              <h3>${event.event_name}</h3>
              <p><strong>Date:</strong> ${new Date(event.event_date).toLocaleDateString('en-US', { weekday: 'long', month: 'long', day: 'numeric', year: 'numeric' })}</p>
              <p><strong>Time:</strong> ${new Date(event.event_date).toLocaleTimeString('en-US', { hour: 'numeric', minute: '2-digit' })}</p>
              <p><strong>Location:</strong> ${event.location.venue}, ${event.location.address}</p>
            </div>
            
            <p>Luxury transportation will be provided by 5CRSE.</p>
            
            <div style="text-align: center; margin: 30px 0;">
              <a href="${process.env.NEXT_PUBLIC_SITE_URL}/rsvp/${event.id}/${Buffer.from(guest.email).toString('base64')}" class="button">Respond to Invitation</a>
            </div>
          </div>
          <div class="footer">
            <p>This invitation was sent by 5CRSE Events on behalf of the event organizer.</p>
            <p>© 2025 5CRSE. All rights reserved.</p>
          </div>
        </div>
      </body>
    </html>
  `;
}

#Database Schema Updates

We'll need to update our Payload CMS collections to support custom events:

#Events Collection Extension

// Additional fields for the Events collection
{
  name: 'isCustomEvent',
  type: 'checkbox',
  label: 'Custom Event',
  defaultValue: false,
},
{
  name: 'creator',
  type: 'relationship',
  relationTo: 'users',
  label: 'Event Creator',
  admin: {
    condition: (data) => data?.isCustomEvent === true,
  },
},
{
  name: 'customEventDetails',
  type: 'group',
  label: 'Custom Event Details',
  admin: {
    condition: (data) => data?.isCustomEvent === true,
  },
  fields: [
    {
      name: 'transportation',
      type: 'group',
      fields: [
        {
          name: 'vehicleType',
          type: 'select',
          options: [
            { label: 'Cadillac Escalade', value: 'escalade' },
            { label: 'Tesla Model X', value: 'tesla' },
          ],
        },
        {
          name: 'passengerCount',
          type: 'number',
          min: 1,
          max: 7,
        },
        {
          name: 'pickupDetails',
          type: 'group',
          fields: [
            {
              name: 'location',
              type: 'text',
            },
            {
              name: 'time',
              type: 'date',
              admin: {
                date: {
                  pickerAppearance: 'dayAndTime',
                },
              },
            },
          ],
        },
        {
          name: 'dropoffDetails',
          type: 'group',
          fields: [
            {
              name: 'location',
              type: 'text',
            },
            {
              name: 'time',
              type: 'date',
              admin: {
                date: {
                  pickerAppearance: 'dayAndTime',
                },
              },
            },
          ],
        },
      ],
    },
    {
      name: 'restaurantPreferences',
      type: 'group',
      admin: {
        condition: (data) => data?.event_type === 'dining',
      },
      fields: [
        {
          name: 'cuisineType',
          type: 'text',
        },
        {
          name: 'priceRange',
          type: 'select',
          options: [
            { label: 'Moderate', value: '$' },
            { label: 'Upscale', value: '$$' },
            { label: 'Fine Dining', value: '$$$' },
            { label: 'Premium', value: '$$$$' },
          ],
        },
        {
          name: 'dietaryRequirements',
          type: 'textarea',
        },
        {
          name: 'specialOccasion',
          type: 'checkbox',
        },
        {
          name: 'occasionType',
          type: 'text',
          admin: {
            condition: (data) => data?.specialOccasion === true,
          },
        },
      ],
    },
    {
      name: 'invitedGuests',
      type: 'array',
      fields: [
        {
          name: 'name',
          type: 'text',
        },
        {
          name: 'email',
          type: 'email',
        },
        {
          name: 'status',
          type: 'select',
          options: [
            { label: 'Pending', value: 'pending' },
            { label: 'Confirmed', value: 'confirmed' },
            { label: 'Declined', value: 'declined' },
          ],
        },
        {
          name: 'invitedAt',
          type: 'date',
        },
        {
          name: 'respondedAt',
          type: 'date',
        },
      ],
    },
  ],
}

#Implementation Priorities & Timeline

  1. Phase 1: Core Experience (4 weeks)

    • Event Type Selection
    • Date & Time Components
    • Premium Transportation UI
    • Basic state management
  2. Phase 2: Location & Venue (3 weeks)

    • Basic venue selection interface
    • Restaurant preferences form (simplified)
    • Custom location input with map picker
  3. Phase 3: Guest System (3 weeks)

    • Guest list management
    • Email template system
    • Basic RSVP tracking
  4. Phase 4: Finalization (3 weeks)

    • Add-on services selection
    • Review & summary screen
    • Basic payment integration
    • Confirmation experience
  5. Future Enhancements

    • OpenTable direct API integration
    • Advanced guest management with dynamic updates
    • Payment plan options
    • Custom event templates

#Questions to Consider

  1. Do we have existing venue partnerships to feature in the location selection step?
  2. What is the pricing structure for different vehicle types and additional services?
  3. What payment processor will we be using for the initial implementation?
  4. How will the 5CRSE Ambassador service be priced and what information should we collect?
  5. What email service will we use for sending invitations?

#Next Steps

  1. Set up the custom event creation routes and page structure
  2. Implement the wizard component framework with state management
  3. Start building the event type selection component
  4. Create transportation selection UI with vehicle details
  5. Develop the state management for the multi-step process