export function libraryFeedbackSurvey(form: FormTs) {
// Library Services Feedback Form
// Demonstrates: MatrixQuestion, StarRating x4, ThumbRating, CheckboxList, RadioButton, Slider, EmojiRating
// Advanced: Conditional visibility, Dynamic labels, Multi-dimensional assessment, Service evaluation
// ============================================
// HEADER
// ============================================
form.addRow(row => {
row.addTextPanel('header', {
label: 'Library Feedback',
computedValue: () => 'Help us improve your library experience. Your feedback shapes our services.',
customStyles: {
backgroundColor: '#7c2d12',
color: 'white',
padding: '24px',
borderRadius: '12px',
textAlign: 'center'
}
});
});
// ============================================
// SECTION 1: Visit Information
// ============================================
const visitSection = form.addSubform('visitSection', {
title: 'About Your Visit'
});
visitSection.addRow(row => {
row.addRadioButton('visitFrequency', {
label: 'How often do you visit the library?',
options: [
{ id: 'first', name: 'This is my first visit' },
{ id: 'rarely', name: 'A few times a year' },
{ id: 'monthly', name: 'A few times a month' },
{ id: 'weekly', name: 'Weekly' },
{ id: 'daily', name: 'Almost daily' }
],
orientation: 'vertical'
}, '1fr');
row.addRadioButton('userType', {
label: 'What best describes you?',
options: [
{ id: 'student', name: 'Student' },
{ id: 'faculty', name: 'Faculty/Staff' },
{ id: 'researcher', name: 'Researcher' },
{ id: 'community', name: 'Community member' },
{ id: 'other', name: 'Other' }
],
orientation: 'vertical'
}, '1fr');
});
visitSection.addSpacer({ height: '16px' });
visitSection.addRow(row => {
row.addCheckboxList('visitPurpose', {
label: 'What brought you to the library today? (Select all that apply)',
options: [
{ id: 'study', name: 'Study/homework' },
{ id: 'research', name: 'Research' },
{ id: 'borrow', name: 'Borrow materials' },
{ id: 'return', name: 'Return materials' },
{ id: 'computer', name: 'Use computers' },
{ id: 'wifi', name: 'Use WiFi' },
{ id: 'printing', name: 'Printing/copying' },
{ id: 'meeting', name: 'Group meeting' },
{ id: 'events', name: 'Attend event/workshop' },
{ id: 'quiet', name: 'Quiet space' },
{ id: 'browse', name: 'Browse collection' },
{ id: 'help', name: 'Get help from staff' }
],
orientation: 'vertical'
});
});
// ============================================
// SECTION 2: Resources & Collections
// ============================================
const resourcesSection = form.addSubform('resourcesSection', {
title: 'Resources & Collections',
customStyles: { backgroundColor: '#fef3c7', padding: '20px', borderRadius: '10px' }
});
resourcesSection.addRow(row => {
row.addThumbRating('foundWhatNeeded', {
label: 'Did you find what you were looking for today?',
showLabels: true,
upLabel: 'Yes',
downLabel: 'No',
size: 'lg',
alignment: 'center'
});
});
resourcesSection.addRow(row => {
row.addTextarea('notFoundDetails', {
label: 'What were you unable to find?',
placeholder: 'Please describe what you were looking for...',
rows: 2,
autoExpand: true,
isVisible: () => resourcesSection.thumbRating('foundWhatNeeded')?.value() === 'down'
});
});
resourcesSection.addSpacer({ height: '16px' });
resourcesSection.addRow(row => {
row.addStarRating('bookCollection', {
label: 'Print Book Collection',
tooltip: 'Quality, variety, and currency of books',
maxStars: 5,
size: 'lg',
showCounter: true,
alignment: 'left'
}, '1fr');
row.addStarRating('digitalResources', {
label: 'Digital Resources',
tooltip: 'Databases, e-books, e-journals',
maxStars: 5,
size: 'lg',
showCounter: true,
alignment: 'left'
}, '1fr');
});
resourcesSection.addRow(row => {
row.addStarRating('periodicals', {
label: 'Journals & Magazines',
tooltip: 'Academic journals and periodicals',
maxStars: 5,
size: 'lg',
showCounter: true,
alignment: 'left'
}, '1fr');
row.addStarRating('multimedia', {
label: 'Multimedia & Media',
tooltip: 'DVDs, audio, streaming resources',
maxStars: 5,
size: 'lg',
showCounter: true,
alignment: 'left'
}, '1fr');
});
// ============================================
// SECTION 3: Staff & Service
// ============================================
const staffSection = form.addSubform('staffSection', {
title: 'Staff & Service'
});
staffSection.addRow(row => {
row.addRadioButton('interactedWithStaff', {
label: 'Did you interact with library staff today?',
options: [
{ id: 'yes', name: 'Yes' },
{ id: 'no', name: 'No' }
],
orientation: 'horizontal'
});
});
// Staff rating section - only visible if interacted with staff
const staffRatingSection = staffSection.addSubform('staffRating', {
isVisible: () => staffSection.radioButton('interactedWithStaff')?.value() === 'yes',
customStyles: { backgroundColor: '#f0fdf4', padding: '16px', borderRadius: '8px', marginTop: '16px' }
});
staffRatingSection.addRow(row => {
row.addStarRating('staffHelpfulness', {
label: 'Helpfulness',
tooltip: 'Willingness to assist',
maxStars: 5,
size: 'lg',
showCounter: true,
alignment: 'left'
}, '1fr');
row.addStarRating('staffKnowledge', {
label: 'Knowledge',
tooltip: 'Ability to answer questions',
maxStars: 5,
size: 'lg',
showCounter: true,
alignment: 'left'
}, '1fr');
});
staffRatingSection.addRow(row => {
row.addStarRating('staffFriendliness', {
label: 'Friendliness',
tooltip: 'Approachability and courtesy',
maxStars: 5,
size: 'lg',
showCounter: true,
alignment: 'left'
}, '1fr');
row.addStarRating('staffAvailability', {
label: 'Availability',
tooltip: 'Easy to find when needed',
maxStars: 5,
size: 'lg',
showCounter: true,
alignment: 'left'
}, '1fr');
});
// ============================================
// SECTION 4: Facilities & Environment
// ============================================
const facilitiesSection = form.addSubform('facilitiesSection', {
title: 'Facilities & Environment'
});
facilitiesSection.addRow(row => {
row.addMatrixQuestion('facilitiesMatrix', {
label: 'Rate the following aspects of our facilities:',
rows: [
{ id: 'quietAreas', label: 'Quiet study areas', description: 'Individual study spaces' },
{ id: 'groupSpaces', label: 'Group study rooms', description: 'Collaborative spaces' },
{ id: 'seating', label: 'Seating comfort', description: 'Chairs, desks, couches' },
{ id: 'cleanliness', label: 'Cleanliness', description: 'Overall tidiness' },
{ id: 'lighting', label: 'Lighting', description: 'Adequate lighting levels' },
{ id: 'temperature', label: 'Temperature', description: 'Heating/cooling comfort' },
{ id: 'noise', label: 'Noise levels', description: 'Appropriate quiet' },
{ id: 'outlets', label: 'Power outlets', description: 'Availability for devices' }
],
columns: [
{ id: 'poor', label: 'Poor' },
{ id: 'fair', label: 'Fair' },
{ id: 'good', label: 'Good' },
{ id: 'excellent', label: 'Excellent' },
{ id: 'na', label: 'N/A' }
],
selectionMode: 'single',
striped: true,
fullWidth: true
});
});
// ============================================
// SECTION 5: Technology & Digital Services
// ============================================
const techSection = form.addSubform('techSection', {
title: 'Technology & Digital Services',
customStyles: { backgroundColor: '#f8fafc', padding: '20px', borderRadius: '10px' }
});
techSection.addRow(row => {
row.addCheckboxList('techUsed', {
label: 'Which technology services did you use? (Select all that apply)',
options: [
{ id: 'wifi', name: 'WiFi' },
{ id: 'computers', name: 'Library computers' },
{ id: 'printing', name: 'Printing/scanning' },
{ id: 'catalog', name: 'Online catalog' },
{ id: 'databases', name: 'Research databases' },
{ id: 'website', name: 'Library website' },
{ id: 'app', name: 'Library mobile app' },
{ id: 'none', name: 'None of these' }
],
orientation: 'vertical'
});
});
techSection.addSpacer({ height: '16px' });
techSection.addRow(row => {
row.addSlider('wifiQuality', {
label: 'WiFi quality (speed and reliability)',
min: 1,
max: 10,
step: 1,
showValue: true,
defaultValue: 5,
isVisible: () => {
const techUsed = techSection.checkboxList('techUsed')?.value() || [];
return techUsed.includes('wifi');
}
});
});
techSection.addRow(row => {
row.addSlider('computerQuality', {
label: 'Computer quality and availability',
min: 1,
max: 10,
step: 1,
showValue: true,
defaultValue: 5,
isVisible: () => {
const techUsed = techSection.checkboxList('techUsed')?.value() || [];
return techUsed.includes('computers');
}
});
});
// ============================================
// SECTION 6: Overall Experience
// ============================================
const overallSection = form.addSubform('overallSection', {
title: 'Overall Experience'
});
overallSection.addRow(row => {
row.addEmojiRating('overallExperience', {
label: 'How was your overall library experience today?',
preset: 'satisfaction',
size: 'lg',
showLabels: true,
alignment: 'center'
});
});
overallSection.addSpacer({ height: '16px' });
overallSection.addRow(row => {
row.addRatingScale('recommendLibrary', {
preset: 'nps',
label: 'How likely are you to recommend our library to others?',
showCategoryLabel: true,
showSegmentColors: true,
size: 'sm',
alignment: 'center'
});
});
// ============================================
// SECTION 7: Suggestions
// ============================================
const suggestionsSection = form.addSubform('suggestionsSection', {
title: 'Suggestions & Comments'
});
suggestionsSection.addRow(row => {
row.addCheckboxList('wantMore', {
label: 'What would you like to see more of?',
options: [
{ id: 'hours', name: 'Extended hours' },
{ id: 'seating', name: 'More seating' },
{ id: 'studyRooms', name: 'More study rooms' },
{ id: 'computers', name: 'More computers' },
{ id: 'outlets', name: 'More power outlets' },
{ id: 'books', name: 'More books in my area' },
{ id: 'ebooks', name: 'More e-books' },
{ id: 'databases', name: 'More databases' },
{ id: 'events', name: 'More workshops/events' },
{ id: 'cafe', name: 'Cafe/refreshments' }
],
orientation: 'vertical'
});
});
suggestionsSection.addSpacer({ height: '16px' });
suggestionsSection.addRow(row => {
row.addTextarea('additionalComments', {
label: 'Any other comments or suggestions?',
placeholder: 'Share your thoughts on how we can improve...',
rows: 3,
autoExpand: true
});
});
// ============================================
// SECTION 8: Summary
// ============================================
const summarySection = form.addSubform('summarySection', {
title: 'Feedback Summary',
isVisible: () => overallSection.emojiRating('overallExperience')?.value() != null
});
summarySection.addRow(row => {
row.addTextPanel('summaryContent', {
computedValue: () => {
const frequency = visitSection.radioButton('visitFrequency')?.value();
const userType = visitSection.radioButton('userType')?.value();
const foundIt = resourcesSection.thumbRating('foundWhatNeeded')?.value();
const bookRating = resourcesSection.starRating('bookCollection')?.value();
const digitalRating = resourcesSection.starRating('digitalResources')?.value();
const overall = overallSection.emojiRating('overallExperience')?.value();
const nps = overallSection.ratingScale('recommendLibrary')?.value();
// Staff ratings
const interacted = staffSection.radioButton('interactedWithStaff')?.value();
const helpfulness = staffRatingSection.starRating('staffHelpfulness')?.value();
const knowledge = staffRatingSection.starRating('staffKnowledge')?.value();
const friendliness = staffRatingSection.starRating('staffFriendliness')?.value();
const availability = staffRatingSection.starRating('staffAvailability')?.value();
if (!overall) return '';
let emoji = '📚';
if (overall === 'excellent' || overall === 'good') emoji = '🌟';
else if (overall === 'bad' || overall === 'very-bad') emoji = '📝';
let summary = `${emoji} Library Feedback Summary\n`;
summary += `${'═'.repeat(28)}\n\n`;
const userLabels: Record<string, string> = {
'student': 'Student',
'faculty': 'Faculty/Staff',
'researcher': 'Researcher',
'community': 'Community Member',
'other': 'Other'
};
const freqLabels: Record<string, string> = {
'first': 'First Visit',
'rarely': 'Occasional',
'monthly': 'Monthly',
'weekly': 'Weekly',
'daily': 'Daily'
};
if (userType) summary += `👤 Visitor: ${userLabels[userType] || userType}\n`;
if (frequency) summary += `📅 Frequency: ${freqLabels[frequency] || frequency}\n`;
summary += `\n📖 Resources:`;
summary += `\n • Found what needed: ${foundIt === 'up' ? 'Yes' : foundIt === 'down' ? 'No' : '-'}`;
if (bookRating) summary += `\n • Books: ${bookRating}/5`;
if (digitalRating) summary += `\n • Digital: ${digitalRating}/5`;
if (interacted === 'yes' && (helpfulness || knowledge)) {
const staffScores = [helpfulness, knowledge, friendliness, availability].filter(s => s != null);
if (staffScores.length > 0) {
const avgStaff = (staffScores.reduce((a, b) => a + (b ?? 0), 0) / staffScores.length).toFixed(1);
summary += `\n\n👥 Staff Avg: ${avgStaff}/5`;
}
}
const overallLabels: Record<string, string> = {
'very-bad': 'Very Poor',
'bad': 'Poor',
'neutral': 'Average',
'good': 'Good',
'excellent': 'Excellent'
};
summary += `\n\n✨ Overall: ${overallLabels[overall] || overall}`;
if (nps != null) {
summary += `\n📣 Would Recommend: ${nps}/10`;
}
return summary;
},
customStyles: () => {
const overall = overallSection.emojiRating('overallExperience')?.value();
const baseStyles = {
padding: '20px',
borderRadius: '10px',
whiteSpace: 'pre-wrap',
fontFamily: 'monospace',
fontSize: '13px',
lineHeight: '1.6'
};
if (overall === 'excellent' || overall === 'good') {
return { ...baseStyles, backgroundColor: '#ecfdf5', borderLeft: '4px solid #10b981' };
} else if (overall === 'bad' || overall === 'very-bad') {
return { ...baseStyles, backgroundColor: '#fef2f2', borderLeft: '4px solid #ef4444' };
}
return { ...baseStyles, backgroundColor: '#fef3c7', borderLeft: '4px solid #f59e0b' };
}
});
});
// ============================================
// FORM CONFIGURATION
// ============================================
form.configureSubmitButton({
label: 'Submit Library Feedback',
isVisible: () => overallSection.emojiRating('overallExperience')?.value() != null
});
form.configureCompletionScreen({
type: 'text',
title: 'Thank You for Your Feedback!',
message: 'Your input helps us create a better library experience for everyone. We read every response and continuously work to improve our services and spaces.'
});
}