export function materialInspection(form: FormTs) {
// Material Quality Inspection Form - Construction materials QC
// Demonstrates: MatrixQuestion, RatingScale, StarRating, RadioButton, ThumbRating, CheckboxList, Slider, conditional visibility, dynamic styling
// ============================================
// HEADER
// ============================================
form.addRow(row => {
row.addTextPanel('header', {
label: 'Material Quality Inspection',
computedValue: () => 'Document material condition and specification compliance',
customStyles: {
backgroundColor: '#78350f',
color: 'white',
padding: '24px',
borderRadius: '12px',
textAlign: 'center'
}
});
});
// ============================================
// SECTION 1: Delivery Information
// ============================================
const deliverySection = form.addSubform('delivery', {
title: 'Delivery Information',
customStyles: { padding: '16px', borderRadius: '8px', border: '1px solid #e2e8f0' }
});
deliverySection.addRow(row => {
row.addTextbox('projectName', {
label: 'Project Name/Number',
placeholder: 'e.g., Main Street Building - PRJ-2024-001',
isRequired: true
});
});
deliverySection.addRow(row => {
row.addDatepicker('deliveryDate', {
label: 'Delivery Date',
isRequired: true
}, '1fr');
row.addTimepicker('deliveryTime', {
label: 'Delivery Time'
}, '1fr');
});
deliverySection.addRow(row => {
row.addTextbox('supplierName', {
label: 'Supplier/Vendor',
placeholder: 'Company name',
isRequired: true
}, '1fr');
row.addTextbox('deliveryTicket', {
label: 'Delivery Ticket/BOL #',
placeholder: 'e.g., DT-12345'
}, '1fr');
});
deliverySection.addRow(row => {
row.addTextbox('poNumber', {
label: 'Purchase Order #',
placeholder: 'e.g., PO-2024-0456'
}, '1fr');
row.addTextbox('inspector', {
label: 'Inspector Name',
placeholder: 'Your name',
isRequired: true
}, '1fr');
});
// ============================================
// SECTION 2: Material Details
// ============================================
const materialSection = form.addSubform('material', {
title: 'Material Details',
isVisible: () => deliverySection.textbox('supplierName')?.value() !== null && deliverySection.textbox('supplierName')?.value() !== ''
});
materialSection.addRow(row => {
row.addDropdown('materialCategory', {
label: 'Material Category',
options: [
{ id: 'concrete', name: 'Concrete/Cement' },
{ id: 'steel', name: 'Steel/Rebar' },
{ id: 'lumber', name: 'Lumber/Wood' },
{ id: 'masonry', name: 'Masonry/Brick/Block' },
{ id: 'roofing', name: 'Roofing Materials' },
{ id: 'insulation', name: 'Insulation' },
{ id: 'drywall', name: 'Drywall/Gypsum' },
{ id: 'plumbing', name: 'Plumbing Materials' },
{ id: 'electrical', name: 'Electrical Materials' },
{ id: 'hvac', name: 'HVAC Materials' },
{ id: 'glass', name: 'Glass/Glazing' },
{ id: 'flooring', name: 'Flooring Materials' },
{ id: 'hardware', name: 'Hardware/Fasteners' },
{ id: 'other', name: 'Other' }
],
placeholder: 'Select category',
isRequired: true
}, '1fr');
row.addTextbox('materialDescription', {
label: 'Material Description',
placeholder: 'e.g., 4x8 Treated Lumber, Grade #2',
isRequired: true
}, '1fr');
});
materialSection.addRow(row => {
row.addDecimal('quantityOrdered', {
label: 'Quantity Ordered',
placeholder: '0',
min: 0,
isRequired: true
}, '1fr');
row.addDecimal('quantityReceived', {
label: 'Quantity Received',
placeholder: '0',
min: 0,
isRequired: true
}, '1fr');
row.addDropdown('unit', {
label: 'Unit',
options: [
{ id: 'ea', name: 'Each' },
{ id: 'pcs', name: 'Pieces' },
{ id: 'lf', name: 'Linear Feet' },
{ id: 'sf', name: 'Square Feet' },
{ id: 'cy', name: 'Cubic Yards' },
{ id: 'ton', name: 'Tons' },
{ id: 'lb', name: 'Pounds' },
{ id: 'bag', name: 'Bags' },
{ id: 'bundle', name: 'Bundles' },
{ id: 'pallet', name: 'Pallets' },
{ id: 'roll', name: 'Rolls' },
{ id: 'box', name: 'Boxes' }
],
placeholder: 'Unit'
}, '1fr');
});
materialSection.addRow(row => {
row.addTextPanel('quantityAlert', {
computedValue: () => {
const ordered = materialSection.decimal('quantityOrdered')?.value();
const received = materialSection.decimal('quantityReceived')?.value();
if (ordered && received) {
if (received < ordered) {
return `⚠️ Short shipment: ${ordered - received} units short`;
} else if (received > ordered) {
return `📦 Over shipment: ${received - ordered} units extra`;
}
}
return '';
},
customStyles: () => {
const ordered = materialSection.decimal('quantityOrdered')?.value();
const received = materialSection.decimal('quantityReceived')?.value();
if (ordered && received && received !== ordered) {
return {
backgroundColor: received < ordered ? '#fef2f2' : '#fef9c3',
padding: '12px 16px',
borderRadius: '8px',
fontWeight: '500'
};
}
return { display: 'none' };
},
isVisible: () => {
const ordered = materialSection.decimal('quantityOrdered')?.value();
const received = materialSection.decimal('quantityReceived')?.value();
return ordered !== null && received !== null && ordered !== received;
}
});
});
// ============================================
// SECTION 3: Visual Inspection
// ============================================
const visualSection = form.addSubform('visual', {
title: 'Visual Inspection',
isVisible: () => materialSection.dropdown('materialCategory')?.value() !== null
});
visualSection.addRow(row => {
row.addStarRating('visualCondition', {
label: 'Overall Visual Condition',
maxStars: 5,
size: 'lg',
alignment: 'center',
showConfettiOnMax: true,
tooltip: '5 = Perfect condition, 1 = Severely damaged'
});
});
visualSection.addRow(row => {
row.addMatrixQuestion('visualMatrix', {
label: 'Inspect the following:',
rows: [
{ id: 'packaging', label: 'Packaging intact', isRequired: true },
{ id: 'damage', label: 'No visible damage', isRequired: true },
{ id: 'labeling', label: 'Proper labeling/marking', isRequired: true },
{ id: 'contamination', label: 'Free from contamination', isRequired: false },
{ id: 'moisture', label: 'No moisture damage', isRequired: false },
{ id: 'color', label: 'Color/appearance correct', isRequired: false }
],
columns: [
{ id: 'na', label: 'N/A' },
{ id: 'fail', label: 'Fail' },
{ id: 'marginal', label: 'Marginal' },
{ id: 'pass', label: 'Pass' }
],
striped: true,
fullWidth: true
});
});
visualSection.addRow(row => {
row.addCheckboxList('defectsFound', {
label: 'Defects observed (select all that apply):',
options: [
{ id: 'none', name: 'No defects - material in good condition' },
{ id: 'broken', name: 'Broken/cracked items' },
{ id: 'bent', name: 'Bent/deformed' },
{ id: 'scratched', name: 'Scratched/marred surface' },
{ id: 'rust', name: 'Rust/corrosion' },
{ id: 'wet', name: 'Water damage/wet' },
{ id: 'dirty', name: 'Dirty/contaminated' },
{ id: 'missing-parts', name: 'Missing parts/components' },
{ id: 'wrong-material', name: 'Wrong material/grade' }
],
orientation: 'vertical'
});
});
visualSection.addSpacer({ isVisible: () => {
const defects = visualSection.checkboxList('defectsFound')?.value() || [];
return defects.length > 0 && !defects.includes('none');
}});
visualSection.addRow(row => {
row.addSlider('defectPercentage', {
label: 'Estimated percentage of material affected by defects',
min: 0,
max: 100,
step: 5,
defaultValue: 0,
unit: '%',
showValue: true,
isVisible: () => {
const defects = visualSection.checkboxList('defectsFound')?.value() || [];
return defects.length > 0 && !defects.includes('none');
}
});
});
visualSection.addRow(row => {
row.addTextarea('defectDescription', {
label: 'Describe defects in detail',
placeholder: 'Location, type, and severity of each defect...',
rows: 3,
autoExpand: true,
isVisible: () => {
const defects = visualSection.checkboxList('defectsFound')?.value() || [];
return defects.length > 0 && !defects.includes('none');
}
});
});
// ============================================
// SECTION 4: Specification Compliance
// ============================================
const specsSection = form.addSubform('specs', {
title: 'Specification Compliance',
isVisible: () => materialSection.dropdown('materialCategory')?.value() !== null
});
specsSection.addRow(row => {
row.addMatrixQuestion('specsMatrix', {
label: 'Verify specifications:',
rows: [
{ id: 'grade', label: 'Grade/quality meets spec', isRequired: true },
{ id: 'size', label: 'Size/dimensions correct', isRequired: true },
{ id: 'type', label: 'Material type matches order', isRequired: true },
{ id: 'brand', label: 'Brand/manufacturer approved', isRequired: false },
{ id: 'certs', label: 'Certifications/test reports included', isRequired: false }
],
columns: [
{ id: 'na', label: 'N/A' },
{ id: 'no', label: 'No' },
{ id: 'partial', label: 'Partial' },
{ id: 'yes', label: 'Yes' }
],
striped: true,
fullWidth: true
});
});
specsSection.addRow(row => {
row.addRadioButton('documentationReceived', {
label: 'Required documentation received?',
options: [
{ id: 'all', name: 'All documentation received' },
{ id: 'partial', name: 'Partial - some documents missing' },
{ id: 'none', name: 'No documentation received' },
{ id: 'na', name: 'N/A - no documentation required' }
],
orientation: 'vertical'
});
});
// ============================================
// SECTION 5: Storage Requirements
// ============================================
const storageSection = form.addSubform('storage', {
title: 'Storage Considerations',
isVisible: () => materialSection.dropdown('materialCategory')?.value() !== null
});
storageSection.addRow(row => {
row.addCheckboxList('storageNeeds', {
label: 'Special storage requirements (select all that apply):',
options: [
{ id: 'none', name: 'No special requirements' },
{ id: 'covered', name: 'Must be covered/protected' },
{ id: 'dry', name: 'Must stay dry' },
{ id: 'flat', name: 'Must be stored flat' },
{ id: 'elevated', name: 'Must be elevated off ground' },
{ id: 'temperature', name: 'Temperature controlled' },
{ id: 'secure', name: 'Secured storage required' },
{ id: 'fifo', name: 'FIFO (First In, First Out)' }
],
orientation: 'vertical'
});
});
// ============================================
// SECTION 6: Acceptance Decision
// ============================================
const decisionSection = form.addSubform('decision', {
title: 'Inspection Decision',
isVisible: () => visualSection.starRating('visualCondition')?.value() !== null,
customStyles: () => {
const decision = decisionSection.radioButton('acceptanceDecision')?.value();
if (decision === 'accept') return { backgroundColor: '#dcfce7', padding: '16px', borderRadius: '8px' };
if (decision === 'conditional') return { backgroundColor: '#fef9c3', padding: '16px', borderRadius: '8px' };
if (decision === 'reject') return { backgroundColor: '#fecaca', padding: '16px', borderRadius: '8px' };
return { padding: '16px', borderRadius: '8px', border: '1px solid #e2e8f0' };
}
});
decisionSection.addRow(row => {
row.addRadioButton('acceptanceDecision', {
label: 'Acceptance Decision',
options: [
{ id: 'accept', name: 'ACCEPT - Material meets all requirements' },
{ id: 'conditional', name: 'CONDITIONAL ACCEPT - Minor issues, usable with notes' },
{ id: 'reject', name: 'REJECT - Material does not meet requirements' },
{ id: 'hold', name: 'HOLD - Requires further evaluation' }
],
orientation: 'vertical',
isRequired: true
});
});
decisionSection.addRow(row => {
row.addTextarea('rejectionReason', {
label: 'Reason for rejection or conditional acceptance',
placeholder: 'Explain the issues and why the material was rejected or conditionally accepted...',
rows: 3,
autoExpand: true,
isRequired: () => {
const decision = decisionSection.radioButton('acceptanceDecision')?.value();
return decision === 'reject' || decision === 'conditional';
},
isVisible: () => {
const decision = decisionSection.radioButton('acceptanceDecision')?.value();
return decision === 'reject' || decision === 'conditional' || decision === 'hold';
}
});
});
decisionSection.addRow(row => {
row.addThumbRating('supplierNotified', {
label: 'Has the supplier been notified of issues?',
showLabels: true,
upLabel: 'Yes',
downLabel: 'Not yet',
alignment: 'center',
size: 'lg',
isVisible: () => {
const decision = decisionSection.radioButton('acceptanceDecision')?.value();
return decision === 'reject' || decision === 'conditional';
}
});
});
// ============================================
// SECTION 7: Summary
// ============================================
const summarySection = form.addSubform('summary', {
title: 'Inspection Summary',
isVisible: () => decisionSection.radioButton('acceptanceDecision')?.value() !== null
});
summarySection.addRow(row => {
row.addTextPanel('summaryContent', {
computedValue: () => {
const project = deliverySection.textbox('projectName')?.value();
const date = deliverySection.datepicker('deliveryDate')?.value();
const supplier = deliverySection.textbox('supplierName')?.value();
const material = materialSection.textbox('materialDescription')?.value();
const category = materialSection.dropdown('materialCategory')?.value();
const ordered = materialSection.decimal('quantityOrdered')?.value();
const received = materialSection.decimal('quantityReceived')?.value();
const unit = materialSection.dropdown('unit')?.value();
const visual = visualSection.starRating('visualCondition')?.value();
const defects = visualSection.checkboxList('defectsFound')?.value() || [];
const decision = decisionSection.radioButton('acceptanceDecision')?.value();
const decisionLabels: Record<string, string> = {
'accept': '✅ ACCEPTED',
'conditional': '⚠️ CONDITIONAL',
'reject': '❌ REJECTED',
'hold': '🔄 ON HOLD'
};
let summary = `MATERIAL INSPECTION REPORT\n`;
summary += `${'═'.repeat(30)}\n\n`;
if (project) summary += `Project: ${project}\n`;
if (date) summary += `Date: ${date}\n`;
if (supplier) summary += `Supplier: ${supplier}\n`;
if (material) {
summary += `\nMaterial: ${material}\n`;
}
if (ordered && received && unit) {
summary += `Quantity: ${received}/${ordered} ${unit}`;
if (received < ordered) summary += ' (SHORT)';
if (received > ordered) summary += ' (OVER)';
summary += '\n';
}
if (visual) {
summary += `\nCondition: ${'★'.repeat(visual)}${'☆'.repeat(5 - visual)}\n`;
}
const hasDefects = defects.length > 0 && !defects.includes('none');
if (hasDefects) {
summary += `Defects: ${defects.length} type(s) found\n`;
}
if (decision) {
summary += `\n${'─'.repeat(30)}\n`;
summary += `DECISION: ${decisionLabels[decision]}`;
}
return summary;
},
customStyles: () => {
const decision = decisionSection.radioButton('acceptanceDecision')?.value();
const baseStyles = {
padding: '16px',
borderRadius: '8px',
whiteSpace: 'pre-wrap',
fontFamily: 'monospace',
fontSize: '13px'
};
if (decision === 'accept') {
return { ...baseStyles, backgroundColor: '#dcfce7', borderLeft: '4px solid #22c55e' };
} else if (decision === 'conditional') {
return { ...baseStyles, backgroundColor: '#fef9c3', borderLeft: '4px solid #eab308' };
} else if (decision === 'reject') {
return { ...baseStyles, backgroundColor: '#fecaca', borderLeft: '4px solid #ef4444' };
}
return { ...baseStyles, backgroundColor: '#f8fafc', borderLeft: '4px solid #78350f' };
}
});
});
// ============================================
// FORM CONFIGURATION
// ============================================
form.configureSubmitButton({
label: () => {
const decision = decisionSection.radioButton('acceptanceDecision')?.value();
if (decision === 'accept') return 'Submit - Material Accepted';
if (decision === 'reject') return 'Submit - Material Rejected';
return 'Submit Inspection Report';
},
isVisible: () => decisionSection.radioButton('acceptanceDecision')?.value() !== null
});
form.configureCompletionScreen({
type: 'text',
title: 'Inspection Report Submitted',
message: () => {
const decision = decisionSection.radioButton('acceptanceDecision')?.value();
if (decision === 'accept') {
return 'Material has been accepted and inspection recorded. Proceed with storage per requirements.';
}
if (decision === 'reject') {
return 'Material has been rejected. Ensure supplier is notified and arrange for return or replacement.';
}
if (decision === 'conditional') {
return 'Material has been conditionally accepted. Document any restrictions and notify relevant parties.';
}
return 'Inspection report has been submitted. Follow up on any pending actions.';
}
});
}