export function hostingPlanQuiz(form: FormTs) {
form.setTitle(() => '๐ Which Hosting Plan Is Right for Your Website?');
// ========== STATE ==========
type HostingType = 'shared' | 'vps' | 'cloud' | 'dedicated' | 'managed';
const scores = form.state<Record<HostingType, number>>({
shared: 0,
vps: 0,
cloud: 0,
dedicated: 0,
managed: 0
});
// ========== SCORING FUNCTIONS ==========
const updateScores = (hostingScores: Partial<Record<HostingType, number>>) => {
scores.update(current => {
const updated = { ...current };
(Object.entries(hostingScores) as [HostingType, number][]).forEach(([type, points]) => {
updated[type] = (updated[type] || 0) + points;
});
return updated;
});
};
const getRecommendation = (): HostingType => {
const s = scores();
const entries = Object.entries(s) as [HostingType, number][];
const sorted = entries.sort((a, b) => b[1] - a[1]);
return sorted[0]?.[0] || 'shared';
};
const getTopThree = (): [HostingType, number][] => {
const s = scores();
const entries = Object.entries(s) as [HostingType, number][];
return entries.sort((a, b) => b[1] - a[1]).slice(0, 3);
};
type HostingInfo = {
name: string;
tagline: string;
bestFor: string;
priceRange: string;
providers: string;
pros: string[];
cons: string[];
};
const hostingInfo: Record<HostingType, HostingInfo> = {
shared: {
name: 'Shared Hosting',
tagline: 'Affordable & Simple',
bestFor: 'Small websites, blogs, portfolios with low traffic',
priceRange: '$3-15/month',
providers: 'Bluehost, Hostinger, SiteGround',
pros: ['Very affordable', 'Easy to set up', 'Managed by provider'],
cons: ['Limited resources', 'Slower performance', 'Less control']
},
vps: {
name: 'VPS Hosting',
tagline: 'Power & Control',
bestFor: 'Growing sites, developers needing root access',
priceRange: '$20-80/month',
providers: 'DigitalOcean, Linode, Vultr',
pros: ['Dedicated resources', 'Root access', 'Scalable'],
cons: ['Requires technical knowledge', 'Self-managed', 'More expensive']
},
cloud: {
name: 'Cloud Hosting',
tagline: 'Scale On Demand',
bestFor: 'High-traffic sites, apps with variable load',
priceRange: '$20-500+/month (usage-based)',
providers: 'AWS, Google Cloud, Azure',
pros: ['Infinite scalability', 'Pay for what you use', 'High availability'],
cons: ['Complex pricing', 'Steep learning curve', 'Can get expensive']
},
dedicated: {
name: 'Dedicated Server',
tagline: 'Maximum Performance',
bestFor: 'Enterprise sites, high-security requirements',
priceRange: '$100-500+/month',
providers: 'OVH, Hetzner, Liquid Web',
pros: ['Full server resources', 'Maximum performance', 'Complete control'],
cons: ['Expensive', 'Requires expertise', 'Fixed capacity']
},
managed: {
name: 'Managed WordPress',
tagline: 'Hassle-Free WordPress',
bestFor: 'WordPress sites wanting speed & security without hassle',
priceRange: '$25-300/month',
providers: 'WP Engine, Kinsta, Flywheel',
pros: ['Optimized for WordPress', 'Automatic updates', 'Expert support'],
cons: ['WordPress only', 'More expensive', 'Some restrictions']
}
};
const getHostingInfo = (type: HostingType): HostingInfo => hostingInfo[type];
const getMatchPercentage = (type: HostingType) => {
const s = scores();
const maxPossible = 40;
return Math.min(100, Math.round((s[type] / maxPossible) * 100));
};
// ========== COMPLETION SCREEN ==========
form.configureCompletionScreen({
type: 'text',
title: '๐ Your Hosting Recommendation Is Ready!',
message: () => `We recommend ${getHostingInfo(getRecommendation()).name} for your needs. Check your email for the detailed comparison guide and setup tips!`
});
// ========== PAGES ==========
const pages = form.addPages('quiz-pages', { heightMode: 'current-page' });
// ========== PAGE 1: Website Type ==========
const page1 = pages.addPage('website-type', { mobileBreakpoint: 500 });
page1.addRow(row => {
row.addTextPanel('header1', {
label: 'Step 1 of 5: Your Website',
computedValue: () => 'Tell us about your website or project',
customStyles: { fontSize: '0.9rem', color: '#6b7280', marginBottom: '1rem' }
});
});
page1.addSpacer({ height: '24px' });
page1.addRow(row => {
row.addRadioButton('siteType', {
label: 'What type of website are you building?',
options: [
{ id: 'blog', name: '๐ Blog or personal site' },
{ id: 'business', name: '๐ข Business/corporate site' },
{ id: 'ecommerce', name: '๐ E-commerce store' },
{ id: 'webapp', name: 'โก Web application (SaaS)' },
{ id: 'enterprise', name: '๐๏ธ Enterprise/high-traffic portal' }
],
orientation: 'vertical',
onValueChange: (v) => {
if (v === 'blog') updateScores({ shared: 4, managed: 3, vps: 1 });
else if (v === 'business') updateScores({ shared: 2, managed: 3, vps: 2, cloud: 1 });
else if (v === 'ecommerce') updateScores({ managed: 3, vps: 3, cloud: 3, dedicated: 1 });
else if (v === 'webapp') updateScores({ vps: 4, cloud: 4, dedicated: 2 });
else if (v === 'enterprise') updateScores({ cloud: 4, dedicated: 4, vps: 2 });
}
});
});
page1.addRow(row => {
row.addRadioButton('platform', {
label: 'What platform will you use?',
options: [
{ id: 'wordpress', name: 'WordPress' },
{ id: 'shopify', name: 'Shopify (hosted separately)' },
{ id: 'custom', name: 'Custom code (Node, Python, etc.)' },
{ id: 'static', name: 'Static site (HTML, Hugo, Gatsby)' },
{ id: 'unsure', name: 'Not sure yet' }
],
orientation: 'vertical',
onValueChange: (v) => {
if (v === 'wordpress') updateScores({ managed: 5, shared: 3, vps: 2 });
else if (v === 'custom') updateScores({ vps: 4, cloud: 4, dedicated: 2 });
else if (v === 'static') updateScores({ shared: 3, cloud: 2 });
else if (v === 'unsure') updateScores({ shared: 2, managed: 2, vps: 2 });
}
});
});
// ========== PAGE 2: Traffic & Scale ==========
const page2 = pages.addPage('traffic', { mobileBreakpoint: 500 });
page2.addRow(row => {
row.addTextPanel('header2', {
label: 'Step 2 of 5: Traffic & Scale',
computedValue: () => 'How much traffic do you expect?',
customStyles: { fontSize: '0.9rem', color: '#6b7280', marginBottom: '1rem' }
});
});
page2.addSpacer({ height: '24px' });
page2.addRow(row => {
row.addRadioButton('traffic', {
label: 'Expected monthly visitors:',
options: [
{ id: 'tiny', name: 'Under 1,000' },
{ id: 'small', name: '1,000 - 10,000' },
{ id: 'medium', name: '10,000 - 100,000' },
{ id: 'large', name: '100,000 - 1,000,000' },
{ id: 'massive', name: 'Over 1,000,000' }
],
orientation: 'vertical',
onValueChange: (v) => {
if (v === 'tiny') updateScores({ shared: 5, managed: 3 });
else if (v === 'small') updateScores({ shared: 3, managed: 4, vps: 2 });
else if (v === 'medium') updateScores({ vps: 4, managed: 3, cloud: 3 });
else if (v === 'large') updateScores({ cloud: 5, dedicated: 4, vps: 2 });
else if (v === 'massive') updateScores({ cloud: 5, dedicated: 5 });
}
});
});
page2.addRow(row => {
row.addRadioButton('trafficPattern', {
label: 'How does your traffic behave?',
options: [
{ id: 'steady', name: '๐ Steady and predictable' },
{ id: 'growing', name: '๐ Growing steadily' },
{ id: 'spiky', name: '๐ Spiky (viral posts, sales events)' },
{ id: 'seasonal', name: '๐๏ธ Seasonal peaks' }
],
orientation: 'vertical',
onValueChange: (v) => {
if (v === 'steady') updateScores({ shared: 2, vps: 3, dedicated: 3 });
else if (v === 'growing') updateScores({ vps: 3, cloud: 3, managed: 2 });
else if (v === 'spiky') updateScores({ cloud: 5, vps: 1 });
else if (v === 'seasonal') updateScores({ cloud: 4, vps: 2 });
}
});
});
// ========== PAGE 3: Technical & Budget ==========
const page3 = pages.addPage('technical', { mobileBreakpoint: 500 });
page3.addRow(row => {
row.addTextPanel('header3', {
label: 'Step 3 of 5: Technical Skills & Budget',
computedValue: () => 'What\'s your technical level and budget?',
customStyles: { fontSize: '0.9rem', color: '#6b7280', marginBottom: '1rem' }
});
});
page3.addSpacer({ height: '24px' });
page3.addRow(row => {
row.addRadioButton('techLevel', {
label: 'Your technical experience:',
options: [
{ id: 'beginner', name: '๐ฑ Beginner - I want it simple' },
{ id: 'intermediate', name: '๐ Intermediate - I can follow guides' },
{ id: 'advanced', name: '๐ป Advanced - I know Linux/servers' },
{ id: 'expert', name: '๐ง Expert - DevOps/SysAdmin experience' }
],
orientation: 'vertical',
onValueChange: (v) => {
if (v === 'beginner') updateScores({ shared: 5, managed: 5 });
else if (v === 'intermediate') updateScores({ shared: 3, managed: 4, vps: 2 });
else if (v === 'advanced') updateScores({ vps: 4, cloud: 3, dedicated: 2 });
else if (v === 'expert') updateScores({ vps: 4, cloud: 5, dedicated: 4 });
}
});
});
page3.addRow(row => {
row.addRadioButton('budget', {
label: 'Monthly hosting budget:',
options: [
{ id: 'minimal', name: 'Under $20/month' },
{ id: 'moderate', name: '$20-50/month' },
{ id: 'comfortable', name: '$50-150/month' },
{ id: 'enterprise', name: '$150+/month' }
],
orientation: 'vertical',
onValueChange: (v) => {
if (v === 'minimal') updateScores({ shared: 5 });
else if (v === 'moderate') updateScores({ shared: 2, managed: 4, vps: 3 });
else if (v === 'comfortable') updateScores({ managed: 3, vps: 4, cloud: 3, dedicated: 2 });
else if (v === 'enterprise') updateScores({ cloud: 4, dedicated: 5, managed: 3 });
}
});
});
// ========== PAGE 4: Requirements ==========
const page4 = pages.addPage('requirements', { mobileBreakpoint: 500 });
page4.addRow(row => {
row.addTextPanel('header4', {
label: 'Step 4 of 5: Special Requirements',
computedValue: () => 'Any specific needs?',
customStyles: { fontSize: '0.9rem', color: '#6b7280', marginBottom: '1rem' }
});
});
page4.addSpacer({ height: '24px' });
page4.addRow(row => {
row.addSuggestionChips('requirements', {
label: 'Select any special requirements:',
suggestions: [
{ id: 'ssl', name: '๐ SSL Certificate' },
{ id: 'backup', name: '๐พ Auto Backups' },
{ id: 'cdn', name: '๐ CDN/Global Speed' },
{ id: 'staging', name: '๐งช Staging Environment' },
{ id: 'compliance', name: '๐ Compliance (HIPAA, PCI)' },
{ id: 'support', name: '๐ง 24/7 Support' }
],
onValueChange: (v) => {
const picks = v || [];
if (picks.includes('ssl')) updateScores({ managed: 1, cloud: 1 });
if (picks.includes('backup')) updateScores({ managed: 2, cloud: 1 });
if (picks.includes('cdn')) updateScores({ cloud: 3, managed: 2 });
if (picks.includes('staging')) updateScores({ managed: 3, vps: 1 });
if (picks.includes('compliance')) updateScores({ dedicated: 4, cloud: 3 });
if (picks.includes('support')) updateScores({ managed: 3, shared: 1 });
}
});
});
page4.addRow(row => {
row.addRadioButton('uptime', {
label: 'How critical is uptime for your site?',
options: [
{ id: 'low', name: 'Nice to have - occasional downtime OK' },
{ id: 'medium', name: 'Important - minimal downtime preferred' },
{ id: 'high', name: 'Critical - downtime costs money' },
{ id: 'mission', name: 'Mission-critical - 99.99% uptime required' }
],
orientation: 'vertical',
onValueChange: (v) => {
if (v === 'low') updateScores({ shared: 3 });
else if (v === 'medium') updateScores({ managed: 3, vps: 2 });
else if (v === 'high') updateScores({ cloud: 4, dedicated: 3 });
else if (v === 'mission') updateScores({ cloud: 5, dedicated: 4 });
}
});
});
// ========== PAGE 5: Results ==========
const page5 = pages.addPage('results', { mobileBreakpoint: 500 });
page5.addRow(row => {
row.addTextPanel('header5', {
label: 'Step 5 of 5: Your Hosting Recommendation',
computedValue: () => 'Here\'s what we recommend',
customStyles: { fontSize: '0.9rem', color: '#6b7280', marginBottom: '1rem' }
});
});
page5.addSpacer({ height: '24px' });
page5.addRow(row => {
row.addTextPanel('mainResult', {
label: '',
computedValue: () => `๐ ${getHostingInfo(getRecommendation()).name}`,
customStyles: {
fontSize: '32px',
fontWeight: 'bold',
textAlign: 'center',
padding: '20px',
borderRadius: '12px',
color: '#059669',
background: '#ecfdf5'
}
});
});
page5.addRow(row => {
row.addTextPanel('tagline', {
label: '',
computedValue: () => getHostingInfo(getRecommendation()).tagline,
customStyles: { textAlign: 'center', fontStyle: 'italic', fontSize: '18px', padding: '10px' }
});
});
page5.addRow(row => {
row.addTextPanel('bestFor', {
label: 'โจ Best For',
computedValue: () => getHostingInfo(getRecommendation()).bestFor,
customStyles: { padding: '12px', background: '#f9fafb', borderRadius: '8px' }
});
});
page5.addRow(row => {
row.addTextPanel('priceRange', {
label: '๐ฐ Price Range',
computedValue: () => getHostingInfo(getRecommendation()).priceRange,
customStyles: { padding: '12px' }
});
});
page5.addRow(row => {
row.addTextPanel('providers', {
label: '๐ Top Providers',
computedValue: () => getHostingInfo(getRecommendation()).providers,
customStyles: { padding: '12px', background: '#f0f9ff', borderRadius: '8px' }
});
});
const alternativesSection = page5.addSubform('alternatives', {
title: '๐ฅ Other Options (click to expand)',
isCollapsible: true,
customStyles: { background: '#f9fafb', borderRadius: '8px', marginTop: '20px' }
});
alternativesSection.addRow(row => {
row.addTextPanel('otherOptions', {
label: 'Your Top 3 Matches',
computedValue: () => {
const top3 = getTopThree();
return top3.map((entry, i) => {
const info = getHostingInfo(entry[0]);
return `${i + 1}. ${info.name} (${getMatchPercentage(entry[0])}% match) - ${info.priceRange}`;
}).join('\n\n');
}
});
});
// ========== PAGE 6: Lead Capture ==========
const page6 = pages.addPage('lead-capture', { mobileBreakpoint: 500 });
page6.addRow(row => {
row.addTextPanel('header6', {
label: 'Get Your Hosting Setup Guide',
computedValue: () => 'We\'ll send you detailed setup instructions',
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: 'Email', isRequired: true, placeholder: 'john@email.com' }, '1fr');
});
page6.addRow(row => {
row.addTextbox('website', { label: 'Website URL (if exists)', placeholder: 'www.example.com' }, '1fr');
row.addEmpty('1fr');
});
page6.addRow(row => {
row.addCheckboxList('consent', {
options: [
{ id: 'guide', name: '๐ Send me the hosting setup guide', isRequired: true },
{ id: 'deals', name: '๐ Send me exclusive hosting deals' },
{ id: 'migration', name: '๐ Help me migrate my current site' }
],
defaultValue: ['guide'],
orientation: 'vertical'
});
});
// ========== SUBMIT BUTTON ==========
form.configureSubmitButton({
label: () => `๐ Get My ${getHostingInfo(getRecommendation()).name} Guide`
});
// ========== PDF REPORT ==========
form.configurePdf('hosting-guide', pdf => {
pdf.configure({
filename: 'hosting-recommendation-guide.pdf',
pageSize: 'A4',
allowUserDownload: true,
downloadButtonLabel: '๐ Download Hosting Guide',
header: {
title: 'Hosting Recommendation',
subtitle: 'Your Personalized Hosting Guide'
},
footer: {
text: 'Generated by FormTs',
showPageNumbers: true
}
});
const rec = getRecommendation();
const info = getHostingInfo(rec);
pdf.addSection('Your Recommendation', section => {
section.addRow(row => {
row.addField('Hosting Type', info.name);
row.addField('Price Range', info.priceRange);
});
section.addText(`Best for: ${info.bestFor}`);
section.addText(`Top Providers: ${info.providers}`);
});
pdf.addSection('Pros & Cons', section => {
section.addText('PROS:');
info.pros.forEach(pro => section.addText(` โ
${pro}`));
section.addSpacer(10);
section.addText('CONS:');
info.cons.forEach(con => section.addText(` โ ๏ธ ${con}`));
});
pdf.addPageBreak();
pdf.addSection('All Options Compared', section => {
section.addTable(
['Type', 'Match', 'Price', 'Best For'],
getTopThree().map(entry => {
const i = getHostingInfo(entry[0]);
return [i.name, `${getMatchPercentage(entry[0])}%`, i.priceRange, i.bestFor];
})
);
});
pdf.addSection('Next Steps', section => {
section.addText('1. Sign up with one of the recommended providers');
section.addText('2. Choose a plan that fits your current needs');
section.addText('3. Set up your domain and SSL certificate');
section.addText('4. Install your platform (WordPress, etc.)');
section.addText('5. Configure backups and security');
});
});
form.configureSubmitBehavior({ sendToServer: true });
}