Components

Table of Contents

  1. Component Architecture Overview

  2. Component Directory Structure

  3. Core Components

  4. Component State Management

  5. Component Communication Patterns

  6. Styling Approach

  7. Performance Considerations

  8. Accessibility Features

  9. Development Guidelines

Component Architecture Overview

Striae's frontend is built using React components organized in a modular structure. This guide covers the major components, their purposes, and how they interact within the application.

Component Directory Structure

app/components/
├── actions/          # Data handling components
├── auth/             # Authentication components
├── button/           # Reusable button components
├── canvas/           # Main canvas for image annotation
├── colors/           # Color picker components
├── footer/           # Footer and modal components
├── icon/             # Icon system
├── mobile/           # Mobile-specific components
├── notice/           # Notification and modal components
├── sidebar/          # Sidebar navigation and controls
├── theme-provider/   # Theme management
├── toast/            # Toast notification system
├── toolbar/          # Main toolbar components
├── turnstile/        # CAPTCHA components
└── user/             # User management components

Core Components

1. Authentication Components

MFAEnrollment (app/components/auth/mfa-enrollment.tsx)

Purpose: Multi-factor authentication setup

Features:

  • Phone number verification

  • SMS code validation

  • Firebase MFA integration

  • reCAPTCHA verification

Type Definition: Uses Firebase authentication types for MFA setup

Key Props:

  • user: User - Firebase user object

  • onSuccess: () => void - Success callback

  • onError: (message: string) => void - Error callback

  • mandatory: boolean - Whether MFA is required

MFAVerification (app/components/auth/mfa-verification.tsx)

Purpose: MFA challenge during login

Features:

  • Multi-factor resolver handling

  • SMS code input and validation

  • Error handling and retry logic

Type Definition: Uses Firebase MultiFactorResolver interface for MFA challenges

2. Canvas System

Canvas (app/components/canvas/canvas.tsx)

Purpose: Main image display and annotation interface

Features:

  • High-resolution image rendering

  • Annotation overlay display

  • Loading states and error handling

  • Flash effects for user feedback (subclass characteristics)

Type Definition: Uses AnnotationData interface from app/types/annotations.ts

Key Props:

interface CanvasProps {
  imageUrl?: string;
  filename?: string;
  company?: string;
  firstName?: string;
  error?: string;
  activeAnnotations?: Set<string>;
  annotationData?: AnnotationData | null;
}

State Management:

  • Image loading states

  • Error handling for network issues

  • Flash effects for user feedback (subclass characteristics)

Key Methods:

  • Image load error detection

  • Annotation overlay rendering

  • User interaction handling

Box Annotations (app/components/canvas/box-annotations.tsx)

Purpose: Interactive box annotation drawing and management system

Features:

  • Mouse-based box drawing with real-time visual feedback

  • Percentage-based coordinate system for device independence

  • Double-click and right-click removal functionality

  • Hover effects with deletion indicators

  • Transparent styling with colored borders

  • Automatic saving integration with existing annotation system

Type Definition: Uses BoxAnnotation interface from app/types/annotations.ts

Key Props:

interface BoxAnnotationsProps {
  imageRef: React.RefObject<HTMLImageElement>;
  activeAnnotations?: Set<string>;
  annotationData?: AnnotationData | null;
  onSave: (data: AnnotationData) => void;
  selectedColor: string;
  isBoxAnnotationMode: boolean;
}

State Management:

  • Drawing state tracking (isDrawing, startPosition, currentBox)

  • Box annotation array management

  • Real-time coordinate calculation and display

  • Integration with toolbar visibility controls

Key Methods:

  • handleMouseDown: Initiates box drawing on mouse press

  • handleMouseMove: Updates current box dimensions during drawing

  • handleMouseUp: Finalizes box creation and triggers save

  • handleDoubleClick / handleRightClick: Box removal functionality

  • calculatePercentageCoordinates: Converts pixel coordinates to percentages

ToolbarColorSelector (app/components/toolbar/toolbar-color-selector.tsx)

Purpose: Dynamic color selection interface for box annotations

Features:

  • Preset color grid with common annotation colors

  • Custom color wheel for precise color selection

  • Confirm/cancel workflow with visual preview

  • Automatic appearance when box annotation tool is active

  • Reset functionality to restore previous color selection

Type Definition: Uses component-specific ToolbarColorSelectorProps interface

Key Props:

interface ToolbarColorSelectorProps {
  isVisible: boolean;
  selectedColor: string;
  onColorSelect: (color: string) => void;
  onConfirm: () => void;
  onCancel: () => void;
}

State Management:

  • Temporary color selection state

  • Preset color array management

  • Visual preview of selected color

  • Confirmation state tracking

Key Methods:

  • handleColorSelect: Updates temporary color selection

  • handleConfirm: Applies selected color and closes selector

  • handleCancel: Reverts to previous color and closes selector

  • resetToDefault: Resets color selection to default value

3. Sidebar System

Purpose: Main sidebar wrapper with footer integration

Features:

  • Sidebar component orchestration

  • Footer modal management

  • Keyboard event handling (Escape key)

  • Patreon widget integration

Type Definition: Uses FileData interface and Firebase User type

Key Props:

interface SidebarContainerProps {
  user: User;
  onImageSelect: (file: FileData) => void;
  imageId?: string;
  onCaseChange: (caseNumber: string) => void;
  currentCase: string;
  files: FileData[];
  // ... additional props for state management
}

Purpose: Core sidebar functionality

Features:

  • Case management interface

  • File upload and selection

  • Image management controls

Type Definition: Uses Firebase User type and FileData interface

Case Sidebar (app/components/sidebar/case-sidebar.tsx)

Purpose: Case-specific sidebar functionality

Features:

  • Case creation and management

  • File upload interface

  • Image selection and deletion

  • Case validation and error handling

Type Definition: Uses component-specific CaseSidebarProps interface with FileData and Firebase User types

Key Props:

interface CaseSidebarProps {
  user: User;
  onImageSelect: (file: FileData) => void;
  onCaseChange: (caseNumber: string) => void;
  imageLoaded: boolean;
  setImageLoaded: (loaded: boolean) => void;
  onNotesClick: () => void;
  files: FileData[];
  setFiles: React.Dispatch<React.SetStateAction<FileData[]>>;
  caseNumber: string;
  setCaseNumber: (caseNumber: string) => void;
  currentCase: string | null;
  setCurrentCase: (caseNumber: string) => void;
}

Notes Sidebar (app/components/sidebar/notes-sidebar.tsx)

Purpose: Annotation and notes management interface

Features:

  • Comprehensive annotation forms

  • Color selection integration

  • Classification options (Bullet, Cartridge Case, Other)

  • Support level selection (ID, Exclusion, Inconclusive)

  • Index type management (number/color)

  • Subclass characteristics

  • Additional notes handling

Type Definition: Uses component-specific interface with custom types for classification options

Key Props:

interface NotesSidebarProps {
  currentCase: string;
  onReturn: () => void;
  user: User;
  imageId: string;
  onAnnotationRefresh?: () => void;
}

Data Types:

type ClassType = 'Bullet' | 'Cartridge Case' | 'Other';
type IndexType = 'number' | 'color';
type SupportLevel = 'ID' | 'Exclusion' | 'Inconclusive';

Cases Modal (app/components/sidebar/cases-modal.tsx)

Purpose: Case selection and management modal

Features:

  • Paginated case listing

  • Case selection interface

  • Loading states and error handling

  • Keyboard navigation (Escape key)

Type Definition: Uses component-specific CasesModalProps interface

Props:

interface CasesModalProps {
  isOpen: boolean;
  onClose: () => void;
  onSelectCase: (caseNum: string) => void;
  currentCase: string;
  user: User;
}

Notes Modal (app/components/sidebar/notes-modal.tsx)

Purpose: Additional notes editing modal

Features:

  • Text area for detailed notes

  • Save/cancel functionality

  • Keyboard event handling

  • Temporary state management

Type Definition: Uses component-specific NotesModalProps interface

Props:

interface NotesModalProps {
  isOpen: boolean;
  onClose: () => void;
  notes: string;
  onSave: (notes: string) => void;
}

Case Export (app/components/sidebar/case-export/case-export.tsx)

Purpose: Comprehensive case data export modal interface with ZIP file support

Features:

  • Case number input with auto-population from current case

  • Format Selection: JSON, CSV/Excel, and ZIP export formats with visual toggle

  • ZIP Export with Images: Single case export with complete data files and associated images

  • Image Inclusion Options: Checkbox to include/exclude images in ZIP exports

  • Single Case Export: Export individual case with complete annotation data

  • Bulk Export: Export all cases with real-time progress tracking

  • Excel Multi-Worksheet: CSV format creates Excel files with summary and individual case worksheets

  • Comprehensive Data: All annotation fields including case identifiers, colors, classifications, and split box annotations

  • Loading states and error handling with detailed error messages

  • Keyboard navigation (Escape key) and accessible controls

  • Automatic case number pre-filling when case is loaded

  • Progress visualization for bulk export operations with case-by-case updates

  • Synchronized UI States: Export button and checkboxes disabled appropriately during operations

Type Definition: Uses component-specific CaseExportProps interface

Props:

interface CaseExportProps {
  isOpen: boolean;
  onClose: () => void;
  onExport: (caseNumber: string, format: ExportFormat, includeImages?: boolean) => void;
  onExportAll: (onProgress: (current: number, total: number, caseName: string) => void, format: ExportFormat) => void;
  currentCaseNumber?: string;
}

export type ExportFormat = 'json' | 'csv';

Enhanced Export Features:

  • ZIP Package Creation: Complete case export with data files and images in structured ZIP archive

  • JSZip Integration: Browser-based ZIP file generation with progress tracking

  • Image Download System: Automatic image fetching and packaging for ZIP exports

  • Data Parity: CSV/Excel exports contain identical data to JSON exports (22+ columns total)

  • Split Box Annotations: Box annotations split into separate rows for improved data analysis

  • Format Indicators: Clear UI showing format types with tooltips explaining functionality

  • Progress Callbacks: Real-time progress updates during bulk export operations

  • Error Recovery: Graceful handling of failed exports with detailed error reporting

  • Performance Optimization: Optional annotation inclusion for faster exports when only metadata is needed

  • Disabled State Management: UI components properly synchronized during export operations

Case Import (app/components/sidebar/case-import/)

Purpose: Modular ZIP package import system for reviewing complete case data in read-only mode

Architecture: Component composition pattern with custom hooks for business logic separation

Directory Structure:

case-import/
├── case-import.tsx          # Main orchestrator component
├── components/              # UI sub-components
│   ├── FileSelector.tsx     # File selection interface
│   ├── CasePreviewSection.tsx   # Case metadata preview
│   ├── ConfirmationPreviewSection.tsx  # Import confirmation details
│   ├── ProgressSection.tsx      # Real-time progress display
│   ├── ExistingCaseSection.tsx  # Existing case management
│   └── ConfirmationDialog.tsx   # Final confirmation modal
├── hooks/                   # Custom business logic hooks
│   ├── useImportState.ts    # State management hook
│   ├── useFilePreview.ts    # File processing hook
│   └── useImportExecution.ts # Import execution hook
├── utils/                   # Pure utility functions
│   └── file-validation.ts   # File type validation
└── index.ts                # Barrel export

Component Architecture Features:

  • Single Responsibility: Each component handles one specific aspect of the import process

  • Custom Hooks Pattern: Business logic encapsulated in reusable hooks

  • Component Composition: Main component orchestrates sub-components without complex logic

  • Barrel Exports: Clean import structure through centralized index.ts

  • Type Safety: Comprehensive TypeScript interfaces for all component interactions

Main Component Props:

interface CaseImportProps {
  isOpen: boolean;
  onClose: () => void;
  onImportComplete: (caseNumber: string, success: boolean) => void;
}

Custom Hooks:

  • useImportState: Manages import progress, file selection, and UI state

  • useFilePreview: Handles ZIP parsing, validation, and preview generation

  • useImportExecution: Orchestrates the complete import process with progress callbacks

Import Process Features:

  • ZIP File Selection: Modular file browser interface with validation

  • Read-Only Case Review: Imported cases automatically protected from modification

  • Progress Tracking: Real-time import progress with stage-by-stage updates

  • Existing Case Detection: Automatic detection and management of existing read-only cases

  • Image Integration: Automatic import and association of all case image data and annotations

  • Metadata Preservation: Complete preservation of original case metadata and timestamps

  • Clear Management: Option to remove imported cases from review bin

  • Error Handling: Comprehensive error reporting with detailed failure messages

  • Security Validation: Prevents import of cases where user was original analyst

  • ZIP Validation: Comprehensive validation of ZIP package structure and contents

  • Case Data Parsing: Support for JSON format with forensic protection warnings

  • Duplicate Prevention: Prevents import if user was original case analyst

  • Progress Callbacks: Multi-stage progress reporting (ZIP parsing, image upload, annotation import)

  • Cleanup Operations: Automatic cleanup of existing case data when overwriting

  • File Mapping: Internal mapping system for connecting imported images to annotation data

  • Integrity Validation: Optional case data integrity verification during import

  • User Profile Integration: Automatic addition of imported cases to user's read-only case list

4. Action Components

Case Management (app/components/actions/case-manage.ts)

Purpose: Complete case lifecycle management

Key Functions:

export const validateCaseNumber = (caseNumber: string): boolean
export const checkExistingCase = async (
  caseNumber: string, 
  user: User
): Promise<boolean>
export const createNewCase = async (
  caseNumber: string, 
  user: User
): Promise<{ success: boolean; message: string }>
export const renameCase = async (
  oldCaseNumber: string,
  newCaseNumber: string,
  user: User
): Promise<{ success: boolean; message: string }>
export const deleteCase = async (
  caseNumber: string,
  user: User
): Promise<{ success: boolean; message: string }>
export const listCases = async (user: User): Promise<string[]>

Features:

  • Case number validation

  • Duplicate case detection

  • Case creation and deletion

  • Case renaming functionality

  • User case list management

Case Export (app/components/actions/case-export/)

Purpose: Modular case data export system with multi-format support including ZIP packages

Architecture: Organized into specialized modules for maintainability and testability

Directory Structure:

case-export/
├── core-export.ts          # Main export orchestration functions
├── data-processing.ts      # Data transformation and CSV generation
├── download-handlers.ts    # Browser download utilities
├── metadata-helpers.ts     # Forensic protection and metadata functions
├── types-constants.ts      # Type definitions and CSV headers
├── validation-utils.ts     # Export validation functions
└── index.ts               # Barrel export

Modular Components:

  • Core Export: Main export functions (exportCaseData, exportAllCases)

  • Data Processing: CSV generation, tabular formatting, metadata rows

  • Download Handlers: Browser-compatible download functions with proper MIME types

  • Metadata Helpers: Forensic warnings, password protection, Excel worksheet protection

  • Types & Constants: Shared type definitions and CSV header configurations

  • Validation Utilities: Case number validation and export prerequisites

Key Functions:

// Core export functions
export const exportCaseData = async (
  user: User,
  caseNumber: string,
  options: ExportOptions
): Promise<CaseExportData>

export const exportAllCases = async (
  user: User,
  options: ExportOptions,
  onProgress?: (current: number, total: number, caseName: string) => void
): Promise<AllCasesExportData>

// Download handlers  
export const downloadCaseAsJSON = (exportData: CaseExportData): void
export const downloadCaseAsCSV = (exportData: CaseExportData): void
export const downloadCaseAsZip = async (exportData: CaseExportData, includeImages: boolean): Promise<void>
export const downloadAllCasesAsJSON = (exportData: AllCasesExportData): void
export const downloadAllCasesAsCSV = (exportData: AllCasesExportData): void

// Validation and metadata
export const validateCaseNumberForExport = (caseNumber: string): boolean
export const getUserExportMetadata = (user: User): ExportMetadata
export const addForensicDataWarning = (content: string): string

Export Type System:

export type ExportFormat = 'json' | 'csv';

export interface ExportOptions {
  includeAnnotations?: boolean;
  format?: 'json' | 'csv' | 'zip';
  includeMetadata?: boolean;
  includeImages?: boolean;
}

Enhanced Features:

  • ZIP Export Functionality: Complete case packaging with data files and images

  • JSZip Integration: Browser-based ZIP file creation with automatic image downloading

  • Comprehensive Single Case Export: Complete file and annotation data collection with metadata

  • Bulk Export with Progress: Export all user cases with real-time progress callbacks and error handling

  • Multi-Format Support: JSON for structured data, CSV for single cases, Excel (.xlsx) for bulk exports, ZIP for complete packages

  • Excel Multi-Worksheet: Bulk CSV exports create Excel files with summary worksheet and individual case worksheets

  • Complete Data Parity: CSV/Excel formats include all annotation fields matching JSON exports

  • Split Box Annotation Format: Box annotations split into separate rows for improved data analysis

  • Enhanced Box Annotations: Includes coordinates, colors, timestamps in structured format (label property removed)

  • Forensic Classification Support: Full case identifiers, color schemes, support levels, and classification data

  • Performance Options: Configurable annotation inclusion for faster exports when only metadata needed

  • Error Recovery: Graceful handling of failed case exports with detailed error reporting and continuation

  • File Download Utilities: Browser-compatible download functions with proper MIME types and cleanup

  • Export Validation: Comprehensive case number and data validation before export operations

  • Image Management: Automatic image URL fetching and packaging for ZIP exports

CSV/Excel Export Columns (22+ total with split format):

  1. File ID, Original Filename, Upload Date, Has Annotations

  2. Case Identifiers: Left Case, Right Case, Left Item, Right Item

  3. Visual Elements: Case Font Color, Index Type, Index Number, Index Color

  4. Classifications: Class Type, Custom Class, Class Note, Support Level

  5. Options: Has Subclass, Include Confirmation

  6. Annotations: Box Annotations Count, Individual Box Annotation Details (split rows with coordinates, colors, timestamps)

  7. Metadata: Additional Notes, Last Updated

ZIP Export Structure:

  • Data Files: JSON and CSV formats included in ZIP package

  • Image Directory: All case images organized in images/ folder within ZIP

  • Structured Layout: Professional organization with clear file naming conventions

  • Progress Tracking: Real-time download progress for images and ZIP creation

XLSX Library Integration:

  • Multi-Worksheet Excel: Summary sheet plus individual case sheets for bulk exports

  • Structured Data Layout: Professional formatting with headers and metadata sections

  • Sheet Naming: Excel-compatible sheet names with case number identifiers

  • Error Sheets: Dedicated worksheets for failed case exports with error details

  • Split Annotation Format: Box annotations displayed in separate rows for better analysis

Case Import (app/components/actions/case-import/)

Purpose: Modular ZIP package import system for read-only case review and collaboration

Architecture: Organized into specialized modules for complex import operations

Directory Structure:

case-import/
├── orchestrator.ts         # Main import orchestration function
├── validation.ts           # Import validation and security checks
├── zip-processing.ts       # ZIP file parsing and preview generation
├── storage-operations.ts   # R2 storage and case management operations
├── image-operations.ts     # Image upload and processing
├── annotation-import.ts    # Annotation data import and mapping
├── confirmation-import.ts  # Confirmation data import processing
└── index.ts               # Barrel export

Modular Components:

  • Orchestrator: Main import workflow coordination (importCaseForReview)

  • Validation: Security checks, exporter UID validation, hash verification

  • ZIP Processing: Archive parsing, case data extraction, preview generation

  • Storage Operations: R2 case storage, read-only case management, user profile updates

  • Image Operations: Blob processing and upload to image worker

  • Annotation Import: Complete annotation data mapping and storage

  • Confirmation Import: Confirmation data processing with integrity validation

Key Functions:

// Main orchestrator
export const importCaseForReview = async (
  user: User,
  zipFile: File,
  options: ImportOptions = {},
  onProgress?: (stage: string, progress: number, details?: string) => void
): Promise<ImportResult>

// Validation functions
export const validateExporterUid = async (exporterUid: string, currentUser: User): Promise<{ exists: boolean; isSelf: boolean }>
export const validateConfirmationHash = (jsonContent: string, expectedHash: string): boolean
export const validateCaseIntegrity = (caseData: CaseExportData, imageFiles: { [filename: string]: Blob }): { isValid: boolean; issues: string[] }

// ZIP processing
export const previewCaseImport = async (zipFile: File): Promise<CaseImportPreview>
export const parseImportZip = async (zipFile: File): Promise<{ caseData: CaseExportData; imageFiles: { [filename: string]: Blob }; metadata?: any }>

// Storage operations  
export const checkReadOnlyCaseExists = async (user: User, caseNumber: string): Promise<boolean>
export const addReadOnlyCaseToUser = async (user: User, metadata: ReadOnlyCaseMetadata): Promise<boolean>
export const storeCaseDataInR2 = async (user: User, caseNumber: string, caseData: CaseExportData): Promise<boolean>
export const listReadOnlyCases = async (user: User): Promise<ReadOnlyCaseMetadata[]>
export const deleteReadOnlyCase = async (user: User, caseNumber: string): Promise<boolean>

// Import operations
export const uploadImageBlob = async (blob: Blob, filename: string, user: User): Promise<string>
export const importAnnotations = async (user: User, caseNumber: string, fileAnnotations: any): Promise<boolean>
export const importConfirmationData = async (user: User, confirmationData: ConfirmationImportData): Promise<ConfirmationImportResult>

Import Type System:

export interface ImportOptions {
  overwriteExisting?: boolean;
  validateIntegrity?: boolean;
  preserveTimestamps?: boolean;
}

export interface ImportResult {
  success: boolean;
  caseNumber: string;
  isReadOnly: boolean;
  filesImported: number;
  annotationsImported: number;
  errors?: string[];
  warnings?: string[];
}

export interface ReadOnlyCaseMetadata {
  caseNumber: string;
  importedAt: string;
  originalExportDate: string;
  originalExportedBy: string;
  sourceHash?: string;
  isReadOnly: true;
}

export interface CaseImportPreview {
  caseNumber: string;
  fileCount: number;
  annotationCount: number;
  exportDate: string;
  exportedBy: string;
  hasImages: boolean;
  canImport: boolean;
  warnings: string[];
}

Core Import Features:

  • Complete ZIP Package Import: Full case data and image import from exported ZIP packages

  • Read-Only Protection: Imported cases are automatically set to read-only mode for secure review

  • Duplicate Prevention: Prevents import if user was the original case analyst

  • Progress Tracking: Multi-stage progress reporting with detailed status updates

  • Image Integration: Automatic upload and association of all case images

  • Metadata Preservation: Complete preservation of original export metadata and timestamps

  • Data Integrity: Comprehensive validation of ZIP contents and case data structure

  • Forensic Warning Handling: Proper removal of forensic warnings for hash validation

  • Confirmation Data Support: Specialized import handling for confirmation data files

  • Error Recovery: Graceful handling of import failures with detailed error reporting

  • Security Validation: Prevents modification of imported cases and restricts access appropriately

Image Management (app/components/actions/image-manage.ts)

Purpose: Image upload and retrieval operations

Key Functions:

export const uploadImage = async (
  file: File, 
  caseNumber: string, 
  apiKey: string
): Promise<UploadResult>

export const getImageUrl = async (
  imageId: string, 
  apiKey: string
): Promise<string>

export const deleteImage = async (
  imageId: string, 
  apiKey: string
): Promise<void>

export const fetchFiles = async (
  caseNumber: string,
  apiKey: string
): Promise<FileData[]>

export const uploadFile = async (
  file: File,
  caseNumber: string,
  apiKey: string
): Promise<{ success: boolean; message: string; fileData?: FileData }>

export const deleteFile = async (
  fileId: string,
  caseNumber: string,
  apiKey: string
): Promise<{ success: boolean; message: string }>

PDF Generation (app/components/actions/generate-pdf.ts)

Purpose: PDF report generation

Features:

  • Dynamic PDF creation

  • Annotation integration

  • Custom formatting

  • Error handling and progress feedback

Key Function:

export const generatePDF = async (
  imageUrl: string,
  caseNumber: string,
  annotationData: AnnotationData | null,
  activeAnnotations: Set<string>,
  firstName?: string
): Promise<{ success: boolean; message: string }>

Notes Management (app/components/actions/notes-manage.ts)

Purpose: Annotation and notes data management

Features:

  • CRUD operations for annotation data

  • Data validation and sanitization

  • Error handling for API operations

Key Functions:

export const getNotes = async (
  caseNumber: string,
  imageId: string,
  apiKey: string
): Promise<AnnotationData | null>

export const saveNotes = async (
  caseNumber: string,
  imageId: string,
  notesData: AnnotationData,
  apiKey: string
): Promise<{ success: boolean; message: string }>

Sign Out (app/components/actions/signout.tsx)

Purpose: User authentication logout

Features:

  • Firebase sign out

  • Local storage cleanup

  • Redirect handling

  • Error handling

Type Definition: Uses component-specific SignOutProps interface

Props:

interface SignOutProps {
  redirectTo?: string;
}

5. UI Components

Button System (app/components/button/)

Purpose: Reusable button components

Components:

  • Button - Standard button with variants

Type Definition: Uses component-specific ButtonProps interface

Props:

interface ButtonProps {
  children: React.ReactNode;
  onClick?: () => void;
  disabled?: boolean;
  type?: 'button' | 'submit' | 'reset';
  variant?: 'primary' | 'secondary' | 'danger';
  size?: 'small' | 'medium' | 'large';
  className?: string;
}

Color System (app/components/colors/colors.tsx)

Purpose: Color selection interface

Features:

  • Predefined color palette

  • Custom color wheel

  • Color validation

  • Real-time preview

Type Definition: Uses component-specific ColorSelectorProps interface

Props:

interface ColorSelectorProps {
  selectedColor: string;
  onColorSelect: (color: string) => void;
}

Purpose: Application footer with navigation and social links

Features:

  • External link navigation

  • Patreon integration

  • Dynamic year display

  • Terms and privacy links

Type Definition: Uses standard React component types without custom interfaces

Icon System (app/components/icon/icon.tsx)

Purpose: Centralized icon management

Features:

  • SVG icon system

  • Consistent sizing and styling

  • Type-safe icon names

  • Available icons: eye, eye-off, class, ID, index, notes, number, print, other unused/misc icons

Type Definition: Uses custom icon type definitions for type-safe icon selection

Usage:

<Icon icon="eye" />
<Icon icon="eye-off" />

Mobile Warning (app/components/mobile/mobile-warning.tsx)

Purpose: Mobile device usage warning

Features:

  • Responsive design detection

  • Route-specific display

  • User experience guidance

  • Desktop-only enforcement

Type Definition: Uses standard React component types without custom interfaces

Notice System (app/components/notice/notice.tsx)

Purpose: Modal notification display

Features:

  • Dynamic content rendering

  • Keyboard event handling (Escape key)

  • Customizable button text

  • Overlay backdrop

Type Definition: Uses component-specific NoticeProps interface

Props:

interface NoticeProps {
  isOpen: boolean;
  onClose: () => void;
  notice: {
    title: string;
    content: React.ReactNode;
    buttonText?: string;
  };
}

Toast System (app/components/toast/toast.tsx)

Purpose: User feedback and notifications

Features:

  • Success and error message display

  • Auto-dismiss functionality

  • Customizable styling

Type Definition: Uses component-specific ToastProps interface

Props:

interface ToastProps {
  message: string;
  type: 'success' | 'error' | 'warning';
  isVisible: boolean;
  onClose: () => void;
}

Toolbar (app/components/toolbar/toolbar.tsx)

Purpose: Main application toolbar

Features:

  • Tool selection management (number, class, index, id, notes, box, print, visibility)

  • PDF generation controls

  • Visibility toggle

  • Active tool state tracking

  • Box annotation mode with color selector integration

Type Definition: Uses component-specific ToolbarProps interface and ToolId type

Props:

interface ToolbarProps {
  onToolSelect?: (toolId: ToolId, active: boolean) => void;
  onGeneratePDF?: () => void;
  canGeneratePDF?: boolean;
  onVisibilityChange?: (visible: boolean) => void;
  isGeneratingPDF?: boolean;
}

type ToolId = 'number' | 'class' | 'index' | 'id' | 'notes' | 'print' | 'visibility' | 'box';

Turnstile CAPTCHA (app/components/turnstile/turnstile.tsx)

Purpose: Cloudflare Turnstile CAPTCHA integration

Features:

  • Security verification

  • Theme customization

  • Widget lifecycle management

  • Callback handling

Type Definition: Uses component-specific TurnstileProps interface extending HTML div attributes

Props:

interface TurnstileProps extends React.HTMLAttributes<HTMLDivElement> {
  className?: string;
  onWidgetId?: (id: string) => void;
  success?: boolean;
  theme?: 'light' | 'dark' | 'auto';
}

Theme Provider (app/components/theme-provider/theme-provider.tsx)

Purpose: Application theme management

Features:

  • Theme context provision

  • Theme persistence

  • System theme detection

  • Theme switching functionality

Type Definition: Uses custom Theme type definition from theme.ts

Theme Types (app/components/theme-provider/theme.ts):

type Theme = 'light' | 'dark' | 'system';

6. User Management Components

User Profile Management (app/components/user/manage-profile.tsx)

Purpose: Comprehensive user profile management

Features:

  • Profile information editing (display name)

  • Email address viewing (read-only)

  • Company information viewing (read-only)

  • Password change functionality

  • User reauthentication

  • Firebase integration

  • Error handling with detailed messages

Type Definition: Uses component-specific ManageProfileProps interface

Props:

interface ManageProfileProps {
  isOpen: boolean;
  onClose: () => void;
}

Key Features:

  • Display name modification

  • Company information management (read-only)

  • Email address display (read-only)

  • User permission status loading

  • Account deletion functionality

  • Firebase error handling integration

Delete Account (app/components/user/delete-account.tsx)

Purpose: Secure account deletion with permission-based restrictions

Features:

  • User account deletion with confirmation

  • Demo account protection (deletion disabled for permitted=false)

  • Dual confirmation requirements (UID + email)

  • Conditional messaging based on account type

  • Email notifications on successful deletion

  • Firebase authentication integration

  • Automatic logout after deletion

Type Definition: Uses component-specific DeleteAccountProps interface with user object type

Props:

interface DeleteAccountProps {
  isOpen: boolean;
  onClose: () => void;
  user: {
    uid: string;
    displayName: string | null;
    email: string | null;
  };
  company: string;
  permitted: boolean;
}

Permission-Based Behavior:

  • Regular Accounts (permitted=true): Full deletion functionality with standard warnings

  • Demo Accounts (permitted=false): Deletion disabled with informational messaging

Security Features:

  • Requires exact UID confirmation

  • Requires exact email address confirmation

  • Demo account protection

  • API key authentication for deletion requests

Inactivity Warning (app/components/user/inactivity-warning.tsx)

Purpose: Session timeout management

Features:

  • Inactivity detection

  • Warning countdown display

  • Session extension handling

Type Definition: Uses custom hook types from useInactivityTimeout hook

Component State Management

Local State Patterns

Most components use React's built-in state management:

// Typical state structure
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState<string | undefined>();
const [data, setData] = useState<DataType | null>(null);

Context Usage

AuthContext (app/contexts/auth.context.ts)

Purpose: Global authentication state

Provided Values:

  • Current user information

  • Authentication status

  • Login/logout functions

Custom Hooks

useInactivityTimeout (app/hooks/useInactivityTimeout.ts)

Purpose: Session inactivity management

Features:

  • Configurable timeout periods

  • Activity detection

  • Automatic logout on timeout

Business Logic Hooks Pattern

The application implements a custom hooks pattern for encapsulating complex business logic, as demonstrated in the case-import system:

useImportState (app/components/sidebar/case-import/hooks/useImportState.ts)

Purpose: Centralized state management for import workflow

Pattern: Encapsulates all stateful logic for the import process

Returns:

interface ImportState {
  // File management
  selectedFile: File | null;
  setSelectedFile: (file: File | null) => void;
  
  // Progress tracking
  isImporting: boolean;
  importProgress: number;
  progressStage: string;
  
  // Case management
  existingCase: string | null;
  previewData: CaseData | null;
  
  // UI state
  showConfirmation: boolean;
  setShowConfirmation: (show: boolean) => void;
}

Benefits:

  • Consolidates related state in one hook

  • Provides clean API for components

  • Enables easy testing of state logic

useFilePreview (app/components/sidebar/case-import/hooks/useFilePreview.ts)

Purpose: File processing and validation logic

Pattern: Handles asynchronous file operations with error handling

Functionality:

interface FilePreviewHook {
  processFile: (file: File) => Promise<ProcessResult>;
  validateZipStructure: (zipData: JSZip) => ValidationResult;
  extractCaseData: (zipData: JSZip) => Promise<CaseData>;
  previewImages: (zipData: JSZip) => Promise<ImagePreview[]>;
}

Benefits:

  • Isolates complex file processing logic

  • Provides reusable validation functions

  • Handles error states consistently

useImportExecution (app/components/sidebar/case-import/hooks/useImportExecution.ts)

Purpose: Orchestrates the complete import process

Pattern: Manages side effects and external API calls

Process Management:

interface ImportExecutionHook {
  executeImport: (importData: ImportData) => Promise<ImportResult>;
  uploadImages: (images: ImageData[]) => Promise<UploadResult[]>;
  saveCaseData: (caseData: CaseData) => Promise<SaveResult>;
  updateUserProfile: (caseNumber: string) => Promise<UpdateResult>;
  reportProgress: (stage: string, progress: number) => void;
}

Benefits:

  • Separates API calls from UI components

  • Provides consistent progress reporting

  • Enables comprehensive error handling

Custom Hooks Best Practices

Single Responsibility: Each hook handles one aspect of business logic

// ✅ Good: Focused responsibility
const useFileValidation = (file: File) => {
  // Only handles file validation logic
};

// ❌ Avoid: Mixed concerns
const useFileAndUserManagement = (file: File, user: User) => {
  // Handles both file operations AND user management
};

Return Object Pattern: Return objects for multiple values

// ✅ Good: Named returns
const useImportState = () => {
  return {
    isLoading,
    error,
    data,
    refetch
  };
};

// ❌ Avoid: Array returns for complex state
const useImportState = () => [isLoading, error, data, refetch];

Error Handling: Consistent error handling patterns

const useAsyncOperation = () => {
  const [error, setError] = useState<string | null>(null);
  const [isLoading, setIsLoading] = useState(false);
  
  const execute = async (params: OperationParams) => {
    setIsLoading(true);
    setError(null);
    
    try {
      const result = await performOperation(params);
      return result;
    } catch (err) {
      setError(err instanceof Error ? err.message : 'Unknown error');
      throw err;
    } finally {
      setIsLoading(false);
    }
  };
  
  return { execute, isLoading, error };
};

Component Communication Patterns

Props Down, Events Up

Components follow React's unidirectional data flow:

// Parent component
const [selectedImage, setSelectedImage] = useState<string>();

// Child component receives data and callbacks
<ImageSelector 
  images={images}
  onImageSelect={setSelectedImage}
/>

Event Handling

Components use callback props for communication:

interface ComponentProps {
  onSuccess: () => void;
  onError: (message: string) => void;
  onDataChange: (data: DataType) => void;
}

Many components follow consistent modal patterns:

// Common modal interface
interface ModalProps {
  isOpen: boolean;
  onClose: () => void;
}

// Keyboard event handling for modals
useEffect(() => {
  const handleEscape = (e: KeyboardEvent) => {
    if (e.key === 'Escape') {
      onClose();
    }
  };

  if (isOpen) {
    document.addEventListener('keydown', handleEscape);
    return () => document.removeEventListener('keydown', handleEscape);
  }
}, [isOpen, onClose]);

Styling Approach

CSS Modules

Components use CSS Modules for scoped styling:

// Component file
import styles from './component.module.css';

// Usage
<div className={styles.container}>
  <button className={styles.primaryButton}>
    Click me
  </button>
</div>

Style Conventions

  • BEM-like naming: styles.componentName__elementName--modifier

  • CSS Custom Properties: For theming and consistency

  • Intuitive Design: Clean, simple, user-friendly interfaces

  • Accessibility: ARIA labels and semantic HTML

Performance Considerations

Component Lifecycle

Components are designed for efficient mounting and unmounting:

useEffect(() => {
  // Setup
  const cleanup = setupComponent();
  
  // Cleanup
  return cleanup;
}, [dependencies]);

7. Audit Trail Components

User Audit Viewer (app/components/audit/user-audit-viewer.tsx)

Purpose: Comprehensive audit trail viewing and management for forensic accountability

Features:

  • Real-time audit entry display with automatic refresh

  • Advanced filtering by date range, action type, and result status

  • Export functionality (CSV, JSON, summary reports)

  • Pagination for large audit datasets

  • User-specific audit trail viewing

  • Compliance status monitoring

  • Security incident tracking

Type Definition: Uses ValidationAuditEntry from audit types

Props:

interface UserAuditViewerProps {
  isOpen: boolean;
  onClose: () => void;
  userId?: string;        // Optional: view specific user's audit trail
  caseNumber?: string;    // Optional: filter by case number
  autoRefresh?: boolean;  // Optional: enable auto-refresh
}

Key Features:

Data Management:

  • Fetches audit entries from Data Worker API

  • Implements client-side filtering and sorting

  • Handles large datasets with efficient pagination

  • Real-time updates with configurable refresh intervals

Filtering Capabilities:

  • Date range filtering (from/to dates)

  • Action type filtering (authentication, case operations, data access, etc.)

  • Result status filtering (success, failure, warning, blocked)

  • User-based filtering for multi-user environments

  • Case-specific filtering for workflow tracking

Export Functionality:

  • CSV Export: Formatted for spreadsheet analysis

  • JSON Export: Complete structured data with metadata

  • Summary Reports: Human-readable compliance summaries

  • Filtered Exports: Respects current filter settings

  • Batch Operations: Export multiple date ranges

UI Components:

  • Filter controls with date pickers and dropdowns

  • Export buttons with format selection

  • Pagination controls with configurable page sizes

  • Loading states and error handling

  • Responsive design for various screen sizes

CSS Classes (from user-audit.module.css):

.auditViewer          /* Main container */
.controls             /* Filter and export controls */
.filterSection        /* Date and type filters */
.exportSection        /* Export functionality */
.auditTable          /* Data display table */
.auditRow            /* Individual audit entries */
.statusIcon          /* Result status indicators */
.pagination          /* Navigation controls */
.loadingState        /* Loading indicators */
.errorState          /* Error display */
.noData              /* Empty state display */

Usage Example:

import { UserAuditViewer } from '~/components/audit/user-audit-viewer';

// Basic usage - current user's audit trail
<UserAuditViewer 
  isOpen={showAudit}
  onClose={() => setShowAudit(false)}
  autoRefresh={true}
/>

// Case-specific audit viewing
<UserAuditViewer 
  isOpen={showCaseAudit}
  onClose={() => setShowCaseAudit(false)}
  caseNumber="CASE-2024-001"
/>

// Administrator view - specific user audit
<UserAuditViewer 
  isOpen={showUserAudit}
  onClose={() => setShowUserAudit(false)}
  userId="user-123"
  autoRefresh={false}
/>

Audit Export Service (app/services/audit-export.service.ts)

Purpose: Handles audit data export functionality with multiple format support

Features:

  • Multiple export formats (CSV, JSON, Summary)

  • Configurable data filtering and formatting

  • Browser-compatible file downloads

  • Batch export operations

  • Custom date range exports

  • Compliance report generation

Export Methods:

interface AuditExportService {
  exportToCsv: (entries: ValidationAuditEntry[], filename?: string) => void;
  exportToJson: (entries: ValidationAuditEntry[], filename?: string) => void;
  generateSummaryReport: (entries: ValidationAuditEntry[]) => AuditSummary;
  exportSummary: (summary: AuditSummary, filename?: string) => void;
  formatDateRange: (startDate: Date, endDate: Date) => string;
}

CSV Export Format:

  • Headers: Timestamp, User, Action, Result, Details, Case Number

  • ISO 8601 timestamp formatting

  • Escaped special characters for spreadsheet compatibility

  • UTF-8 encoding with BOM for Excel compatibility

JSON Export Format:

  • Complete audit entry objects with all metadata

  • Structured hierarchy for programmatic processing

  • Timestamps in ISO 8601 format

  • Includes audit summary metadata

Summary Report Format:

  • Executive summary with key metrics

  • Compliance status assessment

  • Security incident reporting

  • User activity breakdown

  • Time-based analysis

Usage Example:

import { AuditExportService } from '~/services/audit-export.service';

const exportService = new AuditExportService();

// Export filtered entries to CSV
const filtered = entries.filter(entry => 
  entry.action === 'CASE_CREATED' && 
  entry.result === 'success'
);
exportService.exportToCSV(filtered, 'case-creation-audit.csv');

// Generate and export compliance summary
const summary = exportService.generateSummaryReport(entries);
// Generate summary report (text format)
const summary = exportService.generateReportSummary(auditTrail);
console.log(summary); // Display or use the summary text

Integration Pattern:

// Component integration
const handleExport = async (format: 'csv' | 'json' | 'summary') => {
  const entries = await fetchAuditEntries(filters);
  
  switch (format) {
    case 'csv':
      exportService.exportToCSV(entries, 'audit-export.csv');
      break;
    case 'json':
      exportService.exportToJSON(entries, 'audit-export.json');
      break;
    case 'summary':
      // Generate summary report (text format, not file download)
      const summary = exportService.generateReportSummary(auditTrail);
      console.log(summary); // Display in UI or process as needed
      break;
  }
};

Accessibility Features

Built-in Accessibility

  • Semantic HTML: Proper element usage

  • ARIA Labels: Screen reader support

  • Keyboard Navigation: Full keyboard accessibility

  • Focus Management: Proper focus handling

  • Color Contrast: WCAG compliance

Development Guidelines

Component Creation Checklist

  1. ✅ Create component directory

  2. ✅ Implement TypeScript interfaces

  3. ✅ Add CSS Module styling

  4. ✅ Include error handling (follow Error Handling Guide)

  5. ✅ Add loading states

  6. ✅ Implement accessibility features

  7. ✅ Add documentation

Best Practices

  • Single Responsibility: Each component has one clear purpose

  • Type Safety: Full TypeScript coverage

  • Error Boundaries: Graceful error handling (see Error Handling Guide)

  • Performance: Optimized for large datasets

  • Maintainability: Clear, documented code

Updated on