export function customerJourneyFeedback(form: FormTs) {
// Customer Journey Feedback Survey - Multi-page journey mapping
// Demonstrates: Pages (multi-page wizard), StarRating, MatrixQuestion, EmojiRating,
// RatingScale (NPS), dynamic labels, conditional visibility, computed values
// ============================================
// STATE - Track journey scores
// ============================================
const discoveryScore = form.state<number | null>(null);
const purchaseScore = form.state<number | null>(null);
const deliveryScore = form.state<number | null>(null);
const supportScore = form.state<number | null>(null);
// Computed average journey score
const averageScore = form.computedValue(() => {
const scores = [discoveryScore(), purchaseScore(), deliveryScore(), supportScore()].filter(s => s !== null) as number[];
if (scores.length === 0) return null;
return Math.round((scores.reduce((a, b) => a + b, 0) / scores.length) * 10) / 10;
});
// ============================================
// HEADER
// ============================================
form.addRow(row => {
row.addTextPanel('header', {
label: 'Your Journey With Us',
computedValue: () => 'Help us understand your complete experience - from discovery to support.',
customStyles: {
background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
color: 'white',
padding: '28px',
borderRadius: '12px',
textAlign: 'center',
fontSize: '14px'
}
});
});
// ============================================
// MULTI-PAGE JOURNEY WIZARD
// ============================================
const pages = form.addPages('journeyPages', {
heightMode: 'current-page'
});
// ============================================
// PAGE 1: DISCOVERY STAGE
// ============================================
const discoveryPage = pages.addPage('discovery');
discoveryPage.addRow(row => {
row.addTextPanel('discoveryHeader', {
label: 'Stage 1 of 5',
computedValue: () => 'Discovery & Research',
customStyles: {
backgroundColor: '#f0f9ff',
color: '#0369a1',
padding: '16px',
borderRadius: '8px',
fontWeight: 'bold',
textAlign: 'center'
}
});
});
discoveryPage.addRow(row => {
row.addStarRating('discoveryRating', {
label: 'How was your experience finding and learning about our product/service?',
maxStars: 5,
size: 'lg',
alignment: 'center',
showConfettiOnMax: true,
onValueChange: (v) => discoveryScore.set(v ?? null)
});
});
discoveryPage.addRow(row => {
row.addMatrixQuestion('discoveryMatrix', {
label: 'Rate these discovery aspects:',
rows: [
{ id: 'findability', label: 'Easy to find information', isRequired: true },
{ id: 'clarity', label: 'Clear product descriptions' },
{ id: 'comparison', label: 'Easy to compare options' },
{ id: 'trust', label: 'Trustworthy reviews/testimonials' }
],
columns: [
{ id: 'poor', label: 'Poor' },
{ id: 'fair', label: 'Fair' },
{ id: 'good', label: 'Good' },
{ id: 'excellent', label: 'Excellent' }
],
fullWidth: true
});
});
discoveryPage.addRow(row => {
row.addCheckboxList('discoveryChannels', {
label: 'How did you discover us? (Select all that apply)',
options: [
{ id: 'search', name: 'Search engine' },
{ id: 'social', name: 'Social media' },
{ id: 'referral', name: 'Friend/colleague referral' },
{ id: 'ads', name: 'Online advertising' },
{ id: 'content', name: 'Blog/content' },
{ id: 'other', name: 'Other' }
],
orientation: 'vertical'
});
});
discoveryPage.addSpacer({ height: '20px' });
discoveryPage.addRow(row => {
row.addButton('nextToPage2', {
label: 'Continue to Purchase Experience',
onClick: () => pages.goToPage('purchase')
});
});
// ============================================
// PAGE 2: PURCHASE STAGE
// ============================================
const purchasePage = pages.addPage('purchase');
purchasePage.addRow(row => {
row.addTextPanel('purchaseHeader', {
label: 'Stage 2 of 5',
computedValue: () => 'Purchase Experience',
customStyles: {
backgroundColor: '#fef3c7',
color: '#92400e',
padding: '16px',
borderRadius: '8px',
fontWeight: 'bold',
textAlign: 'center'
}
});
});
purchasePage.addRow(row => {
row.addStarRating('purchaseRating', {
label: 'How smooth was the purchasing process?',
maxStars: 5,
size: 'lg',
alignment: 'center',
showConfettiOnMax: true,
onValueChange: (v) => purchaseScore.set(v ?? null)
});
});
purchasePage.addRow(row => {
row.addRatingScale('purchaseEffort', {
label: 'How much effort did it take to complete your purchase?',
preset: 'ces',
showSegmentColors: true,
alignment: 'center'
});
});
purchasePage.addRow(row => {
row.addSuggestionChips('purchasePainPoints', {
label: 'Did you experience any issues? (Select all that apply)',
suggestions: [
{ id: 'none', name: 'No issues' },
{ id: 'pricing', name: 'Confusing pricing' },
{ id: 'checkout', name: 'Complex checkout' },
{ id: 'payment', name: 'Payment problems' },
{ id: 'info', name: 'Missing information' },
{ id: 'slow', name: 'Slow website' }
],
alignment: 'center'
});
});
purchasePage.addSpacer({ height: '20px' });
purchasePage.addRow(row => {
row.addButton('backToPage1', {
label: 'Back',
onClick: () => pages.goToPage('discovery')
}, '1fr');
row.addButton('nextToPage3', {
label: 'Continue to Delivery',
onClick: () => pages.goToPage('delivery')
}, '2fr');
});
// ============================================
// PAGE 3: DELIVERY STAGE
// ============================================
const deliveryPage = pages.addPage('delivery');
deliveryPage.addRow(row => {
row.addTextPanel('deliveryHeader', {
label: 'Stage 3 of 5',
computedValue: () => 'Delivery & Onboarding',
customStyles: {
backgroundColor: '#dcfce7',
color: '#166534',
padding: '16px',
borderRadius: '8px',
fontWeight: 'bold',
textAlign: 'center'
}
});
});
deliveryPage.addRow(row => {
row.addStarRating('deliveryRating', {
label: 'How was the delivery/onboarding experience?',
maxStars: 5,
size: 'lg',
alignment: 'center',
showConfettiOnMax: true,
onValueChange: (v) => deliveryScore.set(v ?? null)
});
});
deliveryPage.addRow(row => {
row.addEmojiRating('deliveryMood', {
label: 'How did the delivery/setup process make you feel?',
preset: 'satisfaction',
size: 'lg',
alignment: 'center'
});
});
deliveryPage.addRow(row => {
row.addRadioButton('deliveryTimeliness', {
label: 'Was delivery/setup completed on time?',
options: [
{ id: 'early', name: 'Earlier than expected' },
{ id: 'ontime', name: 'On time' },
{ id: 'late', name: 'Slightly delayed' },
{ id: 'verylate', name: 'Significantly delayed' }
],
orientation: 'vertical'
});
});
deliveryPage.addRow(row => {
row.addTextarea('deliveryFeedback', {
label: () => {
const rating = deliveryScore();
if (rating !== null && rating <= 2) return 'What went wrong with delivery/onboarding?';
return 'Any comments about the delivery/onboarding experience?';
},
placeholder: 'Your feedback helps us improve...',
rows: 3,
isVisible: () => deliveryScore() !== null
});
});
deliveryPage.addSpacer({ height: '20px' });
deliveryPage.addRow(row => {
row.addButton('backToPage2', {
label: 'Back',
onClick: () => pages.goToPage('purchase')
}, '1fr');
row.addButton('nextToPage4', {
label: 'Continue to Support',
onClick: () => pages.goToPage('support')
}, '2fr');
});
// ============================================
// PAGE 4: SUPPORT STAGE
// ============================================
const supportPage = pages.addPage('support');
supportPage.addRow(row => {
row.addTextPanel('supportHeader', {
label: 'Stage 4 of 5',
computedValue: () => 'Support & Service',
customStyles: {
backgroundColor: '#fce7f3',
color: '#9d174d',
padding: '16px',
borderRadius: '8px',
fontWeight: 'bold',
textAlign: 'center'
}
});
});
supportPage.addRow(row => {
row.addRadioButton('supportUsed', {
label: 'Have you contacted our support team?',
options: [
{ id: 'yes', name: 'Yes, I have' },
{ id: 'no', name: 'No, not needed' },
{ id: 'notyet', name: 'Not yet, but I might' }
],
orientation: 'horizontal'
});
});
const supportRatingSection = supportPage.addSubform('supportRatingSection', {
isVisible: () => supportPage.radioButton('supportUsed')?.value() === 'yes'
});
supportRatingSection.addRow(row => {
row.addStarRating('supportRating', {
label: 'How would you rate the support you received?',
maxStars: 5,
size: 'lg',
alignment: 'center',
showConfettiOnMax: true,
onValueChange: (v) => supportScore.set(v ?? null)
});
});
supportRatingSection.addRow(row => {
row.addMatrixQuestion('supportMatrix', {
label: 'Rate our support team:',
rows: [
{ id: 'response', label: 'Response time' },
{ id: 'knowledge', label: 'Knowledge/expertise' },
{ id: 'friendliness', label: 'Friendliness' },
{ id: 'resolution', label: 'Problem resolution' }
],
columns: [
{ id: 'poor', label: 'Poor' },
{ id: 'fair', label: 'Fair' },
{ id: 'good', label: 'Good' },
{ id: 'excellent', label: 'Excellent' }
],
fullWidth: true
});
});
supportPage.addSpacer({ height: '20px' });
supportPage.addRow(row => {
row.addButton('backToPage3', {
label: 'Back',
onClick: () => pages.goToPage('delivery')
}, '1fr');
row.addButton('nextToPage5', {
label: 'Continue to Summary',
onClick: () => pages.goToPage('summary')
}, '2fr');
});
// ============================================
// PAGE 5: OVERALL SUMMARY
// ============================================
const summaryPage = pages.addPage('summary');
summaryPage.addRow(row => {
row.addTextPanel('summaryHeader', {
label: 'Stage 5 of 5',
computedValue: () => 'Overall Experience',
customStyles: {
background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
color: 'white',
padding: '16px',
borderRadius: '8px',
fontWeight: 'bold',
textAlign: 'center'
}
});
});
// Journey Score Summary
summaryPage.addRow(row => {
row.addTextPanel('journeyScoreSummary', {
label: 'Your Journey Scores',
computedValue: () => {
const discovery = discoveryScore();
const purchase = purchaseScore();
const delivery = deliveryScore();
const support = supportScore();
const avg = averageScore();
let summary = '';
summary += `Discovery: ${discovery !== null ? '★'.repeat(discovery) + '☆'.repeat(5 - discovery) : 'Not rated'}\n`;
summary += `Purchase: ${purchase !== null ? '★'.repeat(purchase) + '☆'.repeat(5 - purchase) : 'Not rated'}\n`;
summary += `Delivery: ${delivery !== null ? '★'.repeat(delivery) + '☆'.repeat(5 - delivery) : 'Not rated'}\n`;
summary += `Support: ${support !== null ? '★'.repeat(support) + '☆'.repeat(5 - support) : 'N/A'}\n`;
summary += `${'─'.repeat(30)}\n`;
summary += `Average Score: ${avg !== null ? avg + '/5' : 'Incomplete'}`;
return summary;
},
customStyles: () => {
const avg = averageScore();
return {
padding: '20px',
borderRadius: '8px',
whiteSpace: 'pre-wrap',
fontFamily: 'monospace',
fontSize: '14px',
backgroundColor: avg !== null && avg >= 4 ? '#dcfce7' : avg !== null && avg >= 3 ? '#fef3c7' : '#fee2e2',
borderLeft: avg !== null && avg >= 4 ? '4px solid #22c55e' : avg !== null && avg >= 3 ? '4px solid #f59e0b' : '4px solid #ef4444'
};
}
});
});
summaryPage.addRow(row => {
row.addRatingScale('npsScore', {
label: 'Based on your complete journey, how likely are you to recommend us?',
preset: 'nps',
showSegmentColors: true,
showCategoryLabel: true,
showConfettiOnPromoter: true,
alignment: 'center'
});
});
summaryPage.addRow(row => {
row.addThumbRating('wouldRepeat', {
label: 'Would you go through this journey again with us?',
showLabels: true,
upLabel: 'Yes, definitely!',
downLabel: 'Probably not',
alignment: 'center',
size: 'lg'
});
});
summaryPage.addSpacer({ height: '20px' });
summaryPage.addRow(row => {
row.addTextarea('overallFeedback', {
label: () => {
const nps = summaryPage.ratingScale('npsScore')?.value();
const category = summaryPage.ratingScale('npsScore')?.npsCategory();
if (category === 'promoter') return 'What made your journey exceptional?';
if (category === 'detractor') return 'What could we have done better throughout your journey?';
return 'Any additional feedback about your experience?';
},
placeholder: 'Share your thoughts...',
rows: 4,
autoExpand: true
});
});
summaryPage.addSpacer({ height: '20px' });
summaryPage.addRow(row => {
row.addButton('backToPage4', {
label: 'Back',
onClick: () => pages.goToPage('support')
});
});
// ============================================
// FORM CONFIGURATION
// ============================================
form.configureSubmitButton({
label: () => {
const avg = averageScore();
if (avg !== null && avg >= 4) return 'Submit Great Journey!';
return 'Submit Feedback';
},
isVisible: () => pages.currentPageIndex() === 4
});
form.configureCompletionScreen({
type: 'text',
title: () => {
const avg = averageScore();
if (avg !== null && avg >= 4) return 'Thank You for the Kind Words!';
if (avg !== null && avg >= 3) return 'Thank You for Your Feedback!';
return 'We Appreciate Your Honesty';
},
message: () => {
const avg = averageScore();
if (avg !== null && avg >= 4) {
return 'We\'re thrilled you had a great experience! Your feedback helps us maintain our high standards.';
}
if (avg !== null && avg >= 3) {
return 'Thank you for taking the time to share your journey. Your insights help us improve every touchpoint.';
}
return 'We\'re sorry your experience wasn\'t perfect. Your detailed feedback will help us make meaningful improvements.';
}
});
}