export function csatTouchpointForm(form: FormTs) {
// Touchpoint CSAT Survey - Multi-page customer journey satisfaction
// Demonstrates: Pages (multi-page wizard), StarRating per touchpoint, EmojiRating, RatingScale, dynamic labels, conditional visibility
// Track scores for summary
const scores = form.state<Record<string, number | null>>({
discovery: null,
consideration: null,
purchase: null,
delivery: null,
support: null
});
// ============================================
// HEADER (always visible)
// ============================================
form.addRow(row => {
row.addTextPanel('header', {
label: 'Your Journey With Us',
computedValue: () => 'Rate your experience at each step of your journey.',
customStyles: {
backgroundColor: '#14b8a6',
color: 'white',
padding: '24px',
borderRadius: '12px',
textAlign: 'center'
}
});
});
// ============================================
// MULTI-PAGE JOURNEY
// ============================================
const pages = form.addPages('journeyPages', {
heightMode: 'current-page'
});
// --- PAGE 1: Discovery ---
const discoveryPage = pages.addPage('discovery');
discoveryPage.addRow(row => {
row.addTextPanel('discoveryTitle', {
label: 'Step 1 of 5: Discovery',
computedValue: () => 'How did you first learn about us?',
customStyles: {
backgroundColor: '#f0fdfa',
padding: '16px',
borderRadius: '8px',
textAlign: 'center',
borderLeft: '4px solid #14b8a6'
}
});
});
discoveryPage.addRow(row => {
row.addDropdown('discoveryChannel', {
label: 'How did you discover us?',
options: [
{ id: 'search', name: 'Search engine (Google, Bing)' },
{ id: 'social', name: 'Social media' },
{ id: 'referral', name: 'Friend or colleague referral' },
{ id: 'ad', name: 'Online advertisement' },
{ id: 'review', name: 'Review site' },
{ id: 'other', name: 'Other' }
],
placeholder: 'Select channel',
isRequired: true
});
});
discoveryPage.addRow(row => {
row.addStarRating('discoveryRating', {
label: 'How easy was it to find the information you needed?',
maxStars: 5,
size: 'lg',
alignment: 'center',
onValueChange: (value) => {
scores.update(s => ({ ...s, discovery: value ?? null }));
}
});
});
discoveryPage.addRow(row => {
row.addTextarea('discoveryFeedback', {
label: 'Any comments about finding us?',
placeholder: 'Optional: Share your discovery experience...',
rows: 2,
isVisible: () => {
const rating = discoveryPage.starRating('discoveryRating')?.value();
return rating !== null && rating !== undefined;
}
});
});
discoveryPage.addRow(row => {
row.addButton('nextToConsideration', {
label: 'Next: Consideration Phase →',
onClick: () => pages.goToPage('consideration'),
isVisible: () => discoveryPage.starRating('discoveryRating')?.value() !== null
});
});
// --- PAGE 2: Consideration ---
const considerationPage = pages.addPage('consideration');
considerationPage.addRow(row => {
row.addTextPanel('considerationTitle', {
label: 'Step 2 of 5: Consideration',
computedValue: () => 'Evaluating your options',
customStyles: {
backgroundColor: '#f0fdfa',
padding: '16px',
borderRadius: '8px',
textAlign: 'center',
borderLeft: '4px solid #14b8a6'
}
});
});
considerationPage.addRow(row => {
row.addStarRating('websiteRating', {
label: 'How helpful was our website in your research?',
maxStars: 5,
size: 'lg',
alignment: 'center'
}, '1fr');
row.addStarRating('infoQuality', {
label: 'Quality of product/service information',
maxStars: 5,
size: 'lg',
alignment: 'center'
}, '1fr');
});
considerationPage.addRow(row => {
row.addEmojiRating('considerationEase', {
label: 'How easy was it to compare options and make a decision?',
preset: 'effort',
size: 'lg',
alignment: 'center',
onValueChange: (value) => {
const ratingMap: Record<string, number> = {
'very-hard': 1, 'hard': 2, 'neutral': 3, 'easy': 4, 'very-easy': 5
};
scores.update(s => ({ ...s, consideration: value ? (ratingMap[value] ?? null) : null }));
}
});
});
considerationPage.addRow(row => {
row.addButton('backToDiscovery', {
label: '← Back',
onClick: () => pages.goToPage('discovery')
}, 'auto');
row.addEmpty('1fr');
row.addButton('nextToPurchase', {
label: 'Next: Purchase →',
onClick: () => pages.goToPage('purchase'),
isVisible: () => considerationPage.emojiRating('considerationEase')?.value() !== null
}, 'auto');
});
// --- PAGE 3: Purchase ---
const purchasePage = pages.addPage('purchase');
purchasePage.addRow(row => {
row.addTextPanel('purchaseTitle', {
label: 'Step 3 of 5: Purchase',
computedValue: () => 'Your buying experience',
customStyles: {
backgroundColor: '#f0fdfa',
padding: '16px',
borderRadius: '8px',
textAlign: 'center',
borderLeft: '4px solid #14b8a6'
}
});
});
purchasePage.addRow(row => {
row.addRatingScale('checkoutEase', {
label: 'How easy was the checkout process?',
preset: 'ces',
lowLabel: 'Very difficult',
highLabel: 'Very easy',
alignment: 'center',
isRequired: true,
onValueChange: (value) => {
scores.update(s => ({ ...s, purchase: value ?? null }));
}
});
});
purchasePage.addRow(row => {
row.addStarRating('paymentOptions', {
label: 'Satisfaction with payment options',
maxStars: 5,
size: 'md',
alignment: 'center'
}, '1fr');
row.addStarRating('pricingClarity', {
label: 'Clarity of pricing (no hidden fees)',
maxStars: 5,
size: 'md',
alignment: 'center'
}, '1fr');
});
purchasePage.addRow(row => {
row.addCheckboxList('purchaseIssues', {
label: 'Did you experience any issues during purchase?',
options: [
{ id: 'none', name: 'No issues' },
{ id: 'slow', name: 'Slow loading pages' },
{ id: 'error', name: 'Error messages' },
{ id: 'payment', name: 'Payment problems' },
{ id: 'coupon', name: 'Coupon/discount issues' },
{ id: 'confusing', name: 'Confusing navigation' }
],
orientation: 'horizontal'
});
});
purchasePage.addRow(row => {
row.addButton('backToConsideration', {
label: '← Back',
onClick: () => pages.goToPage('consideration')
}, 'auto');
row.addEmpty('1fr');
row.addButton('nextToDelivery', {
label: 'Next: Delivery →',
onClick: () => pages.goToPage('delivery'),
isVisible: () => purchasePage.ratingScale('checkoutEase')?.value() !== null
}, 'auto');
});
// --- PAGE 4: Delivery ---
const deliveryPage = pages.addPage('delivery');
deliveryPage.addRow(row => {
row.addTextPanel('deliveryTitle', {
label: 'Step 4 of 5: Delivery',
computedValue: () => 'Receiving your order',
customStyles: {
backgroundColor: '#f0fdfa',
padding: '16px',
borderRadius: '8px',
textAlign: 'center',
borderLeft: '4px solid #14b8a6'
}
});
});
deliveryPage.addRow(row => {
row.addRadioButton('receivedOrder', {
label: 'Have you received your order?',
options: [
{ id: 'yes', name: 'Yes, received' },
{ id: 'partial', name: 'Partially received' },
{ id: 'no', name: 'Not yet / N/A' }
],
orientation: 'horizontal',
isRequired: true
});
});
const deliveryRatingSection = deliveryPage.addSubform('deliveryRatings', {
isVisible: () => {
const received = deliveryPage.radioButton('receivedOrder')?.value();
return received === 'yes' || received === 'partial';
}
});
deliveryRatingSection.addRow(row => {
row.addStarRating('deliverySpeed', {
label: 'Delivery speed',
maxStars: 5,
size: 'lg',
alignment: 'center',
onValueChange: (value) => {
scores.update(s => ({ ...s, delivery: value ?? null }));
}
}, '1fr');
row.addStarRating('packageCondition', {
label: 'Package condition',
maxStars: 5,
size: 'lg',
alignment: 'center'
}, '1fr');
});
deliveryRatingSection.addRow(row => {
row.addStarRating('productMatch', {
label: 'Product matched description',
maxStars: 5,
size: 'lg',
alignment: 'center'
});
});
deliveryPage.addRow(row => {
row.addButton('backToPurchase', {
label: '← Back',
onClick: () => pages.goToPage('purchase')
}, 'auto');
row.addEmpty('1fr');
row.addButton('nextToSupport', {
label: 'Next: Support →',
onClick: () => pages.goToPage('support')
}, 'auto');
});
// --- PAGE 5: Support & Summary ---
const supportPage = pages.addPage('support');
supportPage.addRow(row => {
row.addTextPanel('supportTitle', {
label: 'Step 5 of 5: Support & Overall',
computedValue: () => 'Your support experience and final thoughts',
customStyles: {
backgroundColor: '#f0fdfa',
padding: '16px',
borderRadius: '8px',
textAlign: 'center',
borderLeft: '4px solid #14b8a6'
}
});
});
supportPage.addRow(row => {
row.addRadioButton('contactedSupport', {
label: 'Did you contact customer support?',
options: [
{ id: 'yes', name: 'Yes' },
{ id: 'no', name: 'No, not needed' }
],
orientation: 'horizontal'
});
});
const supportRatingSection = supportPage.addSubform('supportRatings', {
isVisible: () => supportPage.radioButton('contactedSupport')?.value() === 'yes'
});
supportRatingSection.addRow(row => {
row.addStarRating('supportQuality', {
label: 'Quality of support received',
maxStars: 5,
size: 'lg',
alignment: 'center',
onValueChange: (value) => {
scores.update(s => ({ ...s, support: value ?? null }));
}
}, '1fr');
row.addStarRating('supportSpeed', {
label: 'Speed of resolution',
maxStars: 5,
size: 'lg',
alignment: 'center'
}, '1fr');
});
// Overall NPS
const overallSection = supportPage.addSubform('overallRating', {
title: 'Overall Experience',
customStyles: () => {
const category = overallSection.ratingScale('overallNps')?.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' };
}
});
overallSection.addRow(row => {
row.addRatingScale('overallNps', {
label: 'Overall, how likely are you to recommend us?',
preset: 'nps',
showSegmentColors: true,
showCategoryLabel: true,
showConfettiOnPromoter: true,
isRequired: true
});
});
// Journey Summary
const summarySection = supportPage.addSubform('journeySummary', {
title: 'Your Journey Summary',
isVisible: () => overallSection.ratingScale('overallNps')?.value() !== null
});
summarySection.addRow(row => {
row.addTextPanel('summaryContent', {
computedValue: () => {
const s = scores();
const overall = overallSection.ratingScale('overallNps')?.value();
const category = overallSection.ratingScale('overallNps')?.npsCategory();
if (!overall) return '';
const touchpoints: Array<{name: string; score: number | null}> = [
{ name: 'Discovery', score: s['discovery'] ?? null },
{ name: 'Consideration', score: s['consideration'] ?? null },
{ name: 'Purchase', score: s['purchase'] ?? null },
{ name: 'Delivery', score: s['delivery'] ?? null },
{ name: 'Support', score: s['support'] ?? null }
];
let summary = `Journey Satisfaction Summary\n`;
summary += `${'═'.repeat(30)}\n\n`;
for (const tp of touchpoints) {
if (tp.score !== null && tp.score !== undefined) {
const score = tp.score;
const bar = '█'.repeat(score) + '░'.repeat(5 - score);
summary += `${tp.name.padEnd(14)} ${bar} ${score}/5\n`;
}
}
summary += `\n${'─'.repeat(30)}\n`;
summary += `Overall NPS: ${overall}/10`;
if (category) {
const emoji = category === 'promoter' ? ' ✓' : category === 'passive' ? ' ~' : ' ✗';
summary += emoji;
}
// Find lowest scoring touchpoint
const validScores = touchpoints.filter((tp): tp is {name: string; score: number} => tp.score !== null);
if (validScores.length > 0) {
const lowest = validScores.reduce((min, tp) =>
tp.score < min.score ? tp : min
);
if (lowest.score <= 3) {
summary += `\n\nFocus area: ${lowest.name}`;
}
}
return summary;
},
customStyles: {
padding: '16px',
borderRadius: '8px',
backgroundColor: '#f1f5f9',
whiteSpace: 'pre-wrap',
fontFamily: 'monospace',
fontSize: '14px'
}
});
});
summarySection.addSpacer();
summarySection.addRow(row => {
row.addTextarea('finalComments', {
label: 'Any final thoughts on your journey with us?',
placeholder: 'Share what went well or what could be improved...',
rows: 3,
autoExpand: true
});
});
supportPage.addRow(row => {
row.addButton('backToDelivery', {
label: '← Back',
onClick: () => pages.goToPage('delivery')
});
});
// ============================================
// FORM CONFIGURATION
// ============================================
form.configureSubmitButton({
label: 'Submit Journey Feedback',
isVisible: () => {
return pages.currentPageIndex() === 4 &&
overallSection.ratingScale('overallNps')?.value() !== null;
}
});
form.configureCompletionScreen({
type: 'text',
title: 'Thank you for mapping your journey!',
message: 'Your touchpoint-by-touchpoint feedback helps us improve every step of the customer experience. We appreciate your time and insights.'
});
}