export function cruiseFeedbackSurvey(form: FormTs) {
// Cruise Experience Survey - Multi-page comprehensive feedback
// Demonstrates: Pages (multi-page wizard), StarRating, MatrixQuestion, EmojiRating, Slider, CheckboxList
// Track overall state
const overallRating = form.state<number | null>(null);
// ============================================
// HEADER
// ============================================
form.addRow(row => {
row.addTextPanel('header', {
label: 'Cruise Experience Survey',
computedValue: () => 'Share your voyage experience with us',
customStyles: {
background: 'linear-gradient(135deg, #0284c7 0%, #0369a1 100%)',
color: 'white',
padding: '28px',
borderRadius: '12px',
textAlign: 'center'
}
});
});
// ============================================
// MULTI-PAGE WIZARD
// ============================================
const pages = form.addPages('cruisePages', {
heightMode: 'tallest-page'
});
// ============================================
// PAGE 1: Voyage Details & First Impressions
// ============================================
const page1 = pages.addPage('voyage-details');
page1.addRow(row => {
row.addTextPanel('page1Title', {
label: '',
computedValue: () => '🚢 Voyage Details & First Impressions',
customStyles: { fontSize: '18px', fontWeight: 'bold', marginBottom: '16px', color: '#0369a1' }
});
});
const voyageSection = page1.addSubform('voyageSection', {
title: 'Your Voyage',
customStyles: { backgroundColor: '#f0f9ff', padding: '20px', borderRadius: '8px' }
});
voyageSection.addRow(row => {
row.addDropdown('cruiseLength', {
label: 'Cruise duration',
options: [
{ id: '3-4', name: '3-4 nights' },
{ id: '5-7', name: '5-7 nights' },
{ id: '8-10', name: '8-10 nights' },
{ id: '11-14', name: '11-14 nights' },
{ id: '15+', name: '15+ nights' }
],
placeholder: 'Select duration',
isRequired: true
}, '1fr');
row.addDropdown('cabinType', {
label: 'Cabin type',
options: [
{ id: 'interior', name: 'Interior' },
{ id: 'oceanview', name: 'Ocean View' },
{ id: 'balcony', name: 'Balcony' },
{ id: 'suite', name: 'Suite' },
{ id: 'penthouse', name: 'Penthouse/Villa' }
],
placeholder: 'Select cabin type',
isRequired: true
}, '1fr');
});
voyageSection.addRow(row => {
row.addDropdown('travelParty', {
label: 'Who did you travel with?',
options: [
{ id: 'solo', name: 'Solo traveler' },
{ id: 'couple', name: 'Couple' },
{ id: 'family-kids', name: 'Family with children' },
{ id: 'family-adults', name: 'Family (adults only)' },
{ id: 'friends', name: 'Friends group' },
{ id: 'group', name: 'Organized group' }
],
placeholder: 'Select travel party'
}, '1fr');
row.addRadioButton('firstCruise', {
label: 'Is this your first cruise?',
options: [
{ id: 'yes', name: 'Yes' },
{ id: 'no', name: 'No' }
],
orientation: 'horizontal'
}, '1fr');
});
const impressionSection = page1.addSubform('impressionSection', {
title: 'First Impressions',
customStyles: { padding: '20px', borderRadius: '8px', border: '1px solid #e2e8f0' }
});
impressionSection.addRow(row => {
row.addEmojiRating('embarkationMood', {
label: 'How did you feel during embarkation?',
preset: 'satisfaction',
size: 'lg',
showLabels: true,
alignment: 'center'
});
});
impressionSection.addRow(row => {
row.addStarRating('checkInProcess', {
label: 'Check-in process',
maxStars: 5,
size: 'md'
}, '1fr');
row.addStarRating('firstImpressionShip', {
label: 'First impression of the ship',
maxStars: 5,
size: 'md'
}, '1fr');
});
page1.addRow(row => {
row.addButton('nextPage1', {
label: 'Next: Accommodation →',
onClick: () => pages.goToPage('accommodation')
});
});
// ============================================
// PAGE 2: Accommodation
// ============================================
const page2 = pages.addPage('accommodation');
page2.addRow(row => {
row.addTextPanel('page2Title', {
label: '',
computedValue: () => '🛏️ Cabin & Accommodation',
customStyles: { fontSize: '18px', fontWeight: 'bold', marginBottom: '16px', color: '#0369a1' }
});
});
const cabinSection = page2.addSubform('cabinSection', {
title: 'Cabin Experience',
customStyles: { backgroundColor: '#faf5ff', padding: '20px', borderRadius: '8px' }
});
cabinSection.addRow(row => {
row.addStarRating('cabinCleanliness', {
label: 'Cleanliness',
maxStars: 5,
size: 'md'
}, '1fr');
row.addStarRating('cabinComfort', {
label: 'Comfort & bedding',
maxStars: 5,
size: 'md'
}, '1fr');
});
cabinSection.addRow(row => {
row.addStarRating('cabinSize', {
label: 'Size & layout',
maxStars: 5,
size: 'md'
}, '1fr');
row.addStarRating('cabinAmenities', {
label: 'Amenities',
maxStars: 5,
size: 'md'
}, '1fr');
});
cabinSection.addRow(row => {
row.addStarRating('cabinService', {
label: 'Cabin steward service',
maxStars: 5,
size: 'lg',
alignment: 'center',
showConfettiOnMax: true
});
});
cabinSection.addRow(row => {
row.addTextbox('cabinStewardName', {
label: 'Cabin steward name (if you remember)',
placeholder: 'Help us recognize great service'
});
});
page2.addRow(row => {
row.addButton('prevPage2', {
label: '← Back',
onClick: () => pages.goToPage('voyage-details')
});
row.addButton('nextPage2', {
label: 'Next: Dining →',
onClick: () => pages.goToPage('dining')
});
});
// ============================================
// PAGE 3: Dining Experience
// ============================================
const page3 = pages.addPage('dining');
page3.addRow(row => {
row.addTextPanel('page3Title', {
label: '',
computedValue: () => '🍽️ Dining Experience',
customStyles: { fontSize: '18px', fontWeight: 'bold', marginBottom: '16px', color: '#0369a1' }
});
});
const diningSection = page3.addSubform('diningSection', {
title: 'Dining Venues',
customStyles: { backgroundColor: '#fff7ed', padding: '20px', borderRadius: '8px' }
});
diningSection.addRow(row => {
row.addMatrixQuestion('diningRatings', {
label: 'Rate the dining venues you experienced:',
rows: [
{ id: 'main-dining', label: 'Main Dining Room', description: 'Traditional restaurant service', isRequired: true },
{ id: 'buffet', label: 'Buffet', description: 'Casual dining area', isRequired: true },
{ id: 'specialty', label: 'Specialty Restaurant', description: 'Premium dining (if visited)', isRequired: false },
{ id: 'room-service', label: 'Room Service', description: 'In-cabin dining (if used)', isRequired: false },
{ id: 'poolside', label: 'Poolside/Casual', description: 'Grill, pizza, snacks', isRequired: false }
],
columns: [
{ id: 'poor', label: 'Poor' },
{ id: 'fair', label: 'Fair' },
{ id: 'good', label: 'Good' },
{ id: 'very-good', label: 'Very Good' },
{ id: 'excellent', label: 'Excellent' }
],
striped: true,
fullWidth: true
});
});
diningSection.addRow(row => {
row.addStarRating('foodQuality', {
label: 'Overall food quality',
maxStars: 5,
size: 'md'
}, '1fr');
row.addStarRating('foodVariety', {
label: 'Menu variety',
maxStars: 5,
size: 'md'
}, '1fr');
});
diningSection.addRow(row => {
row.addStarRating('diningService', {
label: 'Dining service & staff',
maxStars: 5,
size: 'md'
}, '1fr');
row.addStarRating('diningAmbiance', {
label: 'Dining ambiance',
maxStars: 5,
size: 'md'
}, '1fr');
});
page3.addRow(row => {
row.addButton('prevPage3', {
label: '← Back',
onClick: () => pages.goToPage('accommodation')
});
row.addButton('nextPage3', {
label: 'Next: Entertainment →',
onClick: () => pages.goToPage('entertainment')
});
});
// ============================================
// PAGE 4: Entertainment & Activities
// ============================================
const page4 = pages.addPage('entertainment');
page4.addRow(row => {
row.addTextPanel('page4Title', {
label: '',
computedValue: () => '🎭 Entertainment & Activities',
customStyles: { fontSize: '18px', fontWeight: 'bold', marginBottom: '16px', color: '#0369a1' }
});
});
const entertainmentSection = page4.addSubform('entertainmentSection', {
title: 'Onboard Entertainment',
customStyles: { backgroundColor: '#fdf2f8', padding: '20px', borderRadius: '8px' }
});
entertainmentSection.addRow(row => {
row.addCheckboxList('activitiesEnjoyed', {
label: 'Which activities did you enjoy? (Select all that apply)',
options: [
{ id: 'shows', name: 'Theater shows' },
{ id: 'live-music', name: 'Live music' },
{ id: 'pool', name: 'Pool & sun deck' },
{ id: 'spa', name: 'Spa & wellness' },
{ id: 'casino', name: 'Casino' },
{ id: 'fitness', name: 'Fitness center' },
{ id: 'classes', name: 'Classes & workshops' },
{ id: 'kids-club', name: 'Kids club' },
{ id: 'trivia', name: 'Trivia & games' },
{ id: 'sports', name: 'Sports facilities' }
],
orientation: 'vertical'
});
});
entertainmentSection.addRow(row => {
row.addStarRating('showQuality', {
label: 'Quality of shows',
maxStars: 5,
size: 'md'
}, '1fr');
row.addStarRating('activityVariety', {
label: 'Variety of activities',
maxStars: 5,
size: 'md'
}, '1fr');
});
const excursionSection = page4.addSubform('excursionSection', {
title: 'Shore Excursions',
customStyles: { backgroundColor: '#ecfdf5', padding: '20px', borderRadius: '8px' }
});
excursionSection.addRow(row => {
row.addRadioButton('tookExcursions', {
label: 'Did you take any shore excursions?',
options: [
{ id: 'ship', name: 'Yes, booked through the ship' },
{ id: 'independent', name: 'Yes, independently booked' },
{ id: 'both', name: 'Both ship and independent' },
{ id: 'none', name: 'No excursions taken' }
],
orientation: 'vertical'
});
});
excursionSection.addRow(row => {
row.addStarRating('excursionValue', {
label: 'Excursion value for money',
maxStars: 5,
size: 'md',
isVisible: () => {
const took = excursionSection.radioButton('tookExcursions')?.value();
return took === 'ship' || took === 'both';
}
}, '1fr');
row.addStarRating('excursionQuality', {
label: 'Excursion quality',
maxStars: 5,
size: 'md',
isVisible: () => {
const took = excursionSection.radioButton('tookExcursions')?.value();
return took === 'ship' || took === 'both';
}
}, '1fr');
});
page4.addRow(row => {
row.addButton('prevPage4', {
label: '← Back',
onClick: () => pages.goToPage('dining')
});
row.addButton('nextPage4', {
label: 'Next: Overall →',
onClick: () => pages.goToPage('overall')
});
});
// ============================================
// PAGE 5: Overall Experience
// ============================================
const page5 = pages.addPage('overall');
page5.addRow(row => {
row.addTextPanel('page5Title', {
label: '',
computedValue: () => '⭐ Overall Experience',
customStyles: { fontSize: '18px', fontWeight: 'bold', marginBottom: '16px', color: '#0369a1' }
});
});
const overallSection = page5.addSubform('overallSection', {
title: 'Your Overall Rating',
customStyles: { backgroundColor: '#fef9c3', padding: '20px', borderRadius: '8px' }
});
overallSection.addRow(row => {
row.addStarRating('overallExperience', {
label: 'Overall cruise experience',
maxStars: 5,
size: 'xl',
alignment: 'center',
showConfettiOnMax: true,
onValueChange: (value) => overallRating.set(value ?? null)
});
});
overallSection.addRow(row => {
row.addSlider('valueForMoney', {
label: 'Value for money',
min: 0,
max: 100,
step: 5,
defaultValue: 50,
unit: '%',
showValue: true
});
});
overallSection.addRow(row => {
row.addTextPanel('valueLabel', {
computedValue: () => {
const value = overallSection.slider('valueForMoney')?.value() ?? 50;
if (value >= 80) return 'Excellent value! The cruise exceeded expectations.';
if (value >= 60) return 'Good value for the price paid.';
if (value >= 40) return 'Fair value, met basic expectations.';
return 'Below expectations for the price.';
},
customStyles: () => {
const value = overallSection.slider('valueForMoney')?.value() ?? 50;
const baseStyles = { fontSize: '13px', padding: '8px', borderRadius: '4px', textAlign: 'center' };
if (value >= 60) return { ...baseStyles, backgroundColor: '#dcfce7', color: '#166534' };
if (value >= 40) return { ...baseStyles, backgroundColor: '#fef9c3', color: '#854d0e' };
return { ...baseStyles, backgroundColor: '#fee2e2', color: '#991b1b' };
}
});
});
const recommendSection = page5.addSubform('recommendSection', {
title: 'Recommendation',
customStyles: { backgroundColor: '#eff6ff', padding: '20px', borderRadius: '8px' }
});
recommendSection.addRow(row => {
row.addRatingScale('npsScore', {
preset: 'nps',
label: 'How likely are you to recommend this cruise line to friends or family?',
showCategoryLabel: true,
showSegmentColors: true,
showConfettiOnPromoter: true
});
});
recommendSection.addRow(row => {
row.addThumbRating('wouldCruiseAgain', {
label: 'Would you cruise with us again?',
showLabels: true,
upLabel: 'Definitely yes!',
downLabel: 'Probably not',
size: 'lg',
alignment: 'center'
});
});
// Highlights and improvements
const feedbackSection = page5.addSubform('feedbackSection', {
title: 'Final Thoughts',
customStyles: { padding: '20px', borderRadius: '8px', border: '1px solid #e2e8f0' }
});
feedbackSection.addRow(row => {
row.addSuggestionChips('highlights', {
label: 'What were the highlights of your cruise? (Select up to 3)',
suggestions: [
{ id: 'cabin', name: 'Cabin quality' },
{ id: 'food', name: 'Food & dining' },
{ id: 'service', name: 'Crew service' },
{ id: 'entertainment', name: 'Entertainment' },
{ id: 'destinations', name: 'Destinations' },
{ id: 'excursions', name: 'Shore excursions' },
{ id: 'relaxation', name: 'Relaxation' },
{ id: 'amenities', name: 'Ship amenities' }
],
max: 3,
alignment: 'center'
});
});
feedbackSection.addSpacer();
feedbackSection.addRow(row => {
row.addTextarea('additionalComments', {
label: 'Any additional comments or suggestions?',
placeholder: 'Share what you loved, what could be improved, or any memorable experiences...',
rows: 4,
autoExpand: true
});
});
// Summary
const summarySection = page5.addSubform('summary', {
title: 'Your Feedback Summary'
});
summarySection.addRow(row => {
row.addTextPanel('summaryContent', {
computedValue: () => {
const cruiseLength = voyageSection.dropdown('cruiseLength')?.value();
const cabinType = voyageSection.dropdown('cabinType')?.value();
const overall = overallRating();
const nps = recommendSection.ratingScale('npsScore')?.value();
const wouldReturn = recommendSection.thumbRating('wouldCruiseAgain')?.value();
const highlights = feedbackSection.suggestionChips('highlights')?.value() || [];
const value = overallSection.slider('valueForMoney')?.value() ?? 50;
const lengthLabels: Record<string, string> = {
'3-4': '3-4 nights',
'5-7': '5-7 nights',
'8-10': '8-10 nights',
'11-14': '11-14 nights',
'15+': '15+ nights'
};
const cabinLabels: Record<string, string> = {
'interior': 'Interior',
'oceanview': 'Ocean View',
'balcony': 'Balcony',
'suite': 'Suite',
'penthouse': 'Penthouse'
};
let summary = '🚢 Cruise Feedback Summary\n';
summary += `${'═'.repeat(35)}\n\n`;
summary += `📅 Duration: ${lengthLabels[cruiseLength || ''] || 'Not specified'}\n`;
summary += `🛏️ Cabin: ${cabinLabels[cabinType || ''] || 'Not specified'}\n`;
if (overall) {
summary += `\n⭐ Overall: ${overall}/5 stars`;
}
summary += `\n💰 Value: ${value}%`;
if (nps !== null && nps !== undefined) {
const category = nps >= 9 ? 'Promoter' : nps >= 7 ? 'Passive' : 'Detractor';
summary += `\n📢 NPS: ${nps}/10 (${category})`;
}
if (wouldReturn) {
summary += `\n🔄 Would Return: ${wouldReturn === 'up' ? 'Yes!' : 'Unlikely'}`;
}
if (highlights.length > 0) {
summary += `\n\n✨ Highlights: ${highlights.length} selected`;
}
return summary;
},
customStyles: () => {
const overall = overallRating();
const baseStyles = {
padding: '20px',
borderRadius: '8px',
whiteSpace: 'pre-wrap',
fontFamily: 'monospace',
fontSize: '14px'
};
if (overall && overall >= 4) {
return { ...baseStyles, backgroundColor: '#dcfce7', borderLeft: '4px solid #22c55e' };
} else if (overall && overall >= 3) {
return { ...baseStyles, backgroundColor: '#fef9c3', borderLeft: '4px solid #eab308' };
} else if (overall && overall < 3) {
return { ...baseStyles, backgroundColor: '#fee2e2', borderLeft: '4px solid #ef4444' };
}
return { ...baseStyles, backgroundColor: '#f0f9ff', borderLeft: '4px solid #0284c7' };
}
});
});
page5.addRow(row => {
row.addButton('prevPage5', {
label: '← Back to Entertainment',
onClick: () => pages.goToPage('entertainment')
});
});
// ============================================
// FORM CONFIGURATION
// ============================================
form.configureSubmitButton({
label: () => {
const currentPage = pages.currentPageIndex();
if (currentPage < 4) return 'Continue Survey';
return 'Submit Cruise Feedback';
},
isVisible: () => pages.currentPageIndex() === 4
});
form.configureCompletionScreen({
type: 'text',
title: () => {
const wouldReturn = recommendSection.thumbRating('wouldCruiseAgain')?.value();
if (wouldReturn === 'up') return 'Thank You - See You on Board Again!';
return 'Thank You for Your Feedback!';
},
message: () => {
const overall = overallRating();
if (overall && overall >= 4) {
return 'We are thrilled you had a wonderful cruise experience! Your detailed feedback helps us maintain and improve our service. We look forward to welcoming you aboard again.';
}
return 'Your comprehensive feedback is invaluable to us. We review every survey to continually improve the cruise experience. Thank you for taking the time to share your thoughts.';
}
});
}