export function municipalWebsiteFeedback(form: FormTs) {
// Municipal Website Feedback Form
// Demonstrates: ThumbRating, RatingScale, MatrixQuestion, CheckboxList, conditional visibility, dynamic styling
// ============================================
// HEADER
// ============================================
form.addRow(row => {
row.addTextPanel('header', {
label: 'Help Us Improve Our Website',
computedValue: () => 'Your feedback helps us serve our community better online.',
customStyles: {
background: 'linear-gradient(135deg, #1e3a5f 0%, #2d5a87 100%)',
color: 'white',
padding: '24px',
borderRadius: '12px',
textAlign: 'center'
}
});
});
// ============================================
// SECTION 1: Visit Purpose
// ============================================
const purposeSection = form.addSubform('purposeSection', {
title: 'About Your Visit'
});
purposeSection.addRow(row => {
row.addDropdown('visitPurpose', {
label: 'What brought you to our website today?',
isRequired: true,
options: [
{ id: 'pay-bill', name: 'Pay a bill or fee' },
{ id: 'permit', name: 'Apply for a permit or license' },
{ id: 'find-info', name: 'Find information about services' },
{ id: 'report-issue', name: 'Report an issue or concern' },
{ id: 'meeting-agenda', name: 'View meeting agendas or minutes' },
{ id: 'contact', name: 'Find contact information' },
{ id: 'recreation', name: 'Recreation programs or facilities' },
{ id: 'other', name: 'Other' }
],
placeholder: 'Select your reason for visiting...'
});
});
purposeSection.addRow(row => {
row.addTextbox('otherPurpose', {
label: 'Please describe your purpose',
isVisible: () => purposeSection.dropdown('visitPurpose')?.value() === 'other',
isRequired: () => purposeSection.dropdown('visitPurpose')?.value() === 'other',
placeholder: 'What were you trying to do?'
});
});
purposeSection.addRow(row => {
row.addThumbRating('taskCompleted', {
label: 'Did you find what you were looking for?',
showLabels: true,
upLabel: 'Yes',
downLabel: 'No',
size: 'lg',
alignment: 'center'
});
});
// ============================================
// SECTION 2: Task Failure Follow-up (if not completed)
// ============================================
const failureSection = form.addSubform('failureSection', {
title: 'What Went Wrong?',
isVisible: () => purposeSection.thumbRating('taskCompleted')?.value() === 'down',
customStyles: { backgroundColor: '#fef3c7', padding: '16px', borderRadius: '8px' }
});
failureSection.addRow(row => {
row.addCheckboxList('failureReasons', {
label: 'What prevented you from completing your task?',
orientation: 'vertical',
options: [
{ id: 'not-found', name: 'Could not find the information/service' },
{ id: 'confusing', name: 'Website was confusing to navigate' },
{ id: 'broken-link', name: 'Encountered broken links or errors' },
{ id: 'outdated', name: 'Information seemed outdated' },
{ id: 'mobile-issue', name: 'Didn\'t work well on my device' },
{ id: 'too-slow', name: 'Website was too slow' },
{ id: 'login-issue', name: 'Problems with login/account' },
{ id: 'other', name: 'Other issue' }
]
});
});
failureSection.addSpacer();
failureSection.addRow(row => {
row.addTextarea('failureDetails', {
label: 'Please tell us more about the problem',
placeholder: 'Describe what happened...',
rows: 3,
autoExpand: true
});
});
// ============================================
// SECTION 3: Website Experience Rating
// ============================================
const experienceSection = form.addSubform('experienceSection', {
title: 'Rate Your Experience',
isVisible: () => purposeSection.thumbRating('taskCompleted')?.value() !== null
});
experienceSection.addRow(row => {
row.addMatrixQuestion('websiteRatings', {
label: 'How would you rate the following aspects of our website?',
rows: [
{ id: 'navigation', label: 'Ease of navigation', isRequired: true },
{ id: 'content', label: 'Content clarity', isRequired: true },
{ id: 'design', label: 'Visual design', isRequired: false },
{ id: 'speed', label: 'Loading speed', isRequired: true },
{ id: 'mobile', label: 'Mobile experience', isRequired: false },
{ id: 'search', label: 'Search functionality', isRequired: false }
],
columns: [
{ id: 'poor', label: 'Poor' },
{ id: 'fair', label: 'Fair' },
{ id: 'good', label: 'Good' },
{ id: 'excellent', label: 'Excellent' }
],
striped: true,
fullWidth: true
});
});
// ============================================
// SECTION 4: Accessibility
// ============================================
const accessibilitySection = form.addSubform('accessibilitySection', {
title: 'Accessibility',
isVisible: () => purposeSection.thumbRating('taskCompleted')?.value() !== null
});
accessibilitySection.addRow(row => {
row.addRadioButton('usesAccessibility', {
label: 'Do you use any accessibility features when browsing websites?',
orientation: 'horizontal',
options: [
{ id: 'yes', name: 'Yes' },
{ id: 'no', name: 'No' },
{ id: 'sometimes', name: 'Sometimes' }
]
});
});
accessibilitySection.addRow(row => {
row.addCheckboxList('accessibilityFeatures', {
label: 'Which accessibility features do you use?',
orientation: 'vertical',
isVisible: () => {
const val = accessibilitySection.radioButton('usesAccessibility')?.value();
return val === 'yes' || val === 'sometimes';
},
options: [
{ id: 'screen-reader', name: 'Screen reader' },
{ id: 'magnification', name: 'Text magnification' },
{ id: 'high-contrast', name: 'High contrast mode' },
{ id: 'keyboard-only', name: 'Keyboard navigation' },
{ id: 'voice-control', name: 'Voice control' },
{ id: 'other', name: 'Other assistive technology' }
]
});
});
accessibilitySection.addRow(row => {
row.addRatingScale('accessibilityRating', {
label: 'How accessible did you find our website?',
preset: 'satisfaction',
showSegmentColors: false,
lowLabel: 'Not accessible',
highLabel: 'Very accessible',
alignment: 'center',
isVisible: () => {
const val = accessibilitySection.radioButton('usesAccessibility')?.value();
return val === 'yes' || val === 'sometimes';
}
});
});
// ============================================
// SECTION 5: Overall Satisfaction
// ============================================
const satisfactionSection = form.addSubform('satisfactionSection', {
title: 'Overall Satisfaction',
isVisible: () => purposeSection.thumbRating('taskCompleted')?.value() !== null,
customStyles: () => {
const score = satisfactionSection.ratingScale('overallSatisfaction')?.value();
if (score !== null && score !== undefined) {
if (score >= 4) return { backgroundColor: '#d1fae5', padding: '16px', borderRadius: '8px' };
if (score <= 2) return { backgroundColor: '#fee2e2', padding: '16px', borderRadius: '8px' };
}
return { padding: '16px', borderRadius: '8px' };
}
});
satisfactionSection.addRow(row => {
row.addRatingScale('overallSatisfaction', {
label: 'How satisfied are you with your overall website experience?',
preset: 'satisfaction',
showSegmentColors: true,
alignment: 'center',
size: 'lg'
});
});
satisfactionSection.addRow(row => {
row.addEmojiRating('experienceEmotion', {
label: 'How did this experience make you feel?',
preset: 'satisfaction',
size: 'lg',
alignment: 'center',
showLabels: true
});
});
// ============================================
// SECTION 6: Suggestions
// ============================================
const suggestionsSection = form.addSubform('suggestionsSection', {
title: 'Your Suggestions',
isVisible: () => purposeSection.thumbRating('taskCompleted')?.value() !== null
});
suggestionsSection.addRow(row => {
row.addSuggestionChips('improvementAreas', {
label: 'Which areas need the most improvement? (Select up to 3)',
suggestions: [
{ id: 'search', name: 'Search function' },
{ id: 'navigation', name: 'Site navigation' },
{ id: 'mobile', name: 'Mobile experience' },
{ id: 'forms', name: 'Online forms' },
{ id: 'payments', name: 'Payment options' },
{ id: 'accessibility', name: 'Accessibility' },
{ id: 'content', name: 'Content organization' },
{ id: 'speed', name: 'Page speed' }
],
max: 3,
alignment: 'center'
});
});
suggestionsSection.addSpacer();
suggestionsSection.addRow(row => {
row.addTextarea('additionalFeedback', {
label: 'Any additional suggestions for improving our website?',
placeholder: 'Share your ideas for making our website better...',
rows: 3,
autoExpand: true
});
});
// ============================================
// SECTION 7: Contact Information
// ============================================
const contactSection = form.addSubform('contactSection', {
title: 'Follow-up (Optional)',
isVisible: () => purposeSection.thumbRating('taskCompleted')?.value() !== null
});
contactSection.addRow(row => {
row.addCheckbox('wantsResponse', {
label: 'I would like someone to contact me about my feedback'
});
});
contactSection.addRow(row => {
row.addEmail('contactEmail', {
label: 'Email address',
placeholder: 'your@email.com',
isVisible: () => contactSection.checkbox('wantsResponse')?.value() === true,
isRequired: () => contactSection.checkbox('wantsResponse')?.value() === true
});
});
// ============================================
// SECTION 8: Summary
// ============================================
const summarySection = form.addSubform('summarySection', {
title: 'Feedback Summary',
isVisible: () => {
const completed = purposeSection.thumbRating('taskCompleted')?.value();
const satisfaction = satisfactionSection.ratingScale('overallSatisfaction')?.value();
return completed !== null && satisfaction !== null && satisfaction !== undefined;
}
});
summarySection.addRow(row => {
row.addTextPanel('summaryContent', {
computedValue: () => {
const purpose = purposeSection.dropdown('visitPurpose')?.value();
const completed = purposeSection.thumbRating('taskCompleted')?.value();
const satisfaction = satisfactionSection.ratingScale('overallSatisfaction')?.value();
const emotion = satisfactionSection.emojiRating('experienceEmotion')?.value();
const improvements = suggestionsSection.suggestionChips('improvementAreas')?.value() || [];
if (!purpose) return '';
const purposeLabels: Record<string, string> = {
'pay-bill': 'Pay a bill or fee',
'permit': 'Apply for a permit',
'find-info': 'Find information',
'report-issue': 'Report an issue',
'meeting-agenda': 'View meetings',
'contact': 'Find contact info',
'recreation': 'Recreation programs',
'other': 'Other'
};
let summary = `Municipal Website Feedback\n`;
summary += `${'═'.repeat(30)}\n\n`;
summary += `Visit Purpose: ${purposeLabels[purpose] || purpose}\n`;
summary += `Task Completed: ${completed === 'up' ? 'Yes' : 'No'}\n`;
if (satisfaction !== null && satisfaction !== undefined) {
const satisfactionLabels = ['', 'Very Dissatisfied', 'Dissatisfied', 'Neutral', 'Satisfied', 'Very Satisfied'];
summary += `Satisfaction: ${satisfactionLabels[satisfaction]} (${satisfaction}/5)\n`;
}
if (emotion) {
const emotionLabels: Record<string, string> = {
'very-bad': 'Very Frustrated',
'bad': 'Frustrated',
'neutral': 'Neutral',
'good': 'Satisfied',
'excellent': 'Delighted'
};
summary += `Feeling: ${emotionLabels[emotion] || emotion}\n`;
}
if (improvements.length > 0) {
summary += `\nAreas for Improvement: ${improvements.length} selected`;
}
return summary;
},
customStyles: () => {
const satisfaction = satisfactionSection.ratingScale('overallSatisfaction')?.value();
const baseStyles = {
padding: '16px',
borderRadius: '8px',
whiteSpace: 'pre-wrap',
fontFamily: 'monospace',
fontSize: '14px'
};
if (satisfaction !== null && satisfaction !== undefined) {
if (satisfaction >= 4) {
return { ...baseStyles, backgroundColor: '#d1fae5', borderLeft: '4px solid #10b981' };
} else if (satisfaction <= 2) {
return { ...baseStyles, backgroundColor: '#fee2e2', borderLeft: '4px solid #ef4444' };
}
}
return { ...baseStyles, backgroundColor: '#f0f9ff', borderLeft: '4px solid #0ea5e9' };
}
});
});
// ============================================
// FORM CONFIGURATION
// ============================================
form.configureSubmitButton({
label: 'Submit Feedback',
isVisible: () => purposeSection.thumbRating('taskCompleted')?.value() !== null
});
form.configureCompletionScreen({
type: 'text',
title: 'Thank You for Your Feedback!',
message: 'Your input helps us improve our digital services for all residents. We review all feedback and use it to prioritize website enhancements.'
});
}