export function tutoringRateCalculator(form: FormTs) {
// Subject base rates (per hour)
const subjectRates: Record<string, number> = {
'elementary': 30,
'middle-school': 40,
'high-school': 50,
'ap-honors': 65,
'college': 75,
'test-prep': 80,
'special-ed': 70
};
// Subject category multipliers
const subjectMultipliers: Record<string, number> = {
'math': 1.1,
'science': 1.15,
'english': 1.0,
'foreign-language': 1.1,
'history': 1.0,
'computer-science': 1.2,
'music': 1.1,
'other': 1.0
};
// Session length discounts
const sessionDiscounts: Record<string, number> = {
'30': 0,
'60': 0,
'90': 5,
'120': 10
};
// Package discounts (percentage)
const packageDiscounts: Record<string, number> = {
'single': 0,
'4-sessions': 5,
'8-sessions': 10,
'12-sessions': 15,
'monthly': 20
};
form.addRow(row => {
row.addTextPanel('header', {
computedValue: () => 'Get Your Tutoring Quote',
customStyles: { 'font-size': '1.5rem', 'font-weight': '600', 'color': '#1e293b' }
});
});
form.addSpacer({ height: 20 });
// Student Details Section
const studentSection = form.addSubform('student', { title: '๐จโ๐ Student Information' });
studentSection.addRow(row => {
row.addDropdown('gradeLevel', {
label: 'Grade Level',
options: [
{ id: 'elementary', name: 'Elementary (K-5)' },
{ id: 'middle-school', name: 'Middle School (6-8)' },
{ id: 'high-school', name: 'High School (9-12)' },
{ id: 'ap-honors', name: 'AP/Honors Courses' },
{ id: 'college', name: 'College/University' },
{ id: 'test-prep', name: 'Test Prep (SAT/ACT/GRE)' },
{ id: 'special-ed', name: 'Special Education/Learning Support' }
],
defaultValue: 'high-school',
isRequired: true
}, '1fr');
row.addDropdown('subject', {
label: 'Subject Area',
options: [
{ id: 'math', name: 'Mathematics' },
{ id: 'science', name: 'Science (Physics/Chemistry/Biology)' },
{ id: 'english', name: 'English/Language Arts' },
{ id: 'foreign-language', name: 'Foreign Language' },
{ id: 'history', name: 'History/Social Studies' },
{ id: 'computer-science', name: 'Computer Science/Coding' },
{ id: 'music', name: 'Music/Art' },
{ id: 'other', name: 'Other Subject' }
],
defaultValue: 'math',
isRequired: true
}, '1fr');
});
studentSection.addRow(row => {
row.addInteger('numberOfStudents', {
label: 'Number of Students',
min: 1,
max: 4,
defaultValue: 1,
tooltip: 'Group tutoring discounts apply for 2+ students'
}, '1fr');
row.addDropdown('currentPerformance', {
label: 'Current Performance Level',
options: [
{ id: 'struggling', name: 'Struggling (Below grade level)' },
{ id: 'average', name: 'Average (At grade level)' },
{ id: 'above', name: 'Above Average' },
{ id: 'advanced', name: 'Advanced (Enrichment focus)' }
],
defaultValue: 'average'
}, '1fr');
});
// Session Details Section
const sessionSection = form.addSubform('session', { title: '๐ Session Details' });
sessionSection.addRow(row => {
row.addRadioButton('sessionLength', {
label: 'Session Length',
options: [
{ id: '30', name: '30 minutes' },
{ id: '60', name: '60 minutes (Most popular)' },
{ id: '90', name: '90 minutes (-5%)' },
{ id: '120', name: '2 hours (-10%)' }
],
defaultValue: '60',
orientation: 'vertical',
isRequired: true
});
});
sessionSection.addRow(row => {
row.addRadioButton('format', {
label: 'Session Format',
options: [
{ id: 'in-person', name: 'In-Person (at your location)' },
{ id: 'online', name: 'Online (via video call)' },
{ id: 'hybrid', name: 'Hybrid (mix of both)' }
],
defaultValue: 'online',
orientation: 'vertical',
isRequired: true
});
});
// Package Section
const packageSection = form.addSubform('package', { title: '๐ฆ Package Options' });
packageSection.addRow(row => {
row.addRadioButton('packageType', {
label: 'Session Package',
options: [
{ id: 'single', name: 'Single Session (no commitment)' },
{ id: '4-sessions', name: '4-Session Pack (-5%)' },
{ id: '8-sessions', name: '8-Session Pack (-10%)' },
{ id: '12-sessions', name: '12-Session Pack (-15%)' },
{ id: 'monthly', name: 'Monthly Unlimited (-20%)' }
],
defaultValue: 'single',
orientation: 'vertical',
isRequired: true
});
});
packageSection.addRow(row => {
row.addInteger('sessionsPerWeek', {
label: 'Sessions Per Week',
min: 1,
max: 7,
defaultValue: 2,
isVisible: () => packageSection.radioButton('packageType')?.value() === 'monthly'
}, '1fr');
});
// Additional Services Section
const addonsSection = form.addSubform('addons', { title: 'โจ Additional Services' });
addonsSection.addRow(row => {
row.addCheckbox('homeworkHelp', {
label: 'Homework Help (email support) (+$15/week)',
defaultValue: false
}, '1fr');
row.addCheckbox('progressReports', {
label: 'Weekly Progress Reports (+$10/week)',
defaultValue: false
}, '1fr');
});
addonsSection.addRow(row => {
row.addCheckbox('practiceTests', {
label: 'Practice Tests & Materials (+$25)',
defaultValue: false,
isVisible: () => studentSection.dropdown('gradeLevel')?.value() === 'test-prep'
}, '1fr');
row.addCheckbox('parentConference', {
label: 'Monthly Parent Conference (+$20)',
defaultValue: false
}, '1fr');
});
addonsSection.addRow(row => {
row.addCheckbox('recordedSessions', {
label: 'Session Recordings (+$10/session)',
defaultValue: false,
isVisible: () => sessionSection.radioButton('format')?.value() !== 'in-person'
}, '1fr');
row.addCheckbox('studyGuides', {
label: 'Custom Study Guides (+$30)',
defaultValue: false
}, '1fr');
});
form.addSpacer({ height: 20, showLine: true, lineStyle: 'dashed' });
// Price Summary Section
const summarySection = form.addSubform('summary', { title: '๐ฐ Your Quote', isCollapsible: false });
summarySection.addRow(row => {
row.addPriceDisplay('baseRate', {
label: 'Base Hourly Rate',
computedValue: () => {
const gradeLevel = studentSection.dropdown('gradeLevel')?.value() || 'high-school';
const subject = studentSection.dropdown('subject')?.value() || 'math';
const baseRate = subjectRates[gradeLevel] || 50;
const subjectMult = subjectMultipliers[subject] || 1;
return Math.round(baseRate * subjectMult);
},
variant: 'default',
suffix: '/hr'
}, '1fr');
row.addPriceDisplay('formatAdjustment', {
label: 'Format Adjustment',
computedValue: () => {
const format = sessionSection.radioButton('format')?.value() || 'online';
const gradeLevel = studentSection.dropdown('gradeLevel')?.value() || 'high-school';
const subject = studentSection.dropdown('subject')?.value() || 'math';
const baseRate = subjectRates[gradeLevel] || 50;
const subjectMult = subjectMultipliers[subject] || 1;
const hourlyRate = baseRate * subjectMult;
// In-person costs more due to travel
if (format === 'in-person') return Math.round(hourlyRate * 0.15);
if (format === 'hybrid') return Math.round(hourlyRate * 0.08);
return 0;
},
variant: 'default',
prefix: '+'
}, '1fr');
});
summarySection.addRow(row => {
row.addPriceDisplay('groupDiscount', {
label: 'Group Discount',
computedValue: () => {
const numStudents = studentSection.integer('numberOfStudents')?.value() || 1;
if (numStudents <= 1) return 0;
const gradeLevel = studentSection.dropdown('gradeLevel')?.value() || 'high-school';
const subject = studentSection.dropdown('subject')?.value() || 'math';
const format = sessionSection.radioButton('format')?.value() || 'online';
const baseRate = subjectRates[gradeLevel] || 50;
const subjectMult = subjectMultipliers[subject] || 1;
let hourlyRate = baseRate * subjectMult;
if (format === 'in-person') hourlyRate *= 1.15;
if (format === 'hybrid') hourlyRate *= 1.08;
// 20% discount per additional student (their share)
const discount = hourlyRate * 0.2 * (numStudents - 1);
return -Math.round(discount);
},
variant: 'success',
prefix: ''
}, '1fr');
row.addPriceDisplay('packageDiscount', {
label: 'Package Discount',
computedValue: () => {
const packageType = packageSection.radioButton('packageType')?.value() || 'single';
const discountPct = packageDiscounts[packageType] || 0;
if (discountPct === 0) return 0;
const gradeLevel = studentSection.dropdown('gradeLevel')?.value() || 'high-school';
const subject = studentSection.dropdown('subject')?.value() || 'math';
const format = sessionSection.radioButton('format')?.value() || 'online';
const sessionLength = sessionSection.radioButton('sessionLength')?.value() || '60';
const baseRate = subjectRates[gradeLevel] || 50;
const subjectMult = subjectMultipliers[subject] || 1;
let hourlyRate = baseRate * subjectMult;
if (format === 'in-person') hourlyRate *= 1.15;
if (format === 'hybrid') hourlyRate *= 1.08;
const sessionLengthDiscount = sessionDiscounts[sessionLength] || 0;
hourlyRate = hourlyRate * (1 - sessionLengthDiscount / 100);
const sessionRate = hourlyRate * (parseInt(sessionLength) / 60);
return -Math.round(sessionRate * discountPct / 100);
},
variant: 'success',
prefix: ''
}, '1fr');
});
summarySection.addRow(row => {
row.addPriceDisplay('packageTotal', {
label: 'Package Total',
computedValue: () => {
const packageType = packageSection.radioButton('packageType')?.value() || 'single';
if (packageType === 'single') return 0;
const gradeLevel = studentSection.dropdown('gradeLevel')?.value() || 'high-school';
const subject = studentSection.dropdown('subject')?.value() || 'math';
const format = sessionSection.radioButton('format')?.value() || 'online';
const sessionLength = sessionSection.radioButton('sessionLength')?.value() || '60';
const numStudents = studentSection.integer('numberOfStudents')?.value() || 1;
// Calculate session rate
const baseRate = subjectRates[gradeLevel] || 50;
const subjectMult = subjectMultipliers[subject] || 1;
let hourlyRate = baseRate * subjectMult;
if (format === 'in-person') hourlyRate *= 1.15;
if (format === 'hybrid') hourlyRate *= 1.08;
const sessionLengthDiscount = sessionDiscounts[sessionLength] || 0;
hourlyRate = hourlyRate * (1 - sessionLengthDiscount / 100);
let sessionRate = hourlyRate * (parseInt(sessionLength) / 60);
if (numStudents > 1) sessionRate = sessionRate * (1 - 0.2 * (numStudents - 1) / numStudents);
const packageDiscount = packageDiscounts[packageType] || 0;
sessionRate = sessionRate * (1 - packageDiscount / 100);
const addRecording = addonsSection.checkbox('recordedSessions')?.value() && format !== 'in-person';
if (addRecording) sessionRate += 10;
// Package sessions count
let sessions = 1;
if (packageType === '4-sessions') sessions = 4;
if (packageType === '8-sessions') sessions = 8;
if (packageType === '12-sessions') sessions = 12;
if (packageType === 'monthly') {
const perWeek = packageSection.integer('sessionsPerWeek')?.value() || 2;
sessions = perWeek * 4;
}
// Add weekly add-ons
let weeklyAddons = 0;
const weeks = packageType === 'monthly' ? 4 : Math.ceil(sessions / 2);
if (addonsSection.checkbox('homeworkHelp')?.value()) weeklyAddons += 15 * weeks;
if (addonsSection.checkbox('progressReports')?.value()) weeklyAddons += 10 * weeks;
if (addonsSection.checkbox('parentConference')?.value()) weeklyAddons += 20;
if (addonsSection.checkbox('practiceTests')?.value()) weeklyAddons += 25;
if (addonsSection.checkbox('studyGuides')?.value()) weeklyAddons += 30;
return Math.round(sessionRate * sessions + weeklyAddons);
},
variant: 'default',
isVisible: () => packageSection.radioButton('packageType')?.value() !== 'single'
}, '1fr');
row.addPriceDisplay('monthlyCost', {
label: 'Monthly Cost',
computedValue: () => {
const packageType = packageSection.radioButton('packageType')?.value() || 'single';
if (packageType !== 'monthly') return 0;
const gradeLevel = studentSection.dropdown('gradeLevel')?.value() || 'high-school';
const subject = studentSection.dropdown('subject')?.value() || 'math';
const format = sessionSection.radioButton('format')?.value() || 'online';
const sessionLength = sessionSection.radioButton('sessionLength')?.value() || '60';
const numStudents = studentSection.integer('numberOfStudents')?.value() || 1;
const sessionsPerWeek = packageSection.integer('sessionsPerWeek')?.value() || 2;
// Calculate session rate
const baseRate = subjectRates[gradeLevel] || 50;
const subjectMult = subjectMultipliers[subject] || 1;
let hourlyRate = baseRate * subjectMult;
if (format === 'in-person') hourlyRate *= 1.15;
if (format === 'hybrid') hourlyRate *= 1.08;
const sessionLengthDiscount = sessionDiscounts[sessionLength] || 0;
hourlyRate = hourlyRate * (1 - sessionLengthDiscount / 100);
let sessionRate = hourlyRate * (parseInt(sessionLength) / 60);
if (numStudents > 1) sessionRate = sessionRate * (1 - 0.2 * (numStudents - 1) / numStudents);
sessionRate = sessionRate * 0.8; // Monthly discount
const addRecording = addonsSection.checkbox('recordedSessions')?.value() && format !== 'in-person';
if (addRecording) sessionRate += 10;
const sessionsPerMonth = sessionsPerWeek * 4;
// Weekly add-ons
let monthlyAddons = 0;
if (addonsSection.checkbox('homeworkHelp')?.value()) monthlyAddons += 15 * 4;
if (addonsSection.checkbox('progressReports')?.value()) monthlyAddons += 10 * 4;
if (addonsSection.checkbox('parentConference')?.value()) monthlyAddons += 20;
if (addonsSection.checkbox('practiceTests')?.value()) monthlyAddons += 25;
if (addonsSection.checkbox('studyGuides')?.value()) monthlyAddons += 30;
return Math.round(sessionRate * sessionsPerMonth + monthlyAddons);
},
variant: 'default',
suffix: '/month',
isVisible: () => packageSection.radioButton('packageType')?.value() === 'monthly'
}, '1fr');
});
summarySection.addRow(row => {
row.addTextPanel('perStudentNote', {
computedValue: () => {
const numStudents = studentSection.integer('numberOfStudents')?.value() || 1;
if (numStudents <= 1) return '';
const gradeLevel = studentSection.dropdown('gradeLevel')?.value() || 'high-school';
const subject = studentSection.dropdown('subject')?.value() || 'math';
const format = sessionSection.radioButton('format')?.value() || 'online';
const sessionLength = sessionSection.radioButton('sessionLength')?.value() || '60';
const packageType = packageSection.radioButton('packageType')?.value() || 'single';
const baseRate = subjectRates[gradeLevel] || 50;
const subjectMult = subjectMultipliers[subject] || 1;
let hourlyRate = baseRate * subjectMult;
if (format === 'in-person') hourlyRate *= 1.15;
if (format === 'hybrid') hourlyRate *= 1.08;
const sessionLengthDiscount = sessionDiscounts[sessionLength] || 0;
hourlyRate = hourlyRate * (1 - sessionLengthDiscount / 100);
let sessionRate = hourlyRate * (parseInt(sessionLength) / 60);
sessionRate = sessionRate * (1 - 0.2 * (numStudents - 1) / numStudents);
const packageDiscount = packageDiscounts[packageType] || 0;
sessionRate = sessionRate * (1 - packageDiscount / 100);
const perStudent = Math.round(sessionRate / numStudents);
return `That's only $${perStudent}/session per student in your group!`;
},
customStyles: { 'font-size': '0.9rem', 'color': '#059669', 'text-align': 'center', 'font-weight': '500' },
isVisible: () => (studentSection.integer('numberOfStudents')?.value() || 1) > 1
});
});
const finalSection = form.addSubform('final', {
title: '๐งพ Summary',
isCollapsible: false,
sticky: 'bottom'
});
finalSection.addRow(row => {
row.addPriceDisplay('sessionPrice', {
label: 'Price Per Session',
computedValue: () => {
const gradeLevel = studentSection.dropdown('gradeLevel')?.value() || 'high-school';
const subject = studentSection.dropdown('subject')?.value() || 'math';
const format = sessionSection.radioButton('format')?.value() || 'online';
const sessionLength = sessionSection.radioButton('sessionLength')?.value() || '60';
const packageType = packageSection.radioButton('packageType')?.value() || 'single';
const numStudents = studentSection.integer('numberOfStudents')?.value() || 1;
// Calculate hourly rate
const baseRate = subjectRates[gradeLevel] || 50;
const subjectMult = subjectMultipliers[subject] || 1;
let hourlyRate = baseRate * subjectMult;
// Format adjustment
if (format === 'in-person') hourlyRate *= 1.15;
if (format === 'hybrid') hourlyRate *= 1.08;
// Session length discount
const sessionLengthDiscount = sessionDiscounts[sessionLength] || 0;
hourlyRate = hourlyRate * (1 - sessionLengthDiscount / 100);
// Calculate session rate
let sessionRate = hourlyRate * (parseInt(sessionLength) / 60);
// Group discount
if (numStudents > 1) {
sessionRate = sessionRate * (1 - 0.2 * (numStudents - 1) / numStudents);
}
// Package discount
const packageDiscount = packageDiscounts[packageType] || 0;
sessionRate = sessionRate * (1 - packageDiscount / 100);
// Add recording fee if applicable
const addRecording = addonsSection.checkbox('recordedSessions')?.value() && format !== 'in-person';
if (addRecording) sessionRate += 10;
return Math.round(sessionRate);
},
variant: 'large',
suffix: '/session'
});
});
finalSection.addRow(row => {
row.addTextPanel('disclaimer', {
computedValue: () => 'First session includes a free 15-minute assessment.',
customStyles: { 'font-size': '0.85rem', 'color': '#64748b', 'font-style': 'italic' }
});
});
form.configureSubmitButton({
label: 'Book a Free Consultation'
});
}