export function commercialWindowCleaningCalculator(form: FormTs) {
// Building type base rates (per window)
const buildingRates: Record<string, number> = {
'storefront': 3,
'office-low': 4,
'office-mid': 5,
'office-high': 7,
'warehouse': 3.5,
'restaurant': 4,
'medical': 5,
'retail-mall': 4.5
};
// Floor surcharge multipliers
const floorMultipliers: Record<string, number> = {
'1-3': 1.0,
'4-6': 1.25,
'7-10': 1.5,
'11-20': 1.75,
'20+': 2.0
};
// Access method surcharges
const accessSurcharges: Record<string, number> = {
'ground': 0,
'ladder': 50,
'boom-lift': 200,
'scaffolding': 350,
'rope-access': 500
};
// Service frequency discounts
const frequencyDiscounts: Record<string, number> = {
'one-time': 0,
'weekly': 25,
'bi-weekly': 20,
'monthly': 15,
'quarterly': 10
};
form.addRow(row => {
row.addTextPanel('header', {
computedValue: () => 'Commercial Window Cleaning Quote',
customStyles: { 'font-size': '1.5rem', 'font-weight': '600', 'color': '#1e293b' }
});
});
form.addSpacer({ height: 20 });
// Building Details Section
const buildingSection = form.addSubform('buildingDetails', { title: '๐ข Building Details' });
buildingSection.addRow(row => {
row.addAddress('serviceAddress', {
label: 'Building Address',
placeholder: 'Enter building address...',
showMap: true,
showDistance: true,
referenceAddress: {
formattedAddress: 'Service Center, Denver, CO',
coordinates: { lat: 39.7392, lng: -104.9903 }
},
restrictToCountries: ['US', 'CA'],
distanceUnit: 'miles',
isRequired: true
});
});
buildingSection.addRow(row => {
row.addTextPanel('travelZoneInfo', {
computedValue: () => {
const addressField = buildingSection.address('serviceAddress');
const miles = addressField?.distance();
if (miles == null) return '๐ Enter address to calculate travel fee';
if (miles <= 15) return '๐ Within service area - No travel fee';
if (miles <= 30) return '๐ Extended area - $75 travel fee';
if (miles <= 50) return '๐ Remote area - $150 travel fee';
return '๐ Long distance - $250+ travel fee';
},
customStyles: { 'font-size': '0.9rem', 'color': '#0369a1', 'background': '#e0f2fe', 'padding': '10px', 'border-radius': '6px' }
});
});
buildingSection.addRow(row => {
row.addDropdown('buildingType', {
label: 'Building Type',
options: [
{ id: 'storefront', name: 'Storefront / Retail Shop' },
{ id: 'office-low', name: 'Office Building (1-3 floors)' },
{ id: 'office-mid', name: 'Office Building (4-10 floors)' },
{ id: 'office-high', name: 'High-Rise (11+ floors)' },
{ id: 'warehouse', name: 'Warehouse / Industrial' },
{ id: 'restaurant', name: 'Restaurant / Hospitality' },
{ id: 'medical', name: 'Medical / Healthcare Facility' },
{ id: 'retail-mall', name: 'Shopping Center / Mall' }
],
defaultValue: 'office-low',
isRequired: true
}, '1fr');
row.addDropdown('floorRange', {
label: 'Number of Floors',
options: [
{ id: '1-3', name: '1-3 Floors' },
{ id: '4-6', name: '4-6 Floors' },
{ id: '7-10', name: '7-10 Floors' },
{ id: '11-20', name: '11-20 Floors' },
{ id: '20+', name: '20+ Floors' }
],
defaultValue: '1-3',
isRequired: true
}, '1fr');
});
buildingSection.addRow(row => {
row.addInteger('windowCount', {
label: 'Total Number of Windows',
min: 1,
max: 5000,
defaultValue: 50,
placeholder: 'e.g. 50',
isRequired: true
}, '1fr');
row.addDropdown('windowSize', {
label: 'Average Window Size',
options: [
{ id: 'small', name: 'Small (up to 4 sq ft)' },
{ id: 'standard', name: 'Standard (4-12 sq ft)' },
{ id: 'large', name: 'Large (12-25 sq ft)' },
{ id: 'xlarge', name: 'Extra Large (25+ sq ft)' }
],
defaultValue: 'standard',
isRequired: true
}, '1fr');
});
// Service Options Section
const serviceSection = form.addSubform('serviceOptions', { title: '๐งน Service Options' });
serviceSection.addRow(row => {
row.addRadioButton('cleaningScope', {
label: 'Cleaning Scope',
options: [
{ id: 'exterior', name: 'Exterior Only' },
{ id: 'interior', name: 'Interior Only' },
{ id: 'both', name: 'Interior & Exterior (+80%)' }
],
defaultValue: 'exterior',
orientation: 'horizontal',
isRequired: true
});
});
serviceSection.addRow(row => {
row.addDropdown('accessMethod', {
label: 'Access Method Required',
options: [
{ id: 'ground', name: 'Ground Level / Walk-up' },
{ id: 'ladder', name: 'Ladder Access (+$50)' },
{ id: 'boom-lift', name: 'Boom Lift / Cherry Picker (+$200)' },
{ id: 'scaffolding', name: 'Scaffolding (+$350)' },
{ id: 'rope-access', name: 'Rope Access / Rappelling (+$500)' }
],
defaultValue: 'ground',
isRequired: true
}, '1fr');
row.addDropdown('frequency', {
label: 'Service Frequency',
options: [
{ id: 'one-time', name: 'One-Time Service' },
{ id: 'weekly', name: 'Weekly (-25%)' },
{ id: 'bi-weekly', name: 'Bi-Weekly (-20%)' },
{ id: 'monthly', name: 'Monthly (-15%)' },
{ id: 'quarterly', name: 'Quarterly (-10%)' }
],
defaultValue: 'monthly',
isRequired: true
}, '1fr');
});
// Add-ons Section
const addonsSection = form.addSubform('addons', { title: 'โจ Additional Services' });
addonsSection.addRow(row => {
row.addCheckbox('screenCleaning', {
label: 'Screen Cleaning (+$2/window)',
defaultValue: false
}, '1fr');
row.addCheckbox('trackCleaning', {
label: 'Track & Sill Cleaning (+$1.50/window)',
defaultValue: false
}, '1fr');
});
addonsSection.addRow(row => {
row.addCheckbox('hardWaterRemoval', {
label: 'Hard Water Stain Removal (+$5/window)',
defaultValue: false
}, '1fr');
row.addCheckbox('mirrorCleaning', {
label: 'Interior Mirrors (+$3/mirror)',
defaultValue: false
}, '1fr');
});
addonsSection.addRow(row => {
row.addInteger('mirrorCount', {
label: 'Number of Mirrors',
min: 0,
max: 200,
defaultValue: 10,
isVisible: () => addonsSection.checkbox('mirrorCleaning')?.value() === true
}, '1fr');
row.addCheckbox('afterHours', {
label: 'After Hours Service (+15%)',
defaultValue: false
}, '1fr');
});
addonsSection.addRow(row => {
row.addCheckbox('postConstruction', {
label: 'Post-Construction Cleaning (+50%)',
defaultValue: false
}, '1fr');
row.addCheckbox('skylightCleaning', {
label: 'Skylight Cleaning',
defaultValue: false
}, '1fr');
});
addonsSection.addRow(row => {
row.addInteger('skylightCount', {
label: 'Number of Skylights',
min: 0,
max: 50,
defaultValue: 5,
isVisible: () => addonsSection.checkbox('skylightCleaning')?.value() === true
});
});
form.addSpacer({ height: 20, showLine: true, lineStyle: 'dashed' });
// Helper to calculate travel fee
const getTravelFee = () => {
const addressField = buildingSection.address('serviceAddress');
const miles = addressField?.distance();
if (miles == null || miles <= 15) return 0;
if (miles <= 30) return 75;
if (miles <= 50) return 150;
return 250 + Math.floor((miles - 50) / 10) * 25;
};
// Price Summary Section
const summarySection = form.addSubform('summary', { title: '๐ฐ Quote Summary', isCollapsible: false });
summarySection.addRow(row => {
row.addPriceDisplay('baseWindowCost', {
label: 'Window Cleaning Base',
computedValue: () => {
const buildingType = buildingSection.dropdown('buildingType')?.value() || 'office-low';
const windowCount = buildingSection.integer('windowCount')?.value() || 50;
const windowSize = buildingSection.dropdown('windowSize')?.value() || 'standard';
const cleaningScope = serviceSection.radioButton('cleaningScope')?.value() || 'exterior';
const baseRate = buildingRates?.[buildingType] ?? 4;
let sizeMultiplier = 1.0;
if (windowSize === 'small') sizeMultiplier = 0.75;
else if (windowSize === 'large') sizeMultiplier = 1.5;
else if (windowSize === 'xlarge') sizeMultiplier = 2.0;
let scopeMultiplier = 1.0;
if (cleaningScope === 'both') scopeMultiplier = 1.8;
return windowCount * baseRate * sizeMultiplier * scopeMultiplier;
},
variant: 'default'
}, '1fr');
row.addPriceDisplay('floorSurcharge', {
label: 'Floor Height Adjustment',
computedValue: () => {
const buildingType = buildingSection.dropdown('buildingType')?.value() || 'office-low';
const windowCount = buildingSection.integer('windowCount')?.value() || 50;
const windowSize = buildingSection.dropdown('windowSize')?.value() || 'standard';
const cleaningScope = serviceSection.radioButton('cleaningScope')?.value() || 'exterior';
const floorRange = buildingSection.dropdown('floorRange')?.value() || '1-3';
const baseRate = buildingRates?.[buildingType] ?? 4;
let sizeMultiplier = 1.0;
if (windowSize === 'small') sizeMultiplier = 0.75;
else if (windowSize === 'large') sizeMultiplier = 1.5;
else if (windowSize === 'xlarge') sizeMultiplier = 2.0;
let scopeMultiplier = 1.0;
if (cleaningScope === 'both') scopeMultiplier = 1.8;
const basePrice = windowCount * baseRate * sizeMultiplier * scopeMultiplier;
const floorMultiplier = floorMultipliers?.[floorRange] ?? 1.0;
return basePrice * (floorMultiplier - 1);
},
variant: 'default',
prefix: '+'
}, '1fr');
});
summarySection.addRow(row => {
row.addPriceDisplay('accessCost', {
label: 'Equipment/Access Cost',
computedValue: () => {
const accessMethod = serviceSection.dropdown('accessMethod')?.value() || 'ground';
return accessSurcharges?.[accessMethod] ?? 0;
},
variant: 'default',
prefix: '+'
}, '1fr');
row.addPriceDisplay('addonsTotal', {
label: 'Add-ons Total',
computedValue: () => {
const windowCount = buildingSection.integer('windowCount')?.value() || 50;
let total = 0;
if (addonsSection.checkbox('screenCleaning')?.value()) total += windowCount * 2;
if (addonsSection.checkbox('trackCleaning')?.value()) total += windowCount * 1.5;
if (addonsSection.checkbox('hardWaterRemoval')?.value()) total += windowCount * 5;
if (addonsSection.checkbox('mirrorCleaning')?.value()) {
const mirrors = addonsSection.integer('mirrorCount')?.value() || 0;
total += mirrors * 3;
}
if (addonsSection.checkbox('skylightCleaning')?.value()) {
const skylights = addonsSection.integer('skylightCount')?.value() || 0;
total += skylights * 25;
}
return total;
},
variant: 'default',
prefix: '+'
}, '1fr');
});
summarySection.addRow(row => {
row.addPriceDisplay('travelFee', {
label: 'Travel Fee',
computedValue: () => getTravelFee(),
variant: 'default',
prefix: '+'
});
});
summarySection.addRow(row => {
row.addPriceDisplay('frequencyDiscount', {
label: 'Contract Discount',
computedValue: () => {
const buildingType = buildingSection.dropdown('buildingType')?.value() || 'office-low';
const windowCount = buildingSection.integer('windowCount')?.value() || 50;
const windowSize = buildingSection.dropdown('windowSize')?.value() || 'standard';
const cleaningScope = serviceSection.radioButton('cleaningScope')?.value() || 'exterior';
const floorRange = buildingSection.dropdown('floorRange')?.value() || '1-3';
const frequency = serviceSection.dropdown('frequency')?.value() || 'monthly';
const baseRate = buildingRates?.[buildingType] ?? 4;
let sizeMultiplier = 1.0;
if (windowSize === 'small') sizeMultiplier = 0.75;
else if (windowSize === 'large') sizeMultiplier = 1.5;
else if (windowSize === 'xlarge') sizeMultiplier = 2.0;
let scopeMultiplier = 1.0;
if (cleaningScope === 'both') scopeMultiplier = 1.8;
const basePrice = windowCount * baseRate * sizeMultiplier * scopeMultiplier;
const floorMultiplier = floorMultipliers?.[floorRange] ?? 1.0;
const adjustedBase = basePrice * floorMultiplier;
const discountPercent = frequencyDiscounts?.[frequency] ?? 0;
return -(adjustedBase * discountPercent / 100);
},
variant: 'success',
prefix: ''
});
});
const finalSection = form.addSubform('final', {
title: '๐งพ Total Quote',
isCollapsible: false,
sticky: 'bottom'
});
finalSection.addRow(row => {
row.addPriceDisplay('totalPrice', {
label: 'Total Estimated Price',
computedValue: () => {
const buildingType = buildingSection.dropdown('buildingType')?.value() || 'office-low';
const windowCount = buildingSection.integer('windowCount')?.value() || 50;
const windowSize = buildingSection.dropdown('windowSize')?.value() || 'standard';
const cleaningScope = serviceSection.radioButton('cleaningScope')?.value() || 'exterior';
const floorRange = buildingSection.dropdown('floorRange')?.value() || '1-3';
const accessMethod = serviceSection.dropdown('accessMethod')?.value() || 'ground';
const frequency = serviceSection.dropdown('frequency')?.value() || 'monthly';
// Base window cost
const baseRate = buildingRates?.[buildingType] ?? 4;
let sizeMultiplier = 1.0;
if (windowSize === 'small') sizeMultiplier = 0.75;
else if (windowSize === 'large') sizeMultiplier = 1.5;
else if (windowSize === 'xlarge') sizeMultiplier = 2.0;
let scopeMultiplier = 1.0;
if (cleaningScope === 'both') scopeMultiplier = 1.8;
let total = windowCount * baseRate * sizeMultiplier * scopeMultiplier;
// Floor multiplier
const floorMultiplier = floorMultipliers?.[floorRange] ?? 1.0;
total *= floorMultiplier;
// Access surcharge
total += accessSurcharges?.[accessMethod] ?? 0;
// Add-ons
if (addonsSection.checkbox('screenCleaning')?.value()) total += windowCount * 2;
if (addonsSection.checkbox('trackCleaning')?.value()) total += windowCount * 1.5;
if (addonsSection.checkbox('hardWaterRemoval')?.value()) total += windowCount * 5;
if (addonsSection.checkbox('mirrorCleaning')?.value()) {
const mirrors = addonsSection.integer('mirrorCount')?.value() || 0;
total += mirrors * 3;
}
if (addonsSection.checkbox('skylightCleaning')?.value()) {
const skylights = addonsSection.integer('skylightCount')?.value() || 0;
total += skylights * 25;
}
// After hours surcharge
if (addonsSection.checkbox('afterHours')?.value()) total *= 1.15;
// Post-construction surcharge
if (addonsSection.checkbox('postConstruction')?.value()) total *= 1.5;
// Frequency discount
const discountPercent = frequencyDiscounts?.[frequency] ?? 0;
total *= (1 - discountPercent / 100);
// Add travel fee
total += getTravelFee();
return Math.round(total);
},
variant: 'large',
suffix: () => {
const frequency = serviceSection.dropdown('frequency')?.value();
if (frequency === 'weekly') return '/week';
if (frequency === 'bi-weekly') return '/visit';
if (frequency === 'monthly') return '/month';
if (frequency === 'quarterly') return '/quarter';
return '';
}
});
});
finalSection.addRow(row => {
row.addTextPanel('disclaimer', {
computedValue: () => 'Quote based on standard conditions. Final price may vary after on-site assessment.',
customStyles: { 'font-size': '0.85rem', 'color': '#64748b', 'font-style': 'italic' }
});
});
form.configureSubmitButton({
label: 'Request Site Visit'
});
}