export function petServiceFeedback(form: FormTs) {
// Pet Service Feedback Form - Grooming, boarding, daycare, vet services
// Demonstrates: StarRating, EmojiRating, RatingScale, MatrixQuestion, CheckboxList, Datepicker, SuggestionChips, conditional visibility
// ============================================
// HEADER
// ============================================
form.addRow(row => {
row.addTextPanel('header', {
label: 'Pet Service Feedback',
computedValue: () => 'Help us provide the best care for your furry family members',
customStyles: {
backgroundColor: '#ea580c',
color: 'white',
padding: '24px',
borderRadius: '12px',
textAlign: 'center'
}
});
});
// ============================================
// SECTION 1: Visit Information
// ============================================
const visitSection = form.addSubform('visitSection', {
title: 'Visit Details'
});
visitSection.addRow(row => {
row.addDropdown('serviceType', {
label: 'Type of Service',
options: [
{ id: 'grooming', name: 'Grooming' },
{ id: 'boarding', name: 'Boarding / Pet Hotel' },
{ id: 'daycare', name: 'Doggy Daycare' },
{ id: 'vet', name: 'Veterinary Visit' },
{ id: 'training', name: 'Training / Classes' },
{ id: 'walking', name: 'Dog Walking' },
{ id: 'sitting', name: 'Pet Sitting' },
{ id: 'store', name: 'Pet Store Visit' },
{ id: 'other', name: 'Other' }
],
placeholder: 'Select service type',
isRequired: true
}, '1fr');
row.addDatepicker('visitDate', {
label: 'Date of Service',
maxDate: () => new Date().toISOString()
}, '1fr');
});
visitSection.addRow(row => {
row.addDropdown('petType', {
label: 'Pet Type',
options: [
{ id: 'dog', name: 'Dog' },
{ id: 'cat', name: 'Cat' },
{ id: 'bird', name: 'Bird' },
{ id: 'rabbit', name: 'Rabbit' },
{ id: 'hamster', name: 'Hamster / Guinea Pig' },
{ id: 'reptile', name: 'Reptile' },
{ id: 'fish', name: 'Fish' },
{ id: 'other', name: 'Other' }
],
placeholder: 'Select pet type',
isRequired: true
}, '1fr');
row.addTextbox('petName', {
label: 'Pet\'s Name',
placeholder: 'Enter your pet\'s name'
}, '1fr');
});
visitSection.addRow(row => {
row.addRadioButton('firstVisit', {
label: 'Was this your first visit?',
options: [
{ id: 'yes', name: 'Yes, first time' },
{ id: 'no-few', name: 'No, I\'ve been a few times' },
{ id: 'no-regular', name: 'No, I\'m a regular customer' }
],
orientation: 'horizontal'
});
});
// ============================================
// SECTION 2: Service Quality
// ============================================
const qualitySection = form.addSubform('qualitySection', {
title: 'Service Quality',
isVisible: () => visitSection.dropdown('serviceType')?.value() !== null,
customStyles: () => {
const rating = qualitySection.starRating('overallService')?.value() || 0;
if (rating >= 4) return { backgroundColor: '#fef3c7', padding: '16px', borderRadius: '8px' };
return { padding: '16px', borderRadius: '8px', border: '1px solid #e2e8f0' };
}
});
qualitySection.addRow(row => {
row.addStarRating('overallService', {
label: () => {
const petName = visitSection.textbox('petName')?.value();
return petName ? `How would you rate the service ${petName} received?` : 'How would you rate the overall service?';
},
maxStars: 5,
size: 'xl',
alignment: 'center',
showConfettiOnMax: true
});
});
qualitySection.addRow(row => {
row.addMatrixQuestion('serviceAspects', {
label: 'Rate the following aspects:',
rows: [
{ id: 'care', label: 'Care and attention to your pet', isRequired: true },
{ id: 'handling', label: 'Gentle handling', isRequired: true },
{ id: 'results', label: 'Quality of results', description: 'Grooming outcome, health check, etc.', isRequired: false },
{ id: 'communication', label: 'Communication about your pet', isRequired: false },
{ id: 'timeliness', label: 'Service completed on time', isRequired: false }
],
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
});
});
// Grooming-specific questions
const groomingSection = form.addSubform('groomingSection', {
title: 'Grooming Results',
isVisible: () => visitSection.dropdown('serviceType')?.value() === 'grooming',
customStyles: { padding: '16px', borderRadius: '8px', backgroundColor: '#fefce8' }
});
groomingSection.addRow(row => {
row.addCheckboxList('groomingServices', {
label: 'Services received',
options: [
{ id: 'bath', name: 'Bath' },
{ id: 'haircut', name: 'Haircut / Trim' },
{ id: 'nails', name: 'Nail trim' },
{ id: 'ears', name: 'Ear cleaning' },
{ id: 'teeth', name: 'Teeth brushing' },
{ id: 'dematting', name: 'De-matting' },
{ id: 'deshed', name: 'De-shedding treatment' },
{ id: 'other', name: 'Other' }
],
orientation: 'vertical'
}, '1fr');
row.addStarRating('groomingResult', {
label: 'Rate the grooming result',
maxStars: 5,
size: 'lg',
alignment: 'center'
}, '1fr');
});
// Boarding-specific questions
const boardingSection = form.addSubform('boardingSection', {
title: 'Boarding Experience',
isVisible: () => {
const service = visitSection.dropdown('serviceType')?.value();
return service === 'boarding' || service === 'daycare';
},
customStyles: { padding: '16px', borderRadius: '8px', backgroundColor: '#f0fdfa' }
});
boardingSection.addRow(row => {
row.addMatrixQuestion('boardingAspects', {
label: 'Rate the facility:',
rows: [
{ id: 'cleanliness', label: 'Cleanliness', isRequired: true },
{ id: 'space', label: 'Space and comfort', isRequired: true },
{ id: 'safety', label: 'Safety and security', isRequired: true },
{ id: 'activities', label: 'Activities and enrichment', isRequired: false },
{ id: 'feeding', label: 'Feeding and medication handling', isRequired: false },
{ id: 'updates', label: 'Updates during stay (photos, reports)', isRequired: false }
],
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: Pet's Experience
// ============================================
const petExperienceSection = form.addSubform('petExperience', {
title: () => {
const petName = visitSection.textbox('petName')?.value();
return petName ? `${petName}'s Experience` : 'Your Pet\'s Experience';
},
isVisible: () => visitSection.dropdown('serviceType')?.value() !== null
});
petExperienceSection.addRow(row => {
row.addEmojiRating('petMood', {
label: () => {
const petName = visitSection.textbox('petName')?.value();
return petName ? `How was ${petName}'s mood after the service?` : 'How was your pet\'s mood after the service?';
},
preset: 'mood',
size: 'lg',
showLabels: true,
alignment: 'center'
});
});
petExperienceSection.addRow(row => {
row.addCheckboxList('petBehavior', {
label: () => {
const petName = visitSection.textbox('petName')?.value();
return petName ? `How was ${petName} behaving after pickup?` : 'How was your pet behaving after pickup?';
},
options: [
{ id: 'happy', name: 'Happy and energetic' },
{ id: 'relaxed', name: 'Relaxed and calm' },
{ id: 'tired', name: 'Tired (but content)' },
{ id: 'hungry', name: 'Very hungry' },
{ id: 'stressed', name: 'Stressed or anxious' },
{ id: 'fearful', name: 'Fearful or clingy' },
{ id: 'normal', name: 'Normal behavior' }
],
orientation: 'vertical'
});
});
petExperienceSection.addRow(row => {
row.addTextarea('petConcerns', {
label: 'Any concerns about your pet\'s experience?',
placeholder: 'Share any observations or concerns...',
rows: 2,
autoExpand: true,
isVisible: () => {
const behaviors = petExperienceSection.checkboxList('petBehavior')?.value() || [];
return behaviors.includes('stressed') || behaviors.includes('fearful');
}
});
});
// ============================================
// SECTION 4: Staff & Facility
// ============================================
const staffSection = form.addSubform('staffSection', {
title: 'Staff & Facility',
isVisible: () => visitSection.dropdown('serviceType')?.value() !== null
});
staffSection.addRow(row => {
row.addStarRating('staffFriendliness', {
label: 'Staff friendliness and professionalism',
maxStars: 5,
size: 'lg',
alignment: 'center'
}, '1fr');
row.addStarRating('facilityClean', {
label: 'Facility cleanliness',
maxStars: 5,
size: 'lg',
alignment: 'center'
}, '1fr');
});
staffSection.addRow(row => {
row.addSuggestionChips('staffHighlights', {
label: 'What stood out about the staff?',
suggestions: [
{ id: 'caring', name: 'Genuinely caring' },
{ id: 'knowledgeable', name: 'Knowledgeable' },
{ id: 'patient', name: 'Patient with pets' },
{ id: 'communicative', name: 'Good communicators' },
{ id: 'professional', name: 'Professional' },
{ id: 'friendly', name: 'Very friendly' },
{ id: 'experienced', name: 'Experienced' },
{ id: 'gentle', name: 'Gentle handlers' }
],
max: 4,
alignment: 'center'
});
});
// ============================================
// SECTION 5: Value & Recommendation
// ============================================
const recommendSection = form.addSubform('recommendSection', {
title: 'Overall Impression',
isVisible: () => qualitySection.starRating('overallService')?.value() !== null,
customStyles: () => {
const nps = recommendSection.ratingScale('recommendNPS')?.npsCategory();
if (nps === 'promoter') return { backgroundColor: '#d1fae5', 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' };
}
});
recommendSection.addRow(row => {
row.addRatingScale('valueForMoney', {
preset: 'likert-5',
label: 'The service provided good value for money',
lowLabel: 'Strongly Disagree',
highLabel: 'Strongly Agree',
alignment: 'center'
});
});
recommendSection.addRow(row => {
row.addRatingScale('recommendNPS', {
preset: 'nps',
label: 'How likely are you to recommend us to other pet owners?',
showSegmentColors: true,
showCategoryLabel: true,
showConfettiOnPromoter: true,
alignment: 'center'
});
});
// ============================================
// SECTION 6: Conditional Follow-up
// ============================================
const positiveSection = form.addSubform('positiveSection', {
title: 'What You Loved',
isVisible: () => {
const nps = recommendSection.ratingScale('recommendNPS')?.npsCategory();
return nps === 'promoter';
},
customStyles: { backgroundColor: '#d1fae5', padding: '16px', borderRadius: '8px' }
});
positiveSection.addRow(row => {
row.addTextarea('whatYouLoved', {
label: 'What did you and your pet love most about our service?',
placeholder: 'Share what made your experience special...',
rows: 2,
autoExpand: true
});
});
const improvementSection = form.addSubform('improvementSection', {
title: 'How Can We Improve?',
isVisible: () => {
const nps = recommendSection.ratingScale('recommendNPS')?.npsCategory();
return nps === 'detractor' || nps === 'passive';
},
customStyles: { backgroundColor: '#fef3c7', padding: '16px', borderRadius: '8px' }
});
improvementSection.addRow(row => {
row.addCheckboxList('improvementAreas', {
label: 'What areas need improvement?',
options: [
{ id: 'care', name: 'Pet care quality' },
{ id: 'handling', name: 'Pet handling' },
{ id: 'communication', name: 'Communication' },
{ id: 'timing', name: 'Service timing' },
{ id: 'facility', name: 'Facility cleanliness' },
{ id: 'pricing', name: 'Pricing / Value' },
{ id: 'booking', name: 'Booking process' },
{ id: 'staff', name: 'Staff attitude' }
],
orientation: 'vertical'
});
});
improvementSection.addSpacer();
improvementSection.addRow(row => {
row.addTextarea('improvementDetails', {
label: 'Please share specific feedback',
placeholder: 'Help us understand how to serve you and your pet better...',
rows: 3,
autoExpand: true
});
});
// ============================================
// SECTION 7: Summary
// ============================================
const summarySection = form.addSubform('summarySection', {
title: 'Feedback Summary',
isVisible: () => recommendSection.ratingScale('recommendNPS')?.value() !== null
});
summarySection.addRow(row => {
row.addTextPanel('summaryContent', {
computedValue: () => {
const serviceType = visitSection.dropdown('serviceType')?.value();
const petType = visitSection.dropdown('petType')?.value();
const petName = visitSection.textbox('petName')?.value();
const overallRating = qualitySection.starRating('overallService')?.value();
const staffRating = staffSection.starRating('staffFriendliness')?.value();
const facilityRating = staffSection.starRating('facilityClean')?.value();
const nps = recommendSection.ratingScale('recommendNPS')?.npsCategory();
const petMood = petExperienceSection.emojiRating('petMood')?.value();
if (!overallRating) return 'Please specify your overall rating...';
const serviceLabels: Record<string, string> = {
'grooming': 'Grooming',
'boarding': 'Boarding',
'daycare': 'Daycare',
'vet': 'Vet Visit',
'training': 'Training',
'walking': 'Dog Walking',
'sitting': 'Pet Sitting',
'store': 'Pet Store',
'other': 'Other'
};
const petLabels: Record<string, string> = {
'dog': 'Dog',
'cat': 'Cat',
'bird': 'Bird',
'rabbit': 'Rabbit',
'hamster': 'Small Pet',
'reptile': 'Reptile',
'fish': 'Fish',
'other': 'Other'
};
const moodLabels: Record<string, string> = {
'very-bad': 'Very Stressed',
'bad': 'Unhappy',
'neutral': 'Okay',
'good': 'Happy',
'excellent': 'Very Happy'
};
let summary = `PET SERVICE FEEDBACK\n`;
summary += `${'═'.repeat(25)}\n\n`;
if (petName) {
summary += `Pet: ${petName}`;
if (petType) summary += ` (${petLabels[petType] || petType})`;
summary += '\n';
}
if (serviceType) {
summary += `Service: ${serviceLabels[serviceType] || serviceType}\n`;
}
summary += `\n${'─'.repeat(25)}\n\n`;
summary += `Service Rating: ${'★'.repeat(overallRating)}${'☆'.repeat(5 - overallRating)} (${overallRating}/5)\n`;
if (staffRating) {
summary += `Staff: ${'★'.repeat(staffRating)}${'☆'.repeat(5 - staffRating)} (${staffRating}/5)\n`;
}
if (facilityRating) {
summary += `Facility: ${'★'.repeat(facilityRating)}${'☆'.repeat(5 - facilityRating)} (${facilityRating}/5)\n`;
}
if (petMood) {
summary += `\nPet's mood: ${moodLabels[petMood] || petMood}`;
}
if (nps) {
const emoji = nps === 'promoter' ? '🎉' : nps === 'passive' ? '😐' : '😟';
summary += `\n\n${emoji} NPS: ${nps.charAt(0).toUpperCase() + nps.slice(1)}`;
}
return summary;
},
customStyles: () => {
const nps = recommendSection.ratingScale('recommendNPS')?.npsCategory();
const baseStyles = {
padding: '16px',
borderRadius: '8px',
whiteSpace: 'pre-wrap',
fontFamily: 'monospace',
fontSize: '13px'
};
if (nps === 'promoter') {
return { ...baseStyles, backgroundColor: '#d1fae5', borderLeft: '4px solid #10b981' };
} else if (nps === 'passive') {
return { ...baseStyles, backgroundColor: '#fef3c7', borderLeft: '4px solid #f59e0b' };
} else if (nps === 'detractor') {
return { ...baseStyles, backgroundColor: '#fee2e2', borderLeft: '4px solid #ef4444' };
}
return { ...baseStyles, backgroundColor: '#fff7ed', borderLeft: '4px solid #ea580c' };
}
});
});
// ============================================
// FORM CONFIGURATION
// ============================================
form.configureSubmitButton({
label: 'Submit Feedback',
isVisible: () => recommendSection.ratingScale('recommendNPS')?.value() !== null
});
form.configureCompletionScreen({
type: 'text',
title: () => {
const petName = visitSection.textbox('petName')?.value();
return petName ? `Thank You for Your Feedback About ${petName}!` : 'Thank You for Your Feedback!';
},
message: 'We truly appreciate you taking the time to share your experience. Your feedback helps us provide the best possible care for all our furry, feathered, and scaly friends!'
});
}