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