export function poolCleaningCalculator(form: FormTs) {
// Base prices per pool type (monthly service)
const poolTypePrices: Record<string, number> = {
'above-ground-small': 80,
'above-ground-large': 100,
'in-ground-small': 120,
'in-ground-medium': 150,
'in-ground-large': 200,
'in-ground-xl': 275
};
// One-time cleaning prices
const oneTimeMultiplier = 2.5;
form.addRow(row => {
row.addTextPanel('header', {
computedValue: () => 'Pool Cleaning Service Quote',
customStyles: { 'font-size': '1.5rem', 'font-weight': '600', 'color': '#1e293b' }
});
});
form.addSpacer({ height: 20 });
// Pool Details Section
const poolSection = form.addSubform('poolDetails', { title: '๐ Pool Details' });
poolSection.addRow(row => {
row.addAddress('serviceAddress', {
label: 'Pool Location Address',
placeholder: 'Enter property 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
});
});
poolSection.addRow(row => {
row.addTextPanel('travelZoneInfo', {
computedValue: () => {
const addressField = poolSection.address('serviceAddress');
const miles = addressField?.distance();
if (miles == null) return '๐ Enter address to check service area';
if (miles <= 20) return '๐ Within service area - No travel fee';
if (miles <= 35) return '๐ Extended area - $20/visit travel fee';
if (miles <= 50) return '๐ Remote area - $40/visit travel fee';
return '๐ Outside service area - Contact for availability';
},
customStyles: { 'font-size': '0.9rem', 'color': '#0369a1', 'background': '#e0f2fe', 'padding': '10px', 'border-radius': '6px' }
});
});
poolSection.addRow(row => {
row.addRadioButton('poolType', {
label: 'Pool Type & Size',
options: [
{ id: 'above-ground-small', name: 'Above Ground - Small (up to 15ft) - $80/month' },
{ id: 'above-ground-large', name: 'Above Ground - Large (15ft+) - $100/month' },
{ id: 'in-ground-small', name: 'In-Ground - Small (up to 10,000 gal) - $120/month' },
{ id: 'in-ground-medium', name: 'In-Ground - Medium (10,000-20,000 gal) - $150/month' },
{ id: 'in-ground-large', name: 'In-Ground - Large (20,000-40,000 gal) - $200/month' },
{ id: 'in-ground-xl', name: 'In-Ground - Extra Large (40,000+ gal) - $275/month' }
],
defaultValue: 'in-ground-medium',
orientation: 'vertical',
isRequired: true
});
});
poolSection.addRow(row => {
row.addDropdown('poolSurface', {
label: 'Pool Surface',
options: [
{ id: 'plaster', name: 'Plaster/Gunite' },
{ id: 'vinyl', name: 'Vinyl Liner' },
{ id: 'fiberglass', name: 'Fiberglass' },
{ id: 'tile', name: 'Tile (+15%)' },
{ id: 'pebble', name: 'Pebble Tec (+10%)' }
],
defaultValue: 'plaster'
}, '1fr');
row.addDropdown('poolCondition', {
label: 'Current Pool Condition',
options: [
{ id: 'well-maintained', name: 'Well Maintained' },
{ id: 'moderate', name: 'Needs Some Work (+20%)' },
{ id: 'neglected', name: 'Neglected (+40%)' },
{ id: 'green', name: 'Green/Algae Problem (+60%)' }
],
defaultValue: 'well-maintained'
}, '1fr');
});
// Service Type Section
const serviceSection = form.addSubform('serviceType', { title: '๐
Service Type' });
serviceSection.addRow(row => {
row.addRadioButton('frequency', {
label: 'Service Frequency',
options: [
{ id: 'weekly', name: 'Weekly Service (Standard)' },
{ id: 'biweekly', name: 'Bi-Weekly Service (+10%)' },
{ id: 'monthly', name: 'Monthly Service (+25%)' },
{ id: 'one-time', name: 'One-Time Cleaning (2.5x monthly rate)' }
],
defaultValue: 'weekly',
orientation: 'vertical',
isRequired: true
});
});
serviceSection.addRow(row => {
row.addDropdown('serviceLevel', {
label: 'Service Level',
options: [
{ id: 'basic', name: 'Basic (Skim, Vacuum, Chemicals)' },
{ id: 'standard', name: 'Standard (+ Brush, Filter Check) +$20' },
{ id: 'premium', name: 'Premium (+ Equipment Inspection) +$40' },
{ id: 'full', name: 'Full Service (+ Minor Repairs) +$75' }
],
defaultValue: 'standard'
}, '1fr');
});
// Additional Services Section
const addonsSection = form.addSubform('addons', { title: 'โจ Additional Services' });
addonsSection.addRow(row => {
row.addCheckbox('filterCleaning', {
label: 'Deep Filter Cleaning (+$45)',
defaultValue: false
}, '1fr');
row.addCheckbox('acidWash', {
label: 'Acid Wash (one-time) (+$350)',
defaultValue: false,
isVisible: () => serviceSection.radioButton('frequency')?.value() === 'one-time'
}, '1fr');
});
addonsSection.addRow(row => {
row.addCheckbox('tileCleaning', {
label: 'Tile & Grout Cleaning (+$75)',
defaultValue: false
}, '1fr');
row.addCheckbox('saltCellCleaning', {
label: 'Salt Cell Cleaning (+$65)',
defaultValue: false
}, '1fr');
});
addonsSection.addRow(row => {
row.addCheckbox('poolCover', {
label: 'Pool Cover Service (+$25/visit)',
defaultValue: false
}, '1fr');
row.addCheckbox('chemicalsIncluded', {
label: 'Chemicals Included (+$35)',
defaultValue: true
}, '1fr');
});
addonsSection.addRow(row => {
row.addCheckbox('greenToClean', {
label: 'Green-to-Clean Treatment (+$200)',
defaultValue: false,
isVisible: () => poolSection.dropdown('poolCondition')?.value() === 'green'
}, '1fr');
row.addCheckbox('startupService', {
label: 'Pool Opening/Startup (+$175)',
defaultValue: false
}, '1fr');
});
form.addSpacer({ height: 20, showLine: true, lineStyle: 'dashed' });
// Helper to calculate travel fee (per visit for recurring, one-time for single service)
const getTravelFee = () => {
const addressField = poolSection.address('serviceAddress');
const miles = addressField?.distance();
if (miles == null || miles <= 20) return 0;
if (miles <= 35) return 20;
if (miles <= 50) return 40;
return 60;
};
// Quote Summary Section
const summarySection = form.addSubform('summary', { title: '๐ฐ Your Quote', isCollapsible: false });
const getSurfaceMultiplier = () => {
const surface = poolSection.dropdown('poolSurface')?.value() || 'plaster';
const multipliers: Record<string, number> = {
'plaster': 1.0,
'vinyl': 1.0,
'fiberglass': 1.0,
'tile': 1.15,
'pebble': 1.10
};
return multipliers[surface] || 1.0;
};
const getConditionMultiplier = () => {
const condition = poolSection.dropdown('poolCondition')?.value() || 'well-maintained';
const multipliers: Record<string, number> = {
'well-maintained': 1.0,
'moderate': 1.2,
'neglected': 1.4,
'green': 1.6
};
return multipliers[condition] || 1.0;
};
const getFrequencyMultiplier = () => {
const freq = serviceSection.radioButton('frequency')?.value() || 'weekly';
const multipliers: Record<string, number> = {
'weekly': 1.0,
'biweekly': 1.1,
'monthly': 1.25,
'one-time': oneTimeMultiplier
};
return multipliers[freq] || 1.0;
};
const getServiceLevelAddon = () => {
const level = serviceSection.dropdown('serviceLevel')?.value() || 'standard';
const addons: Record<string, number> = {
'basic': 0,
'standard': 20,
'premium': 40,
'full': 75
};
return addons[level] || 0;
};
summarySection.addRow(row => {
row.addPriceDisplay('baseCost', {
label: 'Base Service Cost',
computedValue: () => {
const poolType = poolSection.radioButton('poolType')?.value() || 'in-ground-medium';
const basePrice = poolTypePrices[poolType] || 150;
return Math.round(basePrice * getSurfaceMultiplier() * getConditionMultiplier() * getFrequencyMultiplier());
},
variant: 'default'
}, '1fr');
row.addPriceDisplay('serviceLevelCost', {
label: 'Service Level Upgrade',
computedValue: () => getServiceLevelAddon(),
variant: 'default',
prefix: '+'
}, '1fr');
});
summarySection.addRow(row => {
row.addPriceDisplay('addonsCost', {
label: 'Additional Services',
computedValue: () => {
let addons = 0;
if (addonsSection.checkbox('filterCleaning')?.value()) addons += 45;
if (addonsSection.checkbox('acidWash')?.value()) addons += 350;
if (addonsSection.checkbox('tileCleaning')?.value()) addons += 75;
if (addonsSection.checkbox('saltCellCleaning')?.value()) addons += 65;
if (addonsSection.checkbox('poolCover')?.value()) addons += 25;
if (addonsSection.checkbox('chemicalsIncluded')?.value()) addons += 35;
if (addonsSection.checkbox('greenToClean')?.value()) addons += 200;
if (addonsSection.checkbox('startupService')?.value()) addons += 175;
return addons;
},
variant: 'default',
prefix: '+'
}, '1fr');
row.addPriceDisplay('travelFee', {
label: () => {
const freq = serviceSection.radioButton('frequency')?.value() || 'weekly';
return freq === 'one-time' ? 'Travel Fee' : 'Monthly Travel Fee';
},
computedValue: () => {
const baseFee = getTravelFee();
if (baseFee === 0) return 0;
const freq = serviceSection.radioButton('frequency')?.value() || 'weekly';
if (freq === 'one-time') return baseFee;
if (freq === 'weekly') return baseFee * 4;
if (freq === 'biweekly') return baseFee * 2;
return baseFee; // monthly
},
variant: 'default',
prefix: '+'
}, '1fr');
});
summarySection.addSpacer({ showLine: true, lineStyle: 'solid', lineColor: '#e2e8f0' });
summarySection.addRow(row => {
row.addPriceDisplay('totalEstimate', {
label: () => {
const freq = serviceSection.radioButton('frequency')?.value() || 'weekly';
return freq === 'one-time' ? 'One-Time Service Total' : 'Monthly Service Cost';
},
computedValue: () => {
const poolType = poolSection.radioButton('poolType')?.value() || 'in-ground-medium';
const basePrice = poolTypePrices[poolType] || 150;
let total = basePrice * getSurfaceMultiplier() * getConditionMultiplier() * getFrequencyMultiplier();
total += getServiceLevelAddon();
// Add-ons
if (addonsSection.checkbox('filterCleaning')?.value()) total += 45;
if (addonsSection.checkbox('acidWash')?.value()) total += 350;
if (addonsSection.checkbox('tileCleaning')?.value()) total += 75;
if (addonsSection.checkbox('saltCellCleaning')?.value()) total += 65;
if (addonsSection.checkbox('poolCover')?.value()) total += 25;
if (addonsSection.checkbox('chemicalsIncluded')?.value()) total += 35;
if (addonsSection.checkbox('greenToClean')?.value()) total += 200;
if (addonsSection.checkbox('startupService')?.value()) total += 175;
// Add travel fee
const baseFee = getTravelFee();
if (baseFee > 0) {
const freq = serviceSection.radioButton('frequency')?.value() || 'weekly';
if (freq === 'one-time') total += baseFee;
else if (freq === 'weekly') total += baseFee * 4;
else if (freq === 'biweekly') total += baseFee * 2;
else total += baseFee;
}
return Math.round(total);
},
variant: 'large'
});
});
summarySection.addRow(row => {
row.addTextPanel('annualSavings', {
computedValue: () => {
const freq = serviceSection.radioButton('frequency')?.value() || 'weekly';
if (freq === 'one-time') return '';
const poolType = poolSection.radioButton('poolType')?.value() || 'in-ground-medium';
const basePrice = poolTypePrices[poolType] || 150;
let monthly = basePrice * getSurfaceMultiplier() * getConditionMultiplier() * getFrequencyMultiplier();
monthly += getServiceLevelAddon();
if (addonsSection.checkbox('poolCover')?.value()) monthly += 25;
if (addonsSection.checkbox('chemicalsIncluded')?.value()) monthly += 35;
const annual = Math.round(monthly * 12);
return `Annual Cost: $${annual.toLocaleString()} (12 months)`;
},
customStyles: { 'font-size': '0.9rem', 'color': '#059669', 'font-weight': '500' }
});
});
// Sticky Summary Section
const finalSection = form.addSubform('final', {
title: '๐งพ Summary',
isCollapsible: false,
sticky: 'bottom'
});
finalSection.addRow(row => {
row.addPriceDisplay('totalEstimate', {
label: () => {
const freq = serviceSection.radioButton('frequency')?.value() || 'weekly';
return freq === 'one-time' ? 'One-Time Total' : 'Monthly Cost';
},
computedValue: () => {
const poolType = poolSection.radioButton('poolType')?.value() || 'in-ground-medium';
const basePrice = poolTypePrices[poolType] || 150;
let total = basePrice * getSurfaceMultiplier() * getConditionMultiplier() * getFrequencyMultiplier();
total += getServiceLevelAddon();
if (addonsSection.checkbox('filterCleaning')?.value()) total += 45;
if (addonsSection.checkbox('acidWash')?.value()) total += 350;
if (addonsSection.checkbox('tileCleaning')?.value()) total += 75;
if (addonsSection.checkbox('saltCellCleaning')?.value()) total += 65;
if (addonsSection.checkbox('poolCover')?.value()) total += 25;
if (addonsSection.checkbox('chemicalsIncluded')?.value()) total += 35;
if (addonsSection.checkbox('greenToClean')?.value()) total += 200;
if (addonsSection.checkbox('startupService')?.value()) total += 175;
// Add travel fee
const baseFee = getTravelFee();
if (baseFee > 0) {
const freq = serviceSection.radioButton('frequency')?.value() || 'weekly';
if (freq === 'one-time') total += baseFee;
else if (freq === 'weekly') total += baseFee * 4;
else if (freq === 'biweekly') total += baseFee * 2;
else total += baseFee;
}
return Math.round(total);
},
variant: 'large'
});
});
finalSection.addRow(row => {
row.addTextPanel('disclaimer', {
computedValue: () => 'Final price confirmed after pool inspection.',
customStyles: { 'font-size': '0.85rem', 'color': '#94a3b8', 'font-style': 'italic' }
});
});
form.configureSubmitButton({
label: 'Schedule Free Inspection'
});
}