export function virtualAssistantCalculator(form: FormTs) {
form.addRow(row => {
row.addTextPanel('header', {
computedValue: () => 'Virtual Assistant Pricing Calculator',
customStyles: { 'font-size': '1.5rem', 'font-weight': '600', 'color': '#1e293b' }
});
});
form.addSpacer({ height: 20 });
// Task Types Section
const tasksSection = form.addSubform('tasks', { title: '📋 Task Types Needed' });
tasksSection.addRow(row => {
row.addCheckbox('adminTasks', {
label: 'Administrative Tasks',
defaultValue: true,
tooltip: 'Email, scheduling, data entry, file management'
}, '1fr');
row.addCheckbox('customerService', {
label: 'Customer Service',
defaultValue: false,
tooltip: 'Phone/chat support, inquiry handling'
}, '1fr');
});
tasksSection.addRow(row => {
row.addCheckbox('socialMedia', {
label: 'Social Media Management',
defaultValue: false,
tooltip: 'Posting, engagement, basic graphics'
}, '1fr');
row.addCheckbox('bookkeeping', {
label: 'Bookkeeping',
defaultValue: false,
tooltip: 'Invoicing, expense tracking, basic accounting'
}, '1fr');
});
tasksSection.addRow(row => {
row.addCheckbox('research', {
label: 'Research & Data',
defaultValue: false,
tooltip: 'Market research, competitor analysis, data collection'
}, '1fr');
row.addCheckbox('contentCreation', {
label: 'Content Creation',
defaultValue: false,
tooltip: 'Blog posts, newsletters, basic design'
}, '1fr');
});
tasksSection.addRow(row => {
row.addCheckbox('projectManagement', {
label: 'Project Management',
defaultValue: false,
tooltip: 'Task coordination, team communication'
}, '1fr');
row.addCheckbox('technicalSupport', {
label: 'Technical Support',
defaultValue: false,
tooltip: 'Website updates, CRM management, tech troubleshooting'
}, '1fr');
});
// Hours & Schedule Section
const scheduleSection = form.addSubform('schedule', { title: '⏰ Hours & Schedule' });
scheduleSection.addRow(row => {
row.addDropdown('hoursPerWeek', {
label: 'Hours per Week',
options: [
{ id: '5', name: '5 hours/week' },
{ id: '10', name: '10 hours/week' },
{ id: '15', name: '15 hours/week' },
{ id: '20', name: '20 hours/week (Part-time)' },
{ id: '30', name: '30 hours/week' },
{ id: '40', name: '40 hours/week (Full-time)' }
],
defaultValue: '10',
isRequired: true
}, '1fr');
row.addDropdown('availability', {
label: 'Availability Needed',
options: [
{ id: 'flexible', name: 'Flexible (async work)' },
{ id: 'business', name: 'Business Hours (your timezone)' },
{ id: 'extended', name: 'Extended Hours' },
{ id: '24-7', name: '24/7 Coverage' }
],
defaultValue: 'flexible',
tooltip: 'Real-time availability costs more'
}, '1fr');
});
// Expertise Section
const expertiseSection = form.addSubform('expertise', { title: '⭐ Expertise Level' });
expertiseSection.addRow(row => {
row.addRadioButton('experienceLevel', {
label: 'Experience Level',
options: [
{ id: 'entry', name: 'Entry Level (1-2 years experience)' },
{ id: 'intermediate', name: 'Intermediate (3-5 years experience)' },
{ id: 'senior', name: 'Senior (5-10 years experience)' },
{ id: 'expert', name: 'Expert/Specialist (10+ years)' }
],
defaultValue: 'intermediate',
isRequired: true
});
});
expertiseSection.addRow(row => {
row.addDropdown('location', {
label: 'VA Location Preference',
options: [
{ id: 'us', name: 'United States' },
{ id: 'canada', name: 'Canada' },
{ id: 'uk', name: 'United Kingdom' },
{ id: 'australia', name: 'Australia' },
{ id: 'philippines', name: 'Philippines' },
{ id: 'india', name: 'India' },
{ id: 'latam', name: 'Latin America' },
{ id: 'any', name: 'No Preference' }
],
defaultValue: 'any',
tooltip: 'Location affects hourly rates significantly'
}, '1fr');
row.addDropdown('language', {
label: 'Language Requirements',
options: [
{ id: 'english', name: 'English Only' },
{ id: 'bilingual', name: 'Bilingual (English + Spanish)' },
{ id: 'multilingual', name: 'Multilingual (3+ languages)' }
],
defaultValue: 'english'
}, '1fr');
});
// Contract Section
const contractSection = form.addSubform('contract', { title: '📄 Contract Details' });
contractSection.addRow(row => {
row.addDropdown('contractLength', {
label: 'Contract Length',
options: [
{ id: 'hourly', name: 'Hourly (No commitment)' },
{ id: 'weekly', name: 'Weekly' },
{ id: 'monthly', name: 'Monthly' },
{ id: '3-month', name: '3 Months (5% discount)' },
{ id: '6-month', name: '6 Months (10% discount)' },
{ id: '12-month', name: '12 Months (15% discount)' }
],
defaultValue: 'monthly',
tooltip: 'Longer commitments get better rates'
}, '1fr');
row.addDropdown('management', {
label: 'Management Style',
options: [
{ id: 'self', name: 'Self-managed (direct hire)' },
{ id: 'agency', name: 'Agency-managed (+20% for oversight)' }
],
defaultValue: 'self',
tooltip: 'Agency management adds fees but provides backup'
}, '1fr');
});
form.addSpacer({ height: 20, showLine: true, lineStyle: 'dashed' });
// Pricing Breakdown
const breakdownSection = form.addSubform('breakdown', { title: '📊 Pricing Breakdown', isCollapsible: true });
breakdownSection.addRow(row => {
row.addPriceDisplay('baseHourlyRate', {
label: 'Base Hourly Rate',
computedValue: () => {
const experienceLevel = expertiseSection.radioButton('experienceLevel')?.value() || 'intermediate';
const location = expertiseSection.dropdown('location')?.value() || 'any';
// Base rates by experience
const experienceRates: Record<string, number> = {
'entry': 15, 'intermediate': 25, 'senior': 40, 'expert': 60
};
// Location multipliers
const locationMultipliers: Record<string, number> = {
'us': 1.5, 'canada': 1.3, 'uk': 1.4, 'australia': 1.4,
'philippines': 0.5, 'india': 0.4, 'latam': 0.6, 'any': 0.8
};
const baseRate = experienceRates[experienceLevel] || 25;
const locationMult = locationMultipliers[location] || 1;
return Math.round(baseRate * locationMult * 100) / 100;
},
variant: 'default'
}, '1fr');
row.addPriceDisplay('taskAdjustment', {
label: 'Task Complexity Adjustment',
computedValue: () => {
const experienceLevel = expertiseSection.radioButton('experienceLevel')?.value() || 'intermediate';
const location = expertiseSection.dropdown('location')?.value() || 'any';
const experienceRates: Record<string, number> = { 'entry': 15, 'intermediate': 25, 'senior': 40, 'expert': 60 };
const locationMultipliers: Record<string, number> = {
'us': 1.5, 'canada': 1.3, 'uk': 1.4, 'australia': 1.4,
'philippines': 0.5, 'india': 0.4, 'latam': 0.6, 'any': 0.8
};
const baseRate = (experienceRates[experienceLevel] || 25) * (locationMultipliers[location] || 1);
// Task complexity adjustments
let adjustment = 0;
if (tasksSection.checkbox('bookkeeping')?.value()) adjustment += baseRate * 0.15;
if (tasksSection.checkbox('contentCreation')?.value()) adjustment += baseRate * 0.1;
if (tasksSection.checkbox('projectManagement')?.value()) adjustment += baseRate * 0.15;
if (tasksSection.checkbox('technicalSupport')?.value()) adjustment += baseRate * 0.2;
return Math.round(adjustment * 100) / 100;
},
variant: 'default'
}, '1fr');
});
breakdownSection.addRow(row => {
row.addPriceDisplay('availabilityPremium', {
label: 'Availability Premium',
computedValue: () => {
const availability = scheduleSection.dropdown('availability')?.value() || 'flexible';
const experienceLevel = expertiseSection.radioButton('experienceLevel')?.value() || 'intermediate';
const location = expertiseSection.dropdown('location')?.value() || 'any';
const experienceRates: Record<string, number> = { 'entry': 15, 'intermediate': 25, 'senior': 40, 'expert': 60 };
const locationMultipliers: Record<string, number> = {
'us': 1.5, 'canada': 1.3, 'uk': 1.4, 'australia': 1.4,
'philippines': 0.5, 'india': 0.4, 'latam': 0.6, 'any': 0.8
};
const baseRate = (experienceRates[experienceLevel] || 25) * (locationMultipliers[location] || 1);
const availabilityMultipliers: Record<string, number> = {
'flexible': 0, 'business': 0.1, 'extended': 0.2, '24-7': 0.5
};
return Math.round(baseRate * (availabilityMultipliers[availability] || 0) * 100) / 100;
},
variant: 'default'
}, '1fr');
row.addPriceDisplay('languagePremium', {
label: 'Language Premium',
computedValue: () => {
const language = expertiseSection.dropdown('language')?.value() || 'english';
const experienceLevel = expertiseSection.radioButton('experienceLevel')?.value() || 'intermediate';
const location = expertiseSection.dropdown('location')?.value() || 'any';
const experienceRates: Record<string, number> = { 'entry': 15, 'intermediate': 25, 'senior': 40, 'expert': 60 };
const locationMultipliers: Record<string, number> = {
'us': 1.5, 'canada': 1.3, 'uk': 1.4, 'australia': 1.4,
'philippines': 0.5, 'india': 0.4, 'latam': 0.6, 'any': 0.8
};
const baseRate = (experienceRates[experienceLevel] || 25) * (locationMultipliers[location] || 1);
const languageMultipliers: Record<string, number> = {
'english': 0, 'bilingual': 0.1, 'multilingual': 0.2
};
return Math.round(baseRate * (languageMultipliers[language] || 0) * 100) / 100;
},
variant: 'default'
}, '1fr');
});
// Quote Section
const quoteSection = form.addSubform('quote', { title: '💰 Your Quote', isCollapsible: false });
quoteSection.addRow(row => {
row.addPriceDisplay('effectiveHourlyRate', {
label: 'Effective Hourly Rate',
computedValue: () => {
const experienceLevel = expertiseSection.radioButton('experienceLevel')?.value() || 'intermediate';
const location = expertiseSection.dropdown('location')?.value() || 'any';
const availability = scheduleSection.dropdown('availability')?.value() || 'flexible';
const language = expertiseSection.dropdown('language')?.value() || 'english';
const management = contractSection.dropdown('management')?.value() || 'self';
const experienceRates: Record<string, number> = { 'entry': 15, 'intermediate': 25, 'senior': 40, 'expert': 60 };
const locationMultipliers: Record<string, number> = {
'us': 1.5, 'canada': 1.3, 'uk': 1.4, 'australia': 1.4,
'philippines': 0.5, 'india': 0.4, 'latam': 0.6, 'any': 0.8
};
let rate = (experienceRates[experienceLevel] || 25) * (locationMultipliers[location] || 1);
// Task adjustments
if (tasksSection.checkbox('bookkeeping')?.value()) rate *= 1.15;
if (tasksSection.checkbox('contentCreation')?.value()) rate *= 1.1;
if (tasksSection.checkbox('projectManagement')?.value()) rate *= 1.15;
if (tasksSection.checkbox('technicalSupport')?.value()) rate *= 1.2;
// Availability
const availabilityMultipliers: Record<string, number> = { 'flexible': 1, 'business': 1.1, 'extended': 1.2, '24-7': 1.5 };
rate *= availabilityMultipliers[availability] || 1;
// Language
const languageMultipliers: Record<string, number> = { 'english': 1, 'bilingual': 1.1, 'multilingual': 1.2 };
rate *= languageMultipliers[language] || 1;
// Agency management
if (management === 'agency') rate *= 1.2;
return Math.round(rate * 100) / 100;
},
variant: 'success'
}, '1fr');
row.addPriceDisplay('weeklyEstimate', {
label: 'Weekly Cost',
computedValue: () => {
const hoursPerWeek = parseInt(scheduleSection.dropdown('hoursPerWeek')?.value() || '10');
const experienceLevel = expertiseSection.radioButton('experienceLevel')?.value() || 'intermediate';
const location = expertiseSection.dropdown('location')?.value() || 'any';
const availability = scheduleSection.dropdown('availability')?.value() || 'flexible';
const language = expertiseSection.dropdown('language')?.value() || 'english';
const management = contractSection.dropdown('management')?.value() || 'self';
const experienceRates: Record<string, number> = { 'entry': 15, 'intermediate': 25, 'senior': 40, 'expert': 60 };
const locationMultipliers: Record<string, number> = {
'us': 1.5, 'canada': 1.3, 'uk': 1.4, 'australia': 1.4,
'philippines': 0.5, 'india': 0.4, 'latam': 0.6, 'any': 0.8
};
let rate = (experienceRates[experienceLevel] || 25) * (locationMultipliers[location] || 1);
if (tasksSection.checkbox('bookkeeping')?.value()) rate *= 1.15;
if (tasksSection.checkbox('contentCreation')?.value()) rate *= 1.1;
if (tasksSection.checkbox('projectManagement')?.value()) rate *= 1.15;
if (tasksSection.checkbox('technicalSupport')?.value()) rate *= 1.2;
const availabilityMultipliers: Record<string, number> = { 'flexible': 1, 'business': 1.1, 'extended': 1.2, '24-7': 1.5 };
rate *= availabilityMultipliers[availability] || 1;
const languageMultipliers: Record<string, number> = { 'english': 1, 'bilingual': 1.1, 'multilingual': 1.2 };
rate *= languageMultipliers[language] || 1;
if (management === 'agency') rate *= 1.2;
return Math.round(rate * hoursPerWeek * 100) / 100;
},
variant: 'default'
}, '1fr');
});
quoteSection.addRow(row => {
row.addPriceDisplay('monthlyEstimate', {
label: 'Monthly Cost',
computedValue: () => {
const hoursPerWeek = parseInt(scheduleSection.dropdown('hoursPerWeek')?.value() || '10');
const contractLength = contractSection.dropdown('contractLength')?.value() || 'monthly';
const experienceLevel = expertiseSection.radioButton('experienceLevel')?.value() || 'intermediate';
const location = expertiseSection.dropdown('location')?.value() || 'any';
const availability = scheduleSection.dropdown('availability')?.value() || 'flexible';
const language = expertiseSection.dropdown('language')?.value() || 'english';
const management = contractSection.dropdown('management')?.value() || 'self';
const experienceRates: Record<string, number> = { 'entry': 15, 'intermediate': 25, 'senior': 40, 'expert': 60 };
const locationMultipliers: Record<string, number> = {
'us': 1.5, 'canada': 1.3, 'uk': 1.4, 'australia': 1.4,
'philippines': 0.5, 'india': 0.4, 'latam': 0.6, 'any': 0.8
};
let rate = (experienceRates[experienceLevel] || 25) * (locationMultipliers[location] || 1);
if (tasksSection.checkbox('bookkeeping')?.value()) rate *= 1.15;
if (tasksSection.checkbox('contentCreation')?.value()) rate *= 1.1;
if (tasksSection.checkbox('projectManagement')?.value()) rate *= 1.15;
if (tasksSection.checkbox('technicalSupport')?.value()) rate *= 1.2;
const availabilityMultipliers: Record<string, number> = { 'flexible': 1, 'business': 1.1, 'extended': 1.2, '24-7': 1.5 };
rate *= availabilityMultipliers[availability] || 1;
const languageMultipliers: Record<string, number> = { 'english': 1, 'bilingual': 1.1, 'multilingual': 1.2 };
rate *= languageMultipliers[language] || 1;
if (management === 'agency') rate *= 1.2;
let monthly = rate * hoursPerWeek * 4.33;
// Contract discounts
const contractDiscounts: Record<string, number> = {
'hourly': 1, 'weekly': 1, 'monthly': 1, '3-month': 0.95, '6-month': 0.9, '12-month': 0.85
};
monthly *= contractDiscounts[contractLength] || 1;
return Math.round(monthly * 100) / 100;
},
variant: 'large'
});
});
quoteSection.addRow(row => {
row.addTextPanel('contractSavings', {
computedValue: () => {
const contractLength = contractSection.dropdown('contractLength')?.value() || 'monthly';
const savings: Record<string, string> = {
'hourly': 'Sign a monthly contract for better rates',
'weekly': 'Sign a monthly contract for better rates',
'monthly': 'Sign a 3+ month contract for discounts',
'3-month': '5% discount applied!',
'6-month': '10% discount applied!',
'12-month': '15% discount applied!'
};
return savings[contractLength] || '';
},
customStyles: { 'font-size': '0.9rem', 'color': '#059669', 'text-align': 'center' }
});
});
// Summary Section
const summarySection = form.addSubform('summary', {
title: '📋 Summary',
isCollapsible: false,
sticky: 'bottom'
});
summarySection.addRow(row => {
row.addTextPanel('summaryText', {
computedValue: () => {
const hoursPerWeek = scheduleSection.dropdown('hoursPerWeek')?.value() || '10';
const experienceLevel = expertiseSection.radioButton('experienceLevel')?.value() || 'intermediate';
const levelLabels: Record<string, string> = {
'entry': 'entry-level', 'intermediate': 'intermediate', 'senior': 'senior', 'expert': 'expert'
};
return `${hoursPerWeek} hours/week with ${levelLabels[experienceLevel] || 'intermediate'} virtual assistant`;
},
customStyles: { 'font-size': '0.95rem', 'font-weight': '500', 'text-align': 'center', 'color': '#1e293b' }
});
});
summarySection.addRow(row => {
row.addTextPanel('disclaimer', {
computedValue: () => 'Rates are estimates and vary by individual VA qualifications. Final pricing confirmed upon matching with a VA.',
customStyles: { 'font-size': '0.8rem', 'color': '#64748b', 'text-align': 'center' }
});
});
form.configureSubmitButton({
label: 'Find a VA'
});
}