export function leagueOrganizationFeedback(form: FormTs) {
// League & Tournament Feedback Form
// Demonstrates: MatrixQuestion, StarRating, EmojiRating, Slider, RadioButton, Dropdown, conditional visibility, dynamic styling
// ============================================
// HEADER
// ============================================
form.addRow(row => {
row.addTextPanel('header', {
label: 'Season Feedback Survey',
computedValue: () => 'Help us make next season even better! Your feedback is essential for improving our league.',
customStyles: {
background: 'linear-gradient(135deg, #2563eb 0%, #3b82f6 100%)',
color: 'white',
padding: '28px',
borderRadius: '12px',
textAlign: 'center'
}
});
});
// ============================================
// SECTION 1: Participant Information
// ============================================
const infoSection = form.addSubform('infoSection', {
title: 'About Your Participation',
customStyles: { backgroundColor: '#eff6ff', padding: '16px', borderRadius: '8px' }
});
infoSection.addRow(row => {
row.addDropdown('role', {
label: 'Your role in the league',
options: [
{ id: 'player-adult', name: 'Player (Adult)' },
{ id: 'player-youth', name: 'Player (Youth)' },
{ id: 'parent', name: 'Parent/Guardian' },
{ id: 'coach', name: 'Coach/Manager' },
{ id: 'team-admin', name: 'Team Administrator' },
{ id: 'volunteer', name: 'Volunteer' }
],
placeholder: 'Select your role',
isRequired: true
}, '1fr');
row.addDropdown('division', {
label: 'Division/Age Group',
options: [
{ id: 'u8', name: 'Under 8' },
{ id: 'u10', name: 'Under 10' },
{ id: 'u12', name: 'Under 12' },
{ id: 'u14', name: 'Under 14' },
{ id: 'u16', name: 'Under 16' },
{ id: 'u18', name: 'Under 18' },
{ id: 'adult-rec', name: 'Adult Recreational' },
{ id: 'adult-comp', name: 'Adult Competitive' }
],
placeholder: 'Select division',
isRequired: true
}, '1fr');
});
infoSection.addRow(row => {
row.addRadioButton('seasonsParticipated', {
label: 'How many seasons have you participated in this league?',
options: [
{ id: 'first', name: 'This was my first season' },
{ id: '2-3', name: '2-3 seasons' },
{ id: '4-6', name: '4-6 seasons' },
{ id: '7+', name: '7 or more seasons' }
],
orientation: 'horizontal'
});
});
// ============================================
// SECTION 2: Organization & Communication
// ============================================
const orgSection = form.addSubform('orgSection', {
title: 'League Organization',
customStyles: { backgroundColor: '#f8fafc', padding: '16px', borderRadius: '8px' }
});
orgSection.addRow(row => {
row.addMatrixQuestion('orgMatrix', {
label: 'Please rate the following aspects of league organization:',
rows: [
{ id: 'registration', label: 'Registration process', isRequired: true },
{ id: 'communication', label: 'League communication', isRequired: true },
{ id: 'website', label: 'Website/app usability' },
{ id: 'schedule-notice', label: 'Advance notice of schedules' },
{ id: 'changes', label: 'Handling of schedule changes' },
{ id: 'responsiveness', label: 'Staff responsiveness to questions' }
],
columns: [
{ id: '1', label: 'Poor' },
{ id: '2', label: 'Fair' },
{ id: '3', label: 'Good' },
{ id: '4', label: 'Very Good' },
{ id: '5', label: 'Excellent' }
],
striped: true,
fullWidth: true
});
});
// ============================================
// SECTION 3: Scheduling
// ============================================
const scheduleSection = form.addSubform('scheduleSection', {
title: 'Game Scheduling'
});
scheduleSection.addRow(row => {
row.addStarRating('scheduleOverall', {
label: 'Overall satisfaction with game scheduling',
maxStars: 5,
size: 'lg',
alignment: 'center',
showConfettiOnMax: true
});
});
scheduleSection.addRow(row => {
row.addCheckboxList('scheduleIssues', {
label: 'Did you experience any scheduling issues?',
options: [
{ id: 'none', name: 'No issues - schedule worked well' },
{ id: 'conflicts', name: 'Games conflicted with other commitments' },
{ id: 'too-early', name: 'Games too early in the day' },
{ id: 'too-late', name: 'Games too late in the day' },
{ id: 'weekday', name: 'Weekday games were difficult' },
{ id: 'back-to-back', name: 'Too many games in short period' },
{ id: 'travel', name: 'Too much travel between venues' },
{ id: 'last-minute', name: 'Last-minute changes were disruptive' }
],
orientation: 'vertical'
}, '1fr');
row.addRadioButton('preferredDays', {
label: 'Preferred game days for next season?',
options: [
{ id: 'weekday', name: 'Weekday evenings' },
{ id: 'saturday', name: 'Saturday' },
{ id: 'sunday', name: 'Sunday' },
{ id: 'weekend', name: 'Either weekend day' },
{ id: 'flexible', name: 'No preference' }
],
orientation: 'vertical'
}, '1fr');
});
scheduleSection.addRow(row => {
row.addSlider('gameFrequency', {
label: 'How many games per week would you prefer?',
min: 1,
max: 4,
step: 1,
defaultValue: 2,
showValue: true,
unit: 'games/week'
});
});
// ============================================
// SECTION 4: Officiating
// ============================================
const refSection = form.addSubform('refSection', {
title: 'Officiating'
});
refSection.addRow(row => {
row.addStarRating('refOverall', {
label: 'Overall quality of officiating',
maxStars: 5,
size: 'lg',
alignment: 'center'
});
});
refSection.addRow(row => {
row.addRatingScale('refConsistency', {
preset: 'likert-5',
label: 'Officials were consistent in their calls throughout games',
lowLabel: 'Strongly Disagree',
highLabel: 'Strongly Agree',
alignment: 'center'
});
});
refSection.addRow(row => {
row.addCheckboxList('refStrengths', {
label: 'What did officials do well?',
options: [
{ id: 'knowledge', name: 'Good knowledge of rules' },
{ id: 'control', name: 'Maintained game control' },
{ id: 'fair', name: 'Fair and impartial' },
{ id: 'communication', name: 'Clear communication' },
{ id: 'safety', name: 'Prioritized player safety' },
{ id: 'professional', name: 'Professional demeanor' }
],
orientation: 'vertical'
}, '1fr');
row.addCheckboxList('refImprovements', {
label: 'Areas for improvement?',
options: [
{ id: 'consistency', name: 'More consistency' },
{ id: 'rules', name: 'Better rule knowledge' },
{ id: 'positioning', name: 'Better positioning' },
{ id: 'communication', name: 'Clearer explanations' },
{ id: 'control', name: 'Better game management' },
{ id: 'on-time', name: 'Arrive on time' }
],
orientation: 'vertical'
}, '1fr');
});
// ============================================
// SECTION 5: Facilities
// ============================================
const facilitiesSection = form.addSubform('facilitiesSection', {
title: 'Venues & Facilities'
});
facilitiesSection.addRow(row => {
row.addMatrixQuestion('venueMatrix', {
label: 'Rate the overall quality of venues used:',
rows: [
{ id: 'field-quality', label: 'Field/Court condition', isRequired: true },
{ id: 'safety', label: 'Safety of playing area' },
{ id: 'parking', label: 'Parking availability' },
{ id: 'restrooms', label: 'Restroom facilities' },
{ id: 'seating', label: 'Spectator seating' },
{ id: 'lighting', label: 'Lighting (if applicable)' }
],
columns: [
{ id: '1', label: 'Poor' },
{ id: '2', label: 'Fair' },
{ id: '3', label: 'Good' },
{ id: '4', label: 'Very Good' },
{ id: '5', label: 'Excellent' },
{ id: 'na', label: 'N/A' }
],
striped: true,
fullWidth: true
});
});
// ============================================
// SECTION 6: Overall Experience
// ============================================
const experienceSection = form.addSubform('experienceSection', {
title: 'Overall Season Experience',
customStyles: () => {
const nps = experienceSection.ratingScale('npsScore')?.npsCategory();
if (nps === 'promoter') return { backgroundColor: '#dcfce7', padding: '16px', borderRadius: '8px' };
if (nps === 'passive') return { backgroundColor: '#fef3c7', padding: '16px', borderRadius: '8px' };
if (nps === 'detractor') return { backgroundColor: '#fee2e2', padding: '16px', borderRadius: '8px' };
return { padding: '16px', borderRadius: '8px', border: '1px dashed #cbd5e1' };
}
});
experienceSection.addRow(row => {
row.addEmojiRating('seasonMood', {
label: 'How would you describe your overall season experience?',
preset: 'satisfaction',
size: 'lg',
showLabels: true,
alignment: 'center'
});
});
experienceSection.addSpacer({ height: '16px' });
experienceSection.addRow(row => {
row.addRatingScale('npsScore', {
preset: 'nps',
label: 'How likely are you to recommend this league to others?',
showCategoryLabel: true,
showSegmentColors: true,
showConfettiOnPromoter: true,
isRequired: true
});
});
experienceSection.addSpacer({ height: '16px' });
experienceSection.addRow(row => {
row.addRadioButton('returnIntent', {
label: 'Do you plan to participate next season?',
options: [
{ id: 'definitely', name: 'Definitely yes' },
{ id: 'probably', name: 'Probably yes' },
{ id: 'unsure', name: 'Not sure yet' },
{ id: 'probably-not', name: 'Probably not' },
{ id: 'no', name: 'Definitely not' }
],
orientation: 'horizontal'
});
});
// ============================================
// SECTION 7: What We Did Well
// ============================================
const strengthsSection = form.addSubform('strengthsSection', {
title: 'What Did We Do Well?',
isVisible: () => {
const score = experienceSection.ratingScale('npsScore')?.value();
return score !== null && score !== undefined && score >= 7;
},
customStyles: { backgroundColor: '#dcfce7', padding: '16px', borderRadius: '8px' }
});
strengthsSection.addRow(row => {
row.addSuggestionChips('highlights', {
label: 'Select the highlights of the season (up to 4)',
suggestions: [
{ id: 'fun', name: 'Fun atmosphere' },
{ id: 'organization', name: 'Well organized' },
{ id: 'competition', name: 'Good competition level' },
{ id: 'sportsmanship', name: 'Great sportsmanship' },
{ id: 'refs', name: 'Quality officiating' },
{ id: 'venues', name: 'Nice facilities' },
{ id: 'communication', name: 'Clear communication' },
{ id: 'value', name: 'Good value for cost' }
],
max: 4,
alignment: 'center'
});
});
// ============================================
// SECTION 8: Areas for Improvement
// ============================================
const improvementSection = form.addSubform('improvementSection', {
title: 'How Can We Improve?',
isVisible: () => {
const score = experienceSection.ratingScale('npsScore')?.value();
return score !== null && score !== undefined && score <= 6;
},
customStyles: { backgroundColor: '#fef3c7', padding: '16px', borderRadius: '8px' }
});
improvementSection.addRow(row => {
row.addCheckboxList('improvementAreas', {
label: 'What areas need the most improvement?',
options: [
{ id: 'scheduling', name: 'Game scheduling' },
{ id: 'communication', name: 'Communication' },
{ id: 'refs', name: 'Officiating quality' },
{ id: 'venues', name: 'Venue quality' },
{ id: 'competitiveness', name: 'Division balance' },
{ id: 'registration', name: 'Registration process' },
{ id: 'cost', name: 'Fees/Value' },
{ id: 'safety', name: 'Player safety' }
],
orientation: 'vertical'
});
});
improvementSection.addSpacer({ height: '12px' });
improvementSection.addRow(row => {
row.addTextarea('improvementDetails', {
label: 'Please share specific suggestions',
placeholder: 'Your ideas help us improve the league for everyone...',
rows: 3,
autoExpand: true
});
});
// ============================================
// SECTION 9: Additional Comments
// ============================================
form.addSpacer({ height: '16px' });
const commentsSection = form.addSubform('commentsSection', {
title: 'Additional Feedback'
});
commentsSection.addRow(row => {
row.addTextarea('additionalComments', {
label: 'Any other comments or suggestions for the league?',
placeholder: 'Share memorable moments, recognize outstanding volunteers, or provide any other feedback...',
rows: 4,
autoExpand: true
});
});
commentsSection.addRow(row => {
row.addCheckbox('allowContact', {
label: 'League administrators may contact me about my feedback'
});
});
commentsSection.addRow(row => {
row.addEmail('contactEmail', {
label: 'Email (optional)',
placeholder: 'your@email.com',
isVisible: () => commentsSection.checkbox('allowContact')?.value() === true
});
});
// ============================================
// SECTION 10: Summary
// ============================================
const summarySection = form.addSubform('summary', {
title: 'Feedback Summary',
isVisible: () => experienceSection.ratingScale('npsScore')?.value() !== null
});
summarySection.addRow(row => {
row.addTextPanel('summaryContent', {
computedValue: () => {
const npsScore = experienceSection.ratingScale('npsScore')?.value();
const npsCategory = experienceSection.ratingScale('npsScore')?.npsCategory();
const mood = experienceSection.emojiRating('seasonMood')?.value();
const returnIntent = experienceSection.radioButton('returnIntent')?.value();
const scheduleRating = scheduleSection.starRating('scheduleOverall')?.value();
const refRating = refSection.starRating('refOverall')?.value();
if (npsScore === null || npsScore === undefined) return '';
let emoji = '';
if (npsCategory === 'promoter') emoji = '🏆';
else if (npsCategory === 'passive') emoji = '🎯';
else emoji = '📋';
let summary = `${emoji} Season Feedback Summary\n`;
summary += `${'═'.repeat(28)}\n\n`;
summary += `📊 NPS: ${npsScore}/10 (${npsCategory?.charAt(0).toUpperCase()}${npsCategory?.slice(1)})\n`;
if (scheduleRating) {
summary += `📅 Scheduling: ${scheduleRating}/5 stars\n`;
}
if (refRating) {
summary += `🏁 Officiating: ${refRating}/5 stars\n`;
}
if (mood) {
const moodLabels: Record<string, string> = {
'very-bad': '😢 Poor season',
'bad': '😕 Below expectations',
'neutral': '😐 Average season',
'good': '😊 Good season',
'excellent': '🤩 Great season!'
};
summary += `\n${moodLabels[mood] || mood}\n`;
}
if (returnIntent) {
const intentLabels: Record<string, string> = {
'definitely': '✅ Definitely returning',
'probably': '👍 Probably returning',
'unsure': '🤔 Undecided',
'probably-not': '⚠️ Probably not returning',
'no': '❌ Not returning'
};
summary += `\n${intentLabels[returnIntent] || returnIntent}`;
}
return summary;
},
customStyles: () => {
const category = experienceSection.ratingScale('npsScore')?.npsCategory();
const baseStyles = {
padding: '16px',
borderRadius: '8px',
whiteSpace: 'pre-wrap',
fontFamily: 'monospace',
fontSize: '14px'
};
if (category === 'promoter') {
return { ...baseStyles, backgroundColor: '#d1fae5', borderLeft: '4px solid #10b981' };
} else if (category === 'passive') {
return { ...baseStyles, backgroundColor: '#fef3c7', borderLeft: '4px solid #f59e0b' };
} else if (category === 'detractor') {
return { ...baseStyles, backgroundColor: '#fee2e2', borderLeft: '4px solid #ef4444' };
}
return baseStyles;
}
});
});
// ============================================
// FORM CONFIGURATION
// ============================================
form.configureSubmitButton({
label: 'Submit Season Feedback',
isVisible: () => experienceSection.ratingScale('npsScore')?.value() !== null
});
form.configureCompletionScreen({
type: 'text',
title: 'Thank You for Your Feedback!',
message: 'Your input is invaluable for improving our league. We look forward to seeing you next season!'
});
}