export function dentalVisitFeedback(form: FormTs) {
// Dental Visit Feedback - Patient satisfaction survey for dental practices
// Demonstrates: Slider (pain scale), EmojiRating, StarRating, MatrixQuestion, RatingScale, ThumbRating, dynamic styling
// ============================================
// HEADER
// ============================================
form.addRow(row => {
row.addTextPanel('header', {
label: 'Dental Visit Feedback',
computedValue: () => 'Your feedback helps us provide better care',
customStyles: {
backgroundColor: '#0ea5e9',
color: 'white',
padding: '24px',
borderRadius: '12px',
textAlign: 'center'
}
});
});
// ============================================
// SECTION 1: Visit Information
// ============================================
const visitInfo = form.addSubform('visitInfo', {
title: 'Visit Details',
customStyles: { padding: '16px', borderRadius: '8px', border: '1px solid #e2e8f0' }
});
visitInfo.addRow(row => {
row.addDropdown('visitType', {
label: 'Type of Visit',
options: [
{ id: 'cleaning', name: 'Cleaning & Checkup' },
{ id: 'filling', name: 'Filling' },
{ id: 'extraction', name: 'Extraction' },
{ id: 'root-canal', name: 'Root Canal' },
{ id: 'crown', name: 'Crown/Bridge' },
{ id: 'whitening', name: 'Whitening' },
{ id: 'orthodontic', name: 'Orthodontic Visit' },
{ id: 'emergency', name: 'Emergency Visit' },
{ id: 'consultation', name: 'Consultation Only' },
{ id: 'other', name: 'Other' }
],
placeholder: 'Select visit type',
isRequired: true
}, '1fr');
row.addDropdown('seenBy', {
label: 'Primary Provider',
options: [
{ id: 'dentist', name: 'Dentist' },
{ id: 'hygienist', name: 'Dental Hygienist' },
{ id: 'orthodontist', name: 'Orthodontist' },
{ id: 'oral-surgeon', name: 'Oral Surgeon' },
{ id: 'multiple', name: 'Multiple Providers' }
],
placeholder: 'Who did you see?'
}, '1fr');
});
visitInfo.addRow(row => {
row.addRadioButton('isFirstVisit', {
label: 'Is this your first visit to our practice?',
options: [
{ id: 'yes', name: 'Yes, first visit' },
{ id: 'no', name: 'No, returning patient' }
],
orientation: 'horizontal'
});
});
// ============================================
// SECTION 2: Pre-Visit Anxiety
// ============================================
const anxietySection = form.addSubform('anxietySection', {
title: 'Dental Anxiety',
customStyles: { padding: '16px', borderRadius: '8px', border: '1px solid #e2e8f0' }
});
anxietySection.addRow(row => {
row.addEmojiRating('anxietyBefore', {
label: 'How anxious were you BEFORE your visit?',
preset: 'custom',
emojis: [
{ id: 'none', emoji: '😌', label: 'Calm' },
{ id: 'mild', emoji: '😐', label: 'Slightly nervous' },
{ id: 'moderate', emoji: '😟', label: 'Anxious' },
{ id: 'severe', emoji: '😰', label: 'Very anxious' },
{ id: 'extreme', emoji: '😱', label: 'Terrified' }
],
size: 'lg',
showLabels: true,
alignment: 'center'
});
});
anxietySection.addRow(row => {
row.addEmojiRating('anxietyAfter', {
label: 'How did you feel AFTER your visit?',
preset: 'custom',
emojis: [
{ id: 'relieved', emoji: '😊', label: 'Relieved' },
{ id: 'calm', emoji: '😌', label: 'Calm' },
{ id: 'neutral', emoji: '😐', label: 'Neutral' },
{ id: 'uncomfortable', emoji: '😕', label: 'Uncomfortable' },
{ id: 'distressed', emoji: '😫', label: 'Distressed' }
],
size: 'lg',
showLabels: true,
alignment: 'center'
});
});
// ============================================
// SECTION 3: Pain Management
// ============================================
const painSection = form.addSubform('painSection', {
title: 'Pain & Comfort',
isVisible: () => {
const visitType = visitInfo.dropdown('visitType')?.value();
return visitType !== 'consultation' && visitType !== null;
},
customStyles: () => {
const pain = painSection.slider('painLevel')?.value();
if (pain !== null && pain !== undefined) {
if (pain <= 2) return { backgroundColor: '#d1fae5', padding: '16px', borderRadius: '8px' };
if (pain <= 5) return { backgroundColor: '#fef3c7', padding: '16px', borderRadius: '8px' };
return { backgroundColor: '#fee2e2', padding: '16px', borderRadius: '8px' };
}
return { padding: '16px', borderRadius: '8px', border: '1px dashed #cbd5e1' };
}
});
painSection.addRow(row => {
row.addSlider('painLevel', {
label: 'Pain level during procedure (0 = no pain, 10 = worst pain)',
min: 0,
max: 10,
step: 1,
showValue: true,
defaultValue: 0
});
});
painSection.addRow(row => {
row.addTextPanel('painDescription', {
computedValue: () => {
const pain = painSection.slider('painLevel')?.value();
if (pain === null || pain === undefined) return 'Move the slider to rate your pain level';
if (pain === 0) return '😊 No pain - perfect!';
if (pain <= 2) return '😌 Minimal discomfort';
if (pain <= 4) return '😐 Mild pain - manageable';
if (pain <= 6) return '😕 Moderate pain';
if (pain <= 8) return '😣 Significant pain';
return '😫 Severe pain - we need to address this';
},
customStyles: () => {
const pain = painSection.slider('painLevel')?.value();
const baseStyles = {
textAlign: 'center',
padding: '12px 16px',
borderRadius: '8px',
fontWeight: 'bold'
};
if (pain !== null && pain !== undefined) {
if (pain <= 2) return { ...baseStyles, backgroundColor: '#10b981', color: 'white' };
if (pain <= 5) return { ...baseStyles, backgroundColor: '#f59e0b', color: 'white' };
return { ...baseStyles, backgroundColor: '#ef4444', color: 'white' };
}
return { ...baseStyles, backgroundColor: '#e2e8f0', color: '#475569' };
}
});
});
painSection.addRow(row => {
row.addThumbRating('anesthesiaEffective', {
label: 'If anesthesia was used, was it effective?',
showLabels: true,
upLabel: 'Yes, worked well',
downLabel: 'No, felt pain',
alignment: 'center',
size: 'lg'
});
});
// ============================================
// SECTION 4: Staff & Care Quality
// ============================================
const staffSection = form.addSubform('staffSection', {
title: 'Staff & Care Quality',
isVisible: () => visitInfo.dropdown('visitType')?.value() !== null,
customStyles: { padding: '16px', borderRadius: '8px', border: '1px solid #e2e8f0' }
});
staffSection.addRow(row => {
row.addMatrixQuestion('staffRatings', {
label: 'Rate our team:',
rows: [
{ id: 'reception', label: 'Front Desk / Reception', description: 'Check-in process and friendliness', isRequired: true },
{ id: 'hygienist', label: 'Dental Hygienist', description: 'Care and technique', isRequired: false },
{ id: 'dentist', label: 'Dentist / Doctor', description: 'Expertise and bedside manner', isRequired: true },
{ id: 'assistant', label: 'Dental Assistant', description: 'Helpfulness during procedure', isRequired: false }
],
columns: [
{ id: 'na', label: 'N/A' },
{ 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
});
});
staffSection.addRow(row => {
row.addStarRating('explanationQuality', {
label: 'How well did the dentist explain your treatment?',
maxStars: 5,
size: 'lg',
alignment: 'center'
});
});
staffSection.addRow(row => {
row.addRatingScale('listenedConcerns', {
preset: 'likert-5',
label: 'The dental team listened to my concerns and questions',
lowLabel: 'Strongly Disagree',
highLabel: 'Strongly Agree',
alignment: 'center'
});
});
// ============================================
// SECTION 5: Wait Time & Scheduling
// ============================================
const waitSection = form.addSubform('waitSection', {
title: 'Wait Time & Scheduling',
isVisible: () => visitInfo.dropdown('visitType')?.value() !== null
});
waitSection.addRow(row => {
row.addDropdown('waitTime', {
label: 'How long did you wait past your appointment time?',
options: [
{ id: 'on-time', name: 'Seen on time or early' },
{ id: '5-10', name: '5-10 minutes' },
{ id: '10-20', name: '10-20 minutes' },
{ id: '20-30', name: '20-30 minutes' },
{ id: '30+', name: 'More than 30 minutes' }
],
placeholder: 'Select wait time'
}, '1fr');
row.addStarRating('waitSatisfaction', {
label: 'Satisfaction with wait',
maxStars: 5,
size: 'lg',
alignment: 'left'
}, '1fr');
});
waitSection.addRow(row => {
row.addRatingScale('easyScheduling', {
preset: 'likert-5',
label: 'It was easy to schedule this appointment',
lowLabel: 'Strongly Disagree',
highLabel: 'Strongly Agree',
alignment: 'center'
});
});
// ============================================
// SECTION 6: Facility
// ============================================
const facilitySection = form.addSubform('facilitySection', {
title: 'Facility & Environment',
isVisible: () => visitInfo.dropdown('visitType')?.value() !== null
});
facilitySection.addRow(row => {
row.addStarRating('cleanliness', {
label: 'Office Cleanliness',
maxStars: 5,
size: 'lg',
alignment: 'left'
}, '1fr');
row.addStarRating('comfort', {
label: 'Comfort of Treatment Area',
maxStars: 5,
size: 'lg',
alignment: 'left'
}, '1fr');
});
facilitySection.addRow(row => {
row.addCheckboxList('facilityHighlights', {
label: 'What did you appreciate about our facility?',
options: [
{ id: 'clean', name: 'Very clean and hygienic' },
{ id: 'modern', name: 'Modern equipment' },
{ id: 'comfortable-chairs', name: 'Comfortable chairs' },
{ id: 'tv', name: 'TV/Entertainment during treatment' },
{ id: 'music', name: 'Relaxing music' },
{ id: 'waiting-area', name: 'Nice waiting area' },
{ id: 'parking', name: 'Easy parking' },
{ id: 'kids-friendly', name: 'Kid-friendly environment' }
],
orientation: 'vertical'
});
});
// ============================================
// SECTION 7: Overall Satisfaction
// ============================================
const overallSection = form.addSubform('overallSection', {
title: 'Overall Experience',
isVisible: () => visitInfo.dropdown('visitType')?.value() !== null,
customStyles: () => {
const rating = overallSection.starRating('overallRating')?.value();
if (rating && rating >= 5) return { backgroundColor: '#d1fae5', padding: '16px', borderRadius: '8px' };
if (rating && rating >= 3) return { backgroundColor: '#fef3c7', padding: '16px', borderRadius: '8px' };
if (rating && rating >= 1) return { backgroundColor: '#fee2e2', padding: '16px', borderRadius: '8px' };
return { padding: '16px', borderRadius: '8px', border: '1px dashed #cbd5e1' };
}
});
overallSection.addRow(row => {
row.addStarRating('overallRating', {
label: 'Overall Experience Rating',
maxStars: 5,
size: 'xl',
alignment: 'center',
showConfettiOnMax: true
});
});
overallSection.addRow(row => {
row.addThumbRating('wouldRecommend', {
label: 'Would you recommend our practice to friends and family?',
showLabels: true,
upLabel: 'Yes!',
downLabel: 'No',
alignment: 'center',
size: 'lg'
});
});
overallSection.addRow(row => {
row.addThumbRating('willReturn', {
label: 'Will you return for future dental care?',
showLabels: true,
upLabel: 'Definitely',
downLabel: 'Probably not',
alignment: 'center',
size: 'lg'
});
});
overallSection.addSpacer();
overallSection.addRow(row => {
row.addTextarea('comments', {
label: 'Additional comments or suggestions',
placeholder: 'Share anything else about your visit...',
rows: 3,
autoExpand: true
});
});
// ============================================
// SECTION 8: Summary
// ============================================
const summarySection = form.addSubform('summarySection', {
title: 'Visit Feedback Summary',
isVisible: () => overallSection.starRating('overallRating')?.value() !== null
});
summarySection.addRow(row => {
row.addTextPanel('summaryContent', {
computedValue: () => {
const visitType = visitInfo.dropdown('visitType')?.value();
const overall = overallSection.starRating('overallRating')?.value();
const pain = painSection.slider('painLevel')?.value();
const anxietyBefore = anxietySection.emojiRating('anxietyBefore')?.value();
const anxietyAfter = anxietySection.emojiRating('anxietyAfter')?.value();
const cleanliness = facilitySection.starRating('cleanliness')?.value();
const explanation = staffSection.starRating('explanationQuality')?.value();
const recommend = overallSection.thumbRating('wouldRecommend')?.value();
const willReturn = overallSection.thumbRating('willReturn')?.value();
if (!overall) return '';
const visitLabels: Record<string, string> = {
'cleaning': 'Cleaning & Checkup',
'filling': 'Filling',
'extraction': 'Extraction',
'root-canal': 'Root Canal',
'crown': 'Crown/Bridge',
'whitening': 'Whitening',
'orthodontic': 'Orthodontic Visit',
'emergency': 'Emergency Visit',
'consultation': 'Consultation',
'other': 'Other'
};
let summary = `DENTAL VISIT FEEDBACK\n`;
summary += `${'═'.repeat(25)}\n\n`;
if (visitType) {
summary += `Visit Type: ${visitLabels[visitType] || visitType}\n`;
}
summary += `Overall: ${'★'.repeat(overall)}${'☆'.repeat(5 - overall)} (${overall}/5)\n`;
if (pain !== null && pain !== undefined) {
const painEmoji = pain <= 2 ? '😊' : pain <= 5 ? '😐' : '😣';
summary += `Pain Level: ${painEmoji} ${pain}/10\n`;
}
if (anxietyBefore && anxietyAfter) {
const improved = ['relieved', 'calm'].includes(anxietyAfter);
summary += `Anxiety: ${improved ? '✅ Reduced' : '⚠️ Present'}\n`;
}
if (cleanliness) {
summary += `Cleanliness: ${cleanliness}/5\n`;
}
if (explanation) {
summary += `Explanation: ${explanation}/5\n`;
}
summary += `\n`;
if (recommend) {
summary += `${recommend === 'up' ? '👍 Would recommend' : '👎 Would not recommend'}\n`;
}
if (willReturn) {
summary += `${willReturn === 'up' ? '🔄 Will return' : '❌ May not return'}\n`;
}
return summary;
},
customStyles: () => {
const overall = overallSection.starRating('overallRating')?.value();
const baseStyles = {
padding: '16px',
borderRadius: '8px',
whiteSpace: 'pre-wrap',
fontFamily: 'monospace',
fontSize: '13px'
};
if (overall && overall >= 4) {
return { ...baseStyles, backgroundColor: '#d1fae5', borderLeft: '4px solid #10b981' };
} else if (overall && overall >= 3) {
return { ...baseStyles, backgroundColor: '#fef3c7', borderLeft: '4px solid #f59e0b' };
} else if (overall && overall >= 1) {
return { ...baseStyles, backgroundColor: '#fee2e2', borderLeft: '4px solid #ef4444' };
}
return { ...baseStyles, backgroundColor: '#f8fafc', borderLeft: '4px solid #0ea5e9' };
}
});
});
// ============================================
// FORM CONFIGURATION
// ============================================
form.configureSubmitButton({
label: 'Submit Feedback',
isVisible: () => overallSection.starRating('overallRating')?.value() !== null
});
form.configureCompletionScreen({
type: 'text',
title: 'Thank You for Your Feedback!',
message: 'Your input helps us provide better dental care. We appreciate you taking the time to share your experience with us.'
});
}