export function contractorFeedbackForm(form: FormTs) {
// Contractor Performance Evaluation - B2B Vendor Assessment
// Demonstrates: MatrixQuestion, StarRating, Slider, RatingScale, ThumbRating, conditional sections
// ============================================
// HEADER
// ============================================
form.addRow(row => {
row.addTextPanel('header', {
label: 'Contractor Performance Evaluation',
computedValue: () => 'Please provide honest feedback on contractor performance. Your input helps improve our vendor relationships.',
customStyles: {
backgroundColor: '#0891b2',
color: 'white',
padding: '24px',
borderRadius: '12px',
textAlign: 'center'
}
});
});
// ============================================
// SECTION 1: Project Context
// ============================================
const contextSection = form.addSubform('contextSection', {
title: 'Project Information'
});
contextSection.addRow(row => {
row.addTextbox('contractorName', {
label: 'Contractor/Vendor Name',
placeholder: 'Enter contractor or company name',
isRequired: true
}, '1fr');
row.addTextbox('projectName', {
label: 'Project Name',
placeholder: 'Enter project or engagement name',
isRequired: true
}, '1fr');
});
contextSection.addRow(row => {
row.addDropdown('projectType', {
label: 'Project Type',
options: [
{ id: 'development', name: 'Software Development' },
{ id: 'design', name: 'Design/Creative' },
{ id: 'consulting', name: 'Consulting/Advisory' },
{ id: 'construction', name: 'Construction/Renovation' },
{ id: 'marketing', name: 'Marketing/Content' },
{ id: 'maintenance', name: 'Maintenance/Support' },
{ id: 'other', name: 'Other' }
],
placeholder: 'Select project type'
}, '1fr');
row.addDropdown('engagementLength', {
label: 'Engagement Duration',
options: [
{ id: 'days', name: 'Less than a week' },
{ id: 'weeks', name: '1-4 weeks' },
{ id: 'months', name: '1-3 months' },
{ id: 'quarter', name: '3-6 months' },
{ id: 'long', name: '6+ months' }
],
placeholder: 'Select duration'
}, '1fr');
});
// ============================================
// SECTION 2: Quality Assessment
// ============================================
const qualitySection = form.addSubform('qualitySection', {
title: 'Work Quality'
});
qualitySection.addRow(row => {
row.addStarRating('overallQuality', {
label: 'Overall Quality of Work',
maxStars: 5,
size: 'lg',
alignment: 'center',
showConfettiOnMax: true
});
});
qualitySection.addRow(row => {
row.addMatrixQuestion('qualityMatrix', {
label: 'Please rate specific quality aspects:',
rows: [
{ id: 'technical', label: 'Technical competence', description: 'Skills and expertise demonstrated' },
{ id: 'attention', label: 'Attention to detail', description: 'Accuracy and thoroughness' },
{ id: 'requirements', label: 'Met requirements', description: 'Delivered what was specified' },
{ id: 'standards', label: 'Quality standards', description: 'Met or exceeded standards' },
{ id: 'documentation', label: 'Documentation quality', description: 'Clarity of deliverable documentation' }
],
columns: [
{ id: '1', label: 'Poor' },
{ id: '2', label: 'Below Avg' },
{ id: '3', label: 'Average' },
{ id: '4', label: 'Good' },
{ id: '5', label: 'Excellent' }
],
striped: true,
fullWidth: true
});
});
// ============================================
// SECTION 3: Timeline & Reliability
// ============================================
const timelineSection = form.addSubform('timelineSection', {
title: 'Timeline & Reliability'
});
timelineSection.addRow(row => {
row.addRadioButton('deliveredOnTime', {
label: 'Was the project delivered on time?',
options: [
{ id: 'early', name: 'Delivered early' },
{ id: 'on-time', name: 'Delivered on time' },
{ id: 'slightly-late', name: 'Slightly late (within acceptable margin)' },
{ id: 'late', name: 'Significantly late' },
{ id: 'very-late', name: 'Very late / missed deadlines' }
],
orientation: 'vertical'
});
});
timelineSection.addRow(row => {
row.addSlider('deadlinesMet', {
label: 'What percentage of intermediate milestones/deadlines were met?',
min: 0,
max: 100,
step: 10,
showValue: true,
unit: '%',
defaultValue: 80
});
});
timelineSection.addRow(row => {
row.addRatingScale('reliability', {
label: 'How reliable was the contractor overall?',
preset: 'likert-5',
lowLabel: 'Unreliable',
highLabel: 'Very reliable',
alignment: 'center'
});
});
// ============================================
// SECTION 4: Communication
// ============================================
const communicationSection = form.addSubform('communicationSection', {
title: 'Communication & Professionalism'
});
communicationSection.addRow(row => {
row.addMatrixQuestion('communicationMatrix', {
label: 'Rate communication and professionalism:',
rows: [
{ id: 'responsive', label: 'Responsiveness', description: 'Timeliness of responses' },
{ id: 'clarity', label: 'Communication clarity', description: 'Clear and understandable' },
{ id: 'proactive', label: 'Proactive updates', description: 'Kept you informed without prompting' },
{ id: 'issues', label: 'Issue handling', description: 'How problems were communicated' },
{ id: 'professional', label: 'Professionalism', description: 'Conduct and attitude' }
],
columns: [
{ id: '1', label: 'Poor' },
{ id: '2', label: 'Below Avg' },
{ id: '3', label: 'Average' },
{ id: '4', label: 'Good' },
{ id: '5', label: 'Excellent' }
],
striped: true,
fullWidth: true
});
});
communicationSection.addRow(row => {
row.addCheckboxList('communicationIssues', {
label: 'Were there any communication issues? (Select all that apply)',
options: [
{ id: 'none', name: 'No issues - communication was excellent' },
{ id: 'slow', name: 'Slow to respond' },
{ id: 'unclear', name: 'Unclear explanations' },
{ id: 'updates', name: 'Lacked proactive updates' },
{ id: 'language', name: 'Language/clarity barriers' },
{ id: 'availability', name: 'Hard to reach' },
{ id: 'defensive', name: 'Defensive about feedback' }
],
orientation: 'vertical'
});
});
// ============================================
// SECTION 5: Budget & Value
// ============================================
const budgetSection = form.addSubform('budgetSection', {
title: 'Budget & Value'
});
budgetSection.addRow(row => {
row.addRadioButton('budgetAdherence', {
label: 'How did the actual cost compare to the agreed budget?',
options: [
{ id: 'under', name: 'Under budget' },
{ id: 'on-budget', name: 'On budget' },
{ id: 'slightly-over', name: 'Slightly over (within acceptable margin)' },
{ id: 'over', name: 'Significantly over budget' }
],
orientation: 'vertical'
});
});
budgetSection.addRow(row => {
row.addRatingScale('valueForMoney', {
label: 'Rate the value for money received:',
preset: 'likert-5',
lowLabel: 'Poor value',
highLabel: 'Excellent value',
alignment: 'center'
});
});
budgetSection.addRow(row => {
row.addEmojiRating('costSurprises', {
label: 'Were there unexpected costs or scope changes?',
preset: 'custom',
emojis: [
{ id: 'many-bad', emoji: '😤', label: 'Many surprises' },
{ id: 'some-bad', emoji: '😕', label: 'Some issues' },
{ id: 'as-expected', emoji: '😐', label: 'As expected' },
{ id: 'well-managed', emoji: '🙂', label: 'Well managed' },
{ id: 'excellent', emoji: '😊', label: 'No surprises' }
],
size: 'lg',
alignment: 'center'
});
});
// ============================================
// SECTION 6: Issues & Problems
// ============================================
const issuesSection = form.addSubform('issuesSection', {
title: 'Issues Encountered',
isVisible: () => {
const quality = qualitySection.starRating('overallQuality')?.value();
return quality !== null && quality !== undefined && quality <= 3;
},
customStyles: {
backgroundColor: '#fef3c7',
padding: '16px',
borderRadius: '8px',
borderLeft: '4px solid #f59e0b'
}
});
issuesSection.addRow(row => {
row.addCheckboxList('issueTypes', {
label: 'What types of issues did you encounter?',
options: [
{ id: 'quality', name: 'Quality below expectations' },
{ id: 'deadline', name: 'Missed deadlines' },
{ id: 'scope', name: 'Scope creep / changes' },
{ id: 'communication', name: 'Communication breakdown' },
{ id: 'cost', name: 'Cost overruns' },
{ id: 'availability', name: 'Availability problems' },
{ id: 'rework', name: 'Excessive rework needed' },
{ id: 'attitude', name: 'Attitude/professionalism issues' }
],
orientation: 'vertical'
});
});
issuesSection.addSpacer();
issuesSection.addRow(row => {
row.addTextarea('issueDetails', {
label: 'Please describe the issues in more detail:',
placeholder: 'Provide specific examples...',
rows: 4,
autoExpand: true
});
});
// ============================================
// SECTION 7: Final Assessment
// ============================================
const finalSection = form.addSubform('finalSection', {
title: 'Final Assessment'
});
finalSection.addRow(row => {
row.addThumbRating('wouldRehire', {
label: 'Would you hire this contractor again?',
showLabels: true,
upLabel: 'Yes, definitely',
downLabel: 'No',
size: 'lg',
alignment: 'center'
});
});
finalSection.addRow(row => {
row.addRatingScale('recommendToOthers', {
label: 'How likely are you to recommend this contractor to colleagues?',
preset: 'nps',
showCategoryLabel: true,
showSegmentColors: true
});
});
finalSection.addSpacer();
finalSection.addRow(row => {
row.addTextarea('strengthsWeaknesses', {
label: 'What were the main strengths and weaknesses?',
placeholder: 'Summarize key positives and areas for improvement...',
rows: 4,
autoExpand: true
});
});
// ============================================
// SECTION 8: Summary
// ============================================
const summarySection = form.addSubform('summarySection', {
title: 'Evaluation Summary',
isVisible: () => {
const quality = qualitySection.starRating('overallQuality')?.value();
return quality !== null;
}
});
summarySection.addRow(row => {
row.addTextPanel('summaryContent', {
computedValue: () => {
const contractor = contextSection.textbox('contractorName')?.value() || 'Contractor';
const quality = qualitySection.starRating('overallQuality')?.value();
const onTime = timelineSection.radioButton('deliveredOnTime')?.value();
const reliability = timelineSection.ratingScale('reliability')?.value();
const value = budgetSection.ratingScale('valueForMoney')?.value();
const rehire = finalSection.thumbRating('wouldRehire')?.value();
const nps = finalSection.ratingScale('recommendToOthers')?.value();
const onTimeLabels: Record<string, string> = {
'early': 'Early',
'on-time': 'On Time',
'slightly-late': 'Slightly Late',
'late': 'Late',
'very-late': 'Very Late'
};
let emoji = (quality ?? 0) >= 4 ? '✅' : (quality ?? 0) >= 3 ? '⚠️' : '❌';
let summary = `${emoji} Contractor Evaluation: ${contractor}\n`;
summary += `${'═'.repeat(35)}\n\n`;
if (quality) summary += `⭐ Quality Rating: ${quality}/5 stars\n`;
if (onTime) summary += `⏰ Delivery: ${onTimeLabels[onTime] || onTime}\n`;
if (reliability) summary += `🎯 Reliability: ${reliability}/5\n`;
if (value) summary += `💰 Value for Money: ${value}/5\n`;
if (rehire) summary += `\n🔄 Would Rehire: ${rehire === 'up' ? 'Yes' : 'No'}`;
if (nps) summary += `\n📊 Recommend Score: ${nps}/10`;
return summary;
},
customStyles: () => {
const quality = qualitySection.starRating('overallQuality')?.value() ?? 0;
const baseStyles = {
padding: '16px',
borderRadius: '8px',
whiteSpace: 'pre-wrap',
fontFamily: 'monospace',
fontSize: '14px'
};
if (quality >= 4) {
return { ...baseStyles, backgroundColor: '#d1fae5', borderLeft: '4px solid #10b981' };
} else if (quality >= 3) {
return { ...baseStyles, backgroundColor: '#fef3c7', borderLeft: '4px solid #f59e0b' };
}
return { ...baseStyles, backgroundColor: '#fee2e2', borderLeft: '4px solid #ef4444' };
}
});
});
// ============================================
// FORM CONFIGURATION
// ============================================
form.configureSubmitButton({
label: 'Submit Evaluation',
isVisible: () => qualitySection.starRating('overallQuality')?.value() !== null
});
form.configureCompletionScreen({
type: 'text',
title: 'Evaluation Submitted',
message: 'Thank you for your detailed contractor feedback. Your input helps us build better vendor relationships and make informed hiring decisions.'
});
}