export function dogTrainingCalculator(form: FormTs) {
// Base prices for training types
const trainingPrices: Record<string, number> = {
'basic-obedience': 150,
'puppy-training': 175,
'advanced-obedience': 225,
'behavior-modification': 300,
'protection-training': 400,
'service-dog': 500
};
// Session type multipliers
const sessionMultipliers: Record<string, number> = {
'private': 1,
'group': 0.6,
'board-and-train': 3.5
};
// Package discounts
const packageDiscounts: Record<string, number> = {
'single': 0,
'4-sessions': 10,
'8-sessions': 15,
'12-sessions': 20
};
form.addRow(row => {
row.addTextPanel('header', {
computedValue: () => 'Dog Training Price Calculator',
customStyles: { 'font-size': '1.5rem', 'font-weight': '600', 'color': '#1e293b' }
});
});
form.addSpacer({ height: 20 });
// Service Location Section
const locationSection = form.addSubform('serviceLocation', { title: '๐ Training Location' });
locationSection.addRow(row => {
row.addRadioButton('trainingLocation', {
label: 'Where will training take place?',
options: [
{ id: 'facility', name: 'At our training facility' },
{ id: 'in-home', name: 'In-home training (we come to you)' }
],
defaultValue: 'facility',
orientation: 'vertical'
});
});
locationSection.addRow(row => {
row.addAddress('homeAddress', {
label: 'Your 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,
isVisible: () => locationSection.radioButton('trainingLocation')?.value() === 'in-home'
});
});
locationSection.addRow(row => {
row.addTextPanel('travelInfo', {
computedValue: () => {
const addressField = locationSection.address('homeAddress');
const miles = addressField?.distance();
if (miles == null) return '๐ Enter address for in-home training fee';
if (miles <= 10) return '๐ Within service area - $15/session travel fee';
if (miles <= 20) return '๐ Extended area - $25/session travel fee';
if (miles <= 30) return '๐ Remote area - $40/session travel fee';
return '๐ Outside service area - Please contact us';
},
customStyles: { 'font-size': '0.9rem', 'color': '#0891b2', 'background': '#ecfeff', 'padding': '10px', 'border-radius': '6px' },
isVisible: () => locationSection.radioButton('trainingLocation')?.value() === 'in-home'
});
});
// Dog Information Section
const dogSection = form.addSubform('dogInfo', { title: '๐ Your Dog' });
dogSection.addRow(row => {
row.addDropdown('dogAge', {
label: 'Dog Age',
options: [
{ id: 'puppy', name: 'Puppy (8 weeks - 6 months)' },
{ id: 'adolescent', name: 'Adolescent (6 months - 2 years)' },
{ id: 'adult', name: 'Adult (2 - 7 years)' },
{ id: 'senior', name: 'Senior (7+ years)' }
],
defaultValue: 'adult',
isRequired: true
}, '1fr');
row.addDropdown('dogSize', {
label: 'Dog Size',
options: [
{ id: 'small', name: 'Small (under 25 lbs)' },
{ id: 'medium', name: 'Medium (25-50 lbs)' },
{ id: 'large', name: 'Large (50-90 lbs)' },
{ id: 'giant', name: 'Giant (90+ lbs)' }
],
defaultValue: 'medium',
isRequired: true
}, '1fr');
});
dogSection.addRow(row => {
row.addDropdown('behaviorLevel', {
label: 'Current Behavior Level',
options: [
{ id: 'well-behaved', name: 'Well-behaved (minor issues)' },
{ id: 'needs-work', name: 'Needs work (common issues)' },
{ id: 'challenging', name: 'Challenging (significant issues)' },
{ id: 'severe', name: 'Severe (aggression/anxiety)' }
],
defaultValue: 'needs-work',
tooltip: 'Severe cases may require specialized behavior modification'
}, '1fr');
row.addInteger('numberOfDogs', {
label: 'Number of Dogs',
min: 1,
max: 3,
defaultValue: 1,
tooltip: 'Additional dogs from same household: 50% off each'
}, '1fr');
});
// Training Program Section
const trainingSection = form.addSubform('trainingProgram', { title: '๐ Training Program' });
trainingSection.addRow(row => {
row.addRadioButton('trainingType', {
label: 'Training Type',
options: [
{ id: 'basic-obedience', name: 'Basic Obedience ($150/session)' },
{ id: 'puppy-training', name: 'Puppy Training ($175/session)' },
{ id: 'advanced-obedience', name: 'Advanced Obedience ($225/session)' },
{ id: 'behavior-modification', name: 'Behavior Modification ($300/session)' },
{ id: 'protection-training', name: 'Protection Training ($400/session)' },
{ id: 'service-dog', name: 'Service Dog Training ($500/session)' }
],
defaultValue: 'basic-obedience',
orientation: 'vertical',
isRequired: true
});
});
trainingSection.addRow(row => {
row.addRadioButton('sessionType', {
label: 'Session Type',
options: [
{ id: 'private', name: 'Private Sessions (1-on-1)' },
{ id: 'group', name: 'Group Classes (40% savings)' },
{ id: 'board-and-train', name: 'Board & Train (intensive)' }
],
defaultValue: 'private',
orientation: 'vertical',
isRequired: true
});
});
trainingSection.addRow(row => {
row.addDropdown('sessionDuration', {
label: 'Session Duration',
options: [
{ id: '30', name: '30 Minutes' },
{ id: '60', name: '60 Minutes (recommended)' },
{ id: '90', name: '90 Minutes (+50%)' }
],
defaultValue: '60',
isRequired: true
}, '1fr');
row.addDropdown('package', {
label: 'Package',
options: [
{ id: 'single', name: 'Single Session' },
{ id: '4-sessions', name: '4 Sessions (-10%)' },
{ id: '8-sessions', name: '8 Sessions (-15%)' },
{ id: '12-sessions', name: '12 Sessions (-20%)' }
],
defaultValue: '4-sessions'
}, '1fr');
});
trainingSection.addRow(row => {
row.addInteger('boardTrainWeeks', {
label: 'Board & Train Duration (weeks)',
min: 2,
max: 8,
defaultValue: 2,
tooltip: 'Minimum 2 weeks recommended for best results',
isVisible: () => trainingSection.radioButton('sessionType')?.value() === 'board-and-train'
}, '1fr');
});
// Add-ons Section
const addonsSection = form.addSubform('addons', { title: 'โจ Add-on Services' });
addonsSection.addRow(row => {
row.addCheckbox('homeVisit', {
label: 'In-Home Training (+$25/session)',
defaultValue: false,
tooltip: 'Training in your home environment',
isVisible: () => locationSection.radioButton('trainingLocation')?.value() === 'facility'
}, '1fr');
row.addCheckbox('progressReport', {
label: 'Written Progress Reports (+$15)',
defaultValue: false,
tooltip: 'Detailed progress reports after each session'
}, '1fr');
});
addonsSection.addRow(row => {
row.addCheckbox('videoRecap', {
label: 'Video Training Recap (+$20)',
defaultValue: false,
tooltip: 'Video summary of techniques to practice'
}, '1fr');
row.addCheckbox('followUpSupport', {
label: 'Phone/Text Support (+$50/month)',
defaultValue: false,
tooltip: 'Unlimited support between sessions'
}, '1fr');
});
addonsSection.addRow(row => {
row.addCheckbox('trainingKit', {
label: 'Training Kit (+$75)',
defaultValue: false,
tooltip: 'Includes treats, clicker, leash, and training guide'
}, '1fr');
row.addCheckbox('certification', {
label: 'CGC Test Preparation (+$100)',
defaultValue: false,
tooltip: 'Canine Good Citizen certification prep',
isVisible: () => {
const type = trainingSection.radioButton('trainingType')?.value();
return type === 'basic-obedience' || type === 'advanced-obedience';
}
}, '1fr');
});
form.addSpacer({ height: 20, showLine: true, lineStyle: 'dashed' });
// Helper to calculate in-home travel fee per session
const getInHomeTravelFee = () => {
if (locationSection.radioButton('trainingLocation')?.value() !== 'in-home') return 0;
const addressField = locationSection.address('homeAddress');
const miles = addressField?.distance();
if (miles == null || miles <= 10) return 15;
if (miles <= 20) return 25;
if (miles <= 30) return 40;
return 50;
};
// Price Summary Section
const summarySection = form.addSubform('summary', { title: '๐ฐ Price Breakdown', isCollapsible: false });
summarySection.addRow(row => {
row.addPriceDisplay('basePrice', {
label: 'Base Session Price',
computedValue: () => {
const trainingType = trainingSection.radioButton('trainingType')?.value() || 'basic-obedience';
const sessionType = trainingSection.radioButton('sessionType')?.value() || 'private';
const duration = trainingSection.dropdown('sessionDuration')?.value() || '60';
let basePrice = trainingPrices[trainingType] || 150;
basePrice *= sessionMultipliers[sessionType] || 1;
// Duration adjustment
if (duration === '30') basePrice *= 0.6;
if (duration === '90') basePrice *= 1.5;
return Math.round(basePrice);
},
variant: 'default'
}, '1fr');
row.addPriceDisplay('additionalDogs', {
label: 'Additional Dogs',
computedValue: () => {
const numDogs = dogSection.integer('numberOfDogs')?.value() || 1;
if (numDogs <= 1) return 0;
const trainingType = trainingSection.radioButton('trainingType')?.value() || 'basic-obedience';
const sessionType = trainingSection.radioButton('sessionType')?.value() || 'private';
const duration = trainingSection.dropdown('sessionDuration')?.value() || '60';
let basePrice = trainingPrices[trainingType] || 150;
basePrice *= sessionMultipliers[sessionType] || 1;
if (duration === '30') basePrice *= 0.6;
if (duration === '90') basePrice *= 1.5;
return Math.round(basePrice * 0.5 * (numDogs - 1));
},
variant: 'default',
prefix: '+'
}, '1fr');
});
summarySection.addRow(row => {
row.addPriceDisplay('addonsTotal', {
label: 'Add-ons',
computedValue: () => {
let total = 0;
if (addonsSection.checkbox('homeVisit')?.value()) total += 25;
if (addonsSection.checkbox('progressReport')?.value()) total += 15;
if (addonsSection.checkbox('videoRecap')?.value()) total += 20;
if (addonsSection.checkbox('followUpSupport')?.value()) total += 50;
if (addonsSection.checkbox('trainingKit')?.value()) total += 75;
if (addonsSection.checkbox('certification')?.value()) total += 100;
return total;
},
variant: 'default',
prefix: '+'
}, '1fr');
row.addPriceDisplay('packageDiscount', {
label: 'Package Discount',
computedValue: () => {
const packageType = trainingSection.dropdown('package')?.value() || 'single';
const discount = packageDiscounts[packageType] || 0;
if (discount === 0) return 0;
const trainingType = trainingSection.radioButton('trainingType')?.value() || 'basic-obedience';
const sessionType = trainingSection.radioButton('sessionType')?.value() || 'private';
const duration = trainingSection.dropdown('sessionDuration')?.value() || '60';
const numDogs = dogSection.integer('numberOfDogs')?.value() || 1;
let sessionPrice = trainingPrices[trainingType] || 150;
sessionPrice *= sessionMultipliers[sessionType] || 1;
if (duration === '30') sessionPrice *= 0.6;
if (duration === '90') sessionPrice *= 1.5;
sessionPrice += sessionPrice * 0.5 * Math.max(0, numDogs - 1);
return -Math.round(sessionPrice * discount / 100);
},
variant: 'success',
prefix: ''
}, '1fr');
});
summarySection.addRow(row => {
row.addPriceDisplay('inHomeTravelFee', {
label: 'In-Home Travel Fee',
computedValue: () => getInHomeTravelFee(),
variant: 'default',
prefix: '+',
suffix: '/session',
isVisible: () => locationSection.radioButton('trainingLocation')?.value() === 'in-home'
});
});
const finalSection = form.addSubform('final', {
title: '๐งพ Summary',
isCollapsible: false,
sticky: 'bottom'
});
finalSection.addRow(row => {
row.addPriceDisplay('perSessionPrice', {
label: 'Per Session',
computedValue: () => {
const trainingType = trainingSection.radioButton('trainingType')?.value() || 'basic-obedience';
const sessionType = trainingSection.radioButton('sessionType')?.value() || 'private';
const duration = trainingSection.dropdown('sessionDuration')?.value() || '60';
const packageType = trainingSection.dropdown('package')?.value() || 'single';
const numDogs = dogSection.integer('numberOfDogs')?.value() || 1;
let sessionPrice = trainingPrices[trainingType] || 150;
sessionPrice *= sessionMultipliers[sessionType] || 1;
if (duration === '30') sessionPrice *= 0.6;
if (duration === '90') sessionPrice *= 1.5;
sessionPrice += sessionPrice * 0.5 * Math.max(0, numDogs - 1);
// Apply discount
const discount = packageDiscounts[packageType] || 0;
sessionPrice *= (1 - discount / 100);
// Add per-session add-ons
if (addonsSection.checkbox('homeVisit')?.value()) sessionPrice += 25;
if (addonsSection.checkbox('progressReport')?.value()) sessionPrice += 15;
if (addonsSection.checkbox('videoRecap')?.value()) sessionPrice += 20;
// In-home travel fee
sessionPrice += getInHomeTravelFee();
return Math.round(sessionPrice);
},
variant: 'default',
suffix: '/session',
isVisible: () => trainingSection.radioButton('sessionType')?.value() !== 'board-and-train'
}, '1fr');
row.addPriceDisplay('totalPrice', {
label: 'Total Package',
computedValue: () => {
const trainingType = trainingSection.radioButton('trainingType')?.value() || 'basic-obedience';
const sessionType = trainingSection.radioButton('sessionType')?.value() || 'private';
const duration = trainingSection.dropdown('sessionDuration')?.value() || '60';
const packageType = trainingSection.dropdown('package')?.value() || 'single';
const numDogs = dogSection.integer('numberOfDogs')?.value() || 1;
let sessionPrice = trainingPrices[trainingType] || 150;
sessionPrice *= sessionMultipliers[sessionType] || 1;
if (duration === '30') sessionPrice *= 0.6;
if (duration === '90') sessionPrice *= 1.5;
sessionPrice += sessionPrice * 0.5 * Math.max(0, numDogs - 1);
// Number of sessions in package
let numSessions = 1;
if (packageType === '4-sessions') numSessions = 4;
if (packageType === '8-sessions') numSessions = 8;
if (packageType === '12-sessions') numSessions = 12;
// Board & train calculation
if (sessionType === 'board-and-train') {
const weeks = trainingSection.integer('boardTrainWeeks')?.value() || 2;
sessionPrice = sessionPrice * weeks;
numSessions = 1;
}
// Apply discount
const discount = packageDiscounts[packageType] || 0;
let total = sessionPrice * numSessions * (1 - discount / 100);
// Add per-session add-ons
const perSessionAddons =
(addonsSection.checkbox('homeVisit')?.value() ? 25 : 0) +
(addonsSection.checkbox('progressReport')?.value() ? 15 : 0) +
(addonsSection.checkbox('videoRecap')?.value() ? 20 : 0) +
getInHomeTravelFee();
total += perSessionAddons * numSessions;
// Add one-time add-ons
if (addonsSection.checkbox('followUpSupport')?.value()) total += 50;
if (addonsSection.checkbox('trainingKit')?.value()) total += 75;
if (addonsSection.checkbox('certification')?.value()) total += 100;
return Math.round(total);
},
variant: 'large'
}, '1fr');
});
finalSection.addRow(row => {
row.addTextPanel('disclaimer', {
computedValue: () => 'Free initial consultation included. Results may vary based on consistency of at-home practice.',
customStyles: { 'font-size': '0.85rem', 'color': '#64748b', 'font-style': 'italic' }
});
});
form.configureSubmitButton({
label: 'Book Training'
});
}