export function grantApplicationForm(form: FormTs) {
// Grant Application Form - Multi-page wizard for non-profit funding requests
// Demonstrates: Multi-page wizard, Money fields, computed totals, conditional sections, MatrixQuestion
// ============================================
// STATE
// ============================================
const totalBudget = form.computedValue(() => {
const personnel = budgetPage?.money('personnelCosts')?.value() || 0;
const equipment = budgetPage?.money('equipmentCosts')?.value() || 0;
const supplies = budgetPage?.money('suppliesCosts')?.value() || 0;
const travel = budgetPage?.money('travelCosts')?.value() || 0;
const other = budgetPage?.money('otherCosts')?.value() || 0;
return personnel + equipment + supplies + travel + other;
});
// ============================================
// HEADER
// ============================================
form.addRow(row => {
row.addTextPanel('header', {
label: 'Grant Application',
computedValue: () => 'Complete this form to apply for funding. All fields marked with * are required.',
customStyles: {
backgroundColor: '#059669',
color: 'white',
padding: '24px',
borderRadius: '12px',
textAlign: 'center'
}
});
});
// ============================================
// MULTI-PAGE WIZARD
// ============================================
const pages = form.addPages('applicationPages', {
heightMode: 'current-page'
});
// ============================================
// PAGE 1: Organization Information
// ============================================
const orgPage = pages.addPage('organization');
orgPage.setTitle(() => 'Step 1: Organization Information');
const orgDetails = orgPage.addSubform('orgDetails', {
title: 'Organization Details'
});
orgDetails.addRow(row => {
row.addTextbox('orgName', {
label: 'Organization Name',
placeholder: 'Enter your organization\'s legal name',
isRequired: true
}, '1fr');
});
orgDetails.addRow(row => {
row.addTextbox('taxId', {
label: 'Tax ID / EIN',
placeholder: '12-3456789',
isRequired: true
}, '1fr');
row.addDropdown('orgType', {
label: 'Organization Type',
options: [
{ id: '501c3', name: '501(c)(3) Non-profit' },
{ id: '501c4', name: '501(c)(4) Social Welfare' },
{ id: 'foundation', name: 'Private Foundation' },
{ id: 'government', name: 'Government Entity' },
{ id: 'educational', name: 'Educational Institution' },
{ id: 'other', name: 'Other' }
],
isRequired: true
}, '1fr');
});
orgDetails.addRow(row => {
row.addEmail('contactEmail', {
label: 'Primary Contact Email',
placeholder: 'contact@organization.org',
isRequired: true
}, '1fr');
row.addTextbox('contactPhone', {
label: 'Phone Number',
placeholder: '(555) 123-4567'
}, '1fr');
});
orgDetails.addRow(row => {
row.addTextbox('contactName', {
label: 'Primary Contact Person',
placeholder: 'Full name',
isRequired: true
}, '1fr');
row.addTextbox('contactTitle', {
label: 'Title/Position',
placeholder: 'Executive Director'
}, '1fr');
});
orgDetails.addSpacer({ height: '20px' });
orgDetails.addRow(row => {
row.addTextarea('orgMission', {
label: 'Organization Mission Statement',
placeholder: 'Briefly describe your organization\'s mission and primary activities...',
rows: 3,
isRequired: true
});
});
orgDetails.addRow(row => {
row.addInteger('yearFounded', {
label: 'Year Founded',
min: 1800,
max: () => new Date().getFullYear(),
placeholder: '2010'
}, '1fr');
row.addMoney('annualBudget', {
label: 'Annual Operating Budget',
currency: '$',
placeholder: 'Total annual budget'
}, '1fr');
});
// Navigation buttons for page 1
orgPage.addSpacer({ height: '30px' });
orgPage.addRow(row => {
row.addEmpty('1fr');
row.addButton('nextToProject', {
label: 'Next: Project Details',
onClick: () => pages.goToPage('project')
}, 'auto');
});
// ============================================
// PAGE 2: Project Details
// ============================================
const projectPage = pages.addPage('project');
projectPage.setTitle(() => 'Step 2: Project Details');
const projectInfo = projectPage.addSubform('projectInfo', {
title: 'Project Information'
});
projectInfo.addRow(row => {
row.addTextbox('projectTitle', {
label: 'Project Title',
placeholder: 'Enter a descriptive title for your project',
isRequired: true
});
});
projectInfo.addRow(row => {
row.addDropdown('projectType', {
label: 'Project Type',
options: [
{ id: 'program', name: 'Program/Service Delivery' },
{ id: 'capital', name: 'Capital/Equipment' },
{ id: 'research', name: 'Research/Study' },
{ id: 'capacity', name: 'Capacity Building' },
{ id: 'general', name: 'General Operating Support' }
],
isRequired: true
}, '1fr');
row.addDropdown('focusArea', {
label: 'Primary Focus Area',
options: [
{ id: 'education', name: 'Education' },
{ id: 'health', name: 'Health & Wellness' },
{ id: 'environment', name: 'Environment' },
{ id: 'arts', name: 'Arts & Culture' },
{ id: 'community', name: 'Community Development' },
{ id: 'social', name: 'Social Services' },
{ id: 'advocacy', name: 'Advocacy' },
{ id: 'other', name: 'Other' }
],
isRequired: true
}, '1fr');
});
projectInfo.addSpacer({ height: '20px' });
projectInfo.addRow(row => {
row.addTextarea('projectSummary', {
label: 'Project Summary',
placeholder: 'Provide a brief overview of the project (2-3 sentences)...',
rows: 3,
isRequired: true,
maxLength: 500
});
});
projectInfo.addRow(row => {
row.addTextarea('projectNeed', {
label: 'Statement of Need',
placeholder: 'Describe the problem or need this project addresses. Include relevant data or statistics...',
rows: 4,
isRequired: true
});
});
projectInfo.addRow(row => {
row.addTextarea('projectActivities', {
label: 'Project Activities',
placeholder: 'Describe the specific activities and methods you will use...',
rows: 4,
isRequired: true
});
});
// Target population
const targetPop = projectPage.addSubform('targetPopulation', {
title: 'Target Population'
});
targetPop.addRow(row => {
row.addCheckboxList('populations', {
label: 'Who will benefit from this project?',
options: [
{ id: 'children', name: 'Children (0-12)' },
{ id: 'youth', name: 'Youth (13-18)' },
{ id: 'adults', name: 'Adults (19-64)' },
{ id: 'seniors', name: 'Seniors (65+)' },
{ id: 'families', name: 'Families' },
{ id: 'veterans', name: 'Veterans' },
{ id: 'immigrants', name: 'Immigrants/Refugees' },
{ id: 'disabled', name: 'People with Disabilities' },
{ id: 'homeless', name: 'Homeless/Housing Insecure' },
{ id: 'lgbtq', name: 'LGBTQ+ Community' }
],
orientation: 'vertical',
min: 1
}, '1fr');
row.addTextarea('geographicArea', {
label: 'Geographic Area Served',
placeholder: 'Describe the geographic area where project activities will take place...',
rows: 3
}, '1fr');
});
targetPop.addRow(row => {
row.addInteger('beneficiariesCount', {
label: 'Estimated Number of Beneficiaries',
min: 1,
placeholder: 'How many people will directly benefit?',
isRequired: true
});
});
// Navigation buttons for page 2
projectPage.addSpacer({ height: '30px' });
projectPage.addRow(row => {
row.addButton('backToOrg', {
label: 'Back',
onClick: () => pages.goToPage('organization')
}, 'auto');
row.addEmpty('1fr');
row.addButton('nextToBudget', {
label: 'Next: Budget',
onClick: () => pages.goToPage('budget')
}, 'auto');
});
// ============================================
// PAGE 3: Budget
// ============================================
const budgetPage = pages.addPage('budget');
budgetPage.setTitle(() => 'Step 3: Budget');
const budgetDetails = budgetPage.addSubform('budgetDetails', {
title: 'Budget Breakdown',
customStyles: { backgroundColor: '#f0fdf4', padding: '16px', borderRadius: '8px' }
});
budgetDetails.addRow(row => {
row.addTextPanel('budgetInstructions', {
computedValue: () => 'Enter the amount requested for each budget category. Leave blank or enter 0 for categories that don\'t apply.',
customStyles: { fontSize: '14px', color: '#6b7280', marginBottom: '16px' }
});
});
budgetDetails.addRow(row => {
row.addMoney('personnelCosts', {
label: 'Personnel & Salaries',
currency: '$',
placeholder: '0.00',
tooltip: 'Staff salaries, benefits, and contractor fees'
}, '1fr');
row.addMoney('equipmentCosts', {
label: 'Equipment & Technology',
currency: '$',
placeholder: '0.00',
tooltip: 'Computers, software, machinery, etc.'
}, '1fr');
});
budgetDetails.addRow(row => {
row.addMoney('suppliesCosts', {
label: 'Supplies & Materials',
currency: '$',
placeholder: '0.00',
tooltip: 'Office supplies, program materials'
}, '1fr');
row.addMoney('travelCosts', {
label: 'Travel & Transportation',
currency: '$',
placeholder: '0.00',
tooltip: 'Staff travel, participant transportation'
}, '1fr');
});
budgetDetails.addRow(row => {
row.addMoney('otherCosts', {
label: 'Other Expenses',
currency: '$',
placeholder: '0.00',
tooltip: 'Any expenses not covered above'
}, '1fr');
row.addPriceDisplay('totalRequested', {
label: 'Total Amount Requested',
computedValue: () => totalBudget(),
currency: '$',
variant: 'highlight',
alignment: 'right'
}, '1fr');
});
budgetDetails.addSpacer({ height: '20px' });
budgetDetails.addRow(row => {
row.addTextarea('budgetNarrative', {
label: 'Budget Narrative',
placeholder: 'Provide additional details about your budget. Explain any large line items or unusual expenses...',
rows: 3,
isVisible: () => totalBudget() > 0
});
});
// Matching funds section
const matchingFunds = budgetPage.addSubform('matchingFunds', {
title: 'Additional Funding',
isVisible: () => totalBudget() > 0
});
matchingFunds.addRow(row => {
row.addRadioButton('hasMatchingFunds', {
label: 'Do you have other funding sources for this project?',
options: [
{ id: 'yes', name: 'Yes' },
{ id: 'no', name: 'No' }
],
orientation: 'horizontal'
});
});
matchingFunds.addRow(row => {
row.addMoney('matchingAmount', {
label: 'Amount from Other Sources',
currency: '$',
isVisible: () => matchingFunds.radioButton('hasMatchingFunds')?.value() === 'yes'
}, '1fr');
row.addTextbox('matchingSources', {
label: 'Source(s) of Other Funding',
placeholder: 'List other funders or revenue sources',
isVisible: () => matchingFunds.radioButton('hasMatchingFunds')?.value() === 'yes'
}, '1fr');
});
// Budget warning
budgetPage.addRow(row => {
row.addTextPanel('budgetWarning', {
computedValue: () => {
const total = totalBudget();
if (total > 100000) {
return 'Note: Requests over $100,000 require additional documentation. A staff member will contact you.';
}
return '';
},
customStyles: () => ({
backgroundColor: totalBudget() > 100000 ? '#fef3c7' : 'transparent',
padding: totalBudget() > 100000 ? '12px' : '0',
borderRadius: '8px',
color: '#92400e'
}),
isVisible: () => totalBudget() > 100000
});
});
// Navigation buttons for page 3
budgetPage.addSpacer({ height: '30px' });
budgetPage.addRow(row => {
row.addButton('backToProject', {
label: 'Back',
onClick: () => pages.goToPage('project')
}, 'auto');
row.addEmpty('1fr');
row.addButton('nextToTimeline', {
label: 'Next: Timeline & Impact',
onClick: () => pages.goToPage('timeline')
}, 'auto');
});
// ============================================
// PAGE 4: Timeline & Impact
// ============================================
const timelinePage = pages.addPage('timeline');
timelinePage.setTitle(() => 'Step 4: Timeline & Expected Impact');
const timeline = timelinePage.addSubform('timeline', {
title: 'Project Timeline'
});
timeline.addRow(row => {
row.addDatepicker('startDate', {
label: 'Proposed Start Date',
isRequired: true,
minDate: () => new Date().toISOString()
}, '1fr');
row.addDatepicker('endDate', {
label: 'Proposed End Date',
isRequired: true,
minDate: () => timeline.datepicker('startDate')?.value() || new Date().toISOString()
}, '1fr');
});
timeline.addRow(row => {
row.addTextarea('milestones', {
label: 'Key Milestones',
placeholder: 'List major project milestones and expected completion dates...\n\nExample:\n- Month 1-2: Staff hiring and training\n- Month 3-6: Program launch and outreach\n- Month 7-12: Full implementation and evaluation',
rows: 5,
isRequired: true
});
});
// Impact metrics
const impact = timelinePage.addSubform('impact', {
title: 'Expected Outcomes & Impact'
});
impact.addRow(row => {
row.addMatrixQuestion('successMetrics', {
label: 'How will you measure success? Rate the importance of each metric:',
rows: [
{ id: 'reach', label: 'Number of people served', isRequired: true },
{ id: 'satisfaction', label: 'Participant satisfaction' },
{ id: 'knowledge', label: 'Knowledge/skill improvement' },
{ id: 'behavior', label: 'Behavior change' },
{ id: 'outcomes', label: 'Long-term outcomes' }
],
columns: [
{ id: 'na', label: 'N/A' },
{ id: 'low', label: 'Low' },
{ id: 'medium', label: 'Medium' },
{ id: 'high', label: 'High' },
{ id: 'critical', label: 'Critical' }
],
alignment: 'center',
fullWidth: true
});
});
impact.addSpacer({ height: '20px' });
impact.addRow(row => {
row.addTextarea('outcomeDescription', {
label: 'Describe Expected Outcomes',
placeholder: 'What specific changes do you expect to see as a result of this project? Be specific and measurable...',
rows: 4,
isRequired: true
});
});
impact.addRow(row => {
row.addTextarea('evaluationPlan', {
label: 'Evaluation Plan',
placeholder: 'How will you track and evaluate progress? What data will you collect?',
rows: 3
});
});
// Sustainability
const sustainability = timelinePage.addSubform('sustainability', {
title: 'Sustainability'
});
sustainability.addRow(row => {
row.addTextarea('sustainabilityPlan', {
label: 'How will this project be sustained after the grant period?',
placeholder: 'Describe your plan for continuing this work or its impact beyond the grant period...',
rows: 3
});
});
// Navigation buttons for page 4
timelinePage.addSpacer({ height: '30px' });
timelinePage.addRow(row => {
row.addButton('backToBudget', {
label: 'Back',
onClick: () => pages.goToPage('budget')
}, 'auto');
row.addEmpty('1fr');
row.addButton('nextToReview', {
label: 'Next: Review & Submit',
onClick: () => pages.goToPage('review')
}, 'auto');
});
// ============================================
// PAGE 5: Review & Submit
// ============================================
const reviewPage = pages.addPage('review');
reviewPage.setTitle(() => 'Step 5: Review & Submit');
const summary = reviewPage.addSubform('summary', {
title: 'Application Summary',
customStyles: { backgroundColor: '#f8fafc', padding: '16px', borderRadius: '8px' }
});
summary.addRow(row => {
row.addTextPanel('summaryContent', {
computedValue: () => {
const orgName = orgDetails.textbox('orgName')?.value() || 'Not provided';
const projectTitle = projectInfo.textbox('projectTitle')?.value() || 'Not provided';
const projectType = projectInfo.dropdown('projectType')?.value() || 'Not selected';
const total = totalBudget();
const beneficiaries = targetPop.integer('beneficiariesCount')?.value() || 0;
const startDate = timeline.datepicker('startDate')?.value() || 'TBD';
const endDate = timeline.datepicker('endDate')?.value() || 'TBD';
const projectTypes: Record<string, string> = {
'program': 'Program/Service Delivery',
'capital': 'Capital/Equipment',
'research': 'Research/Study',
'capacity': 'Capacity Building',
'general': 'General Operating Support'
};
let summaryText = `APPLICATION SUMMARY\n${'═'.repeat(40)}\n\n`;
summaryText += `Organization: ${orgName}\n`;
summaryText += `Project: ${projectTitle}\n`;
summaryText += `Type: ${projectTypes[projectType] || projectType}\n\n`;
summaryText += `Amount Requested: $${total.toLocaleString()}\n`;
summaryText += `Beneficiaries: ${beneficiaries.toLocaleString()}\n`;
summaryText += `Timeline: ${startDate} to ${endDate}\n`;
return summaryText;
},
customStyles: {
whiteSpace: 'pre-wrap',
fontFamily: 'monospace',
fontSize: '14px',
padding: '16px',
backgroundColor: 'white',
borderRadius: '8px',
border: '1px solid #e5e7eb'
}
});
});
// Certification
const certification = reviewPage.addSubform('certification', {
title: 'Certification'
});
certification.addRow(row => {
row.addCheckbox('certifyAccurate', {
label: 'I certify that the information provided in this application is true and accurate to the best of my knowledge.',
isRequired: true
});
});
certification.addRow(row => {
row.addCheckbox('certifyAuthorized', {
label: 'I am authorized to submit this application on behalf of the organization.',
isRequired: true
});
});
certification.addRow(row => {
row.addCheckbox('agreeTerms', {
label: 'I agree to comply with all grant requirements and reporting obligations if funded.',
isRequired: true
});
});
certification.addSpacer({ height: '20px' });
certification.addRow(row => {
row.addTextbox('signatureName', {
label: 'Electronic Signature (Type Full Name)',
placeholder: 'Type your full legal name',
isRequired: true
}, '1fr');
row.addDatepicker('signatureDate', {
label: 'Date',
isRequired: true
}, '200px');
});
// Navigation buttons for page 5
reviewPage.addSpacer({ height: '30px' });
reviewPage.addRow(row => {
row.addButton('backToTimeline', {
label: 'Back',
onClick: () => pages.goToPage('timeline')
}, 'auto');
row.addEmpty('1fr');
});
// ============================================
// FORM CONFIGURATION
// ============================================
form.configureSubmitButton({
label: () => `Submit Application ($${totalBudget().toLocaleString()} Requested)`,
isVisible: () => pages.currentPageIndex() === 4
});
form.configureCompletionScreen({
type: 'text',
title: 'Application Submitted Successfully!',
message: 'Thank you for your grant application. We have received your submission and will review it within 4-6 weeks. You will receive a confirmation email shortly with your application reference number.'
});
}