export function petSittingCalculator(form: FormTs) {
// Base rates per visit type
const visitRates: Record<string, number> = {
'drop-in': 25, // 30-min visit
'extended': 40, // 60-min visit
'overnight': 75, // Overnight stay
'full-day': 55 // Full day care
};
// Pet type base adjustments
const petTypeRates: Record<string, number> = {
'dog-small': 0,
'dog-medium': 5,
'dog-large': 10,
'cat': -5,
'bird': 0,
'fish': -10,
'reptile': 5,
'small-animal': 0
};
// Additional pet discount (percentage off for pets after first)
const additionalPetDiscount = 0.5; // 50% for additional pets of same type
form.addRow(row => {
row.addTextPanel('header', {
computedValue: () => 'Pet Sitting Quote',
customStyles: { 'font-size': '1.5rem', 'font-weight': '600', 'color': '#1e293b' }
});
});
form.addSpacer({ height: 20 });
// Service Location Section
const locationSection = form.addSubform('serviceLocation', { title: '๐ Your Location' });
locationSection.addRow(row => {
row.addAddress('homeAddress', {
label: 'Home Address',
placeholder: 'Enter your home 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('serviceAreaInfo', {
computedValue: () => {
const addressField = locationSection.address('homeAddress');
const miles = addressField?.distance();
if (miles == null) return '๐ Enter address to check service area';
if (miles <= 8) return '๐ Within service area - No travel fee';
if (miles <= 15) return '๐ Extended area - $8 travel fee per visit';
if (miles <= 25) return '๐ Remote area - $15 travel fee per visit';
return '๐ Outside service area - Please contact us';
},
customStyles: { 'font-size': '0.9rem', 'color': '#ea580c', 'background': '#fff7ed', 'padding': '10px', 'border-radius': '6px' }
});
});
// Pet Details Section
const petSection = form.addSubform('petDetails', { title: '๐พ Your Pets' });
petSection.addRow(row => {
row.addDropdown('primaryPetType', {
label: 'Primary Pet Type',
options: [
{ id: 'dog-small', name: 'Dog (Small, under 25 lbs)' },
{ id: 'dog-medium', name: 'Dog (Medium, 25-50 lbs)' },
{ id: 'dog-large', name: 'Dog (Large, 50+ lbs)' },
{ id: 'cat', name: 'Cat' },
{ id: 'bird', name: 'Bird' },
{ id: 'fish', name: 'Fish/Aquarium' },
{ id: 'reptile', name: 'Reptile' },
{ id: 'small-animal', name: 'Small Animal (Hamster, Guinea Pig, etc.)' }
],
defaultValue: 'dog-medium',
isRequired: true
}, '1fr');
row.addInteger('numberOfPets', {
label: 'Number of Pets (same type)',
min: 1,
max: 10,
defaultValue: 1,
isRequired: true
}, '1fr');
});
petSection.addRow(row => {
row.addCheckbox('hasAdditionalPetTypes', {
label: 'I have additional pet types',
defaultValue: false
});
});
petSection.addRow(row => {
row.addDropdown('additionalPetType', {
label: 'Additional Pet Type',
options: [
{ id: 'dog-small', name: 'Dog (Small)' },
{ id: 'dog-medium', name: 'Dog (Medium)' },
{ id: 'dog-large', name: 'Dog (Large)' },
{ id: 'cat', name: 'Cat' },
{ id: 'bird', name: 'Bird' },
{ id: 'small-animal', name: 'Small Animal' }
],
defaultValue: 'cat',
isVisible: () => petSection.checkbox('hasAdditionalPetTypes')?.value() === true
}, '1fr');
row.addInteger('additionalPetCount', {
label: 'Number of Additional Pets',
min: 1,
max: 5,
defaultValue: 1,
isVisible: () => petSection.checkbox('hasAdditionalPetTypes')?.value() === true
}, '1fr');
});
// Service Details Section
const serviceSection = form.addSubform('serviceDetails', { title: '๐
Service Details' });
serviceSection.addRow(row => {
row.addRadioButton('visitType', {
label: 'Visit Type',
options: [
{ id: 'drop-in', name: 'Drop-In Visit (30 min) - $25/visit' },
{ id: 'extended', name: 'Extended Visit (60 min) - $40/visit' },
{ id: 'overnight', name: 'Overnight Stay - $75/night' },
{ id: 'full-day', name: 'Full Day Care (8+ hrs) - $55/day' }
],
defaultValue: 'drop-in',
orientation: 'vertical',
isRequired: true
});
});
serviceSection.addRow(row => {
row.addInteger('numberOfDays', {
label: 'Number of Days',
min: 1,
max: 30,
defaultValue: 3,
isRequired: true
}, '1fr');
row.addInteger('visitsPerDay', {
label: 'Visits Per Day',
min: 1,
max: 4,
defaultValue: 2,
isVisible: () => {
const visitType = serviceSection.radioButton('visitType')?.value();
return visitType === 'drop-in' || visitType === 'extended';
}
}, '1fr');
});
serviceSection.addRow(row => {
row.addCheckbox('isHoliday', {
label: 'Holiday period (+$15/day)',
defaultValue: false
}, '1fr');
row.addCheckbox('isWeekend', {
label: 'Weekend booking (+$5/day)',
defaultValue: false
}, '1fr');
});
serviceSection.addRow(row => {
row.addCheckbox('lastMinute', {
label: 'Last-minute booking (within 48 hours, +20%)',
defaultValue: false
});
});
// Additional Services Section
const addonsSection = form.addSubform('addons', { title: 'โจ Additional Services' });
addonsSection.addRow(row => {
row.addCheckbox('dogWalking', {
label: 'Dog Walking (+$15/walk)',
defaultValue: false,
isVisible: () => {
const petType = petSection.dropdown('primaryPetType')?.value() || '';
return petType.startsWith('dog');
}
}, '1fr');
row.addCheckbox('medicationAdmin', {
label: 'Medication Administration (+$5/visit)',
defaultValue: false
}, '1fr');
});
addonsSection.addRow(row => {
row.addCheckbox('plantWatering', {
label: 'Plant Watering (+$5/visit)',
defaultValue: false
}, '1fr');
row.addCheckbox('mailCollection', {
label: 'Mail & Package Collection (+$3/visit)',
defaultValue: false
}, '1fr');
});
addonsSection.addRow(row => {
row.addCheckbox('photoUpdates', {
label: 'Daily Photo Updates (+$5/day)',
defaultValue: true
}, '1fr');
row.addCheckbox('grooming', {
label: 'Basic Grooming (Brushing) (+$10/visit)',
defaultValue: false
}, '1fr');
});
addonsSection.addRow(row => {
row.addInteger('walkCount', {
label: 'Walks Per Day',
min: 1,
max: 4,
defaultValue: 1,
isVisible: () => {
const petType = petSection.dropdown('primaryPetType')?.value() || '';
return petType.startsWith('dog') && addonsSection.checkbox('dogWalking')?.value() === true;
}
});
});
form.addSpacer({ height: 20, showLine: true, lineStyle: 'dashed' });
// Helper to calculate travel fee per visit
const getTravelFeePerVisit = () => {
const addressField = locationSection.address('homeAddress');
const miles = addressField?.distance();
if (miles == null || miles <= 8) return 0;
if (miles <= 15) return 8;
if (miles <= 25) return 15;
return 20;
};
// Quote Summary Section
const summarySection = form.addSubform('summary', { title: '๐ฐ Quote Summary', isCollapsible: false });
const getBaseVisitCost = () => {
const visitType = serviceSection.radioButton('visitType')?.value() || 'drop-in';
const petType = petSection.dropdown('primaryPetType')?.value() || 'dog-medium';
const numberOfPets = petSection.integer('numberOfPets')?.value() || 1;
const baseRate = visitRates[visitType] || 25;
const petAdjustment = petTypeRates[petType] || 0;
// First pet at full price, additional pets at 50% discount
const firstPetCost = baseRate + petAdjustment;
const additionalPetsCost = (numberOfPets - 1) * (baseRate + petAdjustment) * additionalPetDiscount;
return firstPetCost + additionalPetsCost;
};
const getAdditionalPetsCost = () => {
if (!petSection.checkbox('hasAdditionalPetTypes')?.value()) return 0;
const visitType = serviceSection.radioButton('visitType')?.value() || 'drop-in';
const additionalPetType = petSection.dropdown('additionalPetType')?.value() || 'cat';
const additionalPetCount = petSection.integer('additionalPetCount')?.value() || 0;
const baseRate = visitRates[visitType] || 25;
const petAdjustment = petTypeRates[additionalPetType] || 0;
return additionalPetCount * (baseRate + petAdjustment) * additionalPetDiscount;
};
summarySection.addRow(row => {
row.addPriceDisplay('perVisitCost', {
label: () => {
const visitType = serviceSection.radioButton('visitType')?.value() || 'drop-in';
return visitType === 'overnight' ? 'Per Night Rate' : 'Per Visit Rate';
},
computedValue: () => {
return Math.round(getBaseVisitCost() + getAdditionalPetsCost());
},
variant: 'default'
}, '1fr');
row.addPriceDisplay('dailyCost', {
label: 'Daily Cost',
computedValue: () => {
const visitType = serviceSection.radioButton('visitType')?.value() || 'drop-in';
const visitsPerDay = serviceSection.integer('visitsPerDay')?.value() || 1;
let dailyRate = getBaseVisitCost() + getAdditionalPetsCost();
if (visitType === 'drop-in' || visitType === 'extended') {
dailyRate *= visitsPerDay;
}
// Add daily surcharges
if (serviceSection.checkbox('isHoliday')?.value()) dailyRate += 15;
if (serviceSection.checkbox('isWeekend')?.value()) dailyRate += 5;
// Add daily add-ons
if (addonsSection.checkbox('photoUpdates')?.value()) dailyRate += 5;
return Math.round(dailyRate);
},
variant: 'default'
}, '1fr');
});
summarySection.addRow(row => {
row.addPriceDisplay('addonsTotal', {
label: 'Add-on Services',
computedValue: () => {
const visitType = serviceSection.radioButton('visitType')?.value() || 'drop-in';
const numberOfDays = serviceSection.integer('numberOfDays')?.value() || 1;
const visitsPerDay = serviceSection.integer('visitsPerDay')?.value() || 1;
let totalVisits = visitType === 'drop-in' || visitType === 'extended'
? numberOfDays * visitsPerDay
: numberOfDays;
let addonsTotal = 0;
if (addonsSection.checkbox('dogWalking')?.value()) {
const walksPerDay = addonsSection.integer('walkCount')?.value() || 1;
addonsTotal += 15 * walksPerDay * numberOfDays;
}
if (addonsSection.checkbox('medicationAdmin')?.value()) addonsTotal += 5 * totalVisits;
if (addonsSection.checkbox('plantWatering')?.value()) addonsTotal += 5 * totalVisits;
if (addonsSection.checkbox('mailCollection')?.value()) addonsTotal += 3 * totalVisits;
if (addonsSection.checkbox('grooming')?.value()) addonsTotal += 10 * totalVisits;
return addonsTotal;
},
variant: 'default',
prefix: '+'
});
});
summarySection.addRow(row => {
row.addPriceDisplay('travelFees', {
label: 'Travel Fees (Total)',
computedValue: () => {
const visitType = serviceSection.radioButton('visitType')?.value() || 'drop-in';
const numberOfDays = serviceSection.integer('numberOfDays')?.value() || 1;
const visitsPerDay = serviceSection.integer('visitsPerDay')?.value() || 1;
const totalVisits = visitType === 'drop-in' || visitType === 'extended'
? numberOfDays * visitsPerDay
: numberOfDays;
return getTravelFeePerVisit() * totalVisits;
},
variant: 'default',
prefix: '+'
});
});
const finalSection = form.addSubform('final', {
title: '๐งพ Summary',
isCollapsible: false,
sticky: 'bottom'
});
finalSection.addRow(row => {
row.addPriceDisplay('totalCost', {
label: 'Total Estimated Cost',
computedValue: () => {
const visitType = serviceSection.radioButton('visitType')?.value() || 'drop-in';
const numberOfDays = serviceSection.integer('numberOfDays')?.value() || 1;
const visitsPerDay = serviceSection.integer('visitsPerDay')?.value() || 1;
let dailyRate = getBaseVisitCost() + getAdditionalPetsCost();
if (visitType === 'drop-in' || visitType === 'extended') {
dailyRate *= visitsPerDay;
}
// Daily surcharges
if (serviceSection.checkbox('isHoliday')?.value()) dailyRate += 15;
if (serviceSection.checkbox('isWeekend')?.value()) dailyRate += 5;
if (addonsSection.checkbox('photoUpdates')?.value()) dailyRate += 5;
let total = dailyRate * numberOfDays;
// Add-ons
let totalVisits = visitType === 'drop-in' || visitType === 'extended'
? numberOfDays * visitsPerDay
: numberOfDays;
if (addonsSection.checkbox('dogWalking')?.value()) {
const walksPerDay = addonsSection.integer('walkCount')?.value() || 1;
total += 15 * walksPerDay * numberOfDays;
}
if (addonsSection.checkbox('medicationAdmin')?.value()) total += 5 * totalVisits;
if (addonsSection.checkbox('plantWatering')?.value()) total += 5 * totalVisits;
if (addonsSection.checkbox('mailCollection')?.value()) total += 3 * totalVisits;
if (addonsSection.checkbox('grooming')?.value()) total += 10 * totalVisits;
// Last-minute surcharge
if (serviceSection.checkbox('lastMinute')?.value()) {
total *= 1.2;
}
// Travel fees
total += getTravelFeePerVisit() * totalVisits;
return Math.round(total);
},
variant: 'large'
});
});
finalSection.addRow(row => {
row.addTextPanel('summary', {
computedValue: () => {
const numberOfDays = serviceSection.integer('numberOfDays')?.value() || 1;
const visitType = serviceSection.radioButton('visitType')?.value() || 'drop-in';
const visitsPerDay = serviceSection.integer('visitsPerDay')?.value() || 1;
if (visitType === 'overnight') {
return `${numberOfDays} night${numberOfDays > 1 ? 's' : ''} of overnight pet care`;
} else if (visitType === 'full-day') {
return `${numberOfDays} day${numberOfDays > 1 ? 's' : ''} of full-day pet care`;
} else {
const totalVisits = numberOfDays * visitsPerDay;
return `${totalVisits} visit${totalVisits > 1 ? 's' : ''} over ${numberOfDays} day${numberOfDays > 1 ? 's' : ''}`;
}
},
customStyles: { 'font-size': '0.9rem', 'color': '#475569' }
});
});
finalSection.addRow(row => {
row.addTextPanel('disclaimer', {
computedValue: () => 'Meet & greet required before first booking.',
customStyles: { 'font-size': '0.85rem', 'color': '#94a3b8', 'font-style': 'italic' }
});
});
form.configureSubmitButton({
label: 'Book Pet Sitting'
});
}