export function emergencyServicesFeedback(form: FormTs) {
// Emergency Services Feedback Form
// Demonstrates: RatingScale, StarRating, MatrixQuestion, EmojiRating, Timepicker, RadioButton, SuggestionChips
// ============================================
// HEADER
// ============================================
form.addRow(row => {
row.addTextPanel('header', {
label: 'Emergency Services Feedback',
computedValue: () => 'Help us improve our emergency response. Your feedback matters.',
customStyles: {
backgroundColor: '#dc2626',
color: 'white',
padding: '24px',
borderRadius: '12px',
textAlign: 'center'
}
});
});
// ============================================
// SECTION 1: Incident Details
// ============================================
const incidentSection = form.addSubform('incidentDetails', {
title: 'Incident Information'
});
incidentSection.addRow(row => {
row.addRadioButton('serviceType', {
label: 'Which emergency service did you interact with?',
options: [
{ id: 'police', name: 'Police' },
{ id: 'fire', name: 'Fire Department' },
{ id: 'ambulance', name: 'Ambulance / EMS' },
{ id: 'dispatch', name: '911 Dispatch Only' },
{ id: 'multiple', name: 'Multiple Services' }
],
orientation: 'vertical',
isRequired: true
});
});
incidentSection.addRow(row => {
row.addDatepicker('incidentDate', {
label: 'Date of incident',
maxDate: () => new Date().toISOString(),
isRequired: true
}, '1fr');
row.addTimepicker('incidentTime', {
label: 'Approximate time of call',
isRequired: true
}, '1fr');
});
incidentSection.addRow(row => {
row.addDropdown('incidentType', {
label: 'Type of emergency',
options: () => {
const serviceType = incidentSection.radioButton('serviceType')?.value();
if (serviceType === 'police') {
return [
{ id: 'crime', name: 'Crime in Progress' },
{ id: 'accident', name: 'Traffic Accident' },
{ id: 'domestic', name: 'Domestic Disturbance' },
{ id: 'theft', name: 'Theft / Burglary' },
{ id: 'suspicious', name: 'Suspicious Activity' },
{ id: 'other-police', name: 'Other Police Matter' }
];
} else if (serviceType === 'fire') {
return [
{ id: 'structure-fire', name: 'Structure Fire' },
{ id: 'vehicle-fire', name: 'Vehicle Fire' },
{ id: 'gas-leak', name: 'Gas Leak' },
{ id: 'rescue', name: 'Rescue Operation' },
{ id: 'other-fire', name: 'Other Fire Emergency' }
];
} else if (serviceType === 'ambulance') {
return [
{ id: 'medical', name: 'Medical Emergency' },
{ id: 'injury', name: 'Injury / Trauma' },
{ id: 'cardiac', name: 'Cardiac Emergency' },
{ id: 'breathing', name: 'Breathing Difficulty' },
{ id: 'other-medical', name: 'Other Medical Issue' }
];
} else {
return [
{ id: 'general', name: 'General Emergency' },
{ id: 'information', name: 'Information Request' },
{ id: 'other', name: 'Other' }
];
}
},
placeholder: 'Select type of emergency',
isVisible: () => incidentSection.radioButton('serviceType')?.value() !== null
});
});
// ============================================
// SECTION 2: Response Time Evaluation
// ============================================
const responseSection = form.addSubform('responseEvaluation', {
title: 'Response Time',
isVisible: () => incidentSection.radioButton('serviceType')?.value() !== null &&
incidentSection.radioButton('serviceType')?.value() !== 'dispatch'
});
responseSection.addRow(row => {
row.addRatingScale('responseTimeSatisfaction', {
label: 'How satisfied were you with the response time?',
preset: 'satisfaction',
size: 'lg',
alignment: 'center'
});
});
responseSection.addRow(row => {
row.addRadioButton('estimatedArrival', {
label: 'Approximately how long did it take for help to arrive?',
options: [
{ id: 'under5', name: 'Under 5 minutes' },
{ id: '5to10', name: '5-10 minutes' },
{ id: '10to15', name: '10-15 minutes' },
{ id: '15to30', name: '15-30 minutes' },
{ id: 'over30', name: 'Over 30 minutes' }
],
orientation: 'vertical'
});
});
// ============================================
// SECTION 3: Service Quality Matrix
// ============================================
const qualitySection = form.addSubform('serviceQuality', {
title: 'Service Quality Evaluation',
isVisible: () => incidentSection.radioButton('serviceType')?.value() !== null
});
qualitySection.addRow(row => {
row.addMatrixQuestion('qualityMatrix', {
label: 'Please rate the following aspects of the service you received:',
rows: () => {
const serviceType = incidentSection.radioButton('serviceType')?.value();
const baseRows = [
{ id: 'professionalism', label: 'Professionalism of responders', isRequired: true },
{ id: 'communication', label: 'Clear communication', isRequired: true },
{ id: 'empathy', label: 'Empathy and compassion' }
];
if (serviceType === 'dispatch' || serviceType === 'multiple') {
baseRows.unshift({ id: 'dispatch', label: '911 operator helpfulness', isRequired: true });
}
if (serviceType !== 'dispatch') {
baseRows.push({ id: 'resolution', label: 'Effective resolution of situation' });
}
return baseRows;
},
columns: [
{ id: 'poor', label: 'Poor' },
{ id: 'fair', label: 'Fair' },
{ id: 'good', label: 'Good' },
{ id: 'excellent', label: 'Excellent' }
],
striped: true,
fullWidth: true
});
});
// ============================================
// SECTION 4: Star Ratings for Specific Areas
// ============================================
const ratingsSection = form.addSubform('detailedRatings', {
title: 'Detailed Ratings',
isVisible: () => incidentSection.radioButton('serviceType')?.value() !== null
});
ratingsSection.addRow(row => {
row.addStarRating('overallRating', {
label: 'Overall experience rating',
maxStars: 5,
size: 'lg',
alignment: 'center',
showConfettiOnMax: true
});
});
ratingsSection.addRow(row => {
row.addStarRating('safetyFeeling', {
label: 'How safe did you feel during the interaction?',
maxStars: 5,
size: 'md',
alignment: 'center'
}, '1fr');
row.addStarRating('informationProvided', {
label: 'Quality of information provided',
maxStars: 5,
size: 'md',
alignment: 'center'
}, '1fr');
});
// ============================================
// SECTION 5: Overall Satisfaction (NPS)
// ============================================
const npsSection = form.addSubform('npsSection', {
title: 'Would You Recommend Our Services?',
isVisible: () => incidentSection.radioButton('serviceType')?.value() !== null,
customStyles: () => {
const category = npsSection.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' };
}
});
npsSection.addRow(row => {
row.addRatingScale('npsScore', {
label: 'How likely are you to recommend our emergency services to others?',
preset: 'nps',
showCategoryLabel: true,
showSegmentColors: true,
size: 'md'
});
});
// ============================================
// SECTION 6: Emotional Experience
// ============================================
const emotionSection = form.addSubform('emotionalExperience', {
title: 'Your Experience',
isVisible: () => incidentSection.radioButton('serviceType')?.value() !== null
});
emotionSection.addRow(row => {
row.addEmojiRating('overallFeeling', {
label: 'How do you feel about the overall experience?',
preset: 'satisfaction',
size: 'lg',
showLabels: true,
alignment: 'center'
});
});
// Positive highlights for satisfied respondents
emotionSection.addRow(row => {
row.addSuggestionChips('positiveAspects', {
label: 'What did we do well? (Select all that apply)',
suggestions: [
{ id: 'fast', name: 'Fast response' },
{ id: 'professional', name: 'Professional conduct' },
{ id: 'caring', name: 'Caring attitude' },
{ id: 'clear', name: 'Clear communication' },
{ id: 'thorough', name: 'Thorough service' },
{ id: 'followup', name: 'Good follow-up' }
],
alignment: 'center',
isVisible: () => {
const feeling = emotionSection.emojiRating('overallFeeling')?.value();
return feeling === 'good' || feeling === 'excellent';
}
});
});
// Areas for improvement for unsatisfied respondents
emotionSection.addSpacer();
emotionSection.addRow(row => {
row.addSuggestionChips('improvementAreas', {
label: 'What could we improve? (Select all that apply)',
suggestions: [
{ id: 'speed', name: 'Response speed' },
{ id: 'communication', name: 'Communication' },
{ id: 'attitude', name: 'Staff attitude' },
{ id: 'equipment', name: 'Equipment/Resources' },
{ id: 'followup', name: 'Follow-up care' },
{ id: 'information', name: 'Information provided' }
],
alignment: 'center',
isVisible: () => {
const feeling = emotionSection.emojiRating('overallFeeling')?.value();
return feeling === 'bad' || feeling === 'very-bad' || feeling === 'neutral';
}
});
});
// ============================================
// SECTION 7: Additional Comments
// ============================================
const commentsSection = form.addSubform('comments', {
title: 'Additional Comments',
isVisible: () => incidentSection.radioButton('serviceType')?.value() !== null
});
commentsSection.addSpacer();
commentsSection.addRow(row => {
row.addTextarea('additionalFeedback', {
label: () => {
const npsCategory = npsSection.ratingScale('npsScore')?.npsCategory();
if (npsCategory === 'promoter') return 'What made your experience exceptional?';
if (npsCategory === 'detractor') return 'How can we improve our emergency services?';
return 'Please share any additional feedback or suggestions';
},
placeholder: 'Your comments help us serve the community better...',
rows: 4,
autoExpand: true
});
});
// ============================================
// SECTION 8: Contact Information (Optional)
// ============================================
const contactSection = form.addSubform('contactInfo', {
title: 'Follow-up Contact (Optional)',
isVisible: () => incidentSection.radioButton('serviceType')?.value() !== null
});
contactSection.addRow(row => {
row.addCheckbox('requestCallback', {
label: 'I would like someone to contact me regarding my feedback'
});
});
contactSection.addRow(row => {
row.addTextbox('contactName', {
label: 'Your name',
placeholder: 'Full name',
isVisible: () => contactSection.checkbox('requestCallback')?.value() === true,
isRequired: () => contactSection.checkbox('requestCallback')?.value() === true
}, '1fr');
row.addEmail('contactEmail', {
label: 'Email address',
placeholder: 'your@email.com',
isVisible: () => contactSection.checkbox('requestCallback')?.value() === true,
isRequired: () => contactSection.checkbox('requestCallback')?.value() === true
}, '1fr');
});
// ============================================
// SECTION 9: Summary
// ============================================
const summarySection = form.addSubform('summary', {
title: 'Feedback Summary',
isVisible: () => ratingsSection.starRating('overallRating')?.value() !== null
});
summarySection.addRow(row => {
row.addTextPanel('summaryContent', {
computedValue: () => {
const serviceType = incidentSection.radioButton('serviceType')?.value();
const overallRating = ratingsSection.starRating('overallRating')?.value();
const npsScore = npsSection.ratingScale('npsScore')?.value();
const npsCategory = npsSection.ratingScale('npsScore')?.npsCategory();
const feeling = emotionSection.emojiRating('overallFeeling')?.value();
if (!overallRating) return '';
const serviceLabels: Record<string, string> = {
'police': 'Police',
'fire': 'Fire Department',
'ambulance': 'Ambulance / EMS',
'dispatch': '911 Dispatch',
'multiple': 'Multiple Services'
};
const feelingEmojis: Record<string, string> = {
'very-bad': '😢',
'bad': '😕',
'neutral': '😐',
'good': '😊',
'excellent': '😍'
};
let summary = `Emergency Services Feedback\n`;
summary += `${'═'.repeat(30)}\n\n`;
summary += `Service: ${serviceLabels[serviceType || ''] || 'Not specified'}\n`;
summary += `Overall Rating: ${'★'.repeat(overallRating)}${'☆'.repeat(5 - overallRating)}\n`;
if (npsScore !== null && npsScore !== undefined) {
summary += `Recommendation Score: ${npsScore}/10 (${npsCategory?.charAt(0).toUpperCase()}${npsCategory?.slice(1)})\n`;
}
if (feeling) {
summary += `Experience: ${feelingEmojis[feeling] || ''}\n`;
}
summary += `\nThank you for helping us improve public safety!`;
return summary;
},
customStyles: () => {
const npsCategory = npsSection.ratingScale('npsScore')?.npsCategory();
const baseStyles = {
padding: '16px',
borderRadius: '8px',
whiteSpace: 'pre-wrap',
fontFamily: 'monospace',
fontSize: '14px'
};
if (npsCategory === 'promoter') {
return { ...baseStyles, backgroundColor: '#d1fae5', borderLeft: '4px solid #10b981' };
} else if (npsCategory === 'passive') {
return { ...baseStyles, backgroundColor: '#fef3c7', borderLeft: '4px solid #f59e0b' };
} else if (npsCategory === 'detractor') {
return { ...baseStyles, backgroundColor: '#fee2e2', borderLeft: '4px solid #ef4444' };
}
return { ...baseStyles, backgroundColor: '#f3f4f6', borderLeft: '4px solid #9ca3af' };
}
});
});
// ============================================
// FORM CONFIGURATION
// ============================================
form.configureSubmitButton({
label: 'Submit Feedback',
isVisible: () => incidentSection.radioButton('serviceType')?.value() !== null
});
form.configureCompletionScreen({
type: 'text',
title: 'Thank You for Your Feedback!',
message: 'Your input helps us improve emergency services for our entire community. If you requested a callback, a representative will contact you within 2-3 business days.'
});
}