export function dentalVisitCalculator(form: FormTs) {
form.addRow(row => {
row.addTextPanel('header', {
computedValue: () => 'Dental Visit Cost Calculator',
customStyles: { 'font-size': '1.5rem', 'font-weight': '600', 'color': '#1e293b' }
});
});
form.addSpacer({ height: 20 });
// Visit Type Section
const visitSection = form.addSubform('visit', { title: '๐ฆท Visit Type' });
visitSection.addRow(row => {
row.addRadioButton('visitType', {
label: 'Type of Visit',
options: [
{ id: 'preventive', name: 'Preventive Care (Cleaning, Exam)' },
{ id: 'restorative', name: 'Restorative (Fillings, Crowns)' },
{ id: 'cosmetic', name: 'Cosmetic (Whitening, Veneers)' },
{ id: 'emergency', name: 'Emergency Visit' },
{ id: 'orthodontic', name: 'Orthodontic Consultation' }
],
defaultValue: 'preventive',
orientation: 'vertical',
isRequired: true
});
});
// Preventive Care Section
const preventiveSection = form.addSubform('preventive', {
title: '๐ชฅ Preventive Services',
isVisible: () => visitSection.radioButton('visitType')?.value() === 'preventive'
});
preventiveSection.addRow(row => {
row.addCheckbox('exam', {
label: 'Comprehensive Exam',
defaultValue: true
}, '1fr');
row.addCheckbox('cleaning', {
label: 'Teeth Cleaning (Prophylaxis)',
defaultValue: true
}, '1fr');
});
preventiveSection.addRow(row => {
row.addCheckbox('xrays', {
label: 'X-Rays',
defaultValue: true
}, '1fr');
row.addDropdown('xrayType', {
label: 'X-Ray Type',
options: [
{ id: 'bitewing', name: 'Bitewing (4 films)' },
{ id: 'full-mouth', name: 'Full Mouth Series' },
{ id: 'panoramic', name: 'Panoramic' }
],
defaultValue: 'bitewing',
isVisible: () => preventiveSection.checkbox('xrays')?.value() === true
}, '1fr');
});
preventiveSection.addRow(row => {
row.addCheckbox('fluoride', {
label: 'Fluoride Treatment',
defaultValue: false
}, '1fr');
row.addCheckbox('sealants', {
label: 'Dental Sealants (per tooth)',
defaultValue: false
}, '1fr');
});
preventiveSection.addRow(row => {
row.addInteger('sealantTeeth', {
label: 'Number of Teeth for Sealants',
min: 1,
max: 8,
defaultValue: 4,
isVisible: () => preventiveSection.checkbox('sealants')?.value() === true
}, '1fr');
});
// Restorative Section
const restorativeSection = form.addSubform('restorative', {
title: '๐ง Restorative Procedures',
isVisible: () => visitSection.radioButton('visitType')?.value() === 'restorative'
});
restorativeSection.addRow(row => {
row.addCheckbox('filling', {
label: 'Dental Filling',
defaultValue: false
}, '1fr');
row.addDropdown('fillingType', {
label: 'Filling Type',
options: [
{ id: 'amalgam', name: 'Amalgam (Silver)' },
{ id: 'composite', name: 'Composite (Tooth-Colored)' }
],
defaultValue: 'composite',
isVisible: () => restorativeSection.checkbox('filling')?.value() === true
}, '1fr');
});
restorativeSection.addRow(row => {
row.addDropdown('fillingSurfaces', {
label: 'Filling Size',
options: [
{ id: '1', name: 'Small (1 surface)' },
{ id: '2', name: 'Medium (2 surfaces)' },
{ id: '3', name: 'Large (3+ surfaces)' }
],
defaultValue: '1',
isVisible: () => restorativeSection.checkbox('filling')?.value() === true
}, '1fr');
row.addInteger('fillingCount', {
label: 'Number of Fillings',
min: 1,
max: 10,
defaultValue: 1,
isVisible: () => restorativeSection.checkbox('filling')?.value() === true
}, '1fr');
});
restorativeSection.addRow(row => {
row.addCheckbox('crown', {
label: 'Dental Crown',
defaultValue: false
}, '1fr');
row.addDropdown('crownType', {
label: 'Crown Material',
options: [
{ id: 'porcelain', name: 'Porcelain/Ceramic' },
{ id: 'pfm', name: 'Porcelain-Fused-to-Metal' },
{ id: 'gold', name: 'Gold' },
{ id: 'zirconia', name: 'Zirconia' }
],
defaultValue: 'porcelain',
isVisible: () => restorativeSection.checkbox('crown')?.value() === true
}, '1fr');
});
restorativeSection.addRow(row => {
row.addCheckbox('rootCanal', {
label: 'Root Canal',
defaultValue: false
}, '1fr');
row.addDropdown('rootCanalTooth', {
label: 'Tooth Type',
options: [
{ id: 'anterior', name: 'Front Tooth (Anterior)' },
{ id: 'premolar', name: 'Premolar' },
{ id: 'molar', name: 'Molar' }
],
defaultValue: 'molar',
isVisible: () => restorativeSection.checkbox('rootCanal')?.value() === true
}, '1fr');
});
restorativeSection.addRow(row => {
row.addCheckbox('extraction', {
label: 'Tooth Extraction',
defaultValue: false
}, '1fr');
row.addDropdown('extractionType', {
label: 'Extraction Type',
options: [
{ id: 'simple', name: 'Simple Extraction' },
{ id: 'surgical', name: 'Surgical Extraction' },
{ id: 'wisdom', name: 'Wisdom Tooth' }
],
defaultValue: 'simple',
isVisible: () => restorativeSection.checkbox('extraction')?.value() === true
}, '1fr');
});
// Cosmetic Section
const cosmeticSection = form.addSubform('cosmetic', {
title: 'โจ Cosmetic Procedures',
isVisible: () => visitSection.radioButton('visitType')?.value() === 'cosmetic'
});
cosmeticSection.addRow(row => {
row.addCheckbox('whitening', {
label: 'Teeth Whitening',
defaultValue: false
}, '1fr');
row.addDropdown('whiteningType', {
label: 'Whitening Type',
options: [
{ id: 'in-office', name: 'In-Office Treatment' },
{ id: 'take-home', name: 'Take-Home Kit' },
{ id: 'both', name: 'Both (Best Results)' }
],
defaultValue: 'in-office',
isVisible: () => cosmeticSection.checkbox('whitening')?.value() === true
}, '1fr');
});
cosmeticSection.addRow(row => {
row.addCheckbox('veneers', {
label: 'Porcelain Veneers',
defaultValue: false
}, '1fr');
row.addInteger('veneerCount', {
label: 'Number of Veneers',
min: 1,
max: 10,
defaultValue: 4,
isVisible: () => cosmeticSection.checkbox('veneers')?.value() === true
}, '1fr');
});
cosmeticSection.addRow(row => {
row.addCheckbox('bonding', {
label: 'Dental Bonding',
defaultValue: false
}, '1fr');
row.addInteger('bondingTeeth', {
label: 'Number of Teeth',
min: 1,
max: 6,
defaultValue: 1,
isVisible: () => cosmeticSection.checkbox('bonding')?.value() === true
}, '1fr');
});
// Emergency Section
const emergencySection = form.addSubform('emergency', {
title: '๐จ Emergency Services',
isVisible: () => visitSection.radioButton('visitType')?.value() === 'emergency'
});
emergencySection.addRow(row => {
row.addDropdown('emergencyType', {
label: 'Emergency Type',
options: [
{ id: 'pain', name: 'Severe Toothache/Pain' },
{ id: 'broken', name: 'Broken/Chipped Tooth' },
{ id: 'abscess', name: 'Dental Abscess/Infection' },
{ id: 'knocked-out', name: 'Knocked Out Tooth' },
{ id: 'lost-filling', name: 'Lost Filling/Crown' }
],
defaultValue: 'pain'
}, '1fr');
row.addCheckbox('afterHours', {
label: 'After-Hours Visit',
defaultValue: false
}, '1fr');
});
// Insurance Section
const insuranceSection = form.addSubform('insurance', { title: '๐ฅ Insurance Information' });
insuranceSection.addRow(row => {
row.addRadioButton('hasInsurance', {
label: 'Do you have dental insurance?',
options: [
{ id: 'yes', name: 'Yes' },
{ id: 'no', name: 'No' }
],
defaultValue: 'no',
orientation: 'horizontal'
});
});
insuranceSection.addRow(row => {
row.addDropdown('insurancePlan', {
label: 'Insurance Type',
options: [
{ id: 'ppo', name: 'PPO Plan' },
{ id: 'hmo', name: 'HMO/DMO Plan' },
{ id: 'discount', name: 'Discount Plan' }
],
defaultValue: 'ppo',
isVisible: () => insuranceSection.radioButton('hasInsurance')?.value() === 'yes'
}, '1fr');
row.addCheckbox('deductibleMet', {
label: 'Annual deductible already met',
defaultValue: false,
isVisible: () => insuranceSection.radioButton('hasInsurance')?.value() === 'yes'
}, '1fr');
});
insuranceSection.addRow(row => {
row.addMoney('deductible', {
label: 'Annual Deductible',
defaultValue: 50,
isVisible: () => insuranceSection.radioButton('hasInsurance')?.value() === 'yes' && !insuranceSection.checkbox('deductibleMet')?.value()
}, '1fr');
row.addMoney('annualMax', {
label: 'Annual Maximum',
defaultValue: 1500,
isVisible: () => insuranceSection.radioButton('hasInsurance')?.value() === 'yes'
}, '1fr');
});
form.addSpacer({ height: 20, showLine: true, lineStyle: 'dashed' });
// Pricing Section
const pricingSection = form.addSubform('pricing', { title: '๐ฐ Cost Estimate', isCollapsible: false });
const calculatePrice = () => {
const visitType = visitSection.radioButton('visitType')?.value() || 'preventive';
const hasInsurance = insuranceSection.radioButton('hasInsurance')?.value() === 'yes';
const insurancePlan = insuranceSection.dropdown('insurancePlan')?.value() || 'ppo';
const deductibleMet = insuranceSection.checkbox('deductibleMet')?.value() || false;
const deductible = insuranceSection.money('deductible')?.value() || 50;
const annualMax = insuranceSection.money('annualMax')?.value() || 1500;
let totalCost = 0;
let preventiveCost = 0;
let basicCost = 0;
let majorCost = 0;
// Preventive costs
if (visitType === 'preventive') {
if (preventiveSection.checkbox('exam')?.value()) preventiveCost += 95;
if (preventiveSection.checkbox('cleaning')?.value()) preventiveCost += 125;
if (preventiveSection.checkbox('xrays')?.value()) {
const xrayType = preventiveSection.dropdown('xrayType')?.value() || 'bitewing';
const xrayPrices: Record<string, number> = {
'bitewing': 65,
'full-mouth': 150,
'panoramic': 125
};
preventiveCost += xrayPrices[xrayType] || 65;
}
if (preventiveSection.checkbox('fluoride')?.value()) preventiveCost += 40;
if (preventiveSection.checkbox('sealants')?.value()) {
const teeth = preventiveSection.integer('sealantTeeth')?.value() || 4;
preventiveCost += 50 * teeth;
}
}
// Restorative costs
if (visitType === 'restorative') {
if (restorativeSection.checkbox('filling')?.value()) {
const fillingType = restorativeSection.dropdown('fillingType')?.value() || 'composite';
const surfaces = parseInt(restorativeSection.dropdown('fillingSurfaces')?.value() || '1');
const count = restorativeSection.integer('fillingCount')?.value() || 1;
let fillPrice = fillingType === 'amalgam' ? 150 : 200;
fillPrice += (surfaces - 1) * 50;
basicCost += fillPrice * count;
}
if (restorativeSection.checkbox('crown')?.value()) {
const crownType = restorativeSection.dropdown('crownType')?.value() || 'porcelain';
const crownPrices: Record<string, number> = {
'porcelain': 1200,
'pfm': 1000,
'gold': 1300,
'zirconia': 1400
};
majorCost += crownPrices[crownType] || 1200;
}
if (restorativeSection.checkbox('rootCanal')?.value()) {
const toothType = restorativeSection.dropdown('rootCanalTooth')?.value() || 'molar';
const rootCanalPrices: Record<string, number> = {
'anterior': 700,
'premolar': 850,
'molar': 1100
};
majorCost += rootCanalPrices[toothType] || 1100;
}
if (restorativeSection.checkbox('extraction')?.value()) {
const extractType = restorativeSection.dropdown('extractionType')?.value() || 'simple';
const extractionPrices: Record<string, number> = {
'simple': 150,
'surgical': 300,
'wisdom': 400
};
basicCost += extractionPrices[extractType] || 150;
}
}
// Cosmetic costs (usually not covered by insurance)
let cosmeticCost = 0;
if (visitType === 'cosmetic') {
if (cosmeticSection.checkbox('whitening')?.value()) {
const whiteningType = cosmeticSection.dropdown('whiteningType')?.value() || 'in-office';
const whiteningPrices: Record<string, number> = {
'in-office': 500,
'take-home': 300,
'both': 700
};
cosmeticCost += whiteningPrices[whiteningType] || 500;
}
if (cosmeticSection.checkbox('veneers')?.value()) {
const veneerCount = cosmeticSection.integer('veneerCount')?.value() || 4;
cosmeticCost += 1200 * veneerCount;
}
if (cosmeticSection.checkbox('bonding')?.value()) {
const bondingTeeth = cosmeticSection.integer('bondingTeeth')?.value() || 1;
cosmeticCost += 350 * bondingTeeth;
}
}
// Emergency costs
let emergencyCost = 0;
if (visitType === 'emergency') {
const emergencyType = emergencySection.dropdown('emergencyType')?.value() || 'pain';
const emergencyPrices: Record<string, number> = {
'pain': 200,
'broken': 250,
'abscess': 300,
'knocked-out': 400,
'lost-filling': 175
};
emergencyCost = emergencyPrices[emergencyType] || 200;
if (emergencySection.checkbox('afterHours')?.value()) {
emergencyCost *= 1.5;
}
basicCost += emergencyCost;
}
// Orthodontic consultation
if (visitType === 'orthodontic') {
preventiveCost += 150;
}
totalCost = preventiveCost + basicCost + majorCost + cosmeticCost;
// Insurance calculations
let insurancePays = 0;
let patientPays = totalCost;
let deductibleApplied = 0;
if (hasInsurance && visitType !== 'cosmetic') {
// Coverage percentages by plan type
const coverage = insurancePlan === 'ppo' ? {
preventive: 1.0,
basic: 0.8,
major: 0.5
} : insurancePlan === 'hmo' ? {
preventive: 1.0,
basic: 0.7,
major: 0.4
} : {
preventive: 0.2,
basic: 0.2,
major: 0.2
};
// Apply deductible if not met
if (!deductibleMet && (basicCost > 0 || majorCost > 0)) {
deductibleApplied = Math.min(deductible, basicCost + majorCost);
}
const eligibleForCoverage = preventiveCost + basicCost + majorCost - deductibleApplied;
// Calculate insurance payment
let potentialInsurancePays = 0;
potentialInsurancePays += preventiveCost * coverage.preventive;
potentialInsurancePays += Math.max(0, basicCost - (deductibleMet ? 0 : Math.min(deductible, basicCost))) * coverage.basic;
potentialInsurancePays += Math.max(0, majorCost - (deductibleMet || basicCost >= deductible ? 0 : Math.max(0, deductible - basicCost))) * coverage.major;
// Cap at annual maximum
insurancePays = Math.min(potentialInsurancePays, annualMax);
patientPays = totalCost - insurancePays;
}
return {
totalCost: Math.round(totalCost),
preventiveCost: Math.round(preventiveCost),
basicCost: Math.round(basicCost),
majorCost: Math.round(majorCost),
cosmeticCost: Math.round(cosmeticCost),
insurancePays: Math.round(insurancePays),
patientPays: Math.round(patientPays),
deductibleApplied: Math.round(deductibleApplied),
hasInsurance
};
};
pricingSection.addRow(row => {
row.addPriceDisplay('totalCost', {
label: 'Total Procedure Cost',
computedValue: () => calculatePrice().totalCost,
variant: 'default'
}, '1fr');
row.addPriceDisplay('insurancePays', {
label: 'Insurance Covers',
computedValue: () => calculatePrice().insurancePays,
variant: 'success',
isVisible: () => calculatePrice().hasInsurance && calculatePrice().insurancePays > 0
}, '1fr');
});
pricingSection.addRow(row => {
row.addPriceDisplay('deductible', {
label: 'Deductible Applied',
computedValue: () => calculatePrice().deductibleApplied,
variant: 'default',
isVisible: () => calculatePrice().deductibleApplied > 0
}, '1fr');
});
// Summary Section
const summarySection = form.addSubform('summary', {
title: '๐งพ Your Estimate',
isCollapsible: false,
sticky: 'bottom'
});
summarySection.addRow(row => {
row.addPriceDisplay('patientPays', {
label: () => calculatePrice().hasInsurance ? 'Your Out-of-Pocket Cost' : 'Total Cost',
computedValue: () => calculatePrice().patientPays,
variant: 'large'
});
});
summarySection.addRow(row => {
row.addTextPanel('note', {
computedValue: () => 'This is an estimate only. Actual costs may vary based on treatment complexity. Ask about payment plans and financing options.',
customStyles: { 'font-size': '0.85rem', 'color': '#64748b', 'text-align': 'center' }
});
});
form.configureSubmitButton({
label: 'Schedule Appointment'
});
}