export function clientSatisfactionSurvey(form: FormTs) {
// Client Satisfaction Survey - B2B relationship health assessment
// Demonstrates: RatingScale (NPS), MatrixQuestion, StarRating, Slider, RadioButton, ThumbRating, SuggestionChips
// ============================================
// HEADER
// ============================================
form.addRow(row => {
row.addTextPanel('header', {
label: 'Client Satisfaction Survey',
computedValue: () => 'Your feedback helps us strengthen our partnership and deliver better results.',
customStyles: {
background: 'linear-gradient(135deg, #0f766e 0%, #14b8a6 100%)',
color: 'white',
padding: '24px',
borderRadius: '12px',
textAlign: 'center'
}
});
});
// ============================================
// SECTION 1: Account Information
// ============================================
const accountSection = form.addSubform('accountSection', {
title: 'Account Information'
});
accountSection.addRow(row => {
row.addTextbox('companyName', {
label: 'Company name',
placeholder: 'Your organization...',
isRequired: true
}, '1fr');
row.addDropdown('respondentRole', {
label: 'Your role',
options: [
{ id: 'executive', name: 'Executive/C-Level' },
{ id: 'director', name: 'Director/VP' },
{ id: 'manager', name: 'Manager' },
{ id: 'user', name: 'Day-to-day User' },
{ id: 'technical', name: 'Technical Contact' },
{ id: 'procurement', name: 'Procurement/Finance' },
{ id: 'other', name: 'Other' }
],
placeholder: 'Select role...',
isRequired: true
}, '1fr');
});
accountSection.addRow(row => {
row.addDropdown('relationshipLength', {
label: 'How long have you been a client?',
options: [
{ id: '0-6m', name: 'Less than 6 months' },
{ id: '6-12m', name: '6-12 months' },
{ id: '1-2y', name: '1-2 years' },
{ id: '2-5y', name: '2-5 years' },
{ id: '5y+', name: 'More than 5 years' }
],
placeholder: 'Select duration...'
}, '1fr');
row.addDropdown('engagementLevel', {
label: 'How often do you interact with us?',
options: [
{ id: 'daily', name: 'Daily' },
{ id: 'weekly', name: 'Weekly' },
{ id: 'monthly', name: 'Monthly' },
{ id: 'quarterly', name: 'Quarterly' },
{ id: 'rarely', name: 'Rarely' }
],
placeholder: 'Select frequency...'
}, '1fr');
});
// ============================================
// SECTION 2: Net Promoter Score
// ============================================
const npsSection = form.addSubform('npsSection', {
title: 'Overall Recommendation',
customStyles: () => {
const category = npsSection.ratingScale('clientNps')?.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 #cbd5e1' };
}
});
npsSection.addRow(row => {
row.addRatingScale('clientNps', {
label: 'How likely are you to recommend us to a colleague or business partner?',
preset: 'nps',
showCategoryLabel: true,
showSegmentColors: true,
alignment: 'center',
isRequired: true
});
});
npsSection.addRow(row => {
row.addTextarea('npsReason', {
label: () => {
const category = npsSection.ratingScale('clientNps')?.npsCategory();
switch (category) {
case 'promoter': return 'What makes you willing to recommend us?';
case 'passive': return 'What would it take to earn a 9 or 10?';
case 'detractor': return 'What is the primary reason for your score?';
default: return 'Please share the reason for your score';
}
},
placeholder: () => {
const category = npsSection.ratingScale('clientNps')?.npsCategory();
if (category === 'promoter') return 'We appreciate understanding what we do well...';
if (category === 'detractor') return 'Your candid feedback helps us improve...';
return 'Your feedback is valuable to us...';
},
rows: 3,
autoExpand: true,
isVisible: () => npsSection.ratingScale('clientNps')?.value() !== null
});
});
// ============================================
// SECTION 3: Relationship Health Matrix
// ============================================
const healthSection = form.addSubform('healthSection', {
title: 'Relationship Health'
});
healthSection.addRow(row => {
row.addMatrixQuestion('relationshipMatrix', {
label: 'Rate the following aspects of our partnership:',
rows: [
{ id: 'communication', label: 'Communication quality', isRequired: true },
{ id: 'responsiveness', label: 'Responsiveness to requests', isRequired: true },
{ id: 'understanding', label: 'Understanding your business', isRequired: true },
{ id: 'proactive', label: 'Proactive problem-solving', isRequired: false },
{ id: 'trust', label: 'Trust and transparency', isRequired: false },
{ id: 'value', label: 'Value for investment', isRequired: true }
],
columns: [
{ id: 'poor', label: 'Poor' },
{ id: 'fair', label: 'Fair' },
{ id: 'good', label: 'Good' },
{ id: 'excellent', label: 'Excellent' }
],
striped: true,
fullWidth: true
});
});
// ============================================
// SECTION 4: Service Quality
// ============================================
const serviceSection = form.addSubform('serviceSection', {
title: 'Service Quality'
});
serviceSection.addRow(row => {
row.addStarRating('deliveryQuality', {
label: 'Quality of deliverables',
maxStars: 5,
size: 'lg',
alignment: 'center'
});
});
serviceSection.addRow(row => {
row.addStarRating('timelyDelivery', {
label: 'Timeliness of delivery',
maxStars: 5,
size: 'lg',
alignment: 'center'
});
});
serviceSection.addRow(row => {
row.addStarRating('issueResolution', {
label: 'Issue resolution effectiveness',
maxStars: 5,
size: 'lg',
alignment: 'center'
});
});
// Low scores follow-up
serviceSection.addSpacer();
serviceSection.addRow(row => {
row.addTextarea('serviceIssues', {
label: 'What service issues need immediate attention?',
placeholder: 'Please describe any ongoing concerns...',
rows: 2,
isVisible: () => {
const quality = serviceSection.starRating('deliveryQuality')?.value() ?? 0;
const timely = serviceSection.starRating('timelyDelivery')?.value() ?? 0;
const resolution = serviceSection.starRating('issueResolution')?.value() ?? 0;
return (quality > 0 && quality <= 2) || (timely > 0 && timely <= 2) || (resolution > 0 && resolution <= 2);
}
});
});
// ============================================
// SECTION 5: Account Team Evaluation
// ============================================
const teamSection = form.addSubform('teamSection', {
title: 'Account Team'
});
teamSection.addRow(row => {
row.addStarRating('accountManager', {
label: 'Account manager effectiveness',
maxStars: 5,
size: 'md',
showCounter: true
}, '1fr');
row.addStarRating('technicalTeam', {
label: 'Technical team expertise',
maxStars: 5,
size: 'md',
showCounter: true
}, '1fr');
});
teamSection.addRow(row => {
row.addStarRating('executiveAccess', {
label: 'Executive accessibility',
maxStars: 5,
size: 'md',
showCounter: true
}, '1fr');
row.addStarRating('teamConsistency', {
label: 'Team consistency and continuity',
maxStars: 5,
size: 'md',
showCounter: true
}, '1fr');
});
// ============================================
// SECTION 6: Strategic Alignment
// ============================================
const strategySection = form.addSubform('strategySection', {
title: 'Strategic Alignment'
});
strategySection.addRow(row => {
row.addRatingScale('strategyAlignment', {
label: 'How well do we understand your strategic priorities?',
preset: 'likert-5',
lowLabel: 'Not at all',
highLabel: 'Completely',
alignment: 'center'
});
});
strategySection.addRow(row => {
row.addThumbRating('growthPartner', {
label: 'Do you see us as a strategic growth partner?',
showLabels: true,
upLabel: 'Yes, strategic partner',
downLabel: 'No, just a vendor',
size: 'lg',
alignment: 'center'
});
});
strategySection.addSpacer();
strategySection.addRow(row => {
row.addTextarea('strategyGaps', {
label: 'What would make us a more valuable strategic partner?',
placeholder: 'How can we better align with your business goals?',
rows: 2,
autoExpand: true,
isVisible: () => strategySection.thumbRating('growthPartner')?.value() === 'down'
});
});
// ============================================
// SECTION 7: Future Outlook
// ============================================
const futureSection = form.addSubform('futureSection', {
title: 'Future Outlook'
});
futureSection.addRow(row => {
row.addRadioButton('renewalLikelihood', {
label: 'How likely are you to renew/expand your engagement?',
options: [
{ id: 'definitely', name: 'Definitely will renew' },
{ id: 'likely', name: 'Likely to renew' },
{ id: 'uncertain', name: 'Uncertain' },
{ id: 'unlikely', name: 'Unlikely to renew' },
{ id: 'will-not', name: 'Will not renew' }
],
orientation: 'vertical'
});
});
// At-risk follow-up
futureSection.addRow(row => {
row.addTextarea('renewalConcerns', {
label: 'What concerns affect your renewal decision?',
placeholder: 'Please share so we can address these concerns...',
rows: 2,
isRequired: true,
isVisible: () => {
const likelihood = futureSection.radioButton('renewalLikelihood')?.value();
return likelihood === 'uncertain' || likelihood === 'unlikely' || likelihood === 'will-not';
}
});
});
futureSection.addSpacer();
futureSection.addRow(row => {
row.addSuggestionChips('expansionAreas', {
label: 'Which additional services interest you?',
suggestions: [
{ id: 'none', name: 'None at this time' },
{ id: 'consulting', name: 'Consulting' },
{ id: 'training', name: 'Training' },
{ id: 'support', name: 'Premium Support' },
{ id: 'integration', name: 'Integrations' },
{ id: 'analytics', name: 'Analytics' },
{ id: 'custom', name: 'Custom Development' }
],
alignment: 'left'
});
});
// ============================================
// SECTION 8: Competitive Context
// ============================================
const competitiveSection = form.addSubform('competitiveSection', {
title: 'Competitive Landscape'
});
competitiveSection.addRow(row => {
row.addThumbRating('evaluatingAlternatives', {
label: 'Are you currently evaluating alternatives?',
showLabels: true,
upLabel: 'Yes, evaluating options',
downLabel: 'No, satisfied',
size: 'lg',
alignment: 'center'
});
});
competitiveSection.addRow(row => {
row.addTextarea('competitorAdvantages', {
label: 'What do competitors offer that we should consider?',
placeholder: 'This helps us stay competitive and serve you better...',
rows: 2,
isVisible: () => competitiveSection.thumbRating('evaluatingAlternatives')?.value() === 'up'
});
});
// ============================================
// SECTION 9: Additional Feedback
// ============================================
const additionalSection = form.addSubform('additionalSection', {
title: 'Additional Feedback'
});
additionalSection.addRow(row => {
row.addTextarea('topPriority', {
label: 'What is the #1 thing we should improve?',
placeholder: 'If we could fix one thing, what would have the biggest impact?',
rows: 2,
autoExpand: true
});
});
additionalSection.addRow(row => {
row.addTextarea('appreciation', {
label: 'What do we do particularly well?',
placeholder: 'Share what you appreciate about working with us...',
rows: 2,
autoExpand: true
});
});
additionalSection.addRow(row => {
row.addThumbRating('caseStudy', {
label: 'Would you be open to being a reference or case study?',
showLabels: true,
upLabel: 'Yes, happy to help',
downLabel: 'Not at this time',
size: 'md',
alignment: 'center'
});
});
// ============================================
// SECTION 10: Summary
// ============================================
const summarySection = form.addSubform('summarySection', {
title: 'Feedback Summary',
isVisible: () => npsSection.ratingScale('clientNps')?.value() !== null
});
summarySection.addRow(row => {
row.addTextPanel('summary', {
computedValue: () => {
const company = accountSection.textbox('companyName')?.value() || 'Client';
const nps = npsSection.ratingScale('clientNps')?.value() ?? 0;
const npsCategory = npsSection.ratingScale('clientNps')?.npsCategory();
const quality = serviceSection.starRating('deliveryQuality')?.value() ?? 0;
const timely = serviceSection.starRating('timelyDelivery')?.value() ?? 0;
const resolution = serviceSection.starRating('issueResolution')?.value() ?? 0;
const serviceAvg = (quality + timely + resolution) / 3;
const am = teamSection.starRating('accountManager')?.value() ?? 0;
const tech = teamSection.starRating('technicalTeam')?.value() ?? 0;
const exec = teamSection.starRating('executiveAccess')?.value() ?? 0;
const teamAvg = (am + tech + exec) / 3;
const strategy = strategySection.ratingScale('strategyAlignment')?.value() ?? 0;
const growthPartner = strategySection.thumbRating('growthPartner')?.value();
const renewal = futureSection.radioButton('renewalLikelihood')?.value();
const evaluating = competitiveSection.thumbRating('evaluatingAlternatives')?.value();
const renewalLabels: Record<string, string> = {
'definitely': 'Definite Renewal', 'likely': 'Likely Renewal',
'uncertain': 'Uncertain', 'unlikely': 'At Risk', 'will-not': 'Churn Risk'
};
let summary = `Client Satisfaction: ${company}\n`;
summary += '═'.repeat(35) + '\n\n';
summary += `NPS Score: ${nps}/10 (${npsCategory?.toUpperCase() || 'N/A'})\n\n`;
summary += 'Service Quality:\n';
summary += ` Delivery Quality: ${quality}/5\n`;
summary += ` Timeliness: ${timely}/5\n`;
summary += ` Issue Resolution: ${resolution}/5\n`;
summary += ` Average: ${serviceAvg.toFixed(1)}/5\n\n`;
summary += 'Team Ratings:\n';
summary += ` Account Manager: ${am}/5\n`;
summary += ` Technical Team: ${tech}/5\n`;
summary += ` Executive Access: ${exec}/5\n`;
summary += ` Average: ${teamAvg.toFixed(1)}/5\n\n`;
summary += `Strategic Alignment: ${strategy}/5\n`;
summary += `Growth Partner: ${growthPartner === 'up' ? 'Yes' : growthPartner === 'down' ? 'No' : 'N/A'}\n`;
summary += `Renewal Outlook: ${renewalLabels[renewal || ''] || 'Not answered'}\n`;
// Risk indicators
const risks: string[] = [];
if (npsCategory === 'detractor') risks.push('Detractor - needs immediate attention');
if (serviceAvg < 3 && serviceAvg > 0) risks.push('Service quality below target');
if (renewal === 'uncertain' || renewal === 'unlikely' || renewal === 'will-not') risks.push('Renewal at risk');
if (evaluating === 'up') risks.push('Evaluating competitors');
if (growthPartner === 'down') risks.push('Not seen as strategic partner');
if (risks.length > 0) {
summary += '\n⚠️ RISK INDICATORS:\n';
risks.forEach(risk => summary += ` • ${risk}\n`);
}
// Opportunities
if (npsCategory === 'promoter') {
summary += '\n✨ OPPORTUNITY: Reference/case study candidate';
}
return summary;
},
customStyles: () => {
const npsCategory = npsSection.ratingScale('clientNps')?.npsCategory();
const renewal = futureSection.radioButton('renewalLikelihood')?.value();
const baseStyles = {
padding: '16px',
borderRadius: '8px',
whiteSpace: 'pre-wrap',
fontFamily: 'monospace',
fontSize: '13px'
};
// High risk
if (npsCategory === 'detractor' || renewal === 'unlikely' || renewal === 'will-not') {
return { ...baseStyles, backgroundColor: '#fee2e2', borderLeft: '4px solid #ef4444' };
}
// Promoter
if (npsCategory === 'promoter' && (renewal === 'definitely' || renewal === 'likely')) {
return { ...baseStyles, backgroundColor: '#d1fae5', borderLeft: '4px solid #10b981' };
}
// Default
return { ...baseStyles, backgroundColor: '#f0fdfa', borderLeft: '4px solid #14b8a6' };
}
});
});
// ============================================
// FORM CONFIGURATION
// ============================================
form.configureSubmitButton({
label: 'Submit Survey'
});
form.configureCompletionScreen({
type: 'text',
title: 'Thank you for your feedback!',
message: 'Your insights are invaluable to our partnership. Your account manager will review this feedback and reach out to discuss any concerns or opportunities. We appreciate your continued trust in our team.'
});
}