export function physiotherapyCalculator(form: FormTs) {
// Session duration pricing
const sessionPrices: Record<string, number> = {
'30': 65,
'45': 85,
'60': 110,
'90': 155
};
// Treatment type premiums
const treatmentPremiums: Record<string, number> = {
'general': 0,
'sports': 15,
'post-surgery': 20,
'neurological': 25,
'pediatric': 10,
'geriatric': 10,
'pelvic-floor': 20
};
// Practitioner level multipliers
const practitionerMultipliers: Record<string, number> = {
'standard': 1.0,
'senior': 1.2,
'specialist': 1.4
};
form.addRow(row => {
row.addTextPanel('header', {
computedValue: () => 'Physiotherapy Session Estimate',
customStyles: { 'font-size': '1.5rem', 'font-weight': '600', 'color': '#1e293b' }
});
});
form.addSpacer({ height: 20 });
// Treatment Details Section
const treatmentSection = form.addSubform('treatment', { title: '🏥 Treatment Details' });
treatmentSection.addRow(row => {
row.addRadioButton('treatmentType', {
label: 'Treatment Type',
options: [
{ id: 'general', name: 'General Physiotherapy' },
{ id: 'sports', name: 'Sports Injury (+$15)' },
{ id: 'post-surgery', name: 'Post-Surgery Rehabilitation (+$20)' },
{ id: 'neurological', name: 'Neurological Rehab (+$25)' },
{ id: 'pediatric', name: 'Pediatric Physiotherapy (+$10)' },
{ id: 'geriatric', name: 'Geriatric Care (+$10)' },
{ id: 'pelvic-floor', name: 'Pelvic Floor Therapy (+$20)' }
],
defaultValue: 'general',
orientation: 'vertical',
isRequired: true
});
});
treatmentSection.addRow(row => {
row.addDropdown('bodyArea', {
label: 'Primary Body Area',
options: [
{ id: 'neck', name: 'Neck & Cervical Spine' },
{ id: 'shoulder', name: 'Shoulder & Upper Arm' },
{ id: 'elbow', name: 'Elbow & Forearm' },
{ id: 'wrist', name: 'Wrist & Hand' },
{ id: 'back-upper', name: 'Upper Back (Thoracic)' },
{ id: 'back-lower', name: 'Lower Back (Lumbar)' },
{ id: 'hip', name: 'Hip & Pelvis' },
{ id: 'knee', name: 'Knee' },
{ id: 'ankle', name: 'Ankle & Foot' },
{ id: 'full-body', name: 'Full Body / Multiple Areas' }
],
defaultValue: 'back-lower',
isRequired: true
}, '1fr');
row.addDropdown('condition', {
label: 'Condition Type',
options: [
{ id: 'acute', name: 'Acute (Recent injury)' },
{ id: 'chronic', name: 'Chronic (Long-term)' },
{ id: 'post-op', name: 'Post-Operative' },
{ id: 'preventive', name: 'Preventive / Maintenance' }
],
defaultValue: 'acute',
isRequired: true
}, '1fr');
});
// Session Options Section
const sessionSection = form.addSubform('session', { title: '⏱️ Session Options' });
sessionSection.addRow(row => {
row.addRadioButton('duration', {
label: 'Session Duration',
options: [
{ id: '30', name: '30 minutes - $65' },
{ id: '45', name: '45 minutes - $85' },
{ id: '60', name: '60 minutes - $110 (Most Popular)' },
{ id: '90', name: '90 minutes - $155' }
],
defaultValue: '60',
orientation: 'vertical',
isRequired: true
});
});
sessionSection.addRow(row => {
row.addRadioButton('practitioner', {
label: 'Practitioner Level',
options: [
{ id: 'standard', name: 'Licensed Physiotherapist' },
{ id: 'senior', name: 'Senior Physiotherapist (+20%)' },
{ id: 'specialist', name: 'Clinical Specialist (+40%)' }
],
defaultValue: 'standard',
orientation: 'vertical',
isRequired: true
});
});
sessionSection.addRow(row => {
row.addCheckbox('initialAssessment', {
label: 'Initial Assessment (First Visit) (+$30)',
defaultValue: true
});
});
// Additional Services Section
const servicesSection = form.addSubform('services', { title: '✨ Additional Services' });
servicesSection.addRow(row => {
row.addCheckbox('dryNeedling', {
label: 'Dry Needling / Acupuncture (+$25)',
defaultValue: false
}, '1fr');
row.addCheckbox('cupping', {
label: 'Cupping Therapy (+$20)',
defaultValue: false
}, '1fr');
});
servicesSection.addRow(row => {
row.addCheckbox('tens', {
label: 'TENS / Electrical Stimulation (+$15)',
defaultValue: false
}, '1fr');
row.addCheckbox('ultrasound', {
label: 'Therapeutic Ultrasound (+$15)',
defaultValue: false
}, '1fr');
});
servicesSection.addRow(row => {
row.addCheckbox('massage', {
label: 'Manual Therapy / Massage (+$20)',
defaultValue: false
}, '1fr');
row.addCheckbox('taping', {
label: 'Kinesiology Taping (+$15)',
defaultValue: false
}, '1fr');
});
servicesSection.addRow(row => {
row.addCheckbox('homeProgram', {
label: 'Custom Home Exercise Program (+$25)',
defaultValue: false
}, '1fr');
row.addCheckbox('report', {
label: 'Detailed Progress Report (+$35)',
defaultValue: false
}, '1fr');
});
// Package Options Section
const packageSection = form.addSubform('package', { title: '📦 Session Packages' });
packageSection.addRow(row => {
row.addRadioButton('packageType', {
label: 'Package Option',
options: [
{ id: 'single', name: 'Single Session' },
{ id: 'pack-5', name: '5-Session Package (-10%)' },
{ id: 'pack-10', name: '10-Session Package (-15%)' },
{ id: 'monthly', name: 'Monthly Unlimited (4 sessions) - $350' }
],
defaultValue: 'single',
orientation: 'vertical',
isRequired: true
});
});
form.addSpacer({ height: 20, showLine: true, lineStyle: 'dashed' });
// Price Summary Section
const summarySection = form.addSubform('summary', { title: '💰 Cost Summary', isCollapsible: false });
summarySection.addRow(row => {
row.addPriceDisplay('sessionBase', {
label: 'Session Base Price',
computedValue: () => {
const duration = sessionSection.radioButton('duration')?.value() || '60';
const treatmentType = treatmentSection.radioButton('treatmentType')?.value() || 'general';
const practitioner = sessionSection.radioButton('practitioner')?.value() || 'standard';
const basePrice = sessionPrices[duration] || 110;
const premium = treatmentPremiums[treatmentType] || 0;
const multiplier = practitionerMultipliers[practitioner] || 1.0;
return Math.round((basePrice + premium) * multiplier);
},
variant: 'default'
}, '1fr');
row.addPriceDisplay('assessment', {
label: 'Initial Assessment',
computedValue: () => {
return sessionSection.checkbox('initialAssessment')?.value() ? 30 : 0;
},
variant: 'default',
prefix: '+'
}, '1fr');
});
summarySection.addRow(row => {
row.addPriceDisplay('additionalServices', {
label: 'Additional Services',
computedValue: () => {
let total = 0;
if (servicesSection.checkbox('dryNeedling')?.value()) total += 25;
if (servicesSection.checkbox('cupping')?.value()) total += 20;
if (servicesSection.checkbox('tens')?.value()) total += 15;
if (servicesSection.checkbox('ultrasound')?.value()) total += 15;
if (servicesSection.checkbox('massage')?.value()) total += 20;
if (servicesSection.checkbox('taping')?.value()) total += 15;
if (servicesSection.checkbox('homeProgram')?.value()) total += 25;
if (servicesSection.checkbox('report')?.value()) total += 35;
return total;
},
variant: 'default',
prefix: '+'
}, '1fr');
row.addPriceDisplay('packageDiscount', {
label: 'Package Discount',
computedValue: () => {
const packageType = packageSection.radioButton('packageType')?.value() || 'single';
if (packageType === 'single' || packageType === 'monthly') return 0;
const duration = sessionSection.radioButton('duration')?.value() || '60';
const treatmentType = treatmentSection.radioButton('treatmentType')?.value() || 'general';
const practitioner = sessionSection.radioButton('practitioner')?.value() || 'standard';
const basePrice = sessionPrices[duration] || 110;
const premium = treatmentPremiums[treatmentType] || 0;
const multiplier = practitionerMultipliers[practitioner] || 1.0;
const sessionPrice = (basePrice + premium) * multiplier;
let services = 0;
if (servicesSection.checkbox('dryNeedling')?.value()) services += 25;
if (servicesSection.checkbox('cupping')?.value()) services += 20;
if (servicesSection.checkbox('tens')?.value()) services += 15;
if (servicesSection.checkbox('ultrasound')?.value()) services += 15;
if (servicesSection.checkbox('massage')?.value()) services += 20;
if (servicesSection.checkbox('taping')?.value()) services += 15;
const perSessionTotal = sessionPrice + services;
const sessions = packageType === 'pack-5' ? 5 : 10;
const discount = packageType === 'pack-5' ? 0.10 : 0.15;
return -Math.round(perSessionTotal * sessions * discount);
},
variant: 'success',
prefix: ''
}, '1fr');
});
const finalSection = form.addSubform('final', {
title: '🩺 Your Estimate',
isCollapsible: false,
sticky: 'bottom'
});
finalSection.addRow(row => {
row.addPriceDisplay('totalPrice', {
label: 'Total Cost',
computedValue: () => {
const packageType = packageSection.radioButton('packageType')?.value() || 'single';
if (packageType === 'monthly') {
const assessment = sessionSection.checkbox('initialAssessment')?.value() ? 30 : 0;
const homeProgram = servicesSection.checkbox('homeProgram')?.value() ? 25 : 0;
const report = servicesSection.checkbox('report')?.value() ? 35 : 0;
return 350 + assessment + homeProgram + report;
}
const duration = sessionSection.radioButton('duration')?.value() || '60';
const treatmentType = treatmentSection.radioButton('treatmentType')?.value() || 'general';
const practitioner = sessionSection.radioButton('practitioner')?.value() || 'standard';
const basePrice = sessionPrices[duration] || 110;
const premium = treatmentPremiums[treatmentType] || 0;
const multiplier = practitionerMultipliers[practitioner] || 1.0;
const sessionPrice = (basePrice + premium) * multiplier;
const assessment = sessionSection.checkbox('initialAssessment')?.value() ? 30 : 0;
let services = 0;
if (servicesSection.checkbox('dryNeedling')?.value()) services += 25;
if (servicesSection.checkbox('cupping')?.value()) services += 20;
if (servicesSection.checkbox('tens')?.value()) services += 15;
if (servicesSection.checkbox('ultrasound')?.value()) services += 15;
if (servicesSection.checkbox('massage')?.value()) services += 20;
if (servicesSection.checkbox('taping')?.value()) services += 15;
if (servicesSection.checkbox('homeProgram')?.value()) services += 25;
if (servicesSection.checkbox('report')?.value()) services += 35;
const perSessionTotal = sessionPrice + services;
if (packageType === 'single') {
return Math.round(perSessionTotal + assessment);
}
const sessions = packageType === 'pack-5' ? 5 : 10;
const discount = packageType === 'pack-5' ? 0.10 : 0.15;
const packageTotal = perSessionTotal * sessions * (1 - discount);
return Math.round(packageTotal + assessment);
},
variant: 'large',
suffix: () => {
const packageType = packageSection.radioButton('packageType')?.value();
if (packageType === 'monthly') return '/month';
return '';
}
}, '1fr');
row.addPriceDisplay('perSession', {
label: 'Per Session',
computedValue: () => {
const packageType = packageSection.radioButton('packageType')?.value() || 'single';
const duration = sessionSection.radioButton('duration')?.value() || '60';
const treatmentType = treatmentSection.radioButton('treatmentType')?.value() || 'general';
const practitioner = sessionSection.radioButton('practitioner')?.value() || 'standard';
const basePrice = sessionPrices[duration] || 110;
const premium = treatmentPremiums[treatmentType] || 0;
const multiplier = practitionerMultipliers[practitioner] || 1.0;
const sessionPrice = (basePrice + premium) * multiplier;
let services = 0;
if (servicesSection.checkbox('dryNeedling')?.value()) services += 25;
if (servicesSection.checkbox('cupping')?.value()) services += 20;
if (servicesSection.checkbox('tens')?.value()) services += 15;
if (servicesSection.checkbox('ultrasound')?.value()) services += 15;
if (servicesSection.checkbox('massage')?.value()) services += 20;
if (servicesSection.checkbox('taping')?.value()) services += 15;
const perSessionTotal = sessionPrice + services;
if (packageType === 'monthly') return Math.round(350 / 4);
if (packageType === 'pack-5') return Math.round(perSessionTotal * 0.90);
if (packageType === 'pack-10') return Math.round(perSessionTotal * 0.85);
return Math.round(perSessionTotal);
},
variant: 'default',
isVisible: () => {
const packageType = packageSection.radioButton('packageType')?.value();
return packageType !== 'single';
}
}, '1fr');
});
finalSection.addRow(row => {
row.addTextPanel('insuranceNote', {
computedValue: () => 'Many insurance plans cover physiotherapy. Check with your provider for coverage details.',
customStyles: { 'font-size': '0.9rem', 'color': '#059669', 'font-weight': '500' }
});
});
finalSection.addRow(row => {
row.addTextPanel('disclaimer', {
computedValue: () => 'Prices may vary. Initial assessment recommended for new patients. Insurance direct billing available.',
customStyles: { 'font-size': '0.85rem', 'color': '#64748b', 'font-style': 'italic' }
});
});
form.configureSubmitButton({
label: 'Book Appointment'
});
}