export function officeCleaningCalculator(form: FormTs) {
// Base rates per sq ft by office type
const officeTypeRates: Record<string, number> = {
'standard': 0.08,
'medical': 0.15,
'dental': 0.14,
'coworking': 0.10,
'retail': 0.09,
'warehouse': 0.05,
'industrial': 0.06,
'restaurant': 0.12,
'gym': 0.11
};
// Frequency discounts
const frequencyDiscounts: Record<string, number> = {
'one-time': 0,
'daily': 30,
'3x-week': 25,
'2x-week': 20,
'weekly': 15,
'bi-weekly': 10,
'monthly': 5
};
// Time of day multipliers
const timeMultipliers: Record<string, number> = {
'daytime': 1.0,
'evening': 1.0,
'overnight': 1.15,
'weekend': 1.20
};
// Floor type rates (per sq ft for specialized care)
const floorTypeRates: Record<string, number> = {
'carpet': 0,
'hardwood': 0.02,
'tile': 0.01,
'concrete': 0,
'mixed': 0.01
};
// Helper functions
const getOfficeType = () => officeSection.dropdown('officeType')?.value() || 'standard';
const isMedicalOrDental = () => {
const type = getOfficeType();
return type === 'medical' || type === 'dental';
};
const isRestaurant = () => getOfficeType() === 'restaurant';
const isGym = () => getOfficeType() === 'gym';
const isWarehouseOrIndustrial = () => {
const type = getOfficeType();
return type === 'warehouse' || type === 'industrial';
};
form.addRow(row => {
row.addTextPanel('header', {
computedValue: () => 'Commercial Cleaning Quote',
customStyles: { 'font-size': '1.5rem', 'font-weight': '600', 'color': '#1e293b' }
});
});
form.addSpacer({ height: 20 });
// Office Details Section
const officeSection = form.addSubform('officeDetails', { title: '🏢 Facility Details' });
officeSection.addRow(row => {
row.addDropdown('officeType', {
label: 'Facility Type',
options: [
{ id: 'standard', name: 'Standard Office' },
{ id: 'medical', name: 'Medical Office / Clinic' },
{ id: 'dental', name: 'Dental Office' },
{ id: 'coworking', name: 'Coworking Space' },
{ id: 'retail', name: 'Retail / Showroom' },
{ id: 'restaurant', name: 'Restaurant / Café' },
{ id: 'gym', name: 'Gym / Fitness Center' },
{ id: 'warehouse', name: 'Warehouse / Storage' },
{ id: 'industrial', name: 'Light Industrial' }
],
defaultValue: 'standard',
isRequired: true
}, '1fr');
row.addSlider('squareFootage', {
label: 'Total Square Footage',
min: 500,
max: 50000,
step: 500,
defaultValue: 5000,
showValue: true,
unit: 'sq ft'
}, '1fr');
});
officeSection.addRow(row => {
row.addRadioButton('floorType', {
label: 'Primary Floor Type',
options: [
{ id: 'carpet', name: 'Carpet' },
{ id: 'hardwood', name: 'Hardwood' },
{ id: 'tile', name: 'Tile / Vinyl' },
{ id: 'concrete', name: 'Concrete' },
{ id: 'mixed', name: 'Mixed' }
],
defaultValue: 'carpet',
orientation: 'horizontal'
}, '1fr');
row.addInteger('floors', {
label: 'Number of Floors',
min: 1,
max: 10,
defaultValue: 1
}, '1fr');
});
// Standard office layout
const layoutSection = form.addSubform('layout', {
title: '📐 Space Layout',
isVisible: () => !isWarehouseOrIndustrial()
});
layoutSection.addRow(row => {
row.addInteger('privateOffices', {
label: 'Private Offices',
min: 0,
max: 50,
defaultValue: 5
}, '1fr');
row.addInteger('restrooms', {
label: 'Restrooms',
min: 1,
max: 20,
defaultValue: 2
}, '1fr');
});
layoutSection.addRow(row => {
row.addInteger('kitchenettes', {
label: 'Kitchens / Break Rooms',
min: 0,
max: 10,
defaultValue: 1
}, '1fr');
row.addInteger('conferenceRooms', {
label: 'Conference Rooms',
min: 0,
max: 20,
defaultValue: 2
}, '1fr');
});
// Restaurant specific
const restaurantSection = form.addSubform('restaurantDetails', {
title: '🍽️ Restaurant Details',
isVisible: isRestaurant
});
restaurantSection.addRow(row => {
row.addInteger('diningCapacity', {
label: 'Seating Capacity',
min: 10,
max: 500,
defaultValue: 50
}, '1fr');
row.addRadioButton('kitchenType', {
label: 'Kitchen Type',
options: [
{ id: 'small', name: 'Small / Prep Only' },
{ id: 'standard', name: 'Standard Commercial' },
{ id: 'large', name: 'Large / Full Service' }
],
defaultValue: 'standard',
orientation: 'horizontal'
}, '1fr');
});
restaurantSection.addRow(row => {
row.addCheckboxList('restaurantAreas', {
label: 'Areas to Clean',
options: [
{ id: 'dining', name: 'Dining Area' },
{ id: 'kitchen', name: 'Commercial Kitchen' },
{ id: 'bar', name: 'Bar Area' },
{ id: 'patio', name: 'Outdoor Patio' }
],
defaultValue: ['dining', 'kitchen']
});
});
// Gym specific
const gymSection = form.addSubform('gymDetails', {
title: '💪 Gym Details',
isVisible: isGym
});
gymSection.addRow(row => {
row.addCheckboxList('gymAreas', {
label: 'Areas to Clean',
options: [
{ id: 'weights', name: 'Weight Room / Floor' },
{ id: 'cardio', name: 'Cardio Area' },
{ id: 'locker', name: 'Locker Rooms' },
{ id: 'showers', name: 'Showers' },
{ id: 'pool', name: 'Pool Area' },
{ id: 'studio', name: 'Group Fitness Studios' }
],
defaultValue: ['weights', 'cardio', 'locker', 'showers']
}, '1fr');
row.addInteger('lockerRooms', {
label: 'Number of Locker Rooms',
min: 0,
max: 6,
defaultValue: 2
}, '1fr');
});
// Medical/Dental specific
const medicalSection = form.addSubform('medicalDetails', {
title: '🏥 Medical / Dental Details',
isVisible: isMedicalOrDental
});
medicalSection.addRow(row => {
row.addInteger('examRooms', {
label: 'Exam / Operatory Rooms',
min: 1,
max: 30,
defaultValue: 4
}, '1fr');
row.addInteger('waitingCapacity', {
label: 'Waiting Room Capacity',
min: 5,
max: 100,
defaultValue: 15
}, '1fr');
});
medicalSection.addRow(row => {
row.addCheckboxList('medicalServices', {
label: 'Specialized Services Needed',
options: [
{ id: 'biohazard', name: 'Biohazard Waste Handling (+$100/visit)' },
{ id: 'operatory', name: 'Operatory Deep Clean (+$25/room)' },
{ id: 'sterilization', name: 'Sterilization Area (+$50/visit)' },
{ id: 'hipaa', name: 'HIPAA-Compliant Shredding (+$30/visit)' }
],
defaultValue: []
});
});
// Service Schedule Section
const scheduleSection = form.addSubform('schedule', { title: '📅 Service Schedule' });
scheduleSection.addRow(row => {
row.addRadioButton('frequency', {
label: 'Cleaning Frequency',
options: [
{ id: 'daily', name: 'Daily (Mon-Fri) - 30% off' },
{ id: '3x-week', name: '3x per week - 25% off' },
{ id: '2x-week', name: '2x per week - 20% off' },
{ id: 'weekly', name: 'Weekly - 15% off' },
{ id: 'bi-weekly', name: 'Bi-weekly - 10% off' },
{ id: 'monthly', name: 'Monthly - 5% off' },
{ id: 'one-time', name: 'One-time deep clean' }
],
defaultValue: 'weekly',
orientation: 'vertical',
isRequired: true
});
});
scheduleSection.addRow(row => {
row.addRadioButton('serviceTime', {
label: 'Preferred Service Time',
options: [
{ id: 'daytime', name: 'Daytime (9am-5pm)' },
{ id: 'evening', name: 'Evening (5pm-10pm)' },
{ id: 'overnight', name: 'Overnight (10pm-6am) +15%' },
{ id: 'weekend', name: 'Weekend Only +20%' }
],
defaultValue: 'evening',
orientation: 'horizontal'
}, '1fr');
row.addDatepicker('startDate', {
label: 'Preferred Start Date',
minDate: new Date().toISOString().split('T')[0]
}, '1fr');
});
// Standard Services Section
const servicesSection = form.addSubform('services', { title: '🧹 Standard Services' });
servicesSection.addRow(row => {
row.addCheckboxList('standardServices', {
label: 'Included in Base Price',
options: [
{ id: 'vacuum', name: 'Vacuuming & Floor Cleaning' },
{ id: 'dust', name: 'Dusting All Surfaces' },
{ id: 'trash', name: 'Trash & Recycling Removal' },
{ id: 'restroom', name: 'Restroom Sanitization' },
{ id: 'kitchen', name: 'Kitchen / Break Room' },
{ id: 'glass', name: 'Interior Glass & Mirrors' }
],
defaultValue: ['vacuum', 'dust', 'trash', 'restroom', 'kitchen', 'glass'],
orientation: 'vertical'
}, '1fr');
row.addCheckboxList('additionalStandard', {
label: 'Add to Standard Service',
options: [
{ id: 'desks', name: 'Desk Surface Wipe-down' },
{ id: 'phones', name: 'Phone & Keyboard Sanitize' },
{ id: 'doors', name: 'Door Handle Disinfection' },
{ id: 'elevators', name: 'Elevator Cleaning' }
],
defaultValue: ['desks', 'doors'],
orientation: 'vertical'
}, '1fr');
});
// Add-on Services Section
const addonsSection = form.addSubform('addons', { title: '✨ Premium Add-Ons' });
addonsSection.addRow(row => {
row.addCheckboxList('floorAddons', {
label: 'Floor Care',
options: [
{ id: 'carpet', name: 'Carpet Deep Clean (+$0.15/sq ft)' },
{ id: 'wax', name: 'Hard Floor Waxing (+$0.20/sq ft)' },
{ id: 'strip', name: 'Floor Strip & Refinish (+$0.35/sq ft)' },
{ id: 'grout', name: 'Tile Grout Cleaning (+$0.10/sq ft)' }
],
defaultValue: []
}, '1fr');
row.addCheckboxList('surfaceAddons', {
label: 'Surfaces & Air',
options: [
{ id: 'windows', name: 'Exterior Windows (+$8/window)' },
{ id: 'highDust', name: 'High Dusting / Vents (+$0.03/sq ft)' },
{ id: 'sanitize', name: 'Enhanced Sanitization (+$0.05/sq ft)' },
{ id: 'air', name: 'Air Duct Cleaning (quote)' }
],
defaultValue: []
}, '1fr');
});
addonsSection.addRow(row => {
row.addInteger('windowCount', {
label: 'Number of Exterior Windows',
min: 0,
max: 500,
defaultValue: 20,
isVisible: () => {
const addons = addonsSection.checkboxList('surfaceAddons')?.value() || [];
return addons.includes('windows');
}
}, '1fr');
row.addCheckbox('supplies', {
label: 'Restroom Supplies Provided (+$50/restroom/month)',
defaultValue: false
}, '1fr');
});
form.addSpacer({ height: 20, showLine: true, lineStyle: 'dashed' });
// Price Calculation Helpers
const calculateBasePrice = () => {
const sqft = officeSection.slider('squareFootage')?.value() || 5000;
const officeType = getOfficeType();
const rate = officeTypeRates[officeType] || 0.08;
const floorType = officeSection.radioButton('floorType')?.value() || 'carpet';
const floorRate = floorTypeRates[floorType] || 0;
const floors = officeSection.integer('floors')?.value() || 1;
let basePrice = sqft * (rate + floorRate);
// Multi-floor surcharge
if (floors > 1) {
basePrice *= 1 + ((floors - 1) * 0.05);
}
// Add room-based pricing for standard offices
if (!isWarehouseOrIndustrial()) {
const privateOffices = layoutSection.integer('privateOffices')?.value() || 5;
const restrooms = layoutSection.integer('restrooms')?.value() || 2;
const kitchens = layoutSection.integer('kitchenettes')?.value() || 1;
const conference = layoutSection.integer('conferenceRooms')?.value() || 2;
basePrice += (privateOffices * 5) + (restrooms * 25) + (kitchens * 20) + (conference * 10);
}
// Restaurant specifics
if (isRestaurant()) {
const kitchenType = restaurantSection.radioButton('kitchenType')?.value() || 'standard';
const kitchenMultipliers: Record<string, number> = { 'small': 1.0, 'standard': 1.15, 'large': 1.30 };
basePrice *= kitchenMultipliers[kitchenType] || 1;
const areas = restaurantSection.checkboxList('restaurantAreas')?.value() || [];
if (areas.includes('bar')) basePrice += 75;
if (areas.includes('patio')) basePrice += 50;
}
// Gym specifics
if (isGym()) {
const areas = gymSection.checkboxList('gymAreas')?.value() || [];
const lockerRooms = gymSection.integer('lockerRooms')?.value() || 2;
if (areas.includes('showers')) basePrice += lockerRooms * 40;
if (areas.includes('pool')) basePrice += 150;
if (areas.includes('studio')) basePrice += 50;
}
// Medical specifics
if (isMedicalOrDental()) {
const examRooms = medicalSection.integer('examRooms')?.value() || 4;
basePrice += examRooms * 15;
}
return basePrice;
};
const calculateAddons = () => {
let total = 0;
const sqft = officeSection.slider('squareFootage')?.value() || 5000;
const restrooms = layoutSection.integer('restrooms')?.value() || 2;
const floorAddons = addonsSection.checkboxList('floorAddons')?.value() || [];
if (floorAddons.includes('carpet')) total += sqft * 0.15;
if (floorAddons.includes('wax')) total += sqft * 0.20;
if (floorAddons.includes('strip')) total += sqft * 0.35;
if (floorAddons.includes('grout')) total += sqft * 0.10;
const surfaceAddons = addonsSection.checkboxList('surfaceAddons')?.value() || [];
if (surfaceAddons.includes('windows')) {
const windows = addonsSection.integer('windowCount')?.value() || 20;
total += windows * 8;
}
if (surfaceAddons.includes('highDust')) total += sqft * 0.03;
if (surfaceAddons.includes('sanitize')) total += sqft * 0.05;
if (addonsSection.checkbox('supplies')?.value()) {
total += restrooms * 50;
}
// Medical add-ons
if (isMedicalOrDental()) {
const medServices = medicalSection.checkboxList('medicalServices')?.value() || [];
if (medServices.includes('biohazard')) total += 100;
if (medServices.includes('operatory')) {
const rooms = medicalSection.integer('examRooms')?.value() || 4;
total += rooms * 25;
}
if (medServices.includes('sterilization')) total += 50;
if (medServices.includes('hipaa')) total += 30;
}
return total;
};
const getVisitsPerMonth = () => {
const frequency = scheduleSection.radioButton('frequency')?.value() || 'weekly';
const visits: Record<string, number> = {
'daily': 22, '3x-week': 13, '2x-week': 9, 'weekly': 4,
'bi-weekly': 2, 'monthly': 1, 'one-time': 1
};
return visits[frequency] || 4;
};
// Price Summary Section
const summarySection = form.addSubform('summary', { title: '💰 Your Quote' });
summarySection.addRow(row => {
row.addPriceDisplay('basePrice', {
label: 'Base Cleaning (per visit)',
computedValue: () => Math.round(calculateBasePrice()),
variant: 'default'
}, '1fr');
row.addPriceDisplay('timeAdjustment', {
label: 'Time Premium',
computedValue: () => {
const base = calculateBasePrice();
const time = scheduleSection.radioButton('serviceTime')?.value() || 'evening';
const multiplier = timeMultipliers[time] || 1;
return Math.round(base * (multiplier - 1));
},
variant: 'default',
prefix: '+',
isVisible: () => {
const time = scheduleSection.radioButton('serviceTime')?.value();
return time === 'overnight' || time === 'weekend';
}
}, '1fr');
});
summarySection.addRow(row => {
row.addPriceDisplay('addonsPrice', {
label: 'Premium Add-Ons',
computedValue: () => Math.round(calculateAddons()),
variant: 'default',
prefix: '+',
isVisible: () => calculateAddons() > 0
}, '1fr');
row.addPriceDisplay('frequencyDiscount', {
label: 'Frequency Discount',
computedValue: () => {
const base = calculateBasePrice();
const time = scheduleSection.radioButton('serviceTime')?.value() || 'evening';
const timeMult = timeMultipliers[time] || 1;
const frequency = scheduleSection.radioButton('frequency')?.value() || 'weekly';
const discountPercent = frequencyDiscounts[frequency] || 0;
return -Math.round(base * timeMult * discountPercent / 100);
},
variant: 'success',
isVisible: () => {
const frequency = scheduleSection.radioButton('frequency')?.value();
return frequency !== 'one-time';
}
}, '1fr');
});
summarySection.addSpacer({ showLine: true, lineStyle: 'solid', lineColor: '#e2e8f0' });
summarySection.addRow(row => {
row.addPriceDisplay('perVisitPrice', {
label: 'Price Per Visit',
computedValue: () => {
let total = calculateBasePrice();
const time = scheduleSection.radioButton('serviceTime')?.value() || 'evening';
total *= timeMultipliers[time] || 1;
const frequency = scheduleSection.radioButton('frequency')?.value() || 'weekly';
const discountPercent = frequencyDiscounts[frequency] || 0;
total *= (1 - discountPercent / 100);
return Math.round(total);
},
variant: 'highlight'
}, '1fr');
row.addPriceDisplay('monthlyEstimate', {
label: 'Monthly Estimate',
computedValue: () => {
let perVisit = calculateBasePrice();
const time = scheduleSection.radioButton('serviceTime')?.value() || 'evening';
perVisit *= timeMultipliers[time] || 1;
const frequency = scheduleSection.radioButton('frequency')?.value() || 'weekly';
const discountPercent = frequencyDiscounts[frequency] || 0;
perVisit *= (1 - discountPercent / 100);
const visits = getVisitsPerMonth();
const addons = calculateAddons();
return Math.round((perVisit * visits) + addons);
},
variant: 'large',
suffix: '/mo'
}, '1fr');
});
summarySection.addRow(row => {
row.addTextPanel('visitInfo', {
computedValue: () => {
const frequency = scheduleSection.radioButton('frequency')?.value() || 'weekly';
const info: Record<string, string> = {
'daily': '22 visits/month (Mon-Fri)',
'3x-week': '13 visits/month',
'2x-week': '9 visits/month',
'weekly': '4 visits/month',
'bi-weekly': '2 visits/month',
'monthly': '1 visit/month',
'one-time': 'Single deep clean visit'
};
return info[frequency] || '';
},
customStyles: { 'font-size': '0.9rem', 'color': '#059669', 'text-align': 'center' }
});
});
summarySection.addRow(row => {
row.addTextPanel('disclaimer', {
computedValue: () => 'Final pricing confirmed after walkthrough. Add-on services billed monthly.',
customStyles: { 'font-size': '0.85rem', 'color': '#64748b', 'font-style': 'italic', 'text-align': 'center' }
});
});
form.configureSubmitButton({
label: 'Request Free Walkthrough'
});
}