export function petBoardingCalculator(form: FormTs) {
form.addRow(row => {
row.addTextPanel('header', {
computedValue: () => 'Pet Boarding Cost Calculator',
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 address...',
showMap: true,
showDistance: true,
referenceAddress: {
formattedAddress: 'Service Center, Denver, CO',
coordinates: { lat: 39.7392, lng: -104.9903 }
},
restrictToCountries: ['US', 'CA'],
distanceUnit: 'miles',
isRequired: false,
tooltip: 'Required for pick-up/drop-off service'
});
});
locationSection.addRow(row => {
row.addTextPanel('transportInfo', {
computedValue: () => {
const addressField = locationSection.address('homeAddress');
const miles = addressField?.distance();
if (miles == null) return '📍 Enter address to calculate pick-up/drop-off fee';
if (miles <= 10) return '📍 Within area - $25 pick-up/drop-off (each way)';
if (miles <= 20) return '📍 Extended area - $40 pick-up/drop-off (each way)';
if (miles <= 30) return '📍 Remote area - $55 pick-up/drop-off (each way)';
return '📍 Long distance - $70+ pick-up/drop-off (each way)';
},
customStyles: { 'font-size': '0.9rem', 'color': '#059669', 'background': '#ecfdf5', 'padding': '10px', 'border-radius': '6px' }
});
});
// Pet Details Section
const petSection = form.addSubform('pet', { title: '🐾 Pet Information' });
petSection.addRow(row => {
row.addDropdown('petType', {
label: 'Pet Type',
options: [
{ id: 'dog', name: 'Dog' },
{ id: 'cat', name: 'Cat' },
{ id: 'bird', name: 'Bird' },
{ id: 'small-animal', name: 'Small Animal (Rabbit, Hamster, Guinea Pig)' },
{ id: 'reptile', name: 'Reptile' },
{ id: 'exotic', name: 'Exotic Pet' }
],
defaultValue: 'dog',
isRequired: true
}, '1fr');
row.addInteger('numberOfPets', {
label: 'Number of Pets',
min: 1,
max: 10,
defaultValue: 1,
tooltip: 'Multiple pets from same household may get discounts'
}, '1fr');
});
petSection.addRow(row => {
row.addDropdown('dogSize', {
label: 'Dog Size',
options: [
{ id: 'small', name: 'Small (under 20 lbs)' },
{ id: 'medium', name: 'Medium (20-50 lbs)' },
{ id: 'large', name: 'Large (50-90 lbs)' },
{ id: 'xlarge', name: 'Extra Large (90+ lbs)' }
],
defaultValue: 'medium',
isVisible: () => petSection.dropdown('petType')?.value() === 'dog'
}, '1fr');
row.addCheckbox('puppyOrKitten', {
label: 'Puppy/Kitten (under 1 year)',
defaultValue: false,
tooltip: 'Young animals require extra attention (+15%)',
isVisible: () => {
const type = petSection.dropdown('petType')?.value();
return type === 'dog' || type === 'cat';
}
}, '1fr');
});
petSection.addRow(row => {
row.addCheckbox('specialNeeds', {
label: 'Special needs or medical condition',
defaultValue: false,
tooltip: 'Requires medication, special diet, or extra care'
}, '1fr');
row.addCheckbox('aggressive', {
label: 'Requires separate housing',
defaultValue: false,
tooltip: 'Not good with other animals or requires isolation'
}, '1fr');
});
// Stay Details Section
const staySection = form.addSubform('stay', { title: '📅 Stay Details' });
staySection.addRow(row => {
row.addInteger('nights', {
label: 'Number of Nights',
min: 1,
max: 365,
defaultValue: 5,
isRequired: true
}, '1fr');
row.addDropdown('season', {
label: 'Season',
options: [
{ id: 'regular', name: 'Regular Season' },
{ id: 'holiday', name: 'Holiday Season (+25-50%)' },
{ id: 'summer', name: 'Summer Peak (+15%)' }
],
defaultValue: 'regular',
tooltip: 'Holidays include Thanksgiving, Christmas, New Year\'s, Spring Break'
}, '1fr');
});
// Accommodation Type Section
const accommodationSection = form.addSubform('accommodation', { title: '🏨 Accommodation Type' });
accommodationSection.addRow(row => {
row.addRadioButton('roomType', {
label: 'Room Type',
options: [
{ id: 'standard', name: 'Standard Kennel ($30-45/night) - Basic enclosed space' },
{ id: 'deluxe', name: 'Deluxe Suite ($50-70/night) - Larger space, raised bed' },
{ id: 'luxury', name: 'Luxury Suite ($75-100/night) - Private room, TV, webcam' },
{ id: 'vip', name: 'VIP Suite ($100-150/night) - Premium amenities, outdoor access' }
],
defaultValue: 'deluxe',
isRequired: true,
isVisible: () => petSection.dropdown('petType')?.value() === 'dog'
});
});
accommodationSection.addRow(row => {
row.addRadioButton('catRoomType', {
label: 'Room Type',
options: [
{ id: 'standard', name: 'Standard Condo ($25-35/night) - Multi-level condo' },
{ id: 'deluxe', name: 'Deluxe Condo ($40-55/night) - Large condo with perch' },
{ id: 'luxury', name: 'Luxury Suite ($60-80/night) - Private room, cat tree' }
],
defaultValue: 'deluxe',
isRequired: true,
isVisible: () => petSection.dropdown('petType')?.value() === 'cat'
});
});
accommodationSection.addRow(row => {
row.addTextPanel('smallPetRate', {
computedValue: () => 'Small animals, birds, reptiles, and exotics: $15-35/night depending on species and care requirements',
customStyles: { 'font-size': '0.9rem', 'color': '#475569' },
isVisible: () => {
const type = petSection.dropdown('petType')?.value();
return type !== 'dog' && type !== 'cat';
}
});
});
// Activities & Extras Section
const activitiesSection = form.addSubform('activities', { title: '🎾 Activities & Extras' });
activitiesSection.addRow(row => {
row.addCheckbox('extraPlaytime', {
label: 'Extra Playtime (+$10/day)',
defaultValue: false,
tooltip: '15-minute individual play session',
isVisible: () => {
const type = petSection.dropdown('petType')?.value();
return type === 'dog' || type === 'cat';
}
}, '1fr');
row.addCheckbox('groupPlay', {
label: 'Daycare/Group Play (+$20/day)',
defaultValue: false,
tooltip: 'Supervised socialization with other dogs',
isVisible: () => petSection.dropdown('petType')?.value() === 'dog'
}, '1fr');
});
activitiesSection.addRow(row => {
row.addCheckbox('walks', {
label: 'Extra Walks (+$8/walk)',
defaultValue: false,
isVisible: () => petSection.dropdown('petType')?.value() === 'dog'
}, '1fr');
row.addInteger('walkCount', {
label: 'Walks per Day',
min: 1,
max: 5,
defaultValue: 2,
isVisible: () => activitiesSection.checkbox('walks')?.value() && petSection.dropdown('petType')?.value() === 'dog'
}, '1fr');
});
activitiesSection.addRow(row => {
row.addCheckbox('grooming', {
label: 'Grooming Service (+$35-75)',
defaultValue: false,
tooltip: 'Bath and brush before pickup'
}, '1fr');
row.addCheckbox('training', {
label: 'Training Sessions (+$30/session)',
defaultValue: false,
tooltip: 'Basic obedience reinforcement',
isVisible: () => petSection.dropdown('petType')?.value() === 'dog'
}, '1fr');
});
// Care Services Section
const careSection = form.addSubform('care', { title: '💊 Care Services' });
careSection.addRow(row => {
row.addCheckbox('medication', {
label: 'Medication Administration (+$5/day)',
defaultValue: false,
tooltip: 'Oral medications, eye drops, ear drops'
}, '1fr');
row.addCheckbox('insulinInjection', {
label: 'Insulin Injection (+$10/day)',
defaultValue: false
}, '1fr');
});
careSection.addRow(row => {
row.addCheckbox('specialDiet', {
label: 'Special Diet Preparation (+$5/day)',
defaultValue: false,
tooltip: 'Owner-provided food, special preparation'
}, '1fr');
row.addCheckbox('webcam', {
label: 'Webcam Access (+$5/stay)',
defaultValue: false,
tooltip: 'Live video check-ins',
isVisible: () => {
const roomType = accommodationSection.radioButton('roomType')?.value();
return roomType !== 'luxury' && roomType !== 'vip';
}
}, '1fr');
});
careSection.addRow(row => {
row.addCheckbox('dailyReport', {
label: 'Daily Photo/Report Cards (+$3/day)',
defaultValue: false
}, '1fr');
row.addCheckbox('transportation', {
label: 'Pick-up/Drop-off Service (+$25-50)',
defaultValue: false,
tooltip: 'Distance-based pricing'
}, '1fr');
});
form.addSpacer({ height: 20, showLine: true, lineStyle: 'dashed' });
// Helper to calculate transportation fee (round trip)
const getTransportationFee = () => {
if (!careSection.checkbox('transportation')?.value()) return 0;
const addressField = locationSection.address('homeAddress');
const miles = addressField?.distance();
if (miles == null || miles <= 10) return 50; // $25 each way
if (miles <= 20) return 80; // $40 each way
if (miles <= 30) return 110; // $55 each way
return 140 + Math.floor((miles - 30) / 10) * 20; // $70+ each way
};
// Cost Breakdown Section
const breakdownSection = form.addSubform('breakdown', { title: '📊 Cost Breakdown', isCollapsible: true });
breakdownSection.addRow(row => {
row.addPriceDisplay('accommodationCost', {
label: 'Accommodation',
computedValue: () => {
const petType = petSection.dropdown('petType')?.value() || 'dog';
const nights = staySection.integer('nights')?.value() || 5;
const numberOfPets = petSection.integer('numberOfPets')?.value() || 1;
const dogSize = petSection.dropdown('dogSize')?.value() || 'medium';
let nightlyRate = 0;
if (petType === 'dog') {
const roomType = accommodationSection.radioButton('roomType')?.value() || 'deluxe';
const baseRates: Record<string, number> = { standard: 38, deluxe: 60, luxury: 88, vip: 125 };
nightlyRate = baseRates[roomType] || 60;
const sizeMultiplier: Record<string, number> = { small: 0.85, medium: 1, large: 1.15, xlarge: 1.3 };
nightlyRate *= sizeMultiplier[dogSize] || 1;
} else if (petType === 'cat') {
const catRoom = accommodationSection.radioButton('catRoomType')?.value() || 'deluxe';
const catRates: Record<string, number> = { standard: 30, deluxe: 48, luxury: 70 };
nightlyRate = catRates[catRoom] || 48;
} else {
nightlyRate = 25;
}
const additionalPetDiscount = numberOfPets > 1 ? 0.8 : 1;
return Math.round(nightlyRate * nights * numberOfPets * additionalPetDiscount);
},
variant: 'default'
}, '1fr');
row.addPriceDisplay('seasonalAdjustment', {
label: 'Seasonal Adjustment',
computedValue: () => {
const petType = petSection.dropdown('petType')?.value() || 'dog';
const nights = staySection.integer('nights')?.value() || 5;
const season = staySection.dropdown('season')?.value() || 'regular';
const numberOfPets = petSection.integer('numberOfPets')?.value() || 1;
const dogSize = petSection.dropdown('dogSize')?.value() || 'medium';
let nightlyRate = 0;
if (petType === 'dog') {
const roomType = accommodationSection.radioButton('roomType')?.value() || 'deluxe';
const baseRates: Record<string, number> = { standard: 38, deluxe: 60, luxury: 88, vip: 125 };
nightlyRate = baseRates[roomType] || 60;
const sizeMultiplier: Record<string, number> = { small: 0.85, medium: 1, large: 1.15, xlarge: 1.3 };
nightlyRate *= sizeMultiplier[dogSize] || 1;
} else if (petType === 'cat') {
const catRoom = accommodationSection.radioButton('catRoomType')?.value() || 'deluxe';
const catRates: Record<string, number> = { standard: 30, deluxe: 48, luxury: 70 };
nightlyRate = catRates[catRoom] || 48;
} else {
nightlyRate = 25;
}
const additionalPetDiscount = numberOfPets > 1 ? 0.8 : 1;
const baseTotal = nightlyRate * nights * numberOfPets * additionalPetDiscount;
const seasonMultiplier: Record<string, number> = { regular: 0, holiday: 0.35, summer: 0.15 };
return Math.round(baseTotal * (seasonMultiplier[season] || 0));
},
variant: 'default'
}, '1fr');
});
breakdownSection.addRow(row => {
row.addPriceDisplay('activitiesCost', {
label: 'Activities',
computedValue: () => {
const nights = staySection.integer('nights')?.value() || 5;
let total = 0;
if (activitiesSection.checkbox('extraPlaytime')?.value()) total += 10 * nights;
if (activitiesSection.checkbox('groupPlay')?.value()) total += 20 * nights;
if (activitiesSection.checkbox('walks')?.value()) {
const walkCount = activitiesSection.integer('walkCount')?.value() || 2;
total += 8 * walkCount * nights;
}
if (activitiesSection.checkbox('grooming')?.value()) total += 55;
if (activitiesSection.checkbox('training')?.value()) total += 30 * Math.ceil(nights / 2);
return total;
},
variant: 'default'
}, '1fr');
row.addPriceDisplay('careCost', {
label: 'Care Services',
computedValue: () => {
const nights = staySection.integer('nights')?.value() || 5;
let total = 0;
if (careSection.checkbox('medication')?.value()) total += 5 * nights;
if (careSection.checkbox('insulinInjection')?.value()) total += 10 * nights;
if (careSection.checkbox('specialDiet')?.value()) total += 5 * nights;
if (careSection.checkbox('webcam')?.value()) total += 5;
if (careSection.checkbox('dailyReport')?.value()) total += 3 * nights;
total += getTransportationFee();
if (petSection.checkbox('specialNeeds')?.value()) total += 10 * nights;
if (petSection.checkbox('aggressive')?.value()) total += 15 * nights;
return total;
},
variant: 'default'
}, '1fr');
});
// Summary Section
const summarySection = form.addSubform('summary', {
title: '💰 Total Boarding Cost',
isCollapsible: false,
sticky: 'bottom'
});
summarySection.addRow(row => {
row.addPriceDisplay('totalCost', {
label: 'Total Cost',
computedValue: () => {
const petType = petSection.dropdown('petType')?.value() || 'dog';
const nights = staySection.integer('nights')?.value() || 5;
const season = staySection.dropdown('season')?.value() || 'regular';
const numberOfPets = petSection.integer('numberOfPets')?.value() || 1;
const dogSize = petSection.dropdown('dogSize')?.value() || 'medium';
const puppyKitten = petSection.checkbox('puppyOrKitten')?.value() || false;
let nightlyRate = 0;
if (petType === 'dog') {
const roomType = accommodationSection.radioButton('roomType')?.value() || 'deluxe';
const baseRates: Record<string, number> = { standard: 38, deluxe: 60, luxury: 88, vip: 125 };
nightlyRate = baseRates[roomType] || 60;
const sizeMultiplier: Record<string, number> = { small: 0.85, medium: 1, large: 1.15, xlarge: 1.3 };
nightlyRate *= sizeMultiplier[dogSize] || 1;
} else if (petType === 'cat') {
const catRoom = accommodationSection.radioButton('catRoomType')?.value() || 'deluxe';
const catRates: Record<string, number> = { standard: 30, deluxe: 48, luxury: 70 };
nightlyRate = catRates[catRoom] || 48;
} else {
nightlyRate = 25;
}
const additionalPetDiscount = numberOfPets > 1 ? 0.8 : 1;
let accommodationTotal = nightlyRate * nights * numberOfPets * additionalPetDiscount;
const seasonMultiplier: Record<string, number> = { regular: 1, holiday: 1.35, summer: 1.15 };
accommodationTotal *= seasonMultiplier[season] || 1;
if (puppyKitten) accommodationTotal *= 1.15;
let activitiesTotal = 0;
if (activitiesSection.checkbox('extraPlaytime')?.value()) activitiesTotal += 10 * nights;
if (activitiesSection.checkbox('groupPlay')?.value()) activitiesTotal += 20 * nights;
if (activitiesSection.checkbox('walks')?.value()) {
const walkCount = activitiesSection.integer('walkCount')?.value() || 2;
activitiesTotal += 8 * walkCount * nights;
}
if (activitiesSection.checkbox('grooming')?.value()) activitiesTotal += 55;
if (activitiesSection.checkbox('training')?.value()) activitiesTotal += 30 * Math.ceil(nights / 2);
let careTotal = 0;
if (careSection.checkbox('medication')?.value()) careTotal += 5 * nights;
if (careSection.checkbox('insulinInjection')?.value()) careTotal += 10 * nights;
if (careSection.checkbox('specialDiet')?.value()) careTotal += 5 * nights;
if (careSection.checkbox('webcam')?.value()) careTotal += 5;
if (careSection.checkbox('dailyReport')?.value()) careTotal += 3 * nights;
careTotal += getTransportationFee();
if (petSection.checkbox('specialNeeds')?.value()) careTotal += 10 * nights;
if (petSection.checkbox('aggressive')?.value()) careTotal += 15 * nights;
return Math.round(accommodationTotal + activitiesTotal + careTotal);
},
variant: 'large'
}, '1fr');
row.addTextPanel('perNight', {
label: 'Per Night',
computedValue: () => {
const nights = staySection.integer('nights')?.value() || 5;
const petType = petSection.dropdown('petType')?.value() || 'dog';
const season = staySection.dropdown('season')?.value() || 'regular';
const numberOfPets = petSection.integer('numberOfPets')?.value() || 1;
const dogSize = petSection.dropdown('dogSize')?.value() || 'medium';
let nightlyRate = 0;
if (petType === 'dog') {
const roomType = accommodationSection.radioButton('roomType')?.value() || 'deluxe';
const baseRates: Record<string, number> = { standard: 38, deluxe: 60, luxury: 88, vip: 125 };
nightlyRate = baseRates[roomType] || 60;
const sizeMultiplier: Record<string, number> = { small: 0.85, medium: 1, large: 1.15, xlarge: 1.3 };
nightlyRate *= sizeMultiplier[dogSize] || 1;
} else if (petType === 'cat') {
const catRoom = accommodationSection.radioButton('catRoomType')?.value() || 'deluxe';
const catRates: Record<string, number> = { standard: 30, deluxe: 48, luxury: 70 };
nightlyRate = catRates[catRoom] || 48;
} else {
nightlyRate = 25;
}
const seasonMultiplier: Record<string, number> = { regular: 1, holiday: 1.35, summer: 1.15 };
nightlyRate *= seasonMultiplier[season] || 1;
return `$${Math.round(nightlyRate)}/night`;
},
customStyles: { 'font-size': '1.3rem', 'font-weight': '600', 'text-align': 'center', 'color': '#059669' }
}, '1fr');
});
summarySection.addRow(row => {
row.addTextPanel('staySummary', {
computedValue: () => {
const petType = petSection.dropdown('petType')?.value() || 'dog';
const nights = staySection.integer('nights')?.value() || 5;
const numberOfPets = petSection.integer('numberOfPets')?.value() || 1;
const petNames: Record<string, string> = {
dog: 'dog', cat: 'cat', bird: 'bird', 'small-animal': 'small animal',
reptile: 'reptile', exotic: 'exotic pet'
};
const petLabel = numberOfPets > 1 ? `${numberOfPets} ${petNames[petType]}s` : `1 ${petNames[petType]}`;
return `${petLabel} • ${nights} night${nights > 1 ? 's' : ''}`;
},
customStyles: { 'font-size': '0.95rem', 'text-align': 'center', 'color': '#475569' }
});
});
summarySection.addRow(row => {
row.addTextPanel('disclaimer', {
computedValue: () => 'Current vaccinations required. Prices vary by facility. Holiday rates apply to major holidays and peak travel periods.',
customStyles: { 'font-size': '0.8rem', 'color': '#94a3b8', 'text-align': 'center' }
});
});
form.configureSubmitButton({
label: 'Book Reservation'
});
}