export function photographySessionForm(form: FormTs) {
// Photography Session Feedback - Client feedback after photo sessions
// Demonstrates: Multiple StarRatings, EmojiRating, ThumbRating, conditional sections, computed average
// ============================================
// STATE - Computed average rating
// ============================================
const averageRating = form.computedValue(() => {
const ratings = [
ratingsSection.starRating('communication')?.value(),
ratingsSection.starRating('professionalism')?.value(),
ratingsSection.starRating('creativity')?.value(),
ratingsSection.starRating('direction')?.value(),
ratingsSection.starRating('delivery')?.value()
].filter(r => r !== null && r !== undefined) as number[];
if (ratings.length === 0) return 0;
return Math.round((ratings.reduce((a, b) => a + b, 0) / ratings.length) * 10) / 10;
});
// ============================================
// HEADER
// ============================================
form.addRow(row => {
row.addTextPanel('header', {
label: 'Photo Session Feedback',
computedValue: () => 'We\'d love to hear about your experience! Your feedback helps us improve and serves future clients.',
customStyles: {
backgroundColor: '#7c3aed',
color: 'white',
padding: '24px',
borderRadius: '12px',
textAlign: 'center'
}
});
});
// ============================================
// SECTION 1: Session Details
// ============================================
const sessionSection = form.addSubform('session', {
title: 'Session Information'
});
sessionSection.addRow(row => {
row.addDropdown('sessionType', {
label: 'Type of Session',
options: [
{ id: 'portrait', name: 'Portrait/Headshot' },
{ id: 'family', name: 'Family/Group' },
{ id: 'wedding', name: 'Wedding' },
{ id: 'engagement', name: 'Engagement' },
{ id: 'maternity', name: 'Maternity/Newborn' },
{ id: 'event', name: 'Event Coverage' },
{ id: 'commercial', name: 'Commercial/Product' },
{ id: 'real-estate', name: 'Real Estate' },
{ id: 'other', name: 'Other' }
],
isRequired: true,
placeholder: 'Select session type'
}, '1fr');
row.addDatepicker('sessionDate', {
label: 'Session Date',
maxDate: () => new Date().toISOString()
}, '200px');
});
sessionSection.addRow(row => {
row.addTextbox('photographerName', {
label: 'Photographer Name',
placeholder: 'Who was your photographer?'
}, '1fr');
row.addDropdown('location', {
label: 'Session Location',
options: [
{ id: 'studio', name: 'Studio' },
{ id: 'outdoor', name: 'Outdoor/On-location' },
{ id: 'client-home', name: 'Client\'s Home' },
{ id: 'venue', name: 'Venue/Event Space' },
{ id: 'other', name: 'Other' }
]
}, '1fr');
});
// ============================================
// SECTION 2: Overall Experience
// ============================================
const experienceSection = form.addSubform('experience', {
title: 'Overall Experience',
isVisible: () => sessionSection.dropdown('sessionType')?.value() !== null
});
experienceSection.addRow(row => {
row.addEmojiRating('overallFeeling', {
label: 'How would you describe your overall experience?',
preset: 'satisfaction',
size: 'lg',
showLabels: true,
alignment: 'center'
});
});
experienceSection.addRow(row => {
row.addThumbRating('recommend', {
label: 'Would you recommend us to friends and family?',
size: 'lg',
showLabels: true,
upLabel: 'Yes, definitely!',
downLabel: 'Not really',
alignment: 'center'
});
});
// ============================================
// SECTION 3: Detailed Ratings
// ============================================
const ratingsSection = form.addSubform('ratings', {
title: 'Rate Your Experience',
isVisible: () => sessionSection.dropdown('sessionType')?.value() !== null,
customStyles: { backgroundColor: '#faf5ff', padding: '16px', borderRadius: '8px' }
});
ratingsSection.addRow(row => {
row.addTextPanel('ratingsIntro', {
computedValue: () => 'Please rate each aspect of your photography experience:',
customStyles: { fontSize: '14px', color: '#6b7280', marginBottom: '16px' }
});
});
ratingsSection.addRow(row => {
row.addStarRating('communication', {
label: 'Communication & Responsiveness',
tooltip: 'How well did we communicate before, during, and after the session?',
maxStars: 5,
size: 'lg',
showCounter: true,
showConfettiOnMax: true
}, '1fr');
row.addStarRating('professionalism', {
label: 'Professionalism',
tooltip: 'Punctuality, organization, and professional conduct',
maxStars: 5,
size: 'lg',
showCounter: true,
showConfettiOnMax: true
}, '1fr');
});
ratingsSection.addRow(row => {
row.addStarRating('creativity', {
label: 'Creativity & Artistic Vision',
tooltip: 'Unique ideas, poses, and artistic approach',
maxStars: 5,
size: 'lg',
showCounter: true,
showConfettiOnMax: true
}, '1fr');
row.addStarRating('direction', {
label: 'Direction & Guidance',
tooltip: 'How comfortable and guided did you feel during the session?',
maxStars: 5,
size: 'lg',
showCounter: true,
showConfettiOnMax: true
}, '1fr');
});
ratingsSection.addRow(row => {
row.addStarRating('delivery', {
label: 'Image Quality & Delivery',
tooltip: 'Quality of final images and timeliness of delivery',
maxStars: 5,
size: 'lg',
showCounter: true,
showConfettiOnMax: true
}, '1fr');
row.addEmpty('1fr');
});
// ============================================
// SECTION 4: Image Quality (conditional)
// ============================================
const imageSection = form.addSubform('imageQuality', {
title: 'About Your Photos',
isVisible: () => ratingsSection.starRating('delivery')?.value() !== null
});
imageSection.addRow(row => {
row.addMatrixQuestion('imageAspects', {
label: 'How satisfied are you with these aspects of your final images?',
rows: [
{ id: 'editing', label: 'Color & editing style' },
{ id: 'poses', label: 'Variety of poses/angles' },
{ id: 'quantity', label: 'Number of photos delivered' },
{ id: 'resolution', label: 'Image resolution/quality' },
{ id: 'turnaround', label: 'Delivery turnaround time' }
],
columns: [
{ id: 'poor', label: 'Poor' },
{ id: 'fair', label: 'Fair' },
{ id: 'good', label: 'Good' },
{ id: 'excellent', label: 'Excellent' }
],
alignment: 'center',
fullWidth: true,
striped: true
});
});
imageSection.addRow(row => {
row.addRadioButton('favoriteCount', {
label: 'How many of the delivered images do you consider "favorites"?',
options: [
{ id: 'none', name: 'None' },
{ id: 'few', name: 'A few (1-5)' },
{ id: 'some', name: 'Several (6-15)' },
{ id: 'many', name: 'Many (16-30)' },
{ id: 'most', name: 'Most or all' }
],
orientation: 'horizontal'
});
});
// ============================================
// SECTION 5: Specific Feedback
// ============================================
const feedbackSection = form.addSubform('feedback', {
title: 'Tell Us More',
isVisible: () => experienceSection.emojiRating('overallFeeling')?.value() !== null
});
// Positive feedback
feedbackSection.addRow(row => {
row.addSuggestionChips('highlights', {
label: 'What did you enjoy most? (Select all that apply)',
suggestions: [
{ id: 'relaxed', name: 'Relaxed atmosphere' },
{ id: 'fun', name: 'Fun session' },
{ id: 'creative', name: 'Creative ideas' },
{ id: 'quick', name: 'Quick turnaround' },
{ id: 'quality', name: 'Image quality' },
{ id: 'editing', name: 'Beautiful editing' },
{ id: 'location', name: 'Great location' },
{ id: 'value', name: 'Good value' }
],
alignment: 'center'
});
});
feedbackSection.addSpacer({ height: '20px' });
feedbackSection.addRow(row => {
row.addTextarea('positiveComments', {
label: () => {
const feeling = experienceSection.emojiRating('overallFeeling')?.value();
if (feeling === 'excellent' || feeling === 'good') {
return 'What did you love most about your experience?';
}
return 'What went well during your session?';
},
placeholder: 'Share what made your experience special...',
rows: 3
});
});
// Areas for improvement (shown for lower ratings)
const improvementSection = form.addSubform('improvements', {
title: 'Areas for Improvement',
isVisible: () => {
const feeling = experienceSection.emojiRating('overallFeeling')?.value();
return feeling === 'very-bad' || feeling === 'bad' || feeling === 'neutral';
},
customStyles: { backgroundColor: '#fef3c7', padding: '16px', borderRadius: '8px' }
});
improvementSection.addRow(row => {
row.addCheckboxList('improvementAreas', {
label: 'What areas could we improve?',
options: [
{ id: 'communication', name: 'Better communication' },
{ id: 'timing', name: 'More timely delivery' },
{ id: 'direction', name: 'More guidance/direction' },
{ id: 'variety', name: 'More variety in shots' },
{ id: 'editing', name: 'Different editing style' },
{ id: 'pricing', name: 'Pricing transparency' },
{ id: 'booking', name: 'Easier booking process' },
{ id: 'other', name: 'Other (please specify)' }
],
orientation: 'vertical'
});
});
improvementSection.addSpacer({ height: '20px' });
improvementSection.addRow(row => {
row.addTextarea('improvementDetails', {
label: 'Please share more details about how we can improve:',
placeholder: 'Your honest feedback helps us grow and serve you better...',
rows: 4
});
});
// ============================================
// SECTION 6: Testimonial Permission
// ============================================
const testimonialSection = form.addSubform('testimonial', {
title: 'Share Your Experience',
isVisible: () => {
const recommend = experienceSection.thumbRating('recommend')?.value();
return recommend === 'up';
}
});
testimonialSection.addRow(row => {
row.addCheckbox('allowTestimonial', {
label: 'You may use my feedback as a testimonial on your website/social media'
});
});
testimonialSection.addRow(row => {
row.addTextarea('testimonialQuote', {
label: 'Would you like to write a short testimonial?',
placeholder: 'Write a brief review that we can share with potential clients...',
rows: 3,
isVisible: () => testimonialSection.checkbox('allowTestimonial')?.value() === true
});
});
testimonialSection.addRow(row => {
row.addTextbox('testimonialName', {
label: 'Name to display with testimonial',
placeholder: 'First name or full name',
isVisible: () => testimonialSection.checkbox('allowTestimonial')?.value() === true
}, '1fr');
row.addCheckbox('allowPortfolioUse', {
label: 'You may feature my photos in your portfolio',
isVisible: () => testimonialSection.checkbox('allowTestimonial')?.value() === true
}, '1fr');
});
// ============================================
// SECTION 7: Summary
// ============================================
const summarySection = form.addSubform('summary', {
title: 'Feedback Summary',
isVisible: () => averageRating() > 0
});
summarySection.addRow(row => {
row.addTextPanel('summaryContent', {
computedValue: () => {
const sessionType = sessionSection.dropdown('sessionType')?.value();
const feeling = experienceSection.emojiRating('overallFeeling')?.value();
const recommend = experienceSection.thumbRating('recommend')?.value();
const avg = averageRating();
const highlights = feedbackSection.suggestionChips('highlights')?.value() || [];
const sessionLabels: Record<string, string> = {
'portrait': 'Portrait/Headshot',
'family': 'Family/Group',
'wedding': 'Wedding',
'engagement': 'Engagement',
'maternity': 'Maternity/Newborn',
'event': 'Event Coverage',
'commercial': 'Commercial/Product',
'real-estate': 'Real Estate',
'other': 'Other'
};
const feelingLabels: Record<string, string> = {
'very-bad': 'Very Unsatisfied',
'bad': 'Unsatisfied',
'neutral': 'Neutral',
'good': 'Satisfied',
'excellent': 'Very Satisfied'
};
let summary = 'SESSION FEEDBACK SUMMARY\n';
summary += `${'═'.repeat(30)}\n\n`;
summary += `Session Type: ${sessionLabels[sessionType || ''] || 'Not specified'}\n`;
summary += `Overall Feeling: ${feelingLabels[feeling || ''] || 'Not rated'}\n`;
summary += `Would Recommend: ${recommend === 'up' ? 'Yes!' : recommend === 'down' ? 'No' : 'Not answered'}\n\n`;
summary += `Average Rating: ${'★'.repeat(Math.round(avg))}${'☆'.repeat(5 - Math.round(avg))} (${avg}/5)\n`;
if (highlights.length > 0) {
summary += `\nHighlights: ${highlights.length} aspects appreciated`;
}
return summary;
},
customStyles: () => {
const avg = averageRating();
let bgColor = '#f3f4f6';
let borderColor = '#9ca3af';
if (avg >= 4) {
bgColor = '#d1fae5';
borderColor = '#10b981';
} else if (avg <= 2 && avg > 0) {
bgColor = '#fee2e2';
borderColor = '#ef4444';
} else if (avg > 2 && avg < 4) {
bgColor = '#fef3c7';
borderColor = '#f59e0b';
}
return {
whiteSpace: 'pre-wrap',
fontFamily: 'monospace',
fontSize: '14px',
padding: '16px',
backgroundColor: bgColor,
borderRadius: '8px',
borderLeft: `4px solid ${borderColor}`
};
}
});
});
// ============================================
// FORM CONFIGURATION
// ============================================
form.configureSubmitButton({
label: 'Submit Feedback',
isVisible: () => sessionSection.dropdown('sessionType')?.value() !== null
});
form.configureCompletionScreen({
type: 'text',
title: 'Thank You for Your Feedback!',
message: 'We truly appreciate you taking the time to share your experience. Your feedback helps us continue to grow and deliver exceptional photography services. We hope to capture more beautiful moments with you in the future!'
});
}