export function tourFeedbackForm(form: FormTs) {
// Tour & Excursion Feedback Form
// Demonstrates: StarRating, EmojiRating, MatrixQuestion, SuggestionChips, RatingScale (NPS), Slider, conditional visibility
// ============================================
// HEADER
// ============================================
form.addRow(row => {
row.addTextPanel('header', {
label: 'Share Your Tour Experience',
computedValue: () => 'Your feedback helps us create unforgettable adventures.',
customStyles: {
backgroundColor: '#059669',
color: 'white',
padding: '24px',
borderRadius: '12px',
textAlign: 'center'
}
});
});
// ============================================
// SECTION 1: Tour Information
// ============================================
const tourInfoSection = form.addSubform('tourInfo', {
title: 'Tour Details'
});
tourInfoSection.addRow(row => {
row.addTextbox('tourName', {
label: 'Tour or excursion name',
placeholder: 'e.g., Sunset Sailing Adventure',
isRequired: true
}, '1fr');
row.addDatepicker('tourDate', {
label: 'Date of tour',
isRequired: true
}, '1fr');
});
tourInfoSection.addRow(row => {
row.addDropdown('tourType', {
label: 'Type of experience',
options: [
{ id: 'guided-tour', name: 'Guided sightseeing tour' },
{ id: 'adventure', name: 'Adventure / outdoor activity' },
{ id: 'cultural', name: 'Cultural / historical tour' },
{ id: 'food-wine', name: 'Food & wine experience' },
{ id: 'nature', name: 'Nature / wildlife tour' },
{ id: 'water', name: 'Water activity / cruise' },
{ id: 'multi-day', name: 'Multi-day tour' },
{ id: 'other', name: 'Other' }
],
placeholder: 'Select tour type'
}, '1fr');
row.addDropdown('groupSize', {
label: 'Group size',
options: [
{ id: 'private', name: 'Private tour (just my party)' },
{ id: 'small', name: 'Small group (2-10 people)' },
{ id: 'medium', name: 'Medium group (11-25 people)' },
{ id: 'large', name: 'Large group (25+ people)' }
],
placeholder: 'Select group size'
}, '1fr');
});
// ============================================
// SECTION 2: Overall Experience
// ============================================
const overallSection = form.addSubform('overallExperience', {
title: 'Overall Experience',
customStyles: () => {
const rating = overallSection.starRating('overallRating')?.value();
if (rating && rating >= 4) return { backgroundColor: '#dcfce7', padding: '16px', borderRadius: '8px' };
if (rating && rating <= 2) return { backgroundColor: '#fee2e2', padding: '16px', borderRadius: '8px' };
return { padding: '16px', borderRadius: '8px' };
}
});
overallSection.addRow(row => {
row.addStarRating('overallRating', {
label: 'How would you rate your overall tour experience?',
maxStars: 5,
size: 'xl',
alignment: 'center',
showConfettiOnMax: true
});
});
overallSection.addRow(row => {
row.addEmojiRating('emotionalExperience', {
label: 'How did this tour make you feel?',
preset: 'mood',
size: 'lg',
alignment: 'center'
});
});
// ============================================
// SECTION 3: Tour Guide Rating
// ============================================
const guideSection = form.addSubform('guideRating', {
title: 'Your Tour Guide'
});
guideSection.addRow(row => {
row.addTextbox('guideName', {
label: 'Guide name (if you remember)',
placeholder: 'Optional'
});
});
guideSection.addRow(row => {
row.addMatrixQuestion('guideMatrix', {
label: 'Rate your tour guide on the following:',
rows: [
{ id: 'knowledge', label: 'Knowledge and expertise', isRequired: true },
{ id: 'communication', label: 'Communication and clarity', isRequired: true },
{ id: 'enthusiasm', label: 'Enthusiasm and energy' },
{ id: 'friendliness', label: 'Friendliness and approachability' },
{ id: 'flexibility', label: 'Flexibility and responsiveness' },
{ id: 'safety', label: 'Safety awareness' }
],
columns: [
{ id: '1', label: 'Poor' },
{ id: '2', label: 'Fair' },
{ id: '3', label: 'Good' },
{ id: '4', label: 'Very Good' },
{ id: '5', label: 'Excellent' }
],
striped: true,
fullWidth: true
});
});
// ============================================
// SECTION 4: Tour Components
// ============================================
const componentsSection = form.addSubform('tourComponents', {
title: 'Tour Components'
});
componentsSection.addRow(row => {
row.addStarRating('activitiesRating', {
label: 'Quality of activities and experiences',
maxStars: 5,
size: 'lg',
alignment: 'center'
}, '1fr');
row.addStarRating('locationsRating', {
label: 'Locations visited',
maxStars: 5,
size: 'lg',
alignment: 'center'
}, '1fr');
});
componentsSection.addRow(row => {
row.addStarRating('paceRating', {
label: 'Pace and timing of the tour',
maxStars: 5,
size: 'lg',
alignment: 'center'
}, '1fr');
row.addStarRating('transportRating', {
label: 'Transportation quality',
maxStars: 5,
size: 'lg',
alignment: 'center'
}, '1fr');
});
componentsSection.addRow(row => {
row.addSlider('lengthFeel', {
label: 'How did you feel about the tour length?',
min: 1,
max: 5,
step: 1,
defaultValue: 3,
showValue: false
});
});
componentsSection.addRow(row => {
row.addTextPanel('lengthScale', {
computedValue: () => {
const value = componentsSection.slider('lengthFeel')?.value();
const labels = ['Much too short', 'A bit short', 'Just right', 'A bit long', 'Much too long'];
return labels[(value || 3) - 1];
},
customStyles: {
textAlign: 'center',
fontStyle: 'italic',
color: '#64748b'
}
});
});
// ============================================
// SECTION 5: Value & Expectations
// ============================================
const valueSection = form.addSubform('valueExpectations', {
title: 'Value & Expectations'
});
valueSection.addRow(row => {
row.addRatingScale('valueForMoney', {
label: 'How would you rate the value for money?',
preset: 'satisfaction',
lowLabel: 'Very poor value',
highLabel: 'Excellent value',
alignment: 'center'
});
});
valueSection.addRow(row => {
row.addRadioButton('metExpectations', {
label: 'Did the tour meet your expectations?',
options: [
{ id: 'exceeded', name: 'Exceeded expectations' },
{ id: 'met', name: 'Met expectations' },
{ id: 'below', name: 'Below expectations' }
],
orientation: 'horizontal'
});
});
valueSection.addRow(row => {
row.addTextarea('expectationsDetail', {
label: () => {
const met = valueSection.radioButton('metExpectations')?.value();
if (met === 'exceeded') return 'What exceeded your expectations?';
if (met === 'below') return 'What fell short of your expectations?';
return 'Any comments on expectations?';
},
placeholder: 'Share details...',
rows: 2,
autoExpand: true,
isVisible: () => valueSection.radioButton('metExpectations')?.value() !== null
});
});
// ============================================
// SECTION 6: Highlights
// ============================================
const highlightsSection = form.addSubform('highlights', {
title: 'Tour Highlights',
isVisible: () => {
const rating = overallSection.starRating('overallRating')?.value();
return rating !== null && rating !== undefined && rating >= 3;
}
});
highlightsSection.addRow(row => {
row.addSuggestionChips('bestParts', {
label: 'What were the best parts of the tour? (Select all that apply)',
suggestions: [
{ id: 'guide', name: 'The guide' },
{ id: 'locations', name: 'Beautiful locations' },
{ id: 'activities', name: 'Fun activities' },
{ id: 'learning', name: 'Learning new things' },
{ id: 'food', name: 'Food & refreshments' },
{ id: 'group', name: 'Great group' },
{ id: 'photos', name: 'Photo opportunities' },
{ id: 'unique', name: 'Unique experiences' }
],
alignment: 'center'
});
});
// ============================================
// SECTION 7: Improvements
// ============================================
const improvementsSection = form.addSubform('improvements', {
title: 'Areas for Improvement',
isVisible: () => {
const rating = overallSection.starRating('overallRating')?.value();
return rating !== null && rating !== undefined && rating <= 4;
}
});
improvementsSection.addRow(row => {
row.addSuggestionChips('improvementAreas', {
label: 'What could be improved?',
suggestions: [
{ id: 'guide-knowledge', name: 'Guide knowledge' },
{ id: 'pace', name: 'Tour pace' },
{ id: 'communication', name: 'Communication' },
{ id: 'transport', name: 'Transportation' },
{ id: 'timing', name: 'Timing/schedule' },
{ id: 'group-size', name: 'Group size' },
{ id: 'food', name: 'Food quality' },
{ id: 'value', name: 'Value for money' }
],
alignment: 'center'
});
});
improvementsSection.addSpacer();
improvementsSection.addRow(row => {
row.addTextarea('improvementDetails', {
label: 'Please share specific suggestions for improvement',
placeholder: 'Your suggestions help us create better experiences...',
rows: 3,
autoExpand: true
});
});
// ============================================
// SECTION 8: Recommendation
// ============================================
const npsSection = form.addSubform('recommendation', {
title: 'Would You Recommend?',
customStyles: () => {
const category = npsSection.ratingScale('tourNps')?.npsCategory();
if (category === 'promoter') return { backgroundColor: '#d1fae5', padding: '16px', borderRadius: '8px' };
if (category === 'passive') return { backgroundColor: '#fef3c7', padding: '16px', borderRadius: '8px' };
if (category === 'detractor') return { backgroundColor: '#fee2e2', padding: '16px', borderRadius: '8px' };
return { padding: '16px', borderRadius: '8px' };
}
});
npsSection.addRow(row => {
row.addRatingScale('tourNps', {
label: 'How likely are you to recommend this tour to friends?',
preset: 'nps',
showSegmentColors: true,
showCategoryLabel: true,
showConfettiOnPromoter: true,
isRequired: true
});
});
npsSection.addRow(row => {
row.addCheckbox('wouldBookAgain', {
label: 'I would book another tour with this company',
isVisible: () => npsSection.ratingScale('tourNps')?.value() !== null
});
});
// ============================================
// SECTION 9: Final Comments
// ============================================
const commentsSection = form.addSubform('finalComments', {
title: 'Additional Thoughts',
isVisible: () => npsSection.ratingScale('tourNps')?.value() !== null
});
commentsSection.addSpacer();
commentsSection.addRow(row => {
row.addTextarea('memorableComment', {
label: 'What will you remember most about this tour?',
placeholder: 'Share your most memorable moment...',
rows: 2,
autoExpand: true
});
});
commentsSection.addSpacer();
commentsSection.addRow(row => {
row.addTextarea('additionalFeedback', {
label: 'Any other feedback for us?',
placeholder: 'Share any additional thoughts or suggestions...',
rows: 2,
autoExpand: true
});
});
// ============================================
// SECTION 10: Summary
// ============================================
const summarySection = form.addSubform('summary', {
title: 'Your Feedback Summary',
isVisible: () => npsSection.ratingScale('tourNps')?.value() !== null
});
summarySection.addRow(row => {
row.addTextPanel('summaryContent', {
computedValue: () => {
const tourName = tourInfoSection.textbox('tourName')?.value();
const overall = overallSection.starRating('overallRating')?.value();
const emotion = overallSection.emojiRating('emotionalExperience')?.value();
const nps = npsSection.ratingScale('tourNps')?.value();
const category = npsSection.ratingScale('tourNps')?.npsCategory();
const wouldBook = npsSection.checkbox('wouldBookAgain')?.value();
const highlights = highlightsSection.suggestionChips('bestParts')?.value() || [];
if (!nps) return '';
const emotionLabels: Record<string, string> = {
'sad': 'Disappointed',
'down': 'Underwhelmed',
'neutral': 'Neutral',
'happy': 'Happy',
'excited': 'Thrilled'
};
let summary = `Tour Feedback Summary\n`;
summary += `${'═'.repeat(25)}\n\n`;
if (tourName) summary += `Tour: ${tourName}\n`;
if (overall) {
summary += `Overall: ${'★'.repeat(overall)}${'☆'.repeat(5 - overall)}\n`;
}
if (emotion) {
summary += `Feeling: ${emotionLabels[emotion] || emotion}\n`;
}
summary += `\nNPS: ${nps}/10`;
if (category) {
const label = category === 'promoter' ? ' (Promoter)' :
category === 'passive' ? ' (Passive)' : ' (Detractor)';
summary += label;
}
if (highlights.length > 0) {
summary += `\n\nHighlights: ${highlights.length} selected`;
}
if (wouldBook !== null && wouldBook !== undefined) {
summary += `\n\nWould book again: ${wouldBook ? 'Yes' : 'Maybe not'}`;
}
return summary;
},
customStyles: () => {
const category = npsSection.ratingScale('tourNps')?.npsCategory();
const baseStyles = {
padding: '16px',
borderRadius: '8px',
whiteSpace: 'pre-wrap',
fontFamily: 'monospace',
fontSize: '14px'
};
if (category === 'promoter') {
return { ...baseStyles, backgroundColor: '#d1fae5', borderLeft: '4px solid #10b981' };
} else if (category === 'passive') {
return { ...baseStyles, backgroundColor: '#fef3c7', borderLeft: '4px solid #f59e0b' };
} else if (category === 'detractor') {
return { ...baseStyles, backgroundColor: '#fee2e2', borderLeft: '4px solid #ef4444' };
}
return { ...baseStyles, backgroundColor: '#f1f5f9' };
}
});
});
// ============================================
// FORM CONFIGURATION
// ============================================
form.configureSubmitButton({
label: 'Submit Tour Feedback',
isVisible: () => npsSection.ratingScale('tourNps')?.value() !== null
});
form.configureCompletionScreen({
type: 'text',
title: 'Thank you for your tour feedback!',
message: 'Your insights help us create even better adventures. We hope to welcome you on another journey soon!'
});
}