Skip to main content

Component Library

This document provides documentation for the reusable components in the Kuviq application.

Overview

Components are organized into these categories:

  • Common - Generic, reusable UI components
  • Forms - Form controls and layouts
  • Dashboard - Dashboard widgets
  • Inspections - Inspection-specific components
  • Layout - Page layout components

All components are built with Material-UI and follow consistent patterns for:

  • Accessibility (WCAG AA compliant)
  • Responsive design
  • Theme integration
  • TypeScript types

Common Components

DataTable

A feature-rich data table with sorting, filtering, and pagination.

import DataTable from '@/components/common/DataTable'

Props

PropTypeDescription
dataT[]Array of data items
columnsColumn<T>[]Column definitions
loadingbooleanShow loading state
onRowClick(row: T) => voidRow click handler
sortablebooleanEnable sorting
filterablebooleanEnable filtering
paginationbooleanEnable pagination
pageSizenumberItems per page
selectablebooleanEnable row selection
onSelectionChange(selected: T[]) => voidSelection handler

Example

<DataTable
data={items}
columns={[
{ field: 'name', header: 'Name', sortable: true },
{ field: 'status', header: 'Status', render: (row) => <StatusChip status={row.status} /> },
{ field: 'updatedAt', header: 'Updated', format: 'date' },
]}
onRowClick={(item) => navigate(`/items/${item.id}`)}
pagination
pageSize={25}
/>

List (Deprecated)

Deprecated

The List component is deprecated as of November 2025. Use UnifiedDataTable from the design system instead. Scheduled for removal in Q1 2026.

A unified list component for displaying collections.

// Deprecated - use UnifiedDataTable instead
import List from '@/components/common/list/List'

// New approach
import { UnifiedDataTable } from '@/design-system'

Props

PropTypeDescription
itemsT[]Array of items
renderItem(item: T) => ReactNodeItem renderer
loadingbooleanLoading state
emptyMessagestringEmpty state message
searchablebooleanEnable search
onSearch(query: string) => voidSearch handler

QRScannerClean

QR code scanner using the device camera.

import QRScannerClean from '@/components/common/QRScannerClean'

Props

PropTypeDescription
onScan(data: string) => voidScan success handler
onError(error: Error) => voidError handler
onClose() => voidClose handler
facingMode'user' | 'environment'Camera selection

Example

<QRScannerClean
onScan={(data) => {
const itemId = parseQRCode(data)
navigate(`/items/${itemId}`)
}}
onError={(error) => showError('Failed to scan QR code')}
onClose={() => setShowScanner(false)}
/>

OptimizedImage

Lazy-loaded image with placeholder and error handling.

import OptimizedImage from '@/components/common/OptimizedImage'

Props

PropTypeDescription
srcstringImage source URL
altstringAlt text (required)
widthnumberImage width
heightnumberImage height
placeholderstringPlaceholder image
onLoad() => voidLoad handler
onError() => voidError handler

SessionWarning

Displays session timeout warning dialog.

import SessionWarning from '@/components/common/SessionWarning'

Props

PropTypeDescription
openbooleanDialog visibility
timeRemainingnumberSeconds until logout
onExtend() => voidExtend session
onLogout() => voidManual logout

UsageLimit

Shows usage limit progress and warnings.

import UsageLimit from '@/components/common/UsageLimit'

Props

PropTypeDescription
currentnumberCurrent usage
limitnumberMaximum limit
labelstringDisplay label
showWarningbooleanShow warning at 80%

Accessibility skip link for keyboard navigation.

import SkipLink from '@/components/common/SkipLink'

Usage

Add at the top of your app:

<SkipLink />
<main id="main-content" role="main">
{/* Page content */}
</main>

Form Components

FormLayout

Consistent form layout wrapper.

import { FormLayout } from '@/components/forms/FormLayout'

Props

PropTypeDescription
titlestringForm title
subtitlestringOptional subtitle
loadingbooleanLoading state
onSubmit() => voidSubmit handler
onCancel() => voidCancel handler
submitLabelstringSubmit button text
cancelLabelstringCancel button text

FormField

Form field wrapper with label, error, and helper text.

import { FormField } from '@/components/forms/FormField'

Props

PropTypeDescription
labelstringField label
requiredbooleanMark as required
errorstringError message
helperTextstringHelper text
childrenReactNodeInput element

Example

<FormField label="Name" required error={errors.name}>
<TextField
value={values.name}
onChange={(e) => handleChange('name', e.target.value)}
/>
</FormField>

Dashboard Widgets

DashboardWidget

Base widget component for dashboard cards.

import DashboardWidget from '@/components/dashboard/DashboardWidget'

Props

PropTypeDescription
titlestringWidget title
subtitlestringOptional subtitle
loadingbooleanLoading state
errorErrorError state
actionsReactNodeHeader actions
childrenReactNodeWidget content

StatusSummaryCards

Displays inspection status summary with smart conditional rendering. Shows actionable status cards (Overdue, Due Today, Due This Week) when there are inspections needing attention, or an "All OK" message when everything is up to date.

import { StatusSummaryCards } from '@/components/dashboard/widgets/StatusSummaryCards'

Behavior

  • When inspections need attention: Shows non-zero status cards:
    • Overdue (red) - Past due date
    • Due Today (yellow) - Scheduled for today
    • Due This Week (green) - Next 7 days (excluding today)
  • When all caught up: Shows "All inspections up to date" message, plus optional "Due This Week" card if any upcoming

Clicking each card navigates to the filtered inspections list:

  • Overdue → /inspections?view=overdue
  • Due Today → /inspections?view=due-today
  • Due This Week → /inspections?view=due-this-week

InspectionTrendsWidget

Shows inspection trends over time.

import InspectionTrendsWidget from '@/components/dashboard/InspectionTrendsWidget'

Props

PropTypeDescription
dataTrendData[]Trend data points
period'week' | 'month' | 'year'Time period

NextInspectionsList

Lists upcoming inspections.

import NextInspectionsList from '@/components/dashboard/NextInspectionsList'

Props

PropTypeDescription
inspectionsInspection[]Upcoming inspections
limitnumberMax items to show
onViewAll() => voidView all handler

QuickActions

Quick action buttons for common operations.

import QuickActions from '@/components/dashboard/QuickActions'

ScanButton

QR scan action button.

import ScanButton from '@/components/dashboard/ScanButton'

Props

PropTypeDescription
onScan(itemId: string) => voidScan handler
disabledbooleanDisabled state

Inspection Components

InspectionList

Displays list of inspections with actions.

import InspectionList from '@/components/inspections/InspectionList'

Props

PropTypeDescription
inspectionsInspection[]Inspection list
loadingbooleanLoading state
onView(inspection: Inspection) => voidView handler
onStart(inspection: Inspection) => voidStart handler
onPause(inspection: Inspection) => voidPause handler
onResume(inspection: Inspection) => voidResume handler
onCancel(inspection: Inspection) => voidCancel handler

InspectionExecution

Inspection execution interface.

import InspectionExecution from '@/components/inspections/InspectionExecution'

TemplateList

Displays inspection templates.

import TemplateList from '@/components/inspections/TemplateList'

TemplateForm

Template creation/editing form.

import TemplateForm from '@/components/inspections/TemplateForm'

Layout Components

PageLayout

Standard page layout with header and navigation.

import PageLayout from '@/components/layout/PageLayout'

Props

PropTypeDescription
titlestringPage title
breadcrumbsBreadcrumb[]Breadcrumb trail
actionsReactNodeHeader actions
childrenReactNodePage content

Side navigation drawer.

import NavigationDrawer from '@/components/layout/NavigationDrawer'

ErrorBoundary

React error boundary for graceful error handling.

import ErrorBoundary from '@/components/layout/ErrorBoundary'

Example

<ErrorBoundary fallback={<ErrorPage />}>
<Dashboard />
</ErrorBoundary>

Permission Components

PermissionGuard

Conditionally renders children based on permissions.

import PermissionGuard from '@/components/permissions/PermissionGuard'

Props

PropTypeDescription
permissionPermissionRequired permission
permissionsPermission[]Any of these permissions
requireAllbooleanRequire all permissions
fallbackReactNodeFallback when denied
childrenReactNodeProtected content

Example

<PermissionGuard permission="items.delete">
<Button onClick={handleDelete}>Delete Item</Button>
</PermissionGuard>

FeatureGate

Conditionally renders based on subscription features.

import FeatureGate from '@/components/permissions/FeatureGate'

Props

PropTypeDescription
featurestringFeature name
fallbackReactNodeUpgrade prompt
childrenReactNodeFeature content

Export Components

ExportDialog

Main export dialog that orchestrates the export workflow with templates and custom configuration.

import { ExportDialog } from '@/components/common/export/ExportDialog'

Props

PropTypeDescription
openbooleanDialog visibility
onClose() => voidClose handler
entityTypeEntityTypeType of data to export
titlestringDialog title
selectedIdsstring[]Pre-selected record IDs
defaultConfigPartial<ExportConfig>Default configuration

Sub-Components

The ExportDialog uses these modular sub-components for configuration:

ComponentDescription
ExportBasicConfigFormat selection and filename configuration
ExportFieldSelectionField picker with headers/metadata options
ExportFilterConfigDynamic filter rule management
ExportConditionalFormattingExcel-specific cell styling rules
ExportFormatOptionsDate/number formats, CSV delimiter, Excel multi-sheet

Example

<ExportDialog
open={showExport}
onClose={() => setShowExport(false)}
entityType="items"
title="Items"
selectedIds={selectedItemIds}
/>

ExportTemplateManager

Manages export templates with CRUD operations.

import { ExportTemplateManager } from '@/components/common/export/ExportTemplateManager'

Props

PropTypeDescription
openbooleanDialog visibility
onClose() => voidClose handler
onTemplateSelect(template: ExportTemplate) => voidTemplate selection handler

Best Practices

Accessibility

All components follow WCAG AA guidelines:

  • Minimum 4.5:1 color contrast
  • Keyboard navigation support
  • ARIA attributes where needed
  • Focus management

Responsive Design

Components use MUI breakpoints:

sx={{
width: { xs: '100%', sm: '50%', md: '33%' },
padding: { xs: 2, md: 3 },
}}

Touch Targets

Minimum 44px touch targets on mobile:

sx={{
minWidth: { '@media (pointer: coarse)': 44 },
minHeight: { '@media (pointer: coarse)': 44 },
}}

Responsive Button Layout

Button groups must be responsive. Use column layout on mobile with full-width buttons:

import { useTheme, useMediaQuery, Box, Button } from '@mui/material'

function MyComponent() {
const theme = useTheme()
const isMobile = useMediaQuery(theme.breakpoints.down('sm'))

return (
<Box
sx={{
display: 'flex',
flexDirection: isMobile ? 'column' : 'row',
gap: 1,
}}
>
<Button variant="outlined" fullWidth={isMobile}>
Cancel
</Button>
<Button variant="contained" fullWidth={isMobile}>
{isMobile ? 'Save' : 'Save Changes'}
</Button>
</Box>
)
}

Key patterns:

  • Use fullWidth={isMobile} on all action buttons
  • Use column layout on mobile, row on desktop: flexDirection: isMobile ? 'column' : 'row'
  • Shorten button text on mobile when needed (e.g., "Save" vs "Save Changes")
  • For dialogs, use fullScreen={isMobile} prop on the Dialog component
  • For DialogActions, apply custom styling to stack buttons:
    <DialogActions
    sx={{
    flexDirection: isMobile ? 'column' : 'row',
    gap: isMobile ? 1 : 0,
    p: isMobile ? 2 : undefined,
    '& > :not(:first-of-type)': { ml: isMobile ? 0 : undefined },
    }}
    >

Theme Integration

Use theme tokens for consistency:

sx={{
color: 'primary.main',
backgroundColor: 'background.paper',
borderColor: 'divider',
}}

TypeScript

All components are fully typed:

interface MyComponentProps {
title: string
onAction?: () => void
children: React.ReactNode
}

export default function MyComponent({ title, onAction, children }: MyComponentProps) {
// ...
}