export function travelerTypeQuiz(form: FormTs) {
form.setTitle(() => 'โ๏ธ What Kind of Traveler Are You?');
// ============ SCORING SYSTEM ============
const scores = form.state<Record<string, number>>({
adventurer: 0,
culturalExplorer: 0,
relaxationSeeker: 0,
luxuryTraveler: 0,
budgetExplorer: 0
});
const updateScore = (type: string, points: number) => {
scores.update(current => ({
...current,
[type]: (current[type] || 0) + points
}));
};
const getTravelerType = (): 'adventurer' | 'culturalExplorer' | 'relaxationSeeker' | 'luxuryTraveler' | 'budgetExplorer' => {
const s = scores();
const entries = Object.entries(s);
const sorted = entries.sort((a, b) => b[1] - a[1]);
return sorted[0][0] as 'adventurer' | 'culturalExplorer' | 'relaxationSeeker' | 'luxuryTraveler' | 'budgetExplorer';
};
const getTypeLabel = () => {
const labels: Record<string, string> = {
adventurer: '๐๏ธ The Adventurer',
culturalExplorer: '๐๏ธ The Cultural Explorer',
relaxationSeeker: '๐๏ธ The Relaxation Seeker',
luxuryTraveler: 'โจ The Luxury Traveler',
budgetExplorer: '๐ The Budget Explorer'
};
return labels[getTravelerType()];
};
const getTypeDescription = () => {
const descriptions: Record<string, string> = {
adventurer: 'You crave excitement and new experiences! Whether it\'s hiking through remote mountains, diving into the ocean, or exploring off-the-beaten-path destinations, you\'re happiest when pushing boundaries and creating thrilling memories.',
culturalExplorer: 'You travel to learn and grow! Museums, historical sites, local customs, and authentic experiences draw you in. You want to understand the world through its people, traditions, and stories.',
relaxationSeeker: 'You travel to unwind and recharge! Beautiful beaches, spa retreats, and peaceful settings are your paradise. You believe vacations should leave you refreshed, not exhausted.',
luxuryTraveler: 'You believe in traveling in style! Fine dining, premium accommodations, and exceptional service make your trips memorable. Quality and comfort are non-negotiable.',
budgetExplorer: 'You\'re a savvy traveler who maximizes experiences while minimizing costs! Hostels, street food, and creative planning help you see more of the world without breaking the bank.'
};
return descriptions[getTravelerType()];
};
const getDestinationRecommendations = () => {
const recommendations: Record<string, string[]> = {
adventurer: ['New Zealand - Bungee jumping & hiking', 'Costa Rica - Zip-lining & wildlife', 'Nepal - Himalayan trekking', 'Iceland - Glaciers & volcanoes'],
culturalExplorer: ['Japan - Ancient traditions & modern innovation', 'Italy - Art, history & cuisine', 'Morocco - Medinas & desert culture', 'Peru - Machu Picchu & Inca heritage'],
relaxationSeeker: ['Maldives - Overwater bungalows', 'Bali - Spa retreats & beaches', 'Fiji - Island paradise', 'Santorini - Stunning views & relaxation'],
luxuryTraveler: ['Dubai - Ultimate luxury experiences', 'Monaco - Glamour & sophistication', 'Switzerland - Alpine elegance', 'French Riviera - Coastal luxury'],
budgetExplorer: ['Vietnam - Affordable & amazing', 'Portugal - Great value in Europe', 'Thailand - Budget-friendly paradise', 'Colombia - Diverse & economical']
};
return recommendations[getTravelerType()];
};
// ============ COMPLETION SCREEN ============
form.configureCompletionScreen({
type: 'text',
title: () => getTypeLabel(),
message: () => `${getTypeDescription()}\n\nYour personalized destination recommendations and travel tips have been included in your report!`
});
// ============ PAGES SETUP ============
const pages = form.addPages('quiz-pages', {
heightMode: 'current-page'
});
// ============ PAGE 1: Travel Preferences ============
const page1 = pages.addPage('travel-preferences', { mobileBreakpoint: 500 });
page1.addRow(row => {
row.addTextPanel('header1', {
label: 'Step 1 of 5: Travel Preferences',
computedValue: () => 'Let\'s discover your travel personality!',
customStyles: {
fontSize: '0.9rem',
color: '#6b7280',
marginBottom: '1rem'
}
});
});
page1.addSpacer({ height: '24px' });
page1.addRow(row => {
row.addRadioButton('idealDestination', {
label: 'What\'s your ideal travel destination?',
isRequired: true,
orientation: 'vertical',
options: [
{ id: 'adventure', name: '๐๏ธ Remote mountains or jungles with outdoor activities' },
{ id: 'cultural', name: '๐๏ธ Historic cities with museums and monuments' },
{ id: 'beach', name: '๐๏ธ Tropical beach with crystal clear water' },
{ id: 'luxury', name: 'โจ A world-class resort or exclusive destination' },
{ id: 'offbeat', name: '๐ An underrated destination few people visit' }
],
onValueChange: (val) => {
const points: Record<string, string> = {
adventure: 'adventurer',
cultural: 'culturalExplorer',
beach: 'relaxationSeeker',
luxury: 'luxuryTraveler',
offbeat: 'budgetExplorer'
};
if (val) updateScore(points[val], 3);
}
});
});
page1.addRow(row => {
row.addRadioButton('travelPace', {
label: 'How do you prefer to pace your trips?',
isRequired: true,
orientation: 'vertical',
options: [
{ id: 'packed', name: 'โก Action-packed - see and do as much as possible' },
{ id: 'balanced', name: 'โ๏ธ Balanced - mix of activities and downtime' },
{ id: 'relaxed', name: '๐ด Relaxed - slow pace with lots of rest' },
{ id: 'curated', name: '๐ฏ Curated - only the best experiences, no rushing' }
],
onValueChange: (val) => {
if (val === 'packed') { updateScore('adventurer', 2); updateScore('culturalExplorer', 1); }
if (val === 'balanced') { updateScore('culturalExplorer', 2); updateScore('budgetExplorer', 1); }
if (val === 'relaxed') { updateScore('relaxationSeeker', 3); }
if (val === 'curated') { updateScore('luxuryTraveler', 3); }
}
});
});
// ============ PAGE 2: Accommodation & Budget ============
const page2 = pages.addPage('accommodation', { mobileBreakpoint: 500 });
page2.addRow(row => {
row.addTextPanel('header2', {
label: 'Step 2 of 5: Accommodation & Budget',
computedValue: () => 'Tell us about your travel comfort preferences',
customStyles: {
fontSize: '0.9rem',
color: '#6b7280',
marginBottom: '1rem'
}
});
});
page2.addSpacer({ height: '24px' });
page2.addRow(row => {
row.addRadioButton('accommodation', {
label: 'Where do you prefer to stay when traveling?',
isRequired: true,
orientation: 'vertical',
options: [
{ id: 'camping', name: 'โบ Camping, glamping, or eco-lodges' },
{ id: 'bnb', name: '๐ Local B&Bs or guesthouses' },
{ id: 'hostel', name: '๐๏ธ Hostels or budget hotels' },
{ id: 'resort', name: '๐จ Beach resorts or spa hotels' },
{ id: 'luxury', name: '๐ฐ 5-star hotels or luxury villas' }
],
onValueChange: (val) => {
if (val === 'camping') updateScore('adventurer', 3);
if (val === 'bnb') updateScore('culturalExplorer', 2);
if (val === 'hostel') updateScore('budgetExplorer', 3);
if (val === 'resort') updateScore('relaxationSeeker', 3);
if (val === 'luxury') updateScore('luxuryTraveler', 3);
}
});
});
page2.addRow(row => {
row.addRadioButton('budget', {
label: 'How do you approach travel budgeting?',
isRequired: true,
orientation: 'vertical',
options: [
{ id: 'minimal', name: '๐ต Minimize costs - stretch every dollar' },
{ id: 'moderate', name: '๐ฐ Moderate - comfort without excess' },
{ id: 'flexible', name: '๐ Flexible - splurge on what matters' },
{ id: 'unlimited', name: '๐ Budget isn\'t a concern - quality first' }
],
onValueChange: (val) => {
if (val === 'minimal') updateScore('budgetExplorer', 3);
if (val === 'moderate') { updateScore('culturalExplorer', 1); updateScore('adventurer', 1); }
if (val === 'flexible') updateScore('relaxationSeeker', 2);
if (val === 'unlimited') updateScore('luxuryTraveler', 3);
}
});
});
// ============ PAGE 3: Activities & Interests ============
const page3 = pages.addPage('activities', { mobileBreakpoint: 500 });
page3.addRow(row => {
row.addTextPanel('header3', {
label: 'Step 3 of 5: Activities & Interests',
computedValue: () => 'What do you enjoy doing on vacation?',
customStyles: {
fontSize: '0.9rem',
color: '#6b7280',
marginBottom: '1rem'
}
});
});
page3.addSpacer({ height: '24px' });
page3.addRow(row => {
row.addSuggestionChips('activities', {
label: 'Select your favorite travel activities (pick 3-5):',
isRequired: true,
min: 3,
max: 5,
suggestions: [
{ id: 'hiking', name: '๐ฅพ Hiking' },
{ id: 'diving', name: '๐คฟ Scuba Diving' },
{ id: 'museums', name: '๐๏ธ Museums' },
{ id: 'food', name: '๐ Local Food Tours' },
{ id: 'spa', name: '๐ Spa & Wellness' },
{ id: 'beach', name: '๐๏ธ Beach Lounging' },
{ id: 'nightlife', name: '๐ Nightlife' },
{ id: 'photography', name: '๐ธ Photography' },
{ id: 'shopping', name: '๐๏ธ Shopping' },
{ id: 'festivals', name: '๐ญ Local Festivals' }
],
onValueChange: (vals) => {
if (!vals) return;
const activityScores: Record<string, string> = {
hiking: 'adventurer',
diving: 'adventurer',
museums: 'culturalExplorer',
food: 'culturalExplorer',
spa: 'relaxationSeeker',
beach: 'relaxationSeeker',
nightlife: 'luxuryTraveler',
photography: 'culturalExplorer',
shopping: 'luxuryTraveler',
festivals: 'budgetExplorer'
};
vals.forEach(v => updateScore(activityScores[v], 1));
}
});
});
page3.addRow(row => {
row.addRadioButton('foodPreference', {
label: 'How do you approach food when traveling?',
isRequired: true,
orientation: 'vertical',
options: [
{ id: 'street', name: '๐ Street food and local markets' },
{ id: 'authentic', name: '๐ฒ Authentic local restaurants' },
{ id: 'variety', name: '๐ฝ๏ธ Mix of local and familiar' },
{ id: 'fine', name: '๐จโ๐ณ Fine dining and Michelin stars' }
],
onValueChange: (val) => {
if (val === 'street') updateScore('budgetExplorer', 2);
if (val === 'authentic') updateScore('culturalExplorer', 2);
if (val === 'variety') updateScore('relaxationSeeker', 1);
if (val === 'fine') updateScore('luxuryTraveler', 2);
}
});
});
// ============ PAGE 4: Travel Style ============
const page4 = pages.addPage('style', { mobileBreakpoint: 500 });
page4.addRow(row => {
row.addTextPanel('header4', {
label: 'Step 4 of 5: Travel Style',
computedValue: () => 'How do you like to plan and experience trips?',
customStyles: {
fontSize: '0.9rem',
color: '#6b7280',
marginBottom: '1rem'
}
});
});
page4.addSpacer({ height: '24px' });
page4.addRow(row => {
row.addRadioButton('planning', {
label: 'How much do you plan your trips?',
isRequired: true,
orientation: 'vertical',
options: [
{ id: 'spontaneous', name: '๐ฒ Spontaneous - book a flight and figure it out' },
{ id: 'loose', name: '๐ Loose plan - key reservations, flexible days' },
{ id: 'detailed', name: '๐ Detailed itinerary - every day planned' },
{ id: 'concierge', name: '๐ฉ Let someone else handle it - tours or travel agent' }
],
onValueChange: (val) => {
if (val === 'spontaneous') updateScore('budgetExplorer', 2);
if (val === 'loose') updateScore('adventurer', 2);
if (val === 'detailed') updateScore('culturalExplorer', 2);
if (val === 'concierge') updateScore('luxuryTraveler', 2);
}
});
});
page4.addRow(row => {
row.addRadioButton('companions', {
label: 'Who do you usually travel with?',
isRequired: true,
orientation: 'vertical',
options: [
{ id: 'solo', name: '๐ถ Solo - freedom and self-discovery' },
{ id: 'partner', name: '๐ซ Partner - romantic getaways' },
{ id: 'friends', name: '๐ฏ Friends - shared adventures' },
{ id: 'family', name: '๐จโ๐ฉโ๐งโ๐ฆ Family - quality time together' },
{ id: 'group', name: '๐ Organized group tours' }
],
onValueChange: (val) => {
if (val === 'solo') { updateScore('budgetExplorer', 1); updateScore('adventurer', 1); }
if (val === 'partner') { updateScore('relaxationSeeker', 1); updateScore('luxuryTraveler', 1); }
if (val === 'friends') updateScore('adventurer', 2);
if (val === 'family') updateScore('relaxationSeeker', 2);
if (val === 'group') updateScore('culturalExplorer', 2);
}
});
});
page4.addRow(row => {
row.addEmojiRating('travelFrequency', {
label: 'How often do you travel for leisure?',
isRequired: true,
preset: 'custom',
emojis: [
{ id: 'rarely', emoji: '๐ข', label: 'Rarely (0-1/year)' },
{ id: 'sometimes', emoji: '๐', label: 'Sometimes (2-3/year)' },
{ id: 'often', emoji: '๐', label: 'Often (4-6/year)' },
{ id: 'always', emoji: '๐คฉ', label: 'Always (7+/year)' }
],
onValueChange: (val) => {
if (val === 'always') updateScore('luxuryTraveler', 1);
}
});
});
// ============ PAGE 5: Results ============
const page5 = pages.addPage('results', { mobileBreakpoint: 500 });
page5.addRow(row => {
row.addTextPanel('header5', {
label: 'Step 5 of 5: Your Traveler Type',
computedValue: () => 'Discover your travel personality!',
customStyles: {
fontSize: '0.9rem',
color: '#6b7280',
marginBottom: '1rem'
}
});
});
page5.addSpacer({ height: '24px' });
page5.addRow(row => {
row.addTextPanel('resultType', {
computedValue: () => getTypeLabel(),
customStyles: () => {
const typeColors: Record<string, string> = {
adventurer: '#ea580c',
culturalExplorer: '#7c3aed',
relaxationSeeker: '#0891b2',
luxuryTraveler: '#ca8a04',
budgetExplorer: '#16a34a'
};
return {
fontSize: '1.8rem',
fontWeight: '800',
textAlign: 'center',
color: typeColors[getTravelerType()],
padding: '20px',
background: '#f9fafb',
borderRadius: '12px',
border: `3px solid ${typeColors[getTravelerType()]}`
};
}
});
});
page5.addRow(row => {
row.addTextPanel('resultDescription', {
computedValue: () => getTypeDescription(),
customStyles: {
fontSize: '1rem',
color: '#374151',
textAlign: 'center',
padding: '15px',
lineHeight: '1.6',
marginTop: '15px'
}
});
});
// Destination recommendations
const recommendationsSection = page5.addSubform('recommendations', {
title: '๐ Destinations Perfect for You',
isCollapsible: true,
customStyles: {
marginTop: '1rem',
background: '#ecfdf5',
borderRadius: '8px'
}
});
recommendationsSection.addRow(row => {
row.addTextPanel('destinations', {
computedValue: () => {
const recs = getDestinationRecommendations();
return recs.map((r, i) => `${i + 1}. ${r}`).join('\n');
},
customStyles: {
fontSize: '0.95rem',
color: '#065f46',
whiteSpace: 'pre-line',
padding: '10px'
}
});
});
// Score breakdown
const breakdownSection = page5.addSubform('breakdown', {
title: '๐ Your Travel Style Breakdown',
isCollapsible: true,
customStyles: {
marginTop: '1rem',
background: '#f9fafb',
borderRadius: '8px'
}
});
breakdownSection.addRow(row => {
row.addTextPanel('scores', {
computedValue: () => {
const s = scores();
const total = Object.values(s).reduce((a, b) => a + b, 0);
const labels: Record<string, string> = {
adventurer: '๐๏ธ Adventurer',
culturalExplorer: '๐๏ธ Cultural Explorer',
relaxationSeeker: '๐๏ธ Relaxation Seeker',
luxuryTraveler: 'โจ Luxury Traveler',
budgetExplorer: '๐ Budget Explorer'
};
return Object.entries(s)
.map(([k, v]) => `${labels[k]}: ${Math.round((v / total) * 100)}%`)
.join('\n');
},
customStyles: {
fontSize: '0.9rem',
color: '#4b5563',
whiteSpace: 'pre-line',
padding: '10px'
}
});
});
// ============ 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 Travel Guide',
computedValue: () => 'Enter your details to receive personalized travel recommendations',
customStyles: {
fontSize: '0.9rem',
color: '#6b7280',
marginBottom: '1rem'
}
});
});
page6.addSpacer({ height: '24px' });
page6.addRow(row => {
row.addTextbox('name', {
label: 'Your Name',
isRequired: true,
placeholder: 'Jane Doe'
}, '1fr');
row.addEmail('email', {
label: 'Email Address',
isRequired: true,
placeholder: 'jane@example.com'
}, '1fr');
});
page6.addRow(row => {
row.addCheckboxList('consent', {
options: [
{
id: 'report',
name: 'โ๏ธ Send me my personalized travel guide PDF',
isRequired: true
},
{
id: 'tips',
name: '๐ก Send me travel tips and destination inspiration'
},
{
id: 'deals',
name: '๐ท๏ธ Notify me about travel deals matching my style'
}
],
defaultValue: ['report'],
orientation: 'vertical'
});
});
// ============ PDF REPORT ============
form.configurePdf('travel-guide', pdf => {
pdf.configure({
filename: 'my-traveler-type-guide.pdf',
pageSize: 'A4',
allowUserDownload: true,
downloadButtonLabel: 'โ๏ธ Download Travel Guide',
header: {
title: 'Your Traveler Type Report',
subtitle: 'Personalized Travel Recommendations'
},
footer: {
text: 'Generated by FormTs Travel Quiz',
showPageNumbers: true
}
});
pdf.addSection('Your Traveler Type', section => {
section.addRow(row => {
row.addField('Type', getTypeLabel());
});
section.addSpacer(10);
section.addText(getTypeDescription());
});
pdf.addSection('Recommended Destinations', section => {
const recs = getDestinationRecommendations();
recs.forEach(r => section.addText(`โข ${r}`));
});
pdf.addPageBreak();
pdf.addSection('Travel Style Breakdown', section => {
const s = scores();
const total = Object.values(s).reduce((a, b) => a + b, 0);
section.addTable(
['Travel Style', 'Score', 'Percentage'],
[
['Adventurer', `${s.adventurer}`, `${Math.round((s.adventurer / total) * 100)}%`],
['Cultural Explorer', `${s.culturalExplorer}`, `${Math.round((s.culturalExplorer / total) * 100)}%`],
['Relaxation Seeker', `${s.relaxationSeeker}`, `${Math.round((s.relaxationSeeker / total) * 100)}%`],
['Luxury Traveler', `${s.luxuryTraveler}`, `${Math.round((s.luxuryTraveler / total) * 100)}%`],
['Budget Explorer', `${s.budgetExplorer}`, `${Math.round((s.budgetExplorer / total) * 100)}%`]
]
);
});
pdf.addSection('Tips for Your Travel Style', section => {
const type = getTravelerType();
const tips: Record<string, string[]> = {
adventurer: [
'Book accommodations with easy access to outdoor activities',
'Travel during shoulder seasons for fewer crowds',
'Always have travel insurance for adventure activities',
'Connect with local adventure tour operators'
],
culturalExplorer: [
'Research local customs and etiquette before arrival',
'Book museum tickets in advance to skip lines',
'Learn a few phrases in the local language',
'Stay in neighborhoods with historical significance'
],
relaxationSeeker: [
'Book all-inclusive resorts for stress-free planning',
'Schedule spa treatments in advance',
'Choose destinations with minimal travel time',
'Build in buffer days for unexpected relaxation'
],
luxuryTraveler: [
'Use a travel advisor for VIP experiences',
'Join hotel loyalty programs for upgrades',
'Book private transfers for comfort',
'Research Michelin-starred restaurants early'
],
budgetExplorer: [
'Use flight comparison tools and be flexible with dates',
'Stay in hostels with good reviews and social events',
'Eat where locals eat, not in tourist areas',
'Travel slowly to reduce transportation costs'
]
};
tips[type].forEach(tip => section.addText(`โข ${tip}`));
});
});
// ============ SUBMIT BUTTON ============
form.configureSubmitButton({
label: () => `โ๏ธ Get My Travel Guide (${getTypeLabel()})`
});
form.configureSubmitBehavior({
sendToServer: true
});
}