export function upholsteryCleaningCalculator(form: FormTs) {
// Base prices by furniture type
const furniturePrices: Record<string, number> = {
'armchair': 45,
'loveseat': 75,
'sofa-3seat': 95,
'sofa-4seat': 125,
'sectional-small': 150,
'sectional-large': 225,
'ottoman': 30,
'dining-chair': 25,
'office-chair': 35,
'recliner': 65,
'mattress-twin': 75,
'mattress-full': 95,
'mattress-queen': 115,
'mattress-king': 135
};
// Fabric type multipliers
const fabricMultipliers: Record<string, number> = {
'standard': 1,
'microfiber': 1.1,
'leather': 1.4,
'velvet': 1.3,
'silk': 1.5,
'delicate': 1.5
};
// Condition/stain multipliers
const conditionMultipliers: Record<string, number> = {
'light': 1,
'moderate': 1.25,
'heavy': 1.5,
'extreme': 2
};
form.addRow(row => {
row.addTextPanel('header', {
computedValue: () => 'Upholstery Cleaning Calculator',
customStyles: { 'font-size': '1.5rem', 'font-weight': '600', 'color': '#1e293b' }
});
});
form.addSpacer({ height: 20 });
// Service Location Section
const locationSection = form.addSubform('location', { title: '๐ Service Location' });
locationSection.addRow(row => {
row.addAddress('serviceAddress', {
label: 'Service Address',
placeholder: 'Enter your 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
});
});
locationSection.addRow(row => {
row.addTextPanel('travelZoneInfo', {
computedValue: () => {
const addressField = locationSection.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 - $25 travel fee';
if (miles <= 50) return '๐ Remote area - $45 travel fee';
return '๐ Long distance - $65+ travel fee';
},
customStyles: { 'font-size': '0.9rem', 'color': '#0369a1', 'background': '#e0f2fe', 'padding': '10px', 'border-radius': '6px' }
});
});
// Furniture Selection Section
const furnitureSection = form.addSubform('furniture', { title: '๐๏ธ Furniture to Clean' });
furnitureSection.addRow(row => {
row.addDropdown('furnitureType', {
label: 'Furniture Type',
options: [
{ id: 'armchair', name: 'Armchair ($45)' },
{ id: 'loveseat', name: 'Loveseat ($75)' },
{ id: 'sofa-3seat', name: '3-Seat Sofa ($95)' },
{ id: 'sofa-4seat', name: '4-Seat Sofa ($125)' },
{ id: 'sectional-small', name: 'Small Sectional ($150)' },
{ id: 'sectional-large', name: 'Large Sectional ($225)' },
{ id: 'ottoman', name: 'Ottoman ($30)' },
{ id: 'dining-chair', name: 'Dining Chair ($25)' },
{ id: 'office-chair', name: 'Office Chair ($35)' },
{ id: 'recliner', name: 'Recliner ($65)' },
{ id: 'mattress-twin', name: 'Mattress - Twin ($75)' },
{ id: 'mattress-full', name: 'Mattress - Full ($95)' },
{ id: 'mattress-queen', name: 'Mattress - Queen ($115)' },
{ id: 'mattress-king', name: 'Mattress - King ($135)' }
],
defaultValue: 'sofa-3seat',
isRequired: true
}, '1fr');
row.addInteger('quantity', {
label: 'Quantity',
min: 1,
max: 20,
defaultValue: 1,
tooltip: '10% discount for 3+ pieces'
}, '1fr');
});
furnitureSection.addRow(row => {
row.addDropdown('fabricType', {
label: 'Fabric Type',
options: [
{ id: 'standard', name: 'Standard (cotton, polyester)' },
{ id: 'microfiber', name: 'Microfiber (+10%)' },
{ id: 'leather', name: 'Leather (+40%)' },
{ id: 'velvet', name: 'Velvet (+30%)' },
{ id: 'silk', name: 'Silk (+50%)' },
{ id: 'delicate', name: 'Delicate/Antique (+50%)' }
],
defaultValue: 'standard',
isRequired: true,
tooltip: 'Specialty fabrics require special cleaning methods'
}, '1fr');
row.addDropdown('condition', {
label: 'Soiling Level',
options: [
{ id: 'light', name: 'Light (routine cleaning)' },
{ id: 'moderate', name: 'Moderate (visible stains) +25%' },
{ id: 'heavy', name: 'Heavy (significant staining) +50%' },
{ id: 'extreme', name: 'Extreme (pet/smoke damage) +100%' }
],
defaultValue: 'light',
tooltip: 'Heavier soiling requires more time and products'
}, '1fr');
});
// Stain Treatment Section
const stainSection = form.addSubform('stains', { title: '๐งด Stain Treatment' });
stainSection.addRow(row => {
row.addCheckbox('petStains', {
label: 'Pet Stain Treatment (+$25)',
defaultValue: false,
tooltip: 'Enzyme treatment for urine, vomit'
}, '1fr');
row.addCheckbox('petOdor', {
label: 'Pet Odor Removal (+$35)',
defaultValue: false,
tooltip: 'Deep odor neutralization'
}, '1fr');
});
stainSection.addRow(row => {
row.addCheckbox('foodStains', {
label: 'Food/Beverage Stains (+$15)',
defaultValue: false,
tooltip: 'Coffee, wine, grease, etc.'
}, '1fr');
row.addCheckbox('inkStains', {
label: 'Ink/Dye Stains (+$20)',
defaultValue: false,
tooltip: 'Pen, marker, dye transfer'
}, '1fr');
});
stainSection.addRow(row => {
row.addCheckbox('mildew', {
label: 'Mold/Mildew Treatment (+$45)',
defaultValue: false,
tooltip: 'Antimicrobial treatment'
}, '1fr');
row.addCheckbox('smokeOdor', {
label: 'Smoke Odor Removal (+$40)',
defaultValue: false,
tooltip: 'Cigarette or fire smoke'
}, '1fr');
});
// Additional Services Section
const servicesSection = form.addSubform('services', { title: 'โจ Additional Services' });
servicesSection.addRow(row => {
row.addCheckbox('scotchgard', {
label: 'Fabric Protection (+$30)',
defaultValue: false,
tooltip: 'Scotchgard or similar protectant'
}, '1fr');
row.addCheckbox('deodorizing', {
label: 'Deodorizing Treatment (+$20)',
defaultValue: false,
tooltip: 'Fresh scent application'
}, '1fr');
});
servicesSection.addRow(row => {
row.addCheckbox('sanitizing', {
label: 'Sanitizing/Disinfecting (+$25)',
defaultValue: false,
tooltip: 'Kills bacteria and allergens'
}, '1fr');
row.addCheckbox('leatherCondition', {
label: 'Leather Conditioning (+$35)',
defaultValue: false,
tooltip: 'Moisturize and protect leather',
isVisible: () => furnitureSection.dropdown('fabricType')?.value() === 'leather'
}, '1fr');
});
servicesSection.addRow(row => {
row.addCheckbox('pillowCleaning', {
label: 'Throw Pillow Cleaning (+$10/pillow)',
defaultValue: false
}, '1fr');
row.addInteger('pillowCount', {
label: 'Number of Pillows',
min: 1,
max: 20,
defaultValue: 4,
isVisible: () => servicesSection.checkbox('pillowCleaning')?.value() === true
}, '1fr');
});
// Service Options Section
const optionsSection = form.addSubform('options', { title: '๐ Service Options' });
optionsSection.addRow(row => {
row.addRadioButton('serviceType', {
label: 'Service Type',
options: [
{ id: 'standard', name: 'Standard Service' },
{ id: 'deep', name: 'Deep Cleaning (+35%)' },
{ id: 'express', name: 'Express Same-Day (+50%)' }
],
defaultValue: 'standard',
orientation: 'vertical'
});
});
optionsSection.addRow(row => {
row.addCheckbox('pickup', {
label: 'Pickup & Delivery (+$50)',
defaultValue: false,
tooltip: 'We pick up, clean, and return'
}, '1fr');
row.addCheckbox('onsite', {
label: 'On-Site Service',
defaultValue: true,
tooltip: 'Clean at your location'
}, '1fr');
});
form.addSpacer({ height: 20, showLine: true, lineStyle: 'dashed' });
// Helper to calculate travel fee
const getTravelFee = () => {
const addressField = locationSection.address('serviceAddress');
const miles = addressField?.distance();
if (miles == null || miles <= 15) return 0;
if (miles <= 30) return 25;
if (miles <= 50) return 45;
return 65 + Math.floor((miles - 50) / 15) * 10;
};
// Price Summary Section
const summarySection = form.addSubform('summary', { title: '๐ฐ Price Breakdown', isCollapsible: false });
summarySection.addRow(row => {
row.addPriceDisplay('basePrice', {
label: 'Base Cleaning',
computedValue: () => {
const furnitureType = furnitureSection.dropdown('furnitureType')?.value() || 'sofa-3seat';
const fabricType = furnitureSection.dropdown('fabricType')?.value() || 'standard';
const condition = furnitureSection.dropdown('condition')?.value() || 'light';
const quantity = furnitureSection.integer('quantity')?.value() || 1;
let basePrice = furniturePrices[furnitureType] || 95;
basePrice *= fabricMultipliers[fabricType] || 1;
basePrice *= conditionMultipliers[condition] || 1;
basePrice *= quantity;
// Volume discount
if (quantity >= 3) basePrice *= 0.9;
return Math.round(basePrice);
},
variant: 'default'
}, '1fr');
row.addPriceDisplay('stainTreatment', {
label: 'Stain Treatment',
computedValue: () => {
let total = 0;
if (stainSection.checkbox('petStains')?.value()) total += 25;
if (stainSection.checkbox('petOdor')?.value()) total += 35;
if (stainSection.checkbox('foodStains')?.value()) total += 15;
if (stainSection.checkbox('inkStains')?.value()) total += 20;
if (stainSection.checkbox('mildew')?.value()) total += 45;
if (stainSection.checkbox('smokeOdor')?.value()) total += 40;
return total;
},
variant: 'default',
prefix: '+'
}, '1fr');
});
summarySection.addRow(row => {
row.addPriceDisplay('additionalServices', {
label: 'Additional Services',
computedValue: () => {
let total = 0;
if (servicesSection.checkbox('scotchgard')?.value()) total += 30;
if (servicesSection.checkbox('deodorizing')?.value()) total += 20;
if (servicesSection.checkbox('sanitizing')?.value()) total += 25;
if (servicesSection.checkbox('leatherCondition')?.value()) total += 35;
if (servicesSection.checkbox('pillowCleaning')?.value()) {
const pillowCount = servicesSection.integer('pillowCount')?.value() || 4;
total += pillowCount * 10;
}
return total;
},
variant: 'default',
prefix: '+'
}, '1fr');
row.addPriceDisplay('serviceUpgrade', {
label: 'Service Upgrade',
computedValue: () => {
const serviceType = optionsSection.radioButton('serviceType')?.value() || 'standard';
if (serviceType === 'standard') return 0;
// Calculate base
const furnitureType = furnitureSection.dropdown('furnitureType')?.value() || 'sofa-3seat';
const fabricType = furnitureSection.dropdown('fabricType')?.value() || 'standard';
const condition = furnitureSection.dropdown('condition')?.value() || 'light';
const quantity = furnitureSection.integer('quantity')?.value() || 1;
let basePrice = furniturePrices[furnitureType] || 95;
basePrice *= fabricMultipliers[fabricType] || 1;
basePrice *= conditionMultipliers[condition] || 1;
basePrice *= quantity;
if (quantity >= 3) basePrice *= 0.9;
if (serviceType === 'deep') return Math.round(basePrice * 0.35);
if (serviceType === 'express') return Math.round(basePrice * 0.50);
return 0;
},
variant: 'default',
prefix: '+'
}, '1fr');
});
summarySection.addRow(row => {
row.addPriceDisplay('travelFee', {
label: 'Travel Fee',
computedValue: () => getTravelFee(),
variant: 'default',
prefix: '+'
});
});
const finalSection = form.addSubform('final', {
title: '๐งพ Summary',
isCollapsible: false,
sticky: 'bottom'
});
finalSection.addRow(row => {
row.addPriceDisplay('perPiece', {
label: 'Per Piece',
computedValue: () => {
const furnitureType = furnitureSection.dropdown('furnitureType')?.value() || 'sofa-3seat';
const fabricType = furnitureSection.dropdown('fabricType')?.value() || 'standard';
const condition = furnitureSection.dropdown('condition')?.value() || 'light';
const serviceType = optionsSection.radioButton('serviceType')?.value() || 'standard';
const quantity = furnitureSection.integer('quantity')?.value() || 1;
let price = furniturePrices[furnitureType] || 95;
price *= fabricMultipliers[fabricType] || 1;
price *= conditionMultipliers[condition] || 1;
// Volume discount
if (quantity >= 3) price *= 0.9;
// Service upgrade
if (serviceType === 'deep') price *= 1.35;
if (serviceType === 'express') price *= 1.50;
return Math.round(price);
},
variant: 'default',
suffix: '/piece'
}, '1fr');
row.addPriceDisplay('totalPrice', {
label: 'Total',
computedValue: () => {
const furnitureType = furnitureSection.dropdown('furnitureType')?.value() || 'sofa-3seat';
const fabricType = furnitureSection.dropdown('fabricType')?.value() || 'standard';
const condition = furnitureSection.dropdown('condition')?.value() || 'light';
const serviceType = optionsSection.radioButton('serviceType')?.value() || 'standard';
const quantity = furnitureSection.integer('quantity')?.value() || 1;
// Base price
let total = furniturePrices[furnitureType] || 95;
total *= fabricMultipliers[fabricType] || 1;
total *= conditionMultipliers[condition] || 1;
total *= quantity;
// Volume discount
if (quantity >= 3) total *= 0.9;
// Service upgrade
if (serviceType === 'deep') total *= 1.35;
if (serviceType === 'express') total *= 1.50;
// Stain treatments
if (stainSection.checkbox('petStains')?.value()) total += 25;
if (stainSection.checkbox('petOdor')?.value()) total += 35;
if (stainSection.checkbox('foodStains')?.value()) total += 15;
if (stainSection.checkbox('inkStains')?.value()) total += 20;
if (stainSection.checkbox('mildew')?.value()) total += 45;
if (stainSection.checkbox('smokeOdor')?.value()) total += 40;
// Additional services
if (servicesSection.checkbox('scotchgard')?.value()) total += 30;
if (servicesSection.checkbox('deodorizing')?.value()) total += 20;
if (servicesSection.checkbox('sanitizing')?.value()) total += 25;
if (servicesSection.checkbox('leatherCondition')?.value()) total += 35;
if (servicesSection.checkbox('pillowCleaning')?.value()) {
const pillowCount = servicesSection.integer('pillowCount')?.value() || 4;
total += pillowCount * 10;
}
// Pickup/delivery
if (optionsSection.checkbox('pickup')?.value()) total += 50;
// Travel fee
total += getTravelFee();
return Math.round(total);
},
variant: 'large'
}, '1fr');
});
finalSection.addRow(row => {
row.addTextPanel('disclaimer', {
computedValue: () => 'Final price confirmed after inspection. Results vary based on fabric age and stain type. 100% satisfaction guarantee.',
customStyles: { 'font-size': '0.85rem', 'color': '#64748b', 'font-style': 'italic' }
});
});
form.configureSubmitButton({
label: 'Book Cleaning'
});
}