Skip to main content

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/:

StepDirectoryKey Files
Originatorsrc/components/forms/orignator/Originator form fields, title, description, department
Implementersrc/components/forms/implementer/Target timeline, resource requirements, implementation plan
HSEQsrc/components/forms/hseq/Risk assessment, environmental impact, safety review
Approvalsrc/components/forms/approval/Approval decision, comments, conditions
Implementationsrc/components/forms/implementation/Implementation status, completion notes
Verificationsrc/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:

  1. Locate the form component that uses BooleanTablePcr
  2. Find the defaultRows or initial data array
  3. 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:

BackendUsageConfiguration
CloudinaryImages, small documentsNEXT_PUBLIC_CLOUDINARY_* env vars
AWS S3Large files, archivesCustom Lambda endpoint

Upload flow:

  1. User selects file in the form
  2. File is uploaded to storage backend
  3. URL is stored in the form data
  4. URL is saved to MongoDB with the form document

Display Components​

Read-only display versions of form data are in src/components/display components/:

ComponentPurpose
Display wrappersRender submitted form data in read-only format
Print layoutsFormatted views for PDF/print output
Signature displaysShow 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
PurposePath
Form componentssrc/components/forms/
Display componentssrc/components/display components/
Rich text editorsrc/features/richTextEditor/
Signature featuresrc/features/signitureComponent/
Form contextsrc/context/form.tsx