export function musicLessonCalculator(form: FormTs) {
// Base rates by instrument (per 30 min)
const instrumentRates: Record<string, number> = {
'piano': 40,
'guitar': 35,
'violin': 45,
'drums': 40,
'voice': 45,
'bass': 35,
'saxophone': 50,
'flute': 45,
'clarinet': 45,
'trumpet': 45,
'cello': 50,
'ukulele': 30
};
// Experience multipliers
const experienceMultipliers: Record<string, number> = {
'student': 0.7,
'beginner': 1.0,
'intermediate': 1.25,
'advanced': 1.5,
'professional': 2.0
};
form.addRow(row => {
row.addTextPanel('header', {
computedValue: () => 'Music Lesson Calculator',
customStyles: { 'font-size': '1.5rem', 'font-weight': '600', 'color': '#1e293b' }
});
});
form.addSpacer({ height: 20 });
// Instrument Section
const instrumentSection = form.addSubform('instrument', { title: '🎵 Instrument Selection' });
instrumentSection.addRow(row => {
row.addDropdown('instrument', {
label: 'Instrument',
options: [
{ id: 'piano', name: 'Piano/Keyboard' },
{ id: 'guitar', name: 'Guitar (Acoustic/Electric)' },
{ id: 'violin', name: 'Violin/Viola' },
{ id: 'drums', name: 'Drums/Percussion' },
{ id: 'voice', name: 'Voice/Singing' },
{ id: 'bass', name: 'Bass Guitar' },
{ id: 'saxophone', name: 'Saxophone' },
{ id: 'flute', name: 'Flute' },
{ id: 'clarinet', name: 'Clarinet' },
{ id: 'trumpet', name: 'Trumpet/Brass' },
{ id: 'cello', name: 'Cello' },
{ id: 'ukulele', name: 'Ukulele' }
],
defaultValue: 'piano',
isRequired: true
}, '1fr');
row.addDropdown('studentLevel', {
label: 'Student Level',
options: [
{ id: 'beginner', name: 'Beginner (0-1 years)' },
{ id: 'elementary', name: 'Elementary (1-3 years)' },
{ id: 'intermediate', name: 'Intermediate (3-5 years)' },
{ id: 'advanced', name: 'Advanced (5+ years)' },
{ id: 'professional', name: 'Professional/College' }
],
defaultValue: 'beginner',
isRequired: true,
tooltip: 'Your current skill level'
}, '1fr');
});
// Lesson Details Section
const lessonSection = form.addSubform('lesson', { title: '📚 Lesson Details' });
lessonSection.addRow(row => {
row.addRadioButton('lessonLength', {
label: 'Lesson Duration',
options: [
{ id: '30', name: '30 minutes' },
{ id: '45', name: '45 minutes' },
{ id: '60', name: '60 minutes' },
{ id: '90', name: '90 minutes' }
],
defaultValue: '30',
isRequired: true
});
});
lessonSection.addRow(row => {
row.addDropdown('lessonFormat', {
label: 'Lesson Format',
options: [
{ id: 'in-person', name: 'In-Person (at studio)' },
{ id: 'home', name: 'In-Home (teacher travels)' },
{ id: 'online', name: 'Online (video call)' }
],
defaultValue: 'in-person'
}, '1fr');
row.addDropdown('frequency', {
label: 'Lesson Frequency',
options: [
{ id: 'weekly', name: 'Weekly (4x/month)' },
{ id: 'biweekly', name: 'Bi-weekly (2x/month)' },
{ id: 'single', name: 'Single Lesson' }
],
defaultValue: 'weekly',
isRequired: true
}, '1fr');
});
// Teacher Section
const teacherSection = form.addSubform('teacher', { title: '👨🏫 Teacher Experience' });
teacherSection.addRow(row => {
row.addDropdown('teacherExperience', {
label: 'Teacher Level',
options: [
{ id: 'student', name: 'Student Teacher (learning to teach)' },
{ id: 'beginner', name: 'New Teacher (1-3 years teaching)' },
{ id: 'intermediate', name: 'Experienced (3-10 years teaching)' },
{ id: 'advanced', name: 'Senior Teacher (10+ years)' },
{ id: 'professional', name: 'Professional/Performer' }
],
defaultValue: 'intermediate',
isRequired: true
});
});
teacherSection.addRow(row => {
row.addTextPanel('teacherNote', {
computedValue: () => {
const experience = teacherSection.dropdown('teacherExperience')?.value() || 'intermediate';
const notes: Record<string, string> = {
'student': 'Great for young beginners, most affordable option',
'beginner': 'Enthusiastic teachers building their practice',
'intermediate': 'Balanced experience and value, most popular choice',
'advanced': 'Seasoned professionals, ideal for serious students',
'professional': 'Performers and conservatory graduates, premium instruction'
};
return notes[experience] || '';
},
customStyles: { 'font-size': '0.85rem', 'color': '#64748b', 'text-align': 'center' }
});
});
// Package Options Section
const packageSection = form.addSubform('package', { title: '📦 Package Options' });
packageSection.addRow(row => {
row.addRadioButton('packageType', {
label: 'Payment Option',
options: [
{ id: 'single', name: 'Pay Per Lesson' },
{ id: 'monthly', name: 'Monthly Package (5% off)' },
{ id: 'semester', name: 'Semester Package (10% off)' }
],
defaultValue: 'monthly',
isRequired: true
});
});
packageSection.addRow(row => {
row.addCheckbox('materials', {
label: 'Include Lesson Materials',
defaultValue: false,
tooltip: 'Sheet music, method books, practice materials (+$15/month)'
}, '1fr');
row.addCheckbox('recital', {
label: 'Recital Fee',
defaultValue: false,
tooltip: 'Performance opportunities and recital participation (+$25/semester)'
}, '1fr');
});
form.addSpacer({ height: 20, showLine: true, lineStyle: 'dashed' });
// Price Breakdown Section
const priceSection = form.addSubform('price', { title: '💰 Price Breakdown', isCollapsible: false });
priceSection.addRow(row => {
row.addPriceDisplay('baseRate', {
label: 'Base Lesson Rate',
computedValue: () => {
const instrument = instrumentSection.dropdown('instrument')?.value() || 'piano';
const lessonLength = lessonSection.radioButton('lessonLength')?.value() || '30';
const teacherExp = teacherSection.dropdown('teacherExperience')?.value() || 'intermediate';
const baseRate = instrumentRates[instrument] || 40;
const lengthMultiplier = parseInt(lessonLength) / 30;
const expMultiplier = experienceMultipliers[teacherExp] || 1.0;
return Math.round(baseRate * lengthMultiplier * expMultiplier);
},
variant: 'default',
tooltip: 'Rate per lesson before discounts'
}, '1fr');
row.addPriceDisplay('formatAdjustment', {
label: 'Format Adjustment',
computedValue: () => {
const format = lessonSection.dropdown('lessonFormat')?.value() || 'in-person';
const instrument = instrumentSection.dropdown('instrument')?.value() || 'piano';
const lessonLength = lessonSection.radioButton('lessonLength')?.value() || '30';
const teacherExp = teacherSection.dropdown('teacherExperience')?.value() || 'intermediate';
const baseRate = instrumentRates[instrument] || 40;
const lengthMultiplier = parseInt(lessonLength) / 30;
const expMultiplier = experienceMultipliers[teacherExp] || 1.0;
const lessonRate = baseRate * lengthMultiplier * expMultiplier;
if (format === 'home') return Math.round(lessonRate * 0.2); // +20% for travel
if (format === 'online') return Math.round(lessonRate * -0.1); // -10% for online
return 0;
},
variant: 'default',
prefix: () => {
const format = lessonSection.dropdown('lessonFormat')?.value() || 'in-person';
if (format === 'home') return '+$';
if (format === 'online') return '-$';
return '$';
}
}, '1fr');
});
priceSection.addRow(row => {
row.addPriceDisplay('perLessonRate', {
label: 'Per Lesson Rate',
computedValue: () => {
const instrument = instrumentSection.dropdown('instrument')?.value() || 'piano';
const lessonLength = lessonSection.radioButton('lessonLength')?.value() || '30';
const teacherExp = teacherSection.dropdown('teacherExperience')?.value() || 'intermediate';
const format = lessonSection.dropdown('lessonFormat')?.value() || 'in-person';
const packageType = packageSection.radioButton('packageType')?.value() || 'monthly';
const baseRate = instrumentRates[instrument] || 40;
const lengthMultiplier = parseInt(lessonLength) / 30;
const expMultiplier = experienceMultipliers[teacherExp] || 1.0;
let lessonRate = baseRate * lengthMultiplier * expMultiplier;
// Format adjustment
if (format === 'home') lessonRate *= 1.2;
if (format === 'online') lessonRate *= 0.9;
// Package discount
if (packageType === 'monthly') lessonRate *= 0.95;
if (packageType === 'semester') lessonRate *= 0.90;
return Math.round(lessonRate);
},
variant: 'success'
});
});
// Monthly Cost Section
const monthlySection = form.addSubform('monthly', { title: '📅 Monthly Investment', isCollapsible: false });
monthlySection.addRow(row => {
row.addPriceDisplay('lessonsPerMonth', {
label: 'Lessons per Month',
computedValue: () => {
const frequency = lessonSection.dropdown('frequency')?.value() || 'weekly';
if (frequency === 'weekly') return 4;
if (frequency === 'biweekly') return 2;
return 1;
},
variant: 'default',
prefix: '',
suffix: ' lessons'
}, '1fr');
row.addPriceDisplay('addOns', {
label: 'Add-ons',
computedValue: () => {
const materials = packageSection.checkbox('materials')?.value() || false;
const recital = packageSection.checkbox('recital')?.value() || false;
let addOns = 0;
if (materials) addOns += 15;
if (recital) addOns += Math.round(25 / 4); // Semester fee divided by months
return addOns;
},
variant: 'default',
tooltip: 'Materials and recital fees'
}, '1fr');
});
monthlySection.addRow(row => {
row.addPriceDisplay('monthlyTotal', {
label: 'Monthly Total',
computedValue: () => {
const instrument = instrumentSection.dropdown('instrument')?.value() || 'piano';
const lessonLength = lessonSection.radioButton('lessonLength')?.value() || '30';
const teacherExp = teacherSection.dropdown('teacherExperience')?.value() || 'intermediate';
const format = lessonSection.dropdown('lessonFormat')?.value() || 'in-person';
const frequency = lessonSection.dropdown('frequency')?.value() || 'weekly';
const packageType = packageSection.radioButton('packageType')?.value() || 'monthly';
const materials = packageSection.checkbox('materials')?.value() || false;
const recital = packageSection.checkbox('recital')?.value() || false;
const baseRate = instrumentRates[instrument] || 40;
const lengthMultiplier = parseInt(lessonLength) / 30;
const expMultiplier = experienceMultipliers[teacherExp] || 1.0;
let lessonRate = baseRate * lengthMultiplier * expMultiplier;
if (format === 'home') lessonRate *= 1.2;
if (format === 'online') lessonRate *= 0.9;
if (packageType === 'monthly') lessonRate *= 0.95;
if (packageType === 'semester') lessonRate *= 0.90;
let lessonsPerMonth = 4;
if (frequency === 'biweekly') lessonsPerMonth = 2;
if (frequency === 'single') lessonsPerMonth = 1;
let monthlyTotal = lessonRate * lessonsPerMonth;
if (materials) monthlyTotal += 15;
if (recital) monthlyTotal += Math.round(25 / 4);
return Math.round(monthlyTotal);
},
variant: 'large'
});
});
monthlySection.addRow(row => {
row.addTextPanel('savings', {
computedValue: () => {
const packageType = packageSection.radioButton('packageType')?.value() || 'monthly';
const instrument = instrumentSection.dropdown('instrument')?.value() || 'piano';
const lessonLength = lessonSection.radioButton('lessonLength')?.value() || '30';
const teacherExp = teacherSection.dropdown('teacherExperience')?.value() || 'intermediate';
const format = lessonSection.dropdown('lessonFormat')?.value() || 'in-person';
const frequency = lessonSection.dropdown('frequency')?.value() || 'weekly';
if (packageType === 'single') return 'Pay per lesson - most flexible option';
const baseRate = instrumentRates[instrument] || 40;
const lengthMultiplier = parseInt(lessonLength) / 30;
const expMultiplier = experienceMultipliers[teacherExp] || 1.0;
let lessonRate = baseRate * lengthMultiplier * expMultiplier;
if (format === 'home') lessonRate *= 1.2;
if (format === 'online') lessonRate *= 0.9;
let lessonsPerMonth = 4;
if (frequency === 'biweekly') lessonsPerMonth = 2;
const fullPrice = lessonRate * lessonsPerMonth;
const discount = packageType === 'monthly' ? 0.05 : 0.10;
const savings = Math.round(fullPrice * discount);
return `You save $${savings}/month with ${packageType} package!`;
},
customStyles: { 'font-size': '0.95rem', 'color': '#059669', 'text-align': 'center', 'font-weight': '500' }
});
});
// Summary Section
const summarySection = form.addSubform('summary', {
title: '🎹 Summary',
isCollapsible: false,
sticky: 'bottom'
});
summarySection.addRow(row => {
row.addTextPanel('summaryText', {
computedValue: () => {
const instrument = instrumentSection.dropdown('instrument')?.value() || 'piano';
const lessonLength = lessonSection.radioButton('lessonLength')?.value() || '30';
const frequency = lessonSection.dropdown('frequency')?.value() || 'weekly';
const instrumentNames: Record<string, string> = {
'piano': 'Piano', 'guitar': 'Guitar', 'violin': 'Violin',
'drums': 'Drums', 'voice': 'Voice', 'bass': 'Bass',
'saxophone': 'Saxophone', 'flute': 'Flute', 'clarinet': 'Clarinet',
'trumpet': 'Trumpet', 'cello': 'Cello', 'ukulele': 'Ukulele'
};
const freqLabels: Record<string, string> = {
'weekly': 'weekly', 'biweekly': 'bi-weekly', 'single': 'one-time'
};
return `${instrumentNames[instrument] || 'Piano'} lessons, ${lessonLength} min ${freqLabels[frequency] || 'weekly'}`;
},
customStyles: { 'font-size': '1rem', 'font-weight': '600', 'text-align': 'center', 'color': '#1e293b' }
});
});
summarySection.addRow(row => {
row.addTextPanel('disclaimer', {
computedValue: () => 'Prices are estimates. Actual rates vary by location and teacher. Contact us for exact pricing.',
customStyles: { 'font-size': '0.8rem', 'color': '#64748b', 'text-align': 'center' }
});
});
form.configureSubmitButton({
label: 'Book Trial Lesson'
});
}