export function hiringCostQuiz(form: FormTs) {
form.setTitle(() => '💼 Calculate Your True Cost of Hiring');
// ============ STATE FOR CALCULATIONS ============
const inputs = form.state<{
positionType: string;
salary: number;
hiresPerYear: number;
timeToHire: number;
recruitmentMethod: string;
interviewHours: number;
onboardingWeeks: number;
productivityRampMonths: number;
}>({
positionType: '',
salary: 0,
hiresPerYear: 1,
timeToHire: 30,
recruitmentMethod: 'internal',
interviewHours: 10,
onboardingWeeks: 2,
productivityRampMonths: 3
});
// ============ COST CALCULATIONS ============
const getRecruitmentCost = () => {
const i = inputs();
const methods: Record<string, number> = {
internal: 0.05, // 5% of salary
jobBoards: 0.08, // 8% of salary
agency: 0.20, // 20% of salary
headhunter: 0.30 // 30% of salary
};
return Math.round(i.salary * (methods[i.recruitmentMethod] || 0.1));
};
const getInterviewCost = () => {
const i = inputs();
const hourlyRate = i.salary / 2080; // Annual salary to hourly
const interviewerCost = hourlyRate * 1.3; // Assume interviewer earns 30% more
return Math.round(i.interviewHours * interviewerCost * 3); // 3 interviewers avg
};
const getOnboardingCost = () => {
const i = inputs();
const weeklyRate = i.salary / 52;
const trainerCost = weeklyRate * 0.2; // 20% of trainer's time
const materialsCost = 500; // Avg materials/equipment
return Math.round((i.onboardingWeeks * trainerCost) + materialsCost);
};
const getProductivityLossCost = () => {
const i = inputs();
const monthlyRate = i.salary / 12;
// New hire is 25% productive month 1, 50% month 2, 75% month 3, etc.
let totalLoss = 0;
for (let month = 1; month <= i.productivityRampMonths; month++) {
const productivity = Math.min(0.25 * month, 1);
totalLoss += monthlyRate * (1 - productivity);
}
return Math.round(totalLoss);
};
const getVacancyCost = () => {
const i = inputs();
const dailyRate = i.salary / 260; // Working days per year
const vacancyDays = i.timeToHire;
const productivityImpact = 0.5; // 50% work not done
return Math.round(dailyRate * vacancyDays * productivityImpact);
};
const getAdminCost = () => {
const i = inputs();
const hrHourlyRate = 35; // Avg HR hourly rate
const adminHours = 15 + (i.recruitmentMethod === 'internal' ? 20 : 5);
return Math.round(hrHourlyRate * adminHours);
};
const getTotalCostPerHire = () => {
return getRecruitmentCost() + getInterviewCost() + getOnboardingCost() +
getProductivityLossCost() + getVacancyCost() + getAdminCost();
};
const getAnnualHiringCost = () => {
return getTotalCostPerHire() * inputs().hiresPerYear;
};
const getCostAsPercentOfSalary = () => {
const i = inputs();
if (i.salary === 0) return 0;
return Math.round((getTotalCostPerHire() / i.salary) * 100);
};
const formatCurrency = (val: number) => {
return new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD', maximumFractionDigits: 0 }).format(val);
};
// ============ COMPLETION SCREEN ============
form.configureCompletionScreen({
type: 'text',
title: () => `💼 Your Hiring Cost Analysis`,
message: () => `Your true cost per hire is ${formatCurrency(getTotalCostPerHire())} (${getCostAsPercentOfSalary()}% of salary).\n\nWith ${inputs().hiresPerYear} hires per year, you're spending ${formatCurrency(getAnnualHiringCost())} annually on recruitment and onboarding.\n\nYour detailed breakdown and cost-reduction strategies are in your report.`
});
// ============ PAGES SETUP ============
const pages = form.addPages('quiz-pages', {
heightMode: 'current-page'
});
// ============ PAGE 1: Position Details ============
const page1 = pages.addPage('position-details', { mobileBreakpoint: 500 });
page1.addRow(row => {
row.addTextPanel('header1', {
label: 'Step 1 of 5: Position Details',
computedValue: () => 'Tell us about the positions you\'re hiring for',
customStyles: {
fontSize: '0.9rem',
color: '#6b7280',
marginBottom: '1rem'
}
});
});
page1.addSpacer({ height: '24px' });
page1.addRow(row => {
row.addDropdown('positionType', {
label: 'What type of position are you hiring for?',
isRequired: true,
options: [
{ id: 'entry', name: 'Entry Level' },
{ id: 'mid', name: 'Mid-Level Professional' },
{ id: 'senior', name: 'Senior Professional' },
{ id: 'manager', name: 'Manager/Team Lead' },
{ id: 'director', name: 'Director/VP' },
{ id: 'executive', name: 'C-Level Executive' }
],
placeholder: 'Select position level',
onValueChange: (val) => {
inputs.update(i => ({ ...i, positionType: val || '' }));
}
}, '1fr');
row.addMoney('salary', {
label: 'Average Annual Salary (Base)',
isRequired: true,
currency: '$',
min: 20000,
max: 1000000,
placeholder: '75,000',
onValueChange: (val) => {
inputs.update(i => ({ ...i, salary: val || 0 }));
}
}, '1fr');
});
page1.addRow(row => {
row.addSlider('hiresPerYear', {
label: 'How many positions do you hire for this role type per year?',
isRequired: true,
min: 1,
max: 50,
step: 1,
defaultValue: 3,
showValue: true,
unit: 'hires/year',
onValueChange: (val) => {
inputs.update(i => ({ ...i, hiresPerYear: val || 1 }));
}
});
});
// ============ PAGE 2: Recruitment Process ============
const page2 = pages.addPage('recruitment-process', { mobileBreakpoint: 500 });
page2.addRow(row => {
row.addTextPanel('header2', {
label: 'Step 2 of 5: Recruitment Process',
computedValue: () => 'How do you find and attract candidates?',
customStyles: {
fontSize: '0.9rem',
color: '#6b7280',
marginBottom: '1rem'
}
});
});
page2.addSpacer({ height: '24px' });
page2.addRow(row => {
row.addRadioButton('recruitmentMethod', {
label: 'Primary recruitment method for this role type:',
isRequired: true,
orientation: 'vertical',
options: [
{ id: 'internal', name: '👥 Internal recruiting (HR team + referrals)' },
{ id: 'jobBoards', name: '📋 Job boards (Indeed, LinkedIn, etc.)' },
{ id: 'agency', name: '🏢 Staffing agency (contingency fee)' },
{ id: 'headhunter', name: '🎯 Executive search / headhunter (retained)' }
],
onValueChange: (val) => {
inputs.update(i => ({ ...i, recruitmentMethod: val || 'internal' }));
}
});
});
page2.addRow(row => {
row.addSlider('timeToHire', {
label: 'Average time to fill this position (days from posting to accepted offer):',
isRequired: true,
min: 7,
max: 120,
step: 1,
defaultValue: 30,
showValue: true,
unit: 'days',
onValueChange: (val) => {
inputs.update(i => ({ ...i, timeToHire: val || 30 }));
}
});
});
page2.addRow(row => {
row.addTextPanel('recruitmentCostPreview', {
computedValue: () => {
const method = inputs().recruitmentMethod;
const labels: Record<string, string> = {
internal: 'Internal recruiting typically costs 5-10% of salary in hidden costs',
jobBoards: 'Job board posting + screening typically costs 8-12% of salary',
agency: 'Staffing agencies charge 15-25% of first-year salary',
headhunter: 'Executive search firms charge 25-35% of total compensation'
};
return `💡 ${labels[method] || ''}`;
},
customStyles: {
fontSize: '0.85rem',
color: '#6b7280',
fontStyle: 'italic',
padding: '10px',
background: '#f3f4f6',
borderRadius: '6px',
marginTop: '1rem'
}
});
});
// ============ PAGE 3: Interview Process ============
const page3 = pages.addPage('interview-process', { mobileBreakpoint: 500 });
page3.addRow(row => {
row.addTextPanel('header3', {
label: 'Step 3 of 5: Interview Process',
computedValue: () => 'How much time do you invest in candidate evaluation?',
customStyles: {
fontSize: '0.9rem',
color: '#6b7280',
marginBottom: '1rem'
}
});
});
page3.addSpacer({ height: '24px' });
page3.addRow(row => {
row.addSlider('interviewHours', {
label: 'Total interview hours per candidate (across all rounds & interviewers):',
isRequired: true,
min: 2,
max: 40,
step: 1,
defaultValue: 10,
showValue: true,
unit: 'hours',
tooltip: 'Include phone screens, video calls, on-site interviews, and panel discussions',
onValueChange: (val) => {
inputs.update(i => ({ ...i, interviewHours: val || 10 }));
}
});
});
page3.addRow(row => {
row.addMatrixQuestion('interviewStages', {
label: 'Which interview stages do you typically conduct?',
rows: [
{ id: 'screen', label: 'Initial Phone/Video Screen', description: '15-30 min' },
{ id: 'technical', label: 'Technical Assessment', description: '1-2 hours' },
{ id: 'panel', label: 'Panel Interview', description: '1-2 hours' },
{ id: 'executive', label: 'Executive/Final Round', description: '30-60 min' },
{ id: 'culture', label: 'Culture Fit/Team Meeting', description: '30-60 min' }
],
columns: [
{ id: 'yes', label: 'Yes' },
{ id: 'no', label: 'No' }
],
selectionMode: 'single',
striped: true
});
});
page3.addRow(row => {
row.addTextPanel('interviewCostPreview', {
computedValue: () => {
const cost = getInterviewCost();
return `📊 Estimated interview cost per hire: ${formatCurrency(cost)}`;
},
customStyles: {
fontSize: '0.95rem',
fontWeight: '600',
color: '#1e40af',
textAlign: 'center',
padding: '12px',
background: '#dbeafe',
borderRadius: '8px',
marginTop: '1rem'
}
});
});
// ============ PAGE 4: Onboarding & Ramp-up ============
const page4 = pages.addPage('onboarding', { mobileBreakpoint: 500 });
page4.addRow(row => {
row.addTextPanel('header4', {
label: 'Step 4 of 5: Onboarding & Productivity Ramp',
computedValue: () => 'How long until new hires reach full productivity?',
customStyles: {
fontSize: '0.9rem',
color: '#6b7280',
marginBottom: '1rem'
}
});
});
page4.addSpacer({ height: '24px' });
page4.addRow(row => {
row.addSlider('onboardingWeeks', {
label: 'Formal onboarding/training period:',
isRequired: true,
min: 1,
max: 12,
step: 1,
defaultValue: 2,
showValue: true,
unit: 'weeks',
tooltip: 'Structured training, orientation, compliance training, etc.',
onValueChange: (val) => {
inputs.update(i => ({ ...i, onboardingWeeks: val || 2 }));
}
});
});
page4.addRow(row => {
row.addSlider('productivityRampMonths', {
label: 'Time to full productivity (from start date):',
isRequired: true,
min: 1,
max: 12,
step: 1,
defaultValue: 3,
showValue: true,
unit: 'months',
tooltip: 'Time until the new hire performs at 100% expected output',
onValueChange: (val) => {
inputs.update(i => ({ ...i, productivityRampMonths: val || 3 }));
}
});
});
page4.addRow(row => {
row.addRadioButton('onboardingQuality', {
label: 'How would you rate your current onboarding process?',
isRequired: true,
orientation: 'vertical',
options: [
{ id: 'poor', name: '😟 Minimal - sink or swim approach' },
{ id: 'basic', name: '😐 Basic - paperwork and brief orientation' },
{ id: 'good', name: '🙂 Good - structured program with training' },
{ id: 'excellent', name: '😀 Excellent - comprehensive with mentorship' }
]
});
});
page4.addRow(row => {
row.addTextPanel('productivityCostPreview', {
computedValue: () => {
const loss = getProductivityLossCost();
return `📉 Productivity loss during ramp-up: ${formatCurrency(loss)}`;
},
customStyles: {
fontSize: '0.95rem',
fontWeight: '600',
color: '#dc2626',
textAlign: 'center',
padding: '12px',
background: '#fef2f2',
borderRadius: '8px',
marginTop: '1rem'
}
});
});
// ============ PAGE 5: Results ============
const page5 = pages.addPage('results', { mobileBreakpoint: 500 });
page5.addRow(row => {
row.addTextPanel('header5', {
label: 'Step 5 of 5: Your Hiring Cost Analysis',
computedValue: () => 'Here\'s the true cost breakdown for your hiring',
customStyles: {
fontSize: '0.9rem',
color: '#6b7280',
marginBottom: '1rem'
}
});
});
page5.addSpacer({ height: '24px' });
// Total cost display
page5.addRow(row => {
row.addTextPanel('totalCostPerHire', {
label: '💰 Total Cost Per Hire',
computedValue: () => formatCurrency(getTotalCostPerHire()),
customStyles: {
fontSize: '2rem',
fontWeight: '800',
color: '#dc2626',
textAlign: 'center',
padding: '20px',
background: '#fef2f2',
borderRadius: '12px',
border: '3px solid #dc2626'
}
});
});
page5.addRow(row => {
row.addTextPanel('percentOfSalary', {
computedValue: () => `${getCostAsPercentOfSalary()}% of base salary`,
customStyles: {
fontSize: '1.1rem',
fontWeight: '600',
color: '#4b5563',
textAlign: 'center',
marginTop: '5px'
}
});
});
page5.addRow(row => {
row.addTextPanel('annualCost', {
computedValue: () => `With ${inputs().hiresPerYear} hires/year: ${formatCurrency(getAnnualHiringCost())} annually`,
customStyles: {
fontSize: '1rem',
fontWeight: '600',
color: '#7c3aed',
textAlign: 'center',
padding: '12px',
background: '#f5f3ff',
borderRadius: '8px',
marginTop: '15px'
}
});
});
// Cost breakdown
const breakdownSection = page5.addSubform('breakdown', {
title: '📊 Cost Breakdown',
isCollapsible: true,
customStyles: {
marginTop: '1.5rem',
background: '#f9fafb',
borderRadius: '8px'
}
});
breakdownSection.addRow(row => {
row.addTextPanel('recruitmentLine', {
label: '🔍 Recruitment',
computedValue: () => formatCurrency(getRecruitmentCost()),
customStyles: { padding: '8px 12px', background: '#dbeafe', borderRadius: '6px', marginBottom: '8px' }
}, '1fr');
row.addTextPanel('interviewLine', {
label: '🗣️ Interviewing',
computedValue: () => formatCurrency(getInterviewCost()),
customStyles: { padding: '8px 12px', background: '#dbeafe', borderRadius: '6px', marginBottom: '8px' }
}, '1fr');
});
breakdownSection.addRow(row => {
row.addTextPanel('onboardingLine', {
label: '📚 Onboarding',
computedValue: () => formatCurrency(getOnboardingCost()),
customStyles: { padding: '8px 12px', background: '#dbeafe', borderRadius: '6px', marginBottom: '8px' }
}, '1fr');
row.addTextPanel('vacancyLine', {
label: '⏳ Vacancy Cost',
computedValue: () => formatCurrency(getVacancyCost()),
customStyles: { padding: '8px 12px', background: '#dbeafe', borderRadius: '6px', marginBottom: '8px' }
}, '1fr');
});
breakdownSection.addRow(row => {
row.addTextPanel('productivityLine', {
label: '📉 Productivity Loss',
computedValue: () => formatCurrency(getProductivityLossCost()),
customStyles: { padding: '8px 12px', background: '#fef2f2', borderRadius: '6px', marginBottom: '8px' }
}, '1fr');
row.addTextPanel('adminLine', {
label: '📋 Admin/HR Time',
computedValue: () => formatCurrency(getAdminCost()),
customStyles: { padding: '8px 12px', background: '#dbeafe', borderRadius: '6px', marginBottom: '8px' }
}, '1fr');
});
// ============ PAGE 6: Lead Capture ============
const page6 = pages.addPage('lead-capture', { mobileBreakpoint: 500 });
page6.addRow(row => {
row.addTextPanel('header6', {
label: 'Step 6 of 6: Get Your Report',
computedValue: () => 'Enter your details to receive your hiring cost analysis and reduction strategies',
customStyles: {
fontSize: '0.9rem',
color: '#6b7280',
marginBottom: '1rem'
}
});
});
page6.addSpacer({ height: '24px' });
page6.addRow(row => {
row.addTextbox('name', {
label: 'Your Name',
isRequired: true,
placeholder: 'John Smith'
}, '1fr');
row.addEmail('email', {
label: 'Work Email',
isRequired: true,
placeholder: 'john@company.com'
}, '1fr');
});
page6.addRow(row => {
row.addTextbox('company', {
label: 'Company Name',
placeholder: 'Acme Corp'
}, '1fr');
row.addTextbox('jobTitle', {
label: 'Your Job Title',
placeholder: 'HR Manager'
}, '1fr');
});
page6.addRow(row => {
row.addCheckboxList('consent', {
options: [
{
id: 'report',
name: '📄 Send me the detailed hiring cost report',
isRequired: true
},
{
id: 'tips',
name: '💡 Send me tips to reduce hiring costs'
},
{
id: 'consultation',
name: '📞 I\'d like a free recruitment strategy consultation'
}
],
defaultValue: ['report'],
orientation: 'vertical'
});
});
// ============ PDF REPORT ============
form.configurePdf('hiring-cost-report', pdf => {
pdf.configure({
filename: 'hiring-cost-analysis.pdf',
pageSize: 'A4',
allowUserDownload: true,
downloadButtonLabel: '📄 Download Hiring Cost Report',
header: {
title: 'True Cost of Hiring Analysis',
subtitle: 'Detailed Breakdown & Reduction Strategies'
},
footer: {
text: 'Generated by FormTs Hiring Cost Calculator',
showPageNumbers: true
}
});
pdf.addSection('Executive Summary', section => {
section.addRow(row => {
row.addField('Cost Per Hire', formatCurrency(getTotalCostPerHire()));
row.addField('% of Salary', `${getCostAsPercentOfSalary()}%`);
});
section.addRow(row => {
row.addField('Annual Hires', `${inputs().hiresPerYear}`);
row.addField('Annual Hiring Cost', formatCurrency(getAnnualHiringCost()));
});
});
pdf.addSection('Cost Breakdown', section => {
section.addTable(
['Cost Category', 'Amount', '% of Total'],
[
['Recruitment', formatCurrency(getRecruitmentCost()), `${Math.round((getRecruitmentCost() / getTotalCostPerHire()) * 100)}%`],
['Interviewing', formatCurrency(getInterviewCost()), `${Math.round((getInterviewCost() / getTotalCostPerHire()) * 100)}%`],
['Onboarding', formatCurrency(getOnboardingCost()), `${Math.round((getOnboardingCost() / getTotalCostPerHire()) * 100)}%`],
['Vacancy Cost', formatCurrency(getVacancyCost()), `${Math.round((getVacancyCost() / getTotalCostPerHire()) * 100)}%`],
['Productivity Loss', formatCurrency(getProductivityLossCost()), `${Math.round((getProductivityLossCost() / getTotalCostPerHire()) * 100)}%`],
['Admin/HR Time', formatCurrency(getAdminCost()), `${Math.round((getAdminCost() / getTotalCostPerHire()) * 100)}%`]
]
);
});
pdf.addPageBreak();
pdf.addSection('Cost Reduction Strategies', section => {
section.addText('1. Employee Referral Programs');
section.addText(' - Referral hires cost 50% less and stay 25% longer');
section.addText(' - Implement $1,000-5,000 referral bonuses');
section.addSpacer(10);
section.addText('2. Improve Time-to-Hire');
section.addText(' - Every week of delay costs ~1.9% of annual salary');
section.addText(' - Streamline interview process with structured templates');
section.addSpacer(10);
section.addText('3. Enhance Onboarding');
section.addText(' - Strong onboarding improves retention by 82%');
section.addText(' - Invest in mentorship programs');
section.addSpacer(10);
section.addText('4. Build Talent Pipeline');
section.addText(' - Maintain relationships with passive candidates');
section.addText(' - Reduces time-to-hire by 30%');
});
pdf.addSection('Industry Benchmarks', section => {
section.addTable(
['Position Level', 'Average Cost-per-Hire', 'Your Cost'],
[
['Entry Level', '$4,000 - $7,000', inputs().positionType === 'entry' ? formatCurrency(getTotalCostPerHire()) : '-'],
['Mid-Level', '$7,000 - $15,000', inputs().positionType === 'mid' ? formatCurrency(getTotalCostPerHire()) : '-'],
['Senior', '$15,000 - $30,000', inputs().positionType === 'senior' ? formatCurrency(getTotalCostPerHire()) : '-'],
['Executive', '$40,000 - $100,000+', inputs().positionType === 'executive' ? formatCurrency(getTotalCostPerHire()) : '-']
]
);
});
});
// ============ SUBMIT BUTTON ============
form.configureSubmitButton({
label: () => `📄 Get My Hiring Cost Report (${formatCurrency(getTotalCostPerHire())}/hire)`
});
form.configureSubmitBehavior({
sendToServer: true
});
}