export function cancellationSurvey(form: FormTs) {
// Cancellation Reasons Survey - Intelligent churn prevention with conditional paths
// Demonstrates: RadioButton, CheckboxList, RatingScale, Slider, ThumbRating, conditional visibility, dynamic labels
// ============================================
// HEADER
// ============================================
form.addRow(row => {
row.addTextPanel('header', {
label: "We're Sorry to See You Go",
computedValue: () => "Your feedback helps us improve for everyone",
customStyles: {
background: 'linear-gradient(135deg, #ef4444 0%, #f97316 100%)',
color: 'white',
padding: '24px',
borderRadius: '12px',
textAlign: 'center'
}
});
});
// ============================================
// SECTION 1: Primary Cancellation Reason
// ============================================
const reasonSection = form.addSubform('reasonSection', {
title: 'Why are you cancelling?',
customStyles: { padding: '16px', borderRadius: '8px', border: '1px solid #e2e8f0' }
});
reasonSection.addRow(row => {
row.addRadioButton('primaryReason', {
label: 'Please select the main reason for cancelling',
options: [
{ id: 'too-expensive', name: 'Too expensive for my budget' },
{ id: 'missing-features', name: 'Missing features I need' },
{ id: 'switched-competitor', name: 'Switching to a competitor' },
{ id: 'not-using', name: "Not using it enough" },
{ id: 'technical-issues', name: 'Too many bugs or technical issues' },
{ id: 'hard-to-use', name: 'Too difficult to use' },
{ id: 'temporary', name: 'Temporary pause (will return)' },
{ id: 'business-closed', name: 'Business closing / changing direction' },
{ id: 'other', name: 'Other reason' }
],
orientation: 'vertical',
isRequired: true
});
});
// ============================================
// SECTION 2A: Pricing Follow-up (conditional)
// ============================================
const pricingSection = form.addSubform('pricingSection', {
title: 'π° Help Us Understand Your Pricing Concerns',
isVisible: () => reasonSection.radioButton('primaryReason')?.value() === 'too-expensive',
customStyles: { backgroundColor: '#fef3c7', padding: '16px', borderRadius: '8px' }
});
pricingSection.addRow(row => {
row.addSlider('priceExpectation', {
label: 'What monthly price would be fair for you?',
min: 0,
max: 100,
step: 5,
defaultValue: 20,
unit: '$/mo',
showValue: true
});
});
pricingSection.addRow(row => {
row.addCheckboxList('pricingFactors', {
label: 'What would make the current price worthwhile?',
options: [
{ id: 'more-features', name: 'More features included' },
{ id: 'better-support', name: 'Better customer support' },
{ id: 'team-seats', name: 'More team seats' },
{ id: 'storage', name: 'More storage/usage limits' },
{ id: 'integrations', name: 'Better integrations' },
{ id: 'nothing', name: 'Nothing - price is simply too high' }
],
orientation: 'vertical'
});
});
pricingSection.addRow(row => {
row.addTextPanel('pricingOffer', {
label: 'π Special Offer',
computedValue: () => 'Would you consider staying with 30% off for 3 months?',
customStyles: {
backgroundColor: '#d1fae5',
padding: '12px',
borderRadius: '8px',
fontWeight: 'bold',
textAlign: 'center'
}
});
});
pricingSection.addRow(row => {
row.addThumbRating('acceptPricingOffer', {
label: 'Interested in this offer?',
showLabels: true,
upLabel: "Yes, I'll stay!",
downLabel: 'No thanks',
alignment: 'center',
size: 'lg'
});
});
// ============================================
// SECTION 2B: Features Follow-up (conditional)
// ============================================
const featuresSection = form.addSubform('featuresSection', {
title: 'π§ What Features Are You Missing?',
isVisible: () => reasonSection.radioButton('primaryReason')?.value() === 'missing-features',
customStyles: { backgroundColor: '#e0e7ff', padding: '16px', borderRadius: '8px' }
});
featuresSection.addRow(row => {
row.addCheckboxList('missingFeatures', {
label: 'Which features do you wish we had?',
options: [
{ id: 'reporting', name: 'Advanced reporting/analytics' },
{ id: 'automation', name: 'More automation options' },
{ id: 'integrations', name: 'Specific integrations' },
{ id: 'api', name: 'API access' },
{ id: 'mobile', name: 'Better mobile app' },
{ id: 'collaboration', name: 'Team collaboration features' },
{ id: 'customization', name: 'More customization options' },
{ id: 'export', name: 'Better export/import' }
],
orientation: 'vertical'
});
});
featuresSection.addSpacer();
featuresSection.addRow(row => {
row.addTextarea('featureDetails', {
label: 'Please describe the specific features you need',
placeholder: 'The more detail, the better we can prioritize...',
rows: 3,
autoExpand: true
});
});
// ============================================
// SECTION 2C: Competitor Follow-up (conditional)
// ============================================
const competitorSection = form.addSubform('competitorSection', {
title: 'π Competitor Feedback',
isVisible: () => reasonSection.radioButton('primaryReason')?.value() === 'switched-competitor',
customStyles: { backgroundColor: '#fee2e2', padding: '16px', borderRadius: '8px' }
});
competitorSection.addRow(row => {
row.addTextbox('competitorName', {
label: 'Which competitor are you switching to? (optional)',
placeholder: 'Competitor name...'
});
});
competitorSection.addRow(row => {
row.addCheckboxList('competitorReasons', {
label: 'What attracts you to the competitor?',
options: [
{ id: 'price', name: 'Better pricing' },
{ id: 'features', name: 'More features' },
{ id: 'ui', name: 'Better user interface' },
{ id: 'support', name: 'Better customer support' },
{ id: 'integration', name: 'Better integrations' },
{ id: 'reputation', name: 'Better reputation/reviews' },
{ id: 'recommendation', name: 'Recommended by colleague' }
],
orientation: 'vertical'
});
});
// ============================================
// SECTION 2D: Technical Issues Follow-up (conditional)
// ============================================
const technicalSection = form.addSubform('technicalSection', {
title: 'π Technical Issues',
isVisible: () => reasonSection.radioButton('primaryReason')?.value() === 'technical-issues',
customStyles: { backgroundColor: '#fef3c7', padding: '16px', borderRadius: '8px' }
});
technicalSection.addRow(row => {
row.addCheckboxList('technicalProblems', {
label: 'What issues have you experienced?',
options: [
{ id: 'crashes', name: 'Frequent crashes or errors' },
{ id: 'slow', name: 'Slow performance' },
{ id: 'data-loss', name: 'Data loss or sync issues' },
{ id: 'login', name: 'Login/authentication problems' },
{ id: 'browser', name: 'Browser compatibility issues' },
{ id: 'mobile', name: 'Mobile app problems' },
{ id: 'integrations', name: 'Integration failures' }
],
orientation: 'vertical'
});
});
technicalSection.addSpacer();
technicalSection.addRow(row => {
row.addTextarea('technicalDetails', {
label: 'Please describe the issues in detail',
placeholder: 'Include any error messages or steps to reproduce...',
rows: 3,
autoExpand: true
});
});
technicalSection.addRow(row => {
row.addTextPanel('technicalOffer', {
computedValue: () => 'π Our engineering team would love to help. Can we schedule a call to fix these issues?',
customStyles: {
backgroundColor: '#d1fae5',
padding: '12px',
borderRadius: '8px',
textAlign: 'center'
}
});
});
technicalSection.addRow(row => {
row.addThumbRating('acceptSupportCall', {
label: 'Would you like us to reach out?',
showLabels: true,
upLabel: 'Yes, please help',
downLabel: 'No thanks',
alignment: 'center',
size: 'lg'
});
});
// ============================================
// SECTION 2E: Other Reason Follow-up (conditional)
// ============================================
const otherSection = form.addSubform('otherSection', {
title: 'π Tell Us More',
isVisible: () => reasonSection.radioButton('primaryReason')?.value() === 'other',
customStyles: { backgroundColor: '#f1f5f9', padding: '16px', borderRadius: '8px' }
});
otherSection.addRow(row => {
row.addTextarea('otherReason', {
label: 'Please explain your reason for cancelling',
placeholder: 'Your feedback helps us improve...',
rows: 4,
autoExpand: true,
isRequired: true
});
});
// ============================================
// SECTION 3: Satisfaction History
// ============================================
const satisfactionSection = form.addSubform('satisfactionSection', {
title: 'Looking Back',
isVisible: () => reasonSection.radioButton('primaryReason')?.value() !== null,
customStyles: { padding: '16px', borderRadius: '8px', border: '1px solid #e2e8f0' }
});
satisfactionSection.addRow(row => {
row.addRatingScale('overallSatisfaction', {
preset: 'satisfaction',
label: 'Overall, how satisfied were you with our product?',
alignment: 'center',
size: 'lg'
});
});
satisfactionSection.addRow(row => {
row.addStarRating('valueRating', {
label: 'Value for money',
maxStars: 5,
size: 'md',
alignment: 'center'
}, '1fr');
row.addStarRating('supportRating', {
label: 'Customer support',
maxStars: 5,
size: 'md',
alignment: 'center'
}, '1fr');
});
satisfactionSection.addRow(row => {
row.addStarRating('easeRating', {
label: 'Ease of use',
maxStars: 5,
size: 'md',
alignment: 'center'
}, '1fr');
row.addStarRating('reliabilityRating', {
label: 'Reliability',
maxStars: 5,
size: 'md',
alignment: 'center'
}, '1fr');
});
// ============================================
// SECTION 4: Win-back Opportunity
// ============================================
const winbackSection = form.addSubform('winbackSection', {
title: 'Future Possibilities',
isVisible: () => reasonSection.radioButton('primaryReason')?.value() !== null,
customStyles: { backgroundColor: '#f0fdf4', padding: '16px', borderRadius: '8px' }
});
winbackSection.addRow(row => {
row.addThumbRating('wouldReturn', {
label: 'Would you consider coming back in the future?',
showLabels: true,
upLabel: 'Yes, possibly',
downLabel: 'Unlikely',
alignment: 'center',
size: 'lg'
});
});
winbackSection.addRow(row => {
row.addTextarea('returnConditions', {
label: () => {
const wouldReturn = winbackSection.thumbRating('wouldReturn')?.value();
if (wouldReturn === 'up') return 'What would need to change for you to return?';
return 'What would make you reconsider?';
},
placeholder: 'Specific features, pricing changes, improvements...',
rows: 2,
autoExpand: true,
isVisible: () => winbackSection.thumbRating('wouldReturn')?.value() !== null
});
});
winbackSection.addRow(row => {
row.addCheckbox('keepInformed', {
label: 'Keep me informed about new features and updates'
});
});
winbackSection.addRow(row => {
row.addEmail('contactEmail', {
label: 'Email for updates (optional)',
placeholder: 'your@email.com',
isVisible: () => winbackSection.checkbox('keepInformed')?.value() === true
});
});
// ============================================
// SECTION 5: Final Thoughts
// ============================================
const finalSection = form.addSubform('finalSection', {
title: 'Any Final Thoughts?',
isVisible: () => reasonSection.radioButton('primaryReason')?.value() !== null
});
finalSection.addSpacer();
finalSection.addRow(row => {
row.addTextarea('finalFeedback', {
label: 'Is there anything else you want us to know?',
placeholder: 'Your honest feedback helps us improve for future customers...',
rows: 3,
autoExpand: true
});
});
// ============================================
// SUMMARY SECTION
// ============================================
const summarySection = form.addSubform('summary', {
title: 'Feedback Summary',
isVisible: () => reasonSection.radioButton('primaryReason')?.value() !== null
});
summarySection.addRow(row => {
row.addTextPanel('summaryContent', {
computedValue: () => {
const reason = reasonSection.radioButton('primaryReason')?.value();
const satisfaction = satisfactionSection.ratingScale('overallSatisfaction')?.value();
const wouldReturn = winbackSection.thumbRating('wouldReturn')?.value();
const keepInformed = winbackSection.checkbox('keepInformed')?.value();
const reasonLabels: Record<string, string> = {
'too-expensive': 'π° Pricing',
'missing-features': 'π§ Missing Features',
'switched-competitor': 'π Competitor',
'not-using': 'π Low Usage',
'technical-issues': 'π Technical Issues',
'hard-to-use': 'π Usability',
'temporary': 'βΈοΈ Temporary Pause',
'business-closed': 'π’ Business Change',
'other': 'π Other'
};
let summary = 'Cancellation Feedback\n';
summary += 'β'.repeat(25) + '\n\n';
summary += `Primary Reason: ${reasonLabels[reason || ''] || 'Not specified'}\n`;
if (satisfaction !== null && satisfaction !== undefined) {
summary += `Satisfaction: ${satisfaction}/5\n`;
}
summary += `Return Likelihood: ${wouldReturn === 'up' ? 'Possible' : wouldReturn === 'down' ? 'Unlikely' : 'Not answered'}\n`;
summary += `Stay Informed: ${keepInformed ? 'Yes' : 'No'}\n`;
// Check for offers accepted
const pricingOffer = pricingSection.thumbRating('acceptPricingOffer')?.value();
const supportOffer = technicalSection.thumbRating('acceptSupportCall')?.value();
if (pricingOffer === 'up') {
summary += '\nπ Accepted pricing offer!';
}
if (supportOffer === 'up') {
summary += '\nπ Requested support call';
}
return summary;
},
customStyles: {
padding: '16px',
borderRadius: '8px',
backgroundColor: '#f8fafc',
whiteSpace: 'pre-wrap',
fontFamily: 'monospace',
fontSize: '14px'
}
});
});
// ============================================
// FORM CONFIGURATION
// ============================================
form.configureSubmitButton({
label: 'Submit Feedback & Cancel',
isVisible: () => reasonSection.radioButton('primaryReason')?.value() !== null
});
form.configureCompletionScreen({
type: 'text',
title: 'Thank You for Your Feedback',
message: "We truly appreciate you taking the time to share your thoughts. Your feedback helps us build a better product. We hope to see you again someday!"
});
}