export function prePostIntervention(form: FormTs) {
// Pre/Post Intervention Survey - Research Assessment
// Demonstrates: Multi-page, MatrixQuestion with Likert scales, computed change scores, RatingScale
// ============================================
// STATE - Track pre/post scores for comparison
// ============================================
const preScores = form.state<Record<string, number>>({});
const postScores = form.state<Record<string, number>>({});
const studyPhase = form.state<'pre' | 'post' | 'complete'>('pre');
// ============================================
// HEADER
// ============================================
form.addRow(row => {
row.addTextPanel('header', {
label: 'Pre/Post Intervention Survey',
computedValue: () => 'Measuring outcomes before and after intervention',
customStyles: {
backgroundColor: '#0891b2',
color: 'white',
padding: '24px',
borderRadius: '12px',
textAlign: 'center'
}
});
});
// ============================================
// MULTI-PAGE STRUCTURE
// ============================================
const pages = form.addPages('surveyPages');
// ============================================
// PAGE 1: Participant Information
// ============================================
const page1 = pages.addPage('participantInfo');
page1.addRow(row => {
row.addTextPanel('page1Title', {
label: 'Step 1 of 4: Participant Information',
customStyles: {
backgroundColor: '#cffafe',
color: '#0891b2',
padding: '12px 16px',
borderRadius: '8px',
fontWeight: 'bold'
}
});
});
const participantSection = page1.addSubform('participant', {
title: 'Study Information'
});
participantSection.addRow(row => {
row.addTextbox('participantId', {
label: 'Participant ID',
placeholder: 'e.g., P-001',
isRequired: true
}, '1fr');
row.addTextbox('studyId', {
label: 'Study/Program ID',
placeholder: 'e.g., STUDY-2024-01'
}, '1fr');
});
participantSection.addRow(row => {
row.addDropdown('interventionType', {
label: 'Intervention Type',
options: [
{ id: 'training', name: 'Training Program' },
{ id: 'therapy', name: 'Therapy/Counseling' },
{ id: 'education', name: 'Educational Program' },
{ id: 'wellness', name: 'Wellness Intervention' },
{ id: 'behavioral', name: 'Behavioral Intervention' },
{ id: 'coaching', name: 'Coaching/Mentoring' },
{ id: 'other', name: 'Other Intervention' }
],
isRequired: true
}, '1fr');
row.addInteger('duration', {
label: 'Intervention Duration (weeks)',
min: 1,
max: 52,
placeholder: 'Number of weeks'
}, '1fr');
});
participantSection.addRow(row => {
row.addDatepicker('startDate', {
label: 'Intervention Start Date'
}, '1fr');
row.addDatepicker('assessmentDate', {
label: 'Assessment Date',
defaultValue: new Date().toISOString().slice(0, 10),
isRequired: true
}, '1fr');
});
const demographicsSection = page1.addSubform('demographics', {
title: 'Demographics (Optional)'
});
demographicsSection.addRow(row => {
row.addDropdown('ageGroup', {
label: 'Age Group',
options: [
{ id: '18-24', name: '18-24' },
{ id: '25-34', name: '25-34' },
{ id: '35-44', name: '35-44' },
{ id: '45-54', name: '45-54' },
{ id: '55-64', name: '55-64' },
{ id: '65+', name: '65+' },
{ id: 'prefer-not', name: 'Prefer not to say' }
]
}, '1fr');
row.addDropdown('gender', {
label: 'Gender',
options: [
{ id: 'male', name: 'Male' },
{ id: 'female', name: 'Female' },
{ id: 'non-binary', name: 'Non-binary' },
{ id: 'other', name: 'Other' },
{ id: 'prefer-not', name: 'Prefer not to say' }
]
}, '1fr');
});
page1.addSpacer();
page1.addRow(row => {
row.addButton('nextToPage2', {
label: 'Next: Pre-Intervention Assessment',
onClick: () => pages.goToPage('preAssessment')
});
});
// ============================================
// PAGE 2: Pre-Intervention Assessment
// ============================================
const page2 = pages.addPage('preAssessment');
page2.addRow(row => {
row.addTextPanel('page2Title', {
label: 'Step 2 of 4: Pre-Intervention Assessment',
customStyles: {
backgroundColor: '#cffafe',
color: '#0891b2',
padding: '12px 16px',
borderRadius: '8px',
fontWeight: 'bold'
}
});
});
page2.addRow(row => {
row.addTextPanel('preInstructions', {
computedValue: () => 'Please rate how you feel RIGHT NOW, BEFORE starting the intervention. Be honest - there are no right or wrong answers.',
customStyles: {
backgroundColor: '#fef3c7',
padding: '12px 16px',
borderRadius: '8px',
fontStyle: 'italic',
color: '#92400e'
}
});
});
const preWellbeing = page2.addSubform('preWellbeing', {
title: 'Wellbeing & Satisfaction',
customStyles: { backgroundColor: '#f0fdfa', padding: '16px', borderRadius: '8px' }
});
preWellbeing.addRow(row => {
row.addMatrixQuestion('preWellbeingMatrix', {
label: 'Rate your current state on each dimension:',
rows: [
{ id: 'lifeSatisfaction', label: 'Overall life satisfaction', isRequired: true },
{ id: 'happiness', label: 'General happiness', isRequired: true },
{ id: 'stress', label: 'Stress level (1=very high, 5=very low)', isRequired: true },
{ id: 'energy', label: 'Energy and vitality', isRequired: true },
{ id: 'sleep', label: 'Sleep quality', isRequired: true }
],
columns: [
{ id: '1', label: '1' },
{ id: '2', label: '2' },
{ id: '3', label: '3' },
{ id: '4', label: '4' },
{ id: '5', label: '5' }
],
fullWidth: true,
onValueChange: (value) => {
if (!value) return;
const scores: Record<string, number> = {};
Object.entries(value).forEach(([key, val]) => {
if (val) scores[key] = parseInt(val as string, 10);
});
preScores.update(current => ({ ...current, ...scores }));
}
});
});
const preSkills = page2.addSubform('preSkills', {
title: 'Skills & Confidence',
customStyles: { backgroundColor: '#f0fdf4', padding: '16px', borderRadius: '8px' }
});
preSkills.addRow(row => {
row.addMatrixQuestion('preSkillsMatrix', {
label: 'Rate your current skills and confidence:',
rows: [
{ id: 'selfEfficacy', label: 'Belief in your ability to succeed', isRequired: true },
{ id: 'problemSolving', label: 'Problem-solving abilities', isRequired: true },
{ id: 'communication', label: 'Communication skills', isRequired: true },
{ id: 'resilience', label: 'Ability to cope with challenges', isRequired: true },
{ id: 'motivation', label: 'Motivation level', isRequired: true }
],
columns: [
{ id: '1', label: '1' },
{ id: '2', label: '2' },
{ id: '3', label: '3' },
{ id: '4', label: '4' },
{ id: '5', label: '5' }
],
fullWidth: true,
onValueChange: (value) => {
if (!value) return;
const scores: Record<string, number> = {};
Object.entries(value).forEach(([key, val]) => {
if (val) scores[key] = parseInt(val as string, 10);
});
preScores.update(current => ({ ...current, ...scores }));
}
});
});
page2.addRow(row => {
row.addRatingScale('preOverall', {
label: 'Overall, how would you rate your current state?',
preset: 'satisfaction',
size: 'lg',
alignment: 'center'
});
});
page2.addSpacer();
page2.addRow(row => {
row.addButton('backToPage1', {
label: 'Back',
onClick: () => pages.goToPage('participantInfo')
}, '100px');
row.addEmpty('1fr');
row.addButton('nextToPage3', {
label: 'Next: Post-Intervention Assessment',
onClick: () => {
studyPhase.set('post');
pages.goToPage('postAssessment');
}
}, 'auto');
});
// ============================================
// PAGE 3: Post-Intervention Assessment
// ============================================
const page3 = pages.addPage('postAssessment');
page3.addRow(row => {
row.addTextPanel('page3Title', {
label: 'Step 3 of 4: Post-Intervention Assessment',
customStyles: {
backgroundColor: '#cffafe',
color: '#0891b2',
padding: '12px 16px',
borderRadius: '8px',
fontWeight: 'bold'
}
});
});
page3.addRow(row => {
row.addTextPanel('postInstructions', {
computedValue: () => 'Please rate how you feel NOW, AFTER completing the intervention. Use the same scale as before to enable comparison.',
customStyles: {
backgroundColor: '#d1fae5',
padding: '12px 16px',
borderRadius: '8px',
fontStyle: 'italic',
color: '#065f46'
}
});
});
const postWellbeing = page3.addSubform('postWellbeing', {
title: 'Wellbeing & Satisfaction (Post)',
customStyles: { backgroundColor: '#f0fdfa', padding: '16px', borderRadius: '8px' }
});
postWellbeing.addRow(row => {
row.addMatrixQuestion('postWellbeingMatrix', {
label: 'Rate your current state on each dimension:',
rows: [
{ id: 'lifeSatisfaction', label: 'Overall life satisfaction', isRequired: true },
{ id: 'happiness', label: 'General happiness', isRequired: true },
{ id: 'stress', label: 'Stress level (1=very high, 5=very low)', isRequired: true },
{ id: 'energy', label: 'Energy and vitality', isRequired: true },
{ id: 'sleep', label: 'Sleep quality', isRequired: true }
],
columns: [
{ id: '1', label: '1' },
{ id: '2', label: '2' },
{ id: '3', label: '3' },
{ id: '4', label: '4' },
{ id: '5', label: '5' }
],
fullWidth: true,
onValueChange: (value) => {
if (!value) return;
const scores: Record<string, number> = {};
Object.entries(value).forEach(([key, val]) => {
if (val) scores[key] = parseInt(val as string, 10);
});
postScores.update(current => ({ ...current, ...scores }));
}
});
});
const postSkills = page3.addSubform('postSkills', {
title: 'Skills & Confidence (Post)',
customStyles: { backgroundColor: '#f0fdf4', padding: '16px', borderRadius: '8px' }
});
postSkills.addRow(row => {
row.addMatrixQuestion('postSkillsMatrix', {
label: 'Rate your current skills and confidence:',
rows: [
{ id: 'selfEfficacy', label: 'Belief in your ability to succeed', isRequired: true },
{ id: 'problemSolving', label: 'Problem-solving abilities', isRequired: true },
{ id: 'communication', label: 'Communication skills', isRequired: true },
{ id: 'resilience', label: 'Ability to cope with challenges', isRequired: true },
{ id: 'motivation', label: 'Motivation level', isRequired: true }
],
columns: [
{ id: '1', label: '1' },
{ id: '2', label: '2' },
{ id: '3', label: '3' },
{ id: '4', label: '4' },
{ id: '5', label: '5' }
],
fullWidth: true,
onValueChange: (value) => {
if (!value) return;
const scores: Record<string, number> = {};
Object.entries(value).forEach(([key, val]) => {
if (val) scores[key] = parseInt(val as string, 10);
});
postScores.update(current => ({ ...current, ...scores }));
}
});
});
page3.addRow(row => {
row.addRatingScale('postOverall', {
label: 'Overall, how would you rate your current state?',
preset: 'satisfaction',
size: 'lg',
alignment: 'center'
});
});
page3.addSpacer();
page3.addRow(row => {
row.addButton('backToPage2', {
label: 'Back',
onClick: () => pages.goToPage('preAssessment')
}, '100px');
row.addEmpty('1fr');
row.addButton('nextToPage4', {
label: 'Next: Results & Feedback',
onClick: () => {
studyPhase.set('complete');
pages.goToPage('results');
}
}, 'auto');
});
// ============================================
// PAGE 4: Results & Qualitative Feedback
// ============================================
const page4 = pages.addPage('results');
page4.addRow(row => {
row.addTextPanel('page4Title', {
label: 'Step 4 of 4: Results & Feedback',
customStyles: {
backgroundColor: '#cffafe',
color: '#0891b2',
padding: '12px 16px',
borderRadius: '8px',
fontWeight: 'bold'
}
});
});
const resultsSection = page4.addSubform('resultsSection', {
title: 'Change Summary'
});
resultsSection.addRow(row => {
row.addTextPanel('changeSummary', {
computedValue: () => {
const pre = preScores();
const post = postScores();
if (Object.keys(pre).length === 0 || Object.keys(post).length === 0) {
return 'Complete both pre and post assessments to see your change summary.';
}
const dimensions = [
{ key: 'lifeSatisfaction', label: 'Life Satisfaction' },
{ key: 'happiness', label: 'Happiness' },
{ key: 'stress', label: 'Stress (lower is better)' },
{ key: 'energy', label: 'Energy' },
{ key: 'sleep', label: 'Sleep Quality' },
{ key: 'selfEfficacy', label: 'Self-Efficacy' },
{ key: 'problemSolving', label: 'Problem Solving' },
{ key: 'communication', label: 'Communication' },
{ key: 'resilience', label: 'Resilience' },
{ key: 'motivation', label: 'Motivation' }
];
let summary = 'PRE/POST COMPARISON\n';
summary += ''.repeat(40) + '\n\n';
summary += 'Dimension Pre Post Change\n';
summary += ''.repeat(40) + '\n';
let totalChange = 0;
let count = 0;
dimensions.forEach(dim => {
const preVal = pre[dim.key];
const postVal = post[dim.key];
if (preVal !== undefined && postVal !== undefined) {
const change = postVal - preVal;
totalChange += change;
count++;
const changeStr = change > 0 ? `+${change}` : `${change}`;
const emoji = change > 0 ? '' : change < 0 ? '' : '';
summary += `${dim.label.padEnd(22)} ${preVal} ${postVal} ${changeStr} ${emoji}\n`;
}
});
if (count > 0) {
const avgChange = (totalChange / count).toFixed(2);
summary += '\n' + ''.repeat(40) + '\n';
summary += `Average Change: ${parseFloat(avgChange) >= 0 ? '+' : ''}${avgChange} points\n`;
if (parseFloat(avgChange) > 0.5) {
summary += '\n Overall Improvement Detected';
} else if (parseFloat(avgChange) < -0.5) {
summary += '\n Decline Detected - Review Recommended';
} else {
summary += '\n Stable - Minimal Change';
}
}
return summary;
},
customStyles: () => {
const pre = preScores();
const post = postScores();
let totalChange = 0;
let count = 0;
Object.keys(pre).forEach(key => {
const postVal = post[key];
const preVal = pre[key];
if (postVal !== undefined && preVal !== undefined) {
totalChange += postVal - preVal;
count++;
}
});
const avgChange = count > 0 ? totalChange / count : 0;
const baseStyles = {
padding: '20px',
borderRadius: '8px',
whiteSpace: 'pre-wrap',
fontFamily: 'monospace',
fontSize: '13px'
};
if (avgChange > 0.5) {
return { ...baseStyles, backgroundColor: '#d1fae5', borderLeft: '4px solid #059669' };
} else if (avgChange < -0.5) {
return { ...baseStyles, backgroundColor: '#fee2e2', borderLeft: '4px solid #dc2626' };
}
return { ...baseStyles, backgroundColor: '#f3f4f6', borderLeft: '4px solid #6b7280' };
}
});
});
const feedbackSection = page4.addSubform('feedback', {
title: 'Qualitative Feedback'
});
feedbackSection.addRow(row => {
row.addEmojiRating('overallExperience', {
label: 'How would you rate your overall intervention experience?',
preset: 'satisfaction',
size: 'lg',
showLabels: true,
alignment: 'center'
});
});
feedbackSection.addRow(row => {
row.addRatingScale('recommendLikelihood', {
label: 'How likely are you to recommend this intervention to others?',
preset: 'nps',
showCategoryLabel: true,
showSegmentColors: true
});
});
feedbackSection.addSpacer();
feedbackSection.addRow(row => {
row.addTextarea('mostHelpful', {
label: 'What was most helpful about this intervention?',
placeholder: 'Describe what worked well for you...',
rows: 3
});
});
feedbackSection.addRow(row => {
row.addTextarea('improvements', {
label: 'What could be improved?',
placeholder: 'Share suggestions for improvement...',
rows: 3
});
});
feedbackSection.addRow(row => {
row.addTextarea('additionalComments', {
label: 'Any additional comments or observations?',
placeholder: 'Share any other thoughts...',
rows: 3
});
});
page4.addSpacer();
page4.addRow(row => {
row.addButton('backToPage3', {
label: 'Back',
onClick: () => pages.goToPage('postAssessment')
}, '100px');
});
// ============================================
// FORM CONFIGURATION
// ============================================
form.configureSubmitButton({
label: 'Submit Survey',
isVisible: () => studyPhase() === 'complete'
});
form.configureCompletionScreen({
type: 'text',
title: 'Survey Completed',
message: 'Thank you for completing the pre/post intervention survey. Your responses will help evaluate the effectiveness of this intervention and contribute to research findings. You may receive follow-up communication regarding the study results.'
});
}