export function venueRentalCalculator(form: FormTs) {
// Pricing data
const venueTypeBasePrices: Record<string, number> = {
'banquet-hall': 2000,
'hotel-ballroom': 3500,
'restaurant-private': 1500,
'rooftop': 2500,
'garden-outdoor': 1800,
'barn-rustic': 2200,
'museum-gallery': 4000,
'vineyard-winery': 3000,
'beach-waterfront': 3500,
'country-club': 4500,
'conference-center': 1200,
'loft-industrial': 2000
};
const capacityMultipliers: Record<string, number> = {
'small': 0.6, // up to 50
'medium': 1, // 51-100
'large': 1.5, // 101-200
'xlarge': 2.2, // 201-300
'grand': 3 // 300+
};
form.addRow(row => {
row.addTextPanel('header', {
computedValue: () => 'Venue Rental Cost Calculator',
customStyles: { 'font-size': '1.5rem', 'font-weight': '600', 'color': '#1e293b' }
});
});
form.addSpacer({ height: 20 });
// Event Details Section
const eventSection = form.addSubform('event', { title: '🎉 Event Details' });
eventSection.addRow(row => {
row.addDropdown('eventType', {
label: 'Event Type',
options: [
{ id: 'wedding', name: 'Wedding Reception' },
{ id: 'corporate', name: 'Corporate Event/Meeting' },
{ id: 'birthday', name: 'Birthday/Anniversary Party' },
{ id: 'gala', name: 'Gala/Fundraiser' },
{ id: 'conference', name: 'Conference/Seminar' },
{ id: 'cocktail', name: 'Cocktail Party' },
{ id: 'holiday', name: 'Holiday Party' },
{ id: 'graduation', name: 'Graduation Party' },
{ id: 'baby-shower', name: 'Baby/Bridal Shower' },
{ id: 'reunion', name: 'Family/Class Reunion' }
],
defaultValue: 'wedding',
isRequired: true
}, '1fr');
row.addInteger('guestCount', {
label: 'Expected Guests',
min: 10,
max: 1000,
defaultValue: 100,
isRequired: true
}, '1fr');
});
eventSection.addRow(row => {
row.addDropdown('dayOfWeek', {
label: 'Day of Event',
options: [
{ id: 'weekday', name: 'Monday - Thursday' },
{ id: 'friday', name: 'Friday' },
{ id: 'saturday', name: 'Saturday (Peak)' },
{ id: 'sunday', name: 'Sunday' }
],
defaultValue: 'saturday',
isRequired: true
}, '1fr');
row.addDropdown('season', {
label: 'Season',
options: [
{ id: 'off-peak', name: 'Off-Peak (Jan-Mar, Nov)' },
{ id: 'shoulder', name: 'Shoulder (Apr, Oct, Dec)' },
{ id: 'peak', name: 'Peak Season (May-Sep)' }
],
defaultValue: 'peak'
}, '1fr');
});
// Venue Type Section
const venueSection = form.addSubform('venue', { title: '🏛️ Venue Selection' });
venueSection.addRow(row => {
row.addDropdown('venueType', {
label: 'Venue Type',
options: [
{ id: 'banquet-hall', name: 'Banquet Hall ($2,000 base)' },
{ id: 'hotel-ballroom', name: 'Hotel Ballroom ($3,500 base)' },
{ id: 'restaurant-private', name: 'Restaurant Private Room ($1,500 base)' },
{ id: 'rooftop', name: 'Rooftop Venue ($2,500 base)' },
{ id: 'garden-outdoor', name: 'Garden/Outdoor ($1,800 base)' },
{ id: 'barn-rustic', name: 'Barn/Rustic Venue ($2,200 base)' },
{ id: 'museum-gallery', name: 'Museum/Art Gallery ($4,000 base)' },
{ id: 'vineyard-winery', name: 'Vineyard/Winery ($3,000 base)' },
{ id: 'beach-waterfront', name: 'Beach/Waterfront ($3,500 base)' },
{ id: 'country-club', name: 'Country Club ($4,500 base)' },
{ id: 'conference-center', name: 'Conference Center ($1,200 base)' },
{ id: 'loft-industrial', name: 'Loft/Industrial Space ($2,000 base)' }
],
defaultValue: 'banquet-hall',
isRequired: true
}, '1fr');
row.addDropdown('venueQuality', {
label: 'Venue Tier',
options: [
{ id: 'budget', name: 'Budget-Friendly' },
{ id: 'standard', name: 'Standard' },
{ id: 'upscale', name: 'Upscale' },
{ id: 'luxury', name: 'Luxury/Premium' }
],
defaultValue: 'standard'
}, '1fr');
});
venueSection.addRow(row => {
row.addDropdown('rentalDuration', {
label: 'Rental Duration',
options: [
{ id: '4hr', name: '4 hours' },
{ id: '6hr', name: '6 hours' },
{ id: '8hr', name: '8 hours (Full day)' },
{ id: '10hr', name: '10 hours' },
{ id: '12hr', name: '12 hours (Extended)' },
{ id: 'overnight', name: 'Overnight/Multi-day' }
],
defaultValue: '6hr',
isRequired: true
}, '1fr');
row.addCheckbox('ceremonySpace', {
label: 'Separate Ceremony Space',
defaultValue: false,
tooltip: '+$500-1,500 for dedicated ceremony area'
}, '1fr');
});
// Venue Amenities Section
const amenitiesSection = form.addSubform('amenities', { title: '✨ Venue Amenities' });
amenitiesSection.addRow(row => {
row.addCheckbox('tablesChairs', {
label: 'Tables & Chairs Included',
defaultValue: true,
tooltip: 'If not included, external rental adds $500-1,500'
}, '1fr');
row.addCheckbox('linens', {
label: 'Linens & Tableware',
defaultValue: false,
tooltip: '+$400 for quality linens and place settings'
}, '1fr');
});
amenitiesSection.addRow(row => {
row.addCheckbox('danceFloor', {
label: 'Dance Floor',
defaultValue: true,
tooltip: '+$300 if not included'
}, '1fr');
row.addCheckbox('stage', {
label: 'Stage/Platform',
defaultValue: false,
tooltip: '+$400 for raised stage area'
}, '1fr');
});
amenitiesSection.addRow(row => {
row.addCheckbox('parkingIncluded', {
label: 'Parking Included',
defaultValue: true,
tooltip: 'Valet service adds $500+'
}, '1fr');
row.addCheckbox('valetService', {
label: 'Valet Parking',
defaultValue: false,
tooltip: '+$500 for professional valet service'
}, '1fr');
});
// AV & Equipment Section
const equipmentSection = form.addSubform('equipment', { title: '🎤 Audio/Visual & Equipment' });
equipmentSection.addRow(row => {
row.addDropdown('avPackage', {
label: 'AV Package',
options: [
{ id: 'none', name: 'None (bring your own)' },
{ id: 'basic', name: 'Basic (mic, speakers) - $300' },
{ id: 'standard', name: 'Standard (projector, screen, mic) - $600' },
{ id: 'professional', name: 'Professional (full AV setup) - $1,200' },
{ id: 'premium', name: 'Premium (lighting, video walls) - $2,500' }
],
defaultValue: 'basic'
}, '1fr');
row.addDropdown('lighting', {
label: 'Event Lighting',
options: [
{ id: 'standard', name: 'Standard Venue Lighting' },
{ id: 'uplighting', name: 'Uplighting Package (+$400)' },
{ id: 'custom', name: 'Custom Lighting Design (+$800)' },
{ id: 'premium', name: 'Premium + Gobo Projection (+$1,200)' }
],
defaultValue: 'standard'
}, '1fr');
});
equipmentSection.addRow(row => {
row.addCheckbox('photoBooth', {
label: 'Photo Booth Area',
defaultValue: false,
tooltip: '+$200 for dedicated photo booth space'
}, '1fr');
row.addCheckbox('outdoorHeating', {
label: 'Outdoor Heaters/Fans',
defaultValue: false,
tooltip: '+$300 for climate control equipment'
}, '1fr');
});
// Catering & Bar Section
const cateringSection = form.addSubform('catering', { title: '🍽️ Catering & Bar' });
cateringSection.addRow(row => {
row.addDropdown('cateringPolicy', {
label: 'Catering Arrangement',
options: [
{ id: 'in-house-required', name: 'In-house catering required' },
{ id: 'in-house-optional', name: 'In-house available, outside allowed' },
{ id: 'outside-only', name: 'Outside catering only' },
{ id: 'kitchen-rental', name: 'Kitchen rental available' }
],
defaultValue: 'in-house-optional'
}, '1fr');
row.addDropdown('barService', {
label: 'Bar Service',
options: [
{ id: 'none', name: 'No bar/BYOB' },
{ id: 'beer-wine', name: 'Beer & Wine Only' },
{ id: 'full-bar', name: 'Full Bar Service' },
{ id: 'premium-bar', name: 'Premium Open Bar' }
],
defaultValue: 'full-bar'
}, '1fr');
});
cateringSection.addRow(row => {
row.addCheckbox('corkageFee', {
label: 'Corkage Fee (if BYOB)',
defaultValue: false,
tooltip: '+$15-25 per bottle if bringing own alcohol'
}, '1fr');
row.addCheckbox('cakeCutting', {
label: 'Cake Cutting Fee',
defaultValue: false,
tooltip: '+$2-4 per person for outside cake'
}, '1fr');
});
// Additional Services Section
const servicesSection = form.addSubform('services', { title: '👥 Additional Services' });
servicesSection.addRow(row => {
row.addDropdown('coordinator', {
label: 'Event Coordinator',
options: [
{ id: 'none', name: 'Not needed' },
{ id: 'day-of', name: 'Day-of Coordinator ($500)' },
{ id: 'partial', name: 'Partial Planning ($1,200)' },
{ id: 'full', name: 'Full Planning ($2,500+)' }
],
defaultValue: 'day-of'
}, '1fr');
row.addDropdown('security', {
label: 'Security',
options: [
{ id: 'none', name: 'Not needed' },
{ id: 'one', name: '1 Security Guard ($200)' },
{ id: 'two', name: '2 Security Guards ($400)' },
{ id: 'team', name: 'Security Team ($600+)' }
],
defaultValue: 'none'
}, '1fr');
});
servicesSection.addRow(row => {
row.addCheckbox('cleanupIncluded', {
label: 'Cleanup Included',
defaultValue: true,
tooltip: 'If not included, adds $200-500'
}, '1fr');
row.addCheckbox('setupTeardown', {
label: 'Setup/Teardown Assistance',
defaultValue: false,
tooltip: '+$300 for venue staff assistance'
}, '1fr');
});
servicesSection.addRow(row => {
row.addCheckbox('coatCheck', {
label: 'Coat Check Service',
defaultValue: false,
tooltip: '+$150 for staffed coat check'
}, '1fr');
row.addCheckbox('bridalSuite', {
label: 'Bridal/Getting Ready Suite',
defaultValue: false,
tooltip: '+$300 for private prep room'
}, '1fr');
});
form.addSpacer({ height: 20, showLine: true, lineStyle: 'dashed' });
// Cost Breakdown Section
const breakdownSection = form.addSubform('breakdown', { title: '📊 Cost Breakdown', isCollapsible: false });
breakdownSection.addRow(row => {
row.addPriceDisplay('baseRental', {
label: 'Base Venue Rental',
computedValue: () => {
const venueType = venueSection.dropdown('venueType')?.value() || 'banquet-hall';
const quality = venueSection.dropdown('venueQuality')?.value() || 'standard';
const guests = eventSection.integer('guestCount')?.value() || 100;
const duration = venueSection.dropdown('rentalDuration')?.value() || '6hr';
const dayOfWeek = eventSection.dropdown('dayOfWeek')?.value() || 'saturday';
const season = eventSection.dropdown('season')?.value() || 'peak';
let base = venueTypeBasePrices[venueType] || 2000;
// Capacity multiplier
let capacityKey = 'medium';
if (guests <= 50) capacityKey = 'small';
else if (guests <= 100) capacityKey = 'medium';
else if (guests <= 200) capacityKey = 'large';
else if (guests <= 300) capacityKey = 'xlarge';
else capacityKey = 'grand';
base *= capacityMultipliers[capacityKey];
// Quality multiplier
const qualityMults: Record<string, number> = {
'budget': 0.7, 'standard': 1, 'upscale': 1.4, 'luxury': 2
};
base *= qualityMults[quality] || 1;
// Duration multiplier
const durationMults: Record<string, number> = {
'4hr': 0.7, '6hr': 1, '8hr': 1.3, '10hr': 1.5, '12hr': 1.8, 'overnight': 2.5
};
base *= durationMults[duration] || 1;
// Day of week multiplier
const dayMults: Record<string, number> = {
'weekday': 0.7, 'friday': 0.9, 'saturday': 1, 'sunday': 0.85
};
base *= dayMults[dayOfWeek] || 1;
// Season multiplier
const seasonMults: Record<string, number> = {
'off-peak': 0.75, 'shoulder': 0.9, 'peak': 1
};
base *= seasonMults[season] || 1;
if (venueSection.checkbox('ceremonySpace')?.value()) base += 800;
return Math.round(base);
},
variant: 'default'
}, '1fr');
row.addPriceDisplay('amenitiesCost', {
label: 'Amenities & Rentals',
computedValue: () => {
let cost = 0;
if (!amenitiesSection.checkbox('tablesChairs')?.value()) cost += 800;
if (amenitiesSection.checkbox('linens')?.value()) cost += 400;
if (!amenitiesSection.checkbox('danceFloor')?.value()) cost += 300;
if (amenitiesSection.checkbox('stage')?.value()) cost += 400;
if (amenitiesSection.checkbox('valetService')?.value()) cost += 500;
return cost;
},
variant: 'default'
}, '1fr');
});
breakdownSection.addRow(row => {
row.addPriceDisplay('avCost', {
label: 'AV & Lighting',
computedValue: () => {
const av = equipmentSection.dropdown('avPackage')?.value() || 'basic';
const lighting = equipmentSection.dropdown('lighting')?.value() || 'standard';
const avPrices: Record<string, number> = {
'none': 0, 'basic': 300, 'standard': 600, 'professional': 1200, 'premium': 2500
};
const lightingPrices: Record<string, number> = {
'standard': 0, 'uplighting': 400, 'custom': 800, 'premium': 1200
};
let cost = avPrices[av] + lightingPrices[lighting];
if (equipmentSection.checkbox('photoBooth')?.value()) cost += 200;
if (equipmentSection.checkbox('outdoorHeating')?.value()) cost += 300;
return cost;
},
variant: 'default'
}, '1fr');
row.addPriceDisplay('servicesCost', {
label: 'Additional Services',
computedValue: () => {
const coordinator = servicesSection.dropdown('coordinator')?.value() || 'day-of';
const security = servicesSection.dropdown('security')?.value() || 'none';
const coordinatorPrices: Record<string, number> = {
'none': 0, 'day-of': 500, 'partial': 1200, 'full': 2500
};
const securityPrices: Record<string, number> = {
'none': 0, 'one': 200, 'two': 400, 'team': 600
};
let cost = coordinatorPrices[coordinator] + securityPrices[security];
if (!servicesSection.checkbox('cleanupIncluded')?.value()) cost += 350;
if (servicesSection.checkbox('setupTeardown')?.value()) cost += 300;
if (servicesSection.checkbox('coatCheck')?.value()) cost += 150;
if (servicesSection.checkbox('bridalSuite')?.value()) cost += 300;
return cost;
},
variant: 'default'
}, '1fr');
});
breakdownSection.addRow(row => {
row.addPriceDisplay('feesCost', {
label: 'Fees & Charges',
computedValue: () => {
const guests = eventSection.integer('guestCount')?.value() || 100;
let cost = 0;
if (cateringSection.checkbox('corkageFee')?.value()) cost += 20 * Math.ceil(guests / 5);
if (cateringSection.checkbox('cakeCutting')?.value()) cost += 3 * guests;
return cost;
},
variant: 'default'
}, '1fr');
row.addPriceDisplay('perGuestCost', {
label: 'Cost Per Guest',
computedValue: () => {
const guests = eventSection.integer('guestCount')?.value() || 100;
// Calculate total (simplified)
const venueType = venueSection.dropdown('venueType')?.value() || 'banquet-hall';
const quality = venueSection.dropdown('venueQuality')?.value() || 'standard';
let base = venueTypeBasePrices[venueType] || 2000;
let capacityKey = 'medium';
if (guests <= 50) capacityKey = 'small';
else if (guests <= 100) capacityKey = 'medium';
else if (guests <= 200) capacityKey = 'large';
else if (guests <= 300) capacityKey = 'xlarge';
else capacityKey = 'grand';
base *= capacityMultipliers[capacityKey];
const qualityMults: Record<string, number> = {
'budget': 0.7, 'standard': 1, 'upscale': 1.4, 'luxury': 2
};
base *= qualityMults[quality] || 1;
return Math.round(base / guests);
},
variant: 'default'
}, '1fr');
});
// Summary Section
const summarySection = form.addSubform('summary', {
title: '🏛️ Total Venue Cost',
isCollapsible: false,
sticky: 'bottom'
});
summarySection.addRow(row => {
row.addPriceDisplay('totalCost', {
label: 'Estimated Total',
computedValue: () => {
const venueType = venueSection.dropdown('venueType')?.value() || 'banquet-hall';
const quality = venueSection.dropdown('venueQuality')?.value() || 'standard';
const guests = eventSection.integer('guestCount')?.value() || 100;
const duration = venueSection.dropdown('rentalDuration')?.value() || '6hr';
const dayOfWeek = eventSection.dropdown('dayOfWeek')?.value() || 'saturday';
const season = eventSection.dropdown('season')?.value() || 'peak';
// Base rental
let total = venueTypeBasePrices[venueType] || 2000;
let capacityKey = 'medium';
if (guests <= 50) capacityKey = 'small';
else if (guests <= 100) capacityKey = 'medium';
else if (guests <= 200) capacityKey = 'large';
else if (guests <= 300) capacityKey = 'xlarge';
else capacityKey = 'grand';
total *= capacityMultipliers[capacityKey];
const qualityMults: Record<string, number> = {
'budget': 0.7, 'standard': 1, 'upscale': 1.4, 'luxury': 2
};
total *= qualityMults[quality] || 1;
const durationMults: Record<string, number> = {
'4hr': 0.7, '6hr': 1, '8hr': 1.3, '10hr': 1.5, '12hr': 1.8, 'overnight': 2.5
};
total *= durationMults[duration] || 1;
const dayMults: Record<string, number> = {
'weekday': 0.7, 'friday': 0.9, 'saturday': 1, 'sunday': 0.85
};
total *= dayMults[dayOfWeek] || 1;
const seasonMults: Record<string, number> = {
'off-peak': 0.75, 'shoulder': 0.9, 'peak': 1
};
total *= seasonMults[season] || 1;
if (venueSection.checkbox('ceremonySpace')?.value()) total += 800;
// Amenities
if (!amenitiesSection.checkbox('tablesChairs')?.value()) total += 800;
if (amenitiesSection.checkbox('linens')?.value()) total += 400;
if (!amenitiesSection.checkbox('danceFloor')?.value()) total += 300;
if (amenitiesSection.checkbox('stage')?.value()) total += 400;
if (amenitiesSection.checkbox('valetService')?.value()) total += 500;
// AV & Equipment
const av = equipmentSection.dropdown('avPackage')?.value() || 'basic';
const lighting = equipmentSection.dropdown('lighting')?.value() || 'standard';
const avPrices: Record<string, number> = {
'none': 0, 'basic': 300, 'standard': 600, 'professional': 1200, 'premium': 2500
};
const lightingPrices: Record<string, number> = {
'standard': 0, 'uplighting': 400, 'custom': 800, 'premium': 1200
};
total += avPrices[av] + lightingPrices[lighting];
if (equipmentSection.checkbox('photoBooth')?.value()) total += 200;
if (equipmentSection.checkbox('outdoorHeating')?.value()) total += 300;
// Services
const coordinator = servicesSection.dropdown('coordinator')?.value() || 'day-of';
const security = servicesSection.dropdown('security')?.value() || 'none';
const coordinatorPrices: Record<string, number> = {
'none': 0, 'day-of': 500, 'partial': 1200, 'full': 2500
};
const securityPrices: Record<string, number> = {
'none': 0, 'one': 200, 'two': 400, 'team': 600
};
total += coordinatorPrices[coordinator] + securityPrices[security];
if (!servicesSection.checkbox('cleanupIncluded')?.value()) total += 350;
if (servicesSection.checkbox('setupTeardown')?.value()) total += 300;
if (servicesSection.checkbox('coatCheck')?.value()) total += 150;
if (servicesSection.checkbox('bridalSuite')?.value()) total += 300;
// Fees
if (cateringSection.checkbox('corkageFee')?.value()) total += 20 * Math.ceil(guests / 5);
if (cateringSection.checkbox('cakeCutting')?.value()) total += 3 * guests;
return Math.round(total);
},
variant: 'large'
});
});
summarySection.addRow(row => {
row.addTextPanel('disclaimer', {
computedValue: () => 'Venue prices vary significantly by location and availability. This estimate excludes catering, which is typically $50-200+ per person. Contact venues directly for exact pricing.',
customStyles: { 'font-size': '0.85rem', 'color': '#64748b', 'text-align': 'center' }
});
});
form.configureSubmitButton({
label: 'Request Venue Quote'
});
}