Form System
The platform uses a component-based form system built on React Hook Form and Zod validation. All MOC and PCR forms follow a standardized pattern for rendering, validating, and submitting form data.
Architecture
Form Page (server component)
└─ Form Wrapper (client component)
├─ React Hook Form Provider
├─ Zod Schema Validation
└─ Form Section Components
├─ Text Fields
├─ Boolean Tables
├─ Date Pickers
├─ Rich Text Editors
└─ File Upload Fields
MOC Form Components
All MOC form components live under src/components/forms/:
| Step | Directory | Key Files |
|---|---|---|
| Originator | src/components/forms/orignator/ | Originator form fields, title, description, department |
| Implementer | src/components/forms/implementer/ | Target timeline, resource requirements, implementation plan |
| HSEQ | src/components/forms/hseq/ | Risk assessment, environmental impact, safety review |
| Approval | src/components/forms/approval/ | Approval decision, comments, conditions |
| Implementation | src/components/forms/implementation/ | Implementation status, completion notes |
| Verification | src/components/forms/verification/ | Verification checklist, sign-off |
BooleanTablePcr Component
File: src/components/forms/ (shared form component)
One of the most frequently used form components. It renders a table where each row has:
- A label/question
- A Yes/No toggle
- An optional remarks text field
This component is used extensively in HSEQ assessment forms, implementation checklists, and verification forms.
Structure
interface BooleanTableRow {
label: string;
value: boolean | null;
remarks: string;
}
interface BooleanTablePcrProps {
rows: BooleanTableRow[];
onChange: (rows: BooleanTableRow[]) => void;
disabled?: boolean;
}
Adding a New Row
To add a new question to a boolean table form:
- Locate the form component that uses
BooleanTablePcr - Find the
defaultRowsor initial data array - Add a new entry:
const defaultRows = [
// ...existing rows
{ label: "Your new question here", value: null, remarks: "" },
];
Form Validation
Validation is handled at two levels:
Client-Side (Zod)
Each form step has a Zod schema that validates required fields before submission:
import { z } from "zod";
const originatorSchema = z.object({
title: z.string().min(1, "Title is required"),
description: z.string().min(1, "Description is required"),
department: z.string().min(1, "Department is required"),
// ...additional fields
});
Server-Side
API routes validate incoming data before database operations. Invalid submissions return a 400 status with error details.
Rich Text Editor
File: src/features/richTextEditor/
The platform uses TipTap as its rich text editor for long-form text fields (descriptions, comments, implementation notes). Features include:
- Bold, italic, underline formatting
- Bullet and numbered lists
- Headings
- Links
- Code blocks
File Uploads
File attachments are handled via two storage backends:
| Backend | Usage | Configuration |
|---|---|---|
| Cloudinary | Images, small documents | NEXT_PUBLIC_CLOUDINARY_* env vars |
| AWS S3 | Large files, archives | Custom Lambda endpoint |
Upload flow:
- User selects file in the form
- File is uploaded to storage backend
- URL is stored in the form data
- URL is saved to MongoDB with the form document
Display Components
Read-only display versions of form data are in src/components/display components/:
| Component | Purpose |
|---|---|
| Display wrappers | Render submitted form data in read-only format |
| Print layouts | Formatted views for PDF/print output |
| Signature displays | Show collected signatures with images |
These components mirror the form structure but render data without editing capabilities. They are used in:
- Preview mode when viewing a submitted form
- Print views
- The MOC detail page in read-only tabs
Related Files
| Purpose | Path |
|---|---|
| Form components | src/components/forms/ |
| Display components | src/components/display components/ |
| Rich text editor | src/features/richTextEditor/ |
| Signature feature | src/features/signitureComponent/ |
| Form context | src/context/form.tsx |