export function customerExpectationSurvey(form: FormTs) {
// Expectation vs Reality Survey - Gap Analysis
// Demonstrates: Dual Sliders, Gap Analysis, Dynamic Styling, MatrixQuestion, Computed Values
// ============================================
// HEADER
// ============================================
form.addRow(row => {
row.addTextPanel('header', {
label: 'Expectation vs Reality',
computedValue: () => 'Help us understand how your experience compared to your expectations.',
customStyles: {
backgroundColor: '#7c3aed',
color: 'white',
padding: '24px',
borderRadius: '12px',
textAlign: 'center'
}
});
});
// ============================================
// SECTION 1: Context
// ============================================
const contextSection = form.addSubform('context', {
title: 'About Your Experience'
});
contextSection.addRow(row => {
row.addDropdown('experienceType', {
label: 'What type of experience are you rating?',
options: [
{ id: 'purchase', name: 'Product Purchase' },
{ id: 'service', name: 'Service Interaction' },
{ id: 'support', name: 'Customer Support' },
{ id: 'onboarding', name: 'Onboarding Process' },
{ id: 'delivery', name: 'Delivery Experience' },
{ id: 'other', name: 'Other' }
],
placeholder: 'Select experience type',
isRequired: true
}, '1fr');
row.addDatepicker('experienceDate', {
label: 'When did this happen?',
maxDate: () => new Date().toISOString().split('T')[0]
}, '1fr');
});
// ============================================
// SECTION 2: Overall Expectation vs Reality
// ============================================
const overallSection = form.addSubform('overall', {
title: 'Overall Experience Gap',
customStyles: { backgroundColor: '#f8fafc', padding: '16px', borderRadius: '8px' }
});
overallSection.addRow(row => {
row.addTextPanel('overallInstructions', {
computedValue: () => 'Rate your expectations BEFORE the experience and what you ACTUALLY received.',
customStyles: {
fontStyle: 'italic',
color: '#64748b',
marginBottom: '8px'
}
});
});
overallSection.addRow(row => {
row.addSlider('overallExpectation', {
label: 'What did you EXPECT? (1 = Very Low, 10 = Very High)',
min: 1,
max: 10,
step: 1,
showValue: true,
defaultValue: 5
}, '1fr');
row.addSlider('overallReality', {
label: 'What did you ACTUALLY get? (1 = Very Poor, 10 = Excellent)',
min: 1,
max: 10,
step: 1,
showValue: true,
defaultValue: 5
}, '1fr');
});
// Gap indicator
overallSection.addRow(row => {
row.addTextPanel('overallGap', {
label: 'Experience Gap',
computedValue: () => {
const expectation = overallSection.slider('overallExpectation')?.value() ?? 5;
const reality = overallSection.slider('overallReality')?.value() ?? 5;
const gap = reality - expectation;
if (gap > 0) return `+${gap} - We exceeded your expectations!`;
if (gap < 0) return `${gap} - We fell short of your expectations`;
return '0 - We met your expectations exactly';
},
customStyles: () => {
const expectation = overallSection.slider('overallExpectation')?.value() ?? 5;
const reality = overallSection.slider('overallReality')?.value() ?? 5;
const gap = reality - expectation;
const baseStyles = {
padding: '16px',
borderRadius: '8px',
textAlign: 'center',
fontWeight: 'bold',
fontSize: '18px'
};
if (gap >= 2) return { ...baseStyles, backgroundColor: '#d1fae5', color: '#065f46', border: '2px solid #10b981' };
if (gap > 0) return { ...baseStyles, backgroundColor: '#ecfdf5', color: '#059669' };
if (gap === 0) return { ...baseStyles, backgroundColor: '#fef3c7', color: '#92400e' };
if (gap > -2) return { ...baseStyles, backgroundColor: '#fee2e2', color: '#dc2626' };
return { ...baseStyles, backgroundColor: '#fecaca', color: '#991b1b', border: '2px solid #ef4444' };
}
});
});
// ============================================
// SECTION 3: Detailed Dimensions Matrix
// ============================================
const dimensionsSection = form.addSubform('dimensions', {
title: 'Rate Specific Dimensions',
customStyles: { marginTop: '16px' }
});
dimensionsSection.addRow(row => {
row.addMatrixQuestion('dimensionRatings', {
label: 'How did each aspect compare to your expectations?',
rows: [
{ id: 'quality', label: 'Quality', isRequired: true },
{ id: 'value', label: 'Value for Money', isRequired: true },
{ id: 'speed', label: 'Speed/Timeliness' },
{ id: 'ease', label: 'Ease of Use' },
{ id: 'communication', label: 'Communication' },
{ id: 'support', label: 'Support/Help' }
],
columns: [
{ id: 'far-below', label: 'Far Below' },
{ id: 'below', label: 'Below' },
{ id: 'met', label: 'Met' },
{ id: 'above', label: 'Above' },
{ id: 'far-above', label: 'Far Above' }
],
striped: true,
fullWidth: true
});
});
// ============================================
// SECTION 4: Emotional Response
// ============================================
const emotionalSection = form.addSubform('emotional', {
title: 'Your Emotional Response',
isVisible: () => {
const expectation = overallSection.slider('overallExpectation')?.value();
const reality = overallSection.slider('overallReality')?.value();
return expectation !== null && expectation !== undefined && reality !== null && reality !== undefined;
}
});
emotionalSection.addRow(row => {
row.addEmojiRating('emotionalResponse', {
label: () => {
const expectation = overallSection.slider('overallExpectation')?.value() ?? 5;
const reality = overallSection.slider('overallReality')?.value() ?? 5;
const gap = reality - expectation;
if (gap > 0) return 'How do you feel about exceeding your expectations?';
if (gap < 0) return 'How do you feel about the experience falling short?';
return 'How do you feel about the experience meeting expectations?';
},
preset: 'satisfaction',
size: 'lg',
alignment: 'center'
});
});
// ============================================
// SECTION 5: Deep Dive - Exceeded Expectations
// ============================================
const exceededSection = form.addSubform('exceeded', {
title: 'What Exceeded Your Expectations?',
isVisible: () => {
const expectation = overallSection.slider('overallExpectation')?.value() ?? 5;
const reality = overallSection.slider('overallReality')?.value() ?? 5;
return (reality - expectation) > 0;
},
customStyles: { backgroundColor: '#ecfdf5', padding: '16px', borderRadius: '8px' }
});
exceededSection.addRow(row => {
row.addSuggestionChips('positiveFactors', {
label: 'Select what pleasantly surprised you',
suggestions: [
{ id: 'quality', name: 'Better quality than expected' },
{ id: 'speed', name: 'Faster than expected' },
{ id: 'service', name: 'Outstanding service' },
{ id: 'value', name: 'Great value' },
{ id: 'extras', name: 'Unexpected extras' },
{ id: 'communication', name: 'Excellent communication' }
],
alignment: 'center'
});
});
exceededSection.addSpacer({ height: '16px' });
exceededSection.addRow(row => {
row.addTextarea('whatExceeded', {
label: 'Tell us more about what exceeded your expectations',
placeholder: 'What specific aspects pleasantly surprised you?',
rows: 3
});
});
// ============================================
// SECTION 6: Deep Dive - Fell Short
// ============================================
const shortfallSection = form.addSubform('shortfall', {
title: 'Where Did We Fall Short?',
isVisible: () => {
const expectation = overallSection.slider('overallExpectation')?.value() ?? 5;
const reality = overallSection.slider('overallReality')?.value() ?? 5;
return (reality - expectation) < 0;
},
customStyles: { backgroundColor: '#fef2f2', padding: '16px', borderRadius: '8px' }
});
shortfallSection.addRow(row => {
row.addSuggestionChips('negativeFactors', {
label: 'Select what disappointed you',
suggestions: [
{ id: 'quality', name: 'Lower quality than expected' },
{ id: 'speed', name: 'Slower than expected' },
{ id: 'service', name: 'Poor service' },
{ id: 'value', name: 'Not worth the price' },
{ id: 'missing', name: 'Missing features/items' },
{ id: 'communication', name: 'Poor communication' }
],
alignment: 'center'
});
});
shortfallSection.addSpacer({ height: '16px' });
shortfallSection.addRow(row => {
row.addTextarea('whatFellShort', {
label: 'Tell us specifically where we fell short',
placeholder: 'What did you expect that we failed to deliver?',
rows: 3,
isRequired: true
});
});
// ============================================
// SECTION 7: Future Expectations
// ============================================
const futureSection = form.addSubform('future', {
title: 'Looking Forward'
});
futureSection.addRow(row => {
row.addRatingScale('futureExpectation', {
label: 'Based on this experience, what would you expect next time?',
preset: 'likert-5',
lowLabel: 'Much lower expectations',
highLabel: 'Much higher expectations',
alignment: 'center'
});
});
futureSection.addRow(row => {
row.addStarRating('recommendLikelihood', {
label: 'How likely are you to recommend us based on this experience?',
maxStars: 5,
size: 'lg',
alignment: 'center',
showConfettiOnMax: true
});
});
// ============================================
// SECTION 8: Summary
// ============================================
const summarySection = form.addSubform('summary', {
title: 'Gap Analysis Summary',
isVisible: () => {
const expectation = overallSection.slider('overallExpectation')?.value();
const reality = overallSection.slider('overallReality')?.value();
return expectation !== null && expectation !== undefined && reality !== null && reality !== undefined;
}
});
summarySection.addRow(row => {
row.addTextPanel('gapSummary', {
computedValue: () => {
const expectation = overallSection.slider('overallExpectation')?.value() ?? 5;
const reality = overallSection.slider('overallReality')?.value() ?? 5;
const gap = reality - expectation;
const emotional = emotionalSection.emojiRating('emotionalResponse')?.value();
const futureExp = futureSection.ratingScale('futureExpectation')?.value();
const recommend = futureSection.starRating('recommendLikelihood')?.value();
const dimensionRatings = dimensionsSection.matrixQuestion('dimensionRatings')?.value();
let emoji = '';
let status = '';
if (gap >= 2) { emoji = ''; status = 'Significantly Exceeded'; }
else if (gap > 0) { emoji = ''; status = 'Exceeded'; }
else if (gap === 0) { emoji = ''; status = 'Met'; }
else if (gap > -2) { emoji = ''; status = 'Below'; }
else { emoji = ''; status = 'Significantly Below'; }
let summary = `Gap Analysis Report\n`;
summary += `${''.repeat(25)}\n\n`;
summary += ` Expected: ${expectation}/10\n`;
summary += ` Reality: ${reality}/10\n`;
summary += ` Gap: ${gap > 0 ? '+' : ''}${gap} (${status})\n`;
if (emotional) {
const moodLabels: Record<string, string> = {
'very-bad': ' Very Unhappy',
'bad': ' Unhappy',
'neutral': ' Neutral',
'good': ' Happy',
'excellent': ' Delighted'
};
summary += `\n Feeling: ${moodLabels[emotional] || emotional}\n`;
}
if (dimensionRatings) {
const exceeded = Object.values(dimensionRatings).filter(v => v === 'far-above' || v === 'above').length;
const met = Object.values(dimensionRatings).filter(v => v === 'met').length;
const below = Object.values(dimensionRatings).filter(v => v === 'far-below' || v === 'below').length;
summary += `\n Dimensions: ${exceeded} exceeded, ${met} met, ${below} below\n`;
}
if (recommend) {
summary += `\n Recommendation: ${recommend}/5 stars`;
}
return summary;
},
customStyles: () => {
const expectation = overallSection.slider('overallExpectation')?.value() ?? 5;
const reality = overallSection.slider('overallReality')?.value() ?? 5;
const gap = reality - expectation;
const baseStyles = {
padding: '20px',
borderRadius: '8px',
whiteSpace: 'pre-wrap',
fontFamily: 'monospace',
fontSize: '14px'
};
if (gap >= 2) return { ...baseStyles, backgroundColor: '#d1fae5', borderLeft: '4px solid #10b981' };
if (gap > 0) return { ...baseStyles, backgroundColor: '#ecfdf5', borderLeft: '4px solid #34d399' };
if (gap === 0) return { ...baseStyles, backgroundColor: '#fef3c7', borderLeft: '4px solid #f59e0b' };
if (gap > -2) return { ...baseStyles, backgroundColor: '#fee2e2', borderLeft: '4px solid #ef4444' };
return { ...baseStyles, backgroundColor: '#fecaca', borderLeft: '4px solid #dc2626' };
}
});
});
// ============================================
// FORM CONFIGURATION
// ============================================
form.configureSubmitButton({
label: () => {
const expectation = overallSection.slider('overallExpectation')?.value() ?? 5;
const reality = overallSection.slider('overallReality')?.value() ?? 5;
const gap = reality - expectation;
if (gap > 0) return 'Submit Positive Feedback';
if (gap < 0) return 'Submit Feedback & Help Us Improve';
return 'Submit Feedback';
}
});
form.configureCompletionScreen({
type: 'text',
title: 'Thank you for your detailed feedback!',
message: 'Your gap analysis helps us understand exactly where we excel and where we need to improve. We truly appreciate you taking the time to compare your expectations with reality.'
});
}