export function clubMembershipRenewalSurvey(form: FormTs) {
// Membership Renewal Survey - Pre-renewal feedback and retention
// Demonstrates: RatingScale (NPS), StarRating, EmojiRating, ThumbRating, MatrixQuestion, CheckboxList, Dropdown, Slider, conditional visibility, dynamic labels, npsCategory, computed values
// State for tracking at-risk status
const isAtRisk = form.computedValue(() => {
const nps = satisfactionSection.ratingScale('npsScore')?.value() ?? 10;
const intent = renewalSection.radioButton('renewalIntent')?.value();
return nps <= 6 || intent === 'unlikely' || intent === 'definitely-not';
});
// ============================================
// HEADER
// ============================================
form.addRow(row => {
row.addTextPanel('header', {
label: 'Your Membership Matters',
computedValue: () => 'Help us serve you better as your renewal approaches.',
customStyles: {
backgroundColor: '#0d9488',
color: 'white',
padding: '24px',
borderRadius: '12px',
textAlign: 'center'
}
});
});
// ============================================
// SECTION 1: Member Information
// ============================================
const memberSection = form.addSubform('member', {
title: 'Your Membership'
});
memberSection.addRow(row => {
row.addDropdown('membershipType', {
label: 'What is your current membership type?',
options: [
{ id: 'individual', name: 'Individual Membership' },
{ id: 'family', name: 'Family Membership' },
{ id: 'student', name: 'Student Membership' },
{ id: 'senior', name: 'Senior Membership' },
{ id: 'corporate', name: 'Corporate Membership' },
{ id: 'premium', name: 'Premium/VIP Membership' }
],
isRequired: true
}, '1fr');
row.addDropdown('membershipLength', {
label: 'How long have you been a member?',
options: [
{ id: 'first-year', name: 'This is my first year' },
{ id: '1-2', name: '1-2 years' },
{ id: '3-5', name: '3-5 years' },
{ id: '5-10', name: '5-10 years' },
{ id: 'more-10', name: 'More than 10 years' }
],
isRequired: true
}, '1fr');
});
memberSection.addRow(row => {
row.addSlider('visitFrequency', {
label: 'On average, how many times per month do you visit/use our facilities?',
min: 0,
max: 30,
step: 1,
showValue: true,
unit: ' visits',
defaultValue: 8
});
});
// ============================================
// SECTION 2: Satisfaction & NPS
// ============================================
const satisfactionSection = form.addSubform('satisfaction', {
title: 'Your Satisfaction',
customStyles: () => {
const category = satisfactionSection.ratingScale('npsScore')?.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', border: '1px dashed #e5e7eb' };
}
});
satisfactionSection.addRow(row => {
row.addRatingScale('npsScore', {
label: 'How likely are you to recommend our membership to friends or colleagues?',
preset: 'nps',
showCategoryLabel: true,
showSegmentColors: true,
showConfettiOnPromoter: true,
alignment: 'center',
isRequired: true
});
});
satisfactionSection.addRow(row => {
row.addTextarea('npsReason', {
label: () => {
const category = satisfactionSection.ratingScale('npsScore')?.npsCategory();
if (category === 'promoter') return "What do you love most about your membership?";
if (category === 'passive') return "What would make your membership a 9 or 10?";
if (category === 'detractor') return "We're sorry you're not satisfied. What's not working for you?";
return 'Tell us about your experience';
},
placeholder: () => {
const category = satisfactionSection.ratingScale('npsScore')?.npsCategory();
if (category === 'promoter') return 'Share what makes your membership valuable...';
if (category === 'detractor') return "We want to make this right...";
return 'Your feedback...';
},
rows: 3,
autoExpand: true,
isVisible: () => satisfactionSection.ratingScale('npsScore')?.value() !== null
});
});
// ============================================
// SECTION 3: Value Assessment
// ============================================
const valueSection = form.addSubform('value', {
title: 'Membership Value'
});
valueSection.addRow(row => {
row.addMatrixQuestion('valueRatings', {
label: 'Rate the value you receive from each aspect of your membership:',
rows: [
{ id: 'facilities', label: 'Facilities & Equipment', description: 'Quality and availability', isRequired: true },
{ id: 'programs', label: 'Programs & Classes', description: 'Variety and scheduling', isRequired: true },
{ id: 'staff', label: 'Staff & Service', description: 'Helpfulness and expertise', isRequired: true },
{ id: 'community', label: 'Community & Social', description: 'Member events and networking', isRequired: true },
{ id: 'price', label: 'Price for Value', description: 'Worth what you pay', isRequired: true }
],
columns: [
{ id: 'poor', label: 'Poor' },
{ id: 'below', label: 'Below Avg' },
{ id: 'average', label: 'Average' },
{ id: 'above', label: 'Above Avg' },
{ id: 'excellent', label: 'Excellent' }
],
striped: true,
fullWidth: true
});
});
valueSection.addRow(row => {
row.addStarRating('overallValue', {
label: 'Overall, how would you rate the value of your membership?',
maxStars: 5,
size: 'lg',
alignment: 'center',
showConfettiOnMax: true
});
});
// ============================================
// SECTION 4: Benefits Usage
// ============================================
const benefitsSection = form.addSubform('benefits', {
title: 'Benefits & Programs'
});
benefitsSection.addRow(row => {
row.addCheckboxList('benefitsUsed', {
label: 'Which membership benefits have you used in the past year?',
options: [
{ id: 'fitness-equipment', name: 'Fitness equipment/gym' },
{ id: 'group-classes', name: 'Group fitness classes' },
{ id: 'personal-training', name: 'Personal training' },
{ id: 'pool-spa', name: 'Pool/Spa facilities' },
{ id: 'sports-courts', name: 'Sports courts (tennis, basketball, etc.)' },
{ id: 'member-events', name: 'Member events & socials' },
{ id: 'discounts', name: 'Member discounts' },
{ id: 'childcare', name: 'Childcare services' },
{ id: 'none', name: "I haven't used many benefits" }
],
orientation: 'vertical'
});
});
benefitsSection.addRow(row => {
row.addThumbRating('benefitsSufficient', {
label: 'Do you feel you get enough benefits for your membership fee?',
size: 'lg',
showLabels: true,
upLabel: 'Yes, good value',
downLabel: 'No, need more',
alignment: 'center'
});
});
benefitsSection.addSpacer();
benefitsSection.addRow(row => {
row.addTextarea('additionalBenefits', {
label: 'What additional benefits would make your membership more valuable?',
placeholder: 'Tell us what you wish we offered...',
rows: 2,
autoExpand: true,
isVisible: () => benefitsSection.thumbRating('benefitsSufficient')?.value() === 'down'
});
});
// ============================================
// SECTION 5: Renewal Intent
// ============================================
const renewalSection = form.addSubform('renewal', {
title: 'Your Renewal Decision'
});
renewalSection.addRow(row => {
row.addEmojiRating('renewalFeeling', {
label: 'How do you feel about renewing your membership?',
preset: 'satisfaction',
size: 'lg',
showLabels: true,
alignment: 'center'
});
});
renewalSection.addRow(row => {
row.addRadioButton('renewalIntent', {
label: 'At this point, how likely are you to renew your membership?',
options: [
{ id: 'definitely', name: 'Definitely will renew' },
{ id: 'probably', name: 'Probably will renew' },
{ id: 'undecided', name: 'Undecided - need to think about it' },
{ id: 'unlikely', name: 'Probably will not renew' },
{ id: 'definitely-not', name: 'Definitely will not renew' }
],
orientation: 'vertical',
isRequired: true,
isVisible: () => renewalSection.emojiRating('renewalFeeling')?.value() !== null
});
});
// At-risk follow-up
renewalSection.addRow(row => {
row.addCheckboxList('nonRenewalReasons', {
label: "We're sorry to hear that. What factors are influencing your decision?",
options: [
{ id: 'cost', name: 'Cost is too high' },
{ id: 'usage', name: "Don't use it enough" },
{ id: 'moving', name: 'Moving/Relocating' },
{ id: 'alternative', name: 'Found an alternative' },
{ id: 'facilities', name: 'Unhappy with facilities' },
{ id: 'service', name: 'Poor customer service' },
{ id: 'schedule', name: 'Hours/schedule issues' },
{ id: 'life-changes', name: 'Life changes (health, family, etc.)' },
{ id: 'other', name: 'Other reason' }
],
orientation: 'vertical',
isVisible: () => {
const intent = renewalSection.radioButton('renewalIntent')?.value();
return intent === 'unlikely' || intent === 'definitely-not' || intent === 'undecided';
}
});
});
renewalSection.addSpacer();
renewalSection.addRow(row => {
row.addTextarea('whatWouldChange', {
label: 'What would change your mind about renewing?',
placeholder: 'We want to keep you as a member. What can we do?',
rows: 3,
autoExpand: true,
isVisible: () => {
const intent = renewalSection.radioButton('renewalIntent')?.value();
return intent === 'unlikely' || intent === 'definitely-not' || intent === 'undecided';
}
});
});
// ============================================
// SECTION 6: Contact for Follow-up
// ============================================
const contactSection = form.addSubform('contact', {
title: 'Stay in Touch',
isVisible: () => isAtRisk()
});
contactSection.addRow(row => {
row.addTextPanel('contactNotice', {
computedValue: () => "We value your membership and would like to discuss how we can better serve you.",
customStyles: {
backgroundColor: '#fef3c7',
padding: '12px 16px',
borderRadius: '8px',
borderLeft: '4px solid #f59e0b',
fontSize: '14px'
}
});
});
contactSection.addRow(row => {
row.addRadioButton('contactPreference', {
label: 'Would you be open to a brief call to discuss your concerns?',
options: [
{ id: 'yes-call', name: 'Yes, please call me' },
{ id: 'yes-email', name: 'I prefer email' },
{ id: 'no', name: 'No thanks, I just wanted to share feedback' }
],
orientation: 'vertical'
});
});
contactSection.addRow(row => {
row.addTextbox('contactPhone', {
label: 'Best phone number to reach you:',
placeholder: '(555) 123-4567',
isVisible: () => contactSection.radioButton('contactPreference')?.value() === 'yes-call'
});
});
// ============================================
// SECTION 7: Summary
// ============================================
const summarySection = form.addSubform('summary', {
title: () => isAtRisk() ? 'Member Status: At Risk' : 'Member Feedback Summary',
isVisible: () => satisfactionSection.ratingScale('npsScore')?.value() !== null
});
summarySection.addRow(row => {
row.addTextPanel('summaryContent', {
computedValue: () => {
const nps = satisfactionSection.ratingScale('npsScore')?.value();
const npsCategory = satisfactionSection.ratingScale('npsScore')?.npsCategory();
const overallValue = valueSection.starRating('overallValue')?.value();
const renewalIntent = renewalSection.radioButton('renewalIntent')?.value();
const membershipLength = memberSection.dropdown('membershipLength')?.value();
const visits = memberSection.slider('visitFrequency')?.value();
if (nps === null || nps === undefined) return '';
const intentLabels: Record<string, string> = {
'definitely': 'Will Renew',
'probably': 'Likely to Renew',
'undecided': 'Undecided',
'unlikely': 'Unlikely to Renew',
'definitely-not': 'Will Not Renew'
};
const lengthLabels: Record<string, string> = {
'first-year': 'First year',
'1-2': '1-2 years',
'3-5': '3-5 years',
'5-10': '5-10 years',
'more-10': '10+ years'
};
let summary = `Member Renewal Assessment\n`;
summary += `${'═'.repeat(28)}\n\n`;
if (membershipLength) {
summary += `Tenure: ${lengthLabels[membershipLength] || membershipLength}\n`;
}
if (visits !== undefined) {
summary += `Activity: ${visits} visits/month\n`;
}
summary += `\nNPS: ${nps}/10 (${npsCategory})\n`;
if (overallValue !== null && overallValue !== undefined) {
summary += `Value Rating: ${overallValue}/5 stars\n`;
}
if (renewalIntent) {
summary += `\nRenewal Status: ${intentLabels[renewalIntent] || renewalIntent}\n`;
}
if (isAtRisk()) {
summary += `\n⚠️ ATTENTION NEEDED\nThis member may need personal outreach.`;
}
return summary;
},
customStyles: () => {
const baseStyles = {
padding: '16px',
borderRadius: '8px',
whiteSpace: 'pre-wrap',
fontFamily: 'monospace',
fontSize: '14px'
};
if (isAtRisk()) {
return { ...baseStyles, backgroundColor: '#fee2e2', borderLeft: '4px solid #ef4444' };
}
const category = satisfactionSection.ratingScale('npsScore')?.npsCategory();
if (category === 'promoter') {
return { ...baseStyles, backgroundColor: '#d1fae5', borderLeft: '4px solid #10b981' };
} else if (category === 'passive') {
return { ...baseStyles, backgroundColor: '#fef3c7', borderLeft: '4px solid #f59e0b' };
}
return { ...baseStyles, backgroundColor: '#f3f4f6', borderLeft: '4px solid #0d9488' };
}
});
});
// ============================================
// FORM CONFIGURATION
// ============================================
form.configureSubmitButton({
label: () => isAtRisk() ? 'Submit & Request Follow-up' : 'Submit Feedback',
isVisible: () => renewalSection.radioButton('renewalIntent')?.value() !== null
});
form.configureCompletionScreen({
type: 'text',
title: () => {
const category = satisfactionSection.ratingScale('npsScore')?.npsCategory();
if (category === 'promoter') return 'Thank You for Your Loyalty!';
if (isAtRisk()) return "We've Heard You";
return 'Thank You for Your Feedback!';
},
message: () => {
const category = satisfactionSection.ratingScale('npsScore')?.npsCategory();
const contactPref = contactSection.radioButton('contactPreference')?.value();
if (category === 'promoter') {
return 'We truly appreciate your support and kind words. Members like you are the heart of our community. See you soon!';
}
if (isAtRisk() && (contactPref === 'yes-call' || contactPref === 'yes-email')) {
return 'A member of our team will reach out to you within 48 hours. We value your membership and want to make things right.';
}
if (isAtRisk()) {
return 'We appreciate your honest feedback and take your concerns seriously. We hope you will give us another chance to serve you better.';
}
return 'Your feedback helps us improve the membership experience for everyone. We look forward to seeing you soon!';
}
});
}