medOS ultra

OR Count Sheet Spec

Component spec for the OR surgical-count sheet.

10 min read diagramsUpdated 2026-05-23docs/architecture/or-count-sheet-spec.md

File: web/sandbox/targets/OrCountSectionTarget.tsx (938 lines) Sandbox URL: http://localhost:5179/?target=OrCountSection Registry key: OrCountSection in web/sandbox/registry.ts Based on: Real production Count.tsx at web/packages/periops-kit/src/operating-room/components/list-or-patient/table-data/dialog/time-out/Count.tsx


Purpose

Standalone sandbox prototype of the OR Instrument Count Sheet used by Thai hospital scrub and circulating nurses during surgery. Models the AORN (Association of periOperative Registered Nurses) dual-nurse counting standard where both the scrub nurse and circulating nurse independently count surgical items at each phase, then reconcile.

Production data path: orRequest.timeOut.intraoperative.count


Architecture

State Management

Uses useReducer with a single StateActionreducer pattern. No external state (Redux/Zustand/Supabase).

State
├── operations: Operation[]    // Multi-operation support (tabs)
└── activeOpIdx: number        // Currently selected tab

14 Reducer Actions

Action Purpose
SET_COUNT Set a nurse’s count for a specific item/phase/role
SET_TOTAL Set the expected total for an item
SET_ACTIVE_PHASE Switch between the 4 counting phases
ATTEST Record nurse name (from dropdown) as attestation for a phase
SET_ACTIVE_OP Switch between operation tabs
ADD_OPERATION Add a new operation (via dialog)
REMOVE_OPERATION Remove an operation tab (minimum 1 enforced)
ADD_ITEM Add a custom free-text item to current operation
REMOVE_ITEM Remove a custom item (only items with id.startsWith('custom-'))
SET_VERIFICATION Set N/A / Corrected / Uncorrected for sponge/needles/instruments
TOGGLE_SURGEON_FIELD Toggle surgeon notified/unnotified checkbox
SET_SURGEON_SIGNATURE Set signature text for surgeon notification
SEED_DEMO Populate 2 demo operations with realistic data
RESET Clear to single empty operation

Data Model

Operation

type Operation = {
  id: string;                    // 'op-{timestamp}-{random}'
  name: string;                  // Thai name (e.g. 'ผ่าตัดถุงน้ำดี')
  name_en: string;               // English name (e.g. 'Laparoscopic Cholecystectomy')
  surgeon: string;               // Surgeon name (e.g. 'นพ. พัฒน์ / Dr. Phat')
  items: CountItem[];            // 12 standard + N custom items
  activePhase: CountPhase;       // Currently selected phase
  attestations: Record<CountPhase, Record<Role, string>>;
  // '' = not attested, nurse Thai name = attested
  verification: Record<VerificationSectionKey, VerificationSection>;
};

CountItem

type CountItem = {
  id: string;                    // Standard: 'gauze', 'needle', etc. Custom: 'custom-{ts}-{rand}'
  name: string;                  // Thai name
  name_en: string;               // English name
  total: number;                 // Expected total count
  counts: Record<CountPhase, Record<Role, number | null>>;
  // null = not yet counted, number = counted
};

VerificationSection

type VerificationSection = {
  sponge: CountVerificationStatus;       // '' | 'n/a' | 'corrected' | 'uncorrected'
  needles: CountVerificationStatus;
  instruments: CountVerificationStatus;
  surgeonNotified: boolean;              // Checkbox
  surgeonNotifiedSignature: string;      // Sign field (appears when checkbox checked)
  surgeonUnnotified: boolean;            // Checkbox
  surgeonUnnotifiedSignature: string;    // bySign field (appears when checkbox checked)
};

Enums

type Role = 'scrub' | 'circulator';
type CountPhase = 'initial' | 'first' | 'closing' | 'final';
type VerificationSectionKey = 'firstProcedure' | 'preImplantClosing';
type CountVerificationStatus = 'n/a' | 'corrected' | 'uncorrected' | '';

4 Counting Phases

# Key EN Label TH Label Color
1 initial Initial นับเริ่มต้น #8b5cf6 (purple)
2 first 1st Count นับครั้งที่ 1 #3b82f6 (blue)
3 closing Closing ก่อนปิดแผล #f59e0b (amber)
4 final Final สุดท้าย #22c55e (green)

Each phase has its own count values per item per role, and its own attestation state.


2 Roles (No Surgeon Column)

Key EN Label TH Label
scrub Scrub Nurse พยาบาลส่งเครื่องมือ
circulator Circulating Nurse พยาบาลรอบนอก

Important: The Thai label for circulating nurse is พยาบาลรอบนอก (NOT พยาบาลหมุนเวียน).


12 Standard Items

# ID EN Name TH Name
1 gauze Gauze ผ้าก๊อซ
2 swab-large Swab (Large) ผ้าซับเลือดใหญ่
3 swab-small Swab (Small) ผ้าซับเลือดเล็ก
4 blood-gauze Blood Gauze ก๊อซชุบเลือด
5 needle Needle เข็ม
6 blade Blade ใบมีด
7 instrument Instrument เครื่องมือ
8 peanut Peanut ถั่ว (Peanut)
9 drain Drain สายระบาย
10 cottonoid Cottonoid / Patty สำลีแผ่น
11 vascular Vascular หนีบหลอดเลือด
12 sling Sling สลิง

Custom items can be added per-operation via the inline AddItemRow at the bottom of the table (EN + TH text fields, + Add button). Custom items get id: 'custom-{timestamp}-{random}' and show a red delete icon in the Match column.


2 Verification Sections

Key EN Label TH Label Color
firstProcedure The First Procedure นับครั้งแรก #3b82f6 (blue)
preImplantClosing Pre-Implant — Closing Count นับก่อนปิดแผล #f59e0b (amber)

Each section has 3 categories with radio-style selection (N/A / Corrected / Uncorrected):

  • Sponge
  • Needles
  • Instruments

Conditional: “If count uncorrected” Block

When any category in a section is set to Uncorrected, a red-bordered panel appears:

If count uncorrected / กรณีนับไม่ตรง
┌──────────────────────────────────────────────────────────┐
│ ☐ Surgeon notified taken x-ray                          │
│   แจ้งศัลยแพทย์แล้ว ถ่ายภาพรังสี         [Sign / ลงชื่อ] │
│                                                          │
│ ☐ Surgeon unnotified                                     │
│   ไม่ได้แจ้งศัลยแพทย์                  [bySign / ลงชื่อ] │
└──────────────────────────────────────────────────────────┘

Behavior:

  • Checkboxes toggle independently per section
  • Signature text field appears only when the corresponding checkbox is checked
  • surgeonNotified checkbox color: #3b82f6 (blue)
  • surgeonUnnotified checkbox color: #f59e0b (amber)
  • The block auto-hides when all categories return to N/A or Corrected

Production data path:

orRequest.timeOut.intraoperative.count.uncorrected[]
  ├── surgeonNotified + surgeonNotifiedSignature
  └── surgeonUnnotified + surgeonUnnotifiedSignature

Attestation (Nurse Dropdown)

Each phase has attestation for both roles. The attestation uses a Select dropdown populated with 8 sample Thai nurses:

ID Thai Name EN Name
n1 พย. สุภาพร วงศ์สว่าง Supaporn W.
n2 พย. นิตยา ศรีสุข Nittaya S.
n3 พย. อรุณี แก้วประเสริฐ Arunee K.
n4 พย. พรทิพย์ ชัยมงคล Porntip C.
n5 พย. ดวงใจ สุขสมบูรณ์ Duangjai S.
n6 พย. จารุวรรณ พงศ์พิพัฒน์ Jaruwan P.
n7 พย. วราภรณ์ ทองคำ Waraporn T.
n8 พย. กัลยา เจริญสุข Kanlaya C.

Attestation state: string per role per phase — empty string = not attested, nurse Thai name = attested.

UI layout:

ลงชื่อรับรอง / Attestation — {Phase} ({PhaseTH})

Scrub Nurse              [พย. สุภาพร วงศ์สว่าง ▼]  ✓
พยาบาลส่งเครื่องมือ

Circulating Nurse        [เลือกพยาบาล / Select nurse ▼]  ○
พยาบาลรอบนอก

When both nurses are selected → green “count verified” alert appears. Phase tab gets a green checkmark.


Match / Discrepancy Logic

Per item, per active phase:

Condition Match Column Row Style
total === 0 (dash) Normal
Both counts null or only one entered Empty circle Normal
Both counts match total Green checkmark Normal
Any count differs from total, or scrub ≠ circulator Red warning Light red background

When discrepancies exist, a yellow Alert banner appears above the table:

N discrepanc(y/ies) — Item1, Item2, …


Multi-Operation Support

  • Tab bar at top with scrollable operation tabs
  • Add: + icon button → AddOperationDialog (TH name, EN name, surgeon fields)
  • Remove: icon inside each tab (only visible when >1 operations)
  • Minimum 1 operation enforced (REMOVE_OPERATION is no-op when length <= 1)
  • Summary chip bar appears when >1 operations showing {name}: N/4 phases completion

Component Tree

OrCountSectionTarget (main, default export)
├── Header (title + Reset/Seed Demo buttons)
├── Operation Tabs (MUI Tabs + Add button)
│   └── OperationCountTable (per active operation)
│       ├── Operation Header (name, Thai name, surgeon chip)
│       ├── Phase Tabs (4 clickable phase boxes)
│       ├── Discrepancy Alert (conditional)
│       ├── Count Table (MUI Table)
│       │   ├── Header Row (# | Item | Total | Scrub | Circulator | Match)
│       │   ├── Item Rows × 12+ (number inputs per cell)
│       │   └── AddItemRow (inline EN/TH text fields + Add button)
│       ├── Verification Sections × 2
│       │   ├── Category Radios (Sponge/Needles/Instruments × N/A/Corrected/Uncorrected)
│       │   └── Surgeon Notification Block (conditional on Uncorrected)
│       │       ├── surgeonNotified checkbox + signature
│       │       └── surgeonUnnotified checkbox + signature
│       └── Attestation Section
│           ├── Scrub Nurse Select dropdown
│           ├── Circulating Nurse Select dropdown
│           └── Verified Alert (conditional on both selected)
├── All Operations Summary (conditional on >1 ops)
└── AddOperationDialog

Seed Demo Data

SEED_DEMO creates 2 operations:

Operation 1: Laparoscopic Cholecystectomy

  • TH: ผ่าตัดถุงน้ำดี
  • Surgeon: นพ. พัฒน์ / Dr. Phat
  • Pre-filled totals: Gauze=20, Swab(L)=5, Swab(S)=10, Needle=6, Blade=2, Instrument=15, Peanut=5, Drain=1, Vascular=2
  • Phases completed: Initial + 1st Count (both with matching scrub/circulator counts)
  • Attested by: พย. สุภาพร วงศ์สว่าง (scrub) + พย. พรทิพย์ ชัยมงคล (circulator)
  • Closing + Final: Empty (not yet counted)

Operation 2: Appendectomy

  • TH: ผ่าตัดไส้ติ่ง
  • Surgeon: นพ. สมปอง / Dr. Sompong
  • Pre-filled totals: Gauze=10, Swab(L)=5, Swab(S)=5, Needle=4, Blade=1, Instrument=12, Drain=1
  • No phases completed, no attestations

UI Tech Stack

  • Framework: React 19 + TypeScript
  • Components: MUI v7 (Table, Paper, Stack, Tabs, Select, MenuItem, FormControl, TextField, Alert, Dialog, Chip, IconButton, Tooltip, Typography)
  • Icons: @mui/icons-material (ContentCut, CheckCircle, RadioButtonUnchecked, WarningAmber, Add, RestartAlt, DeleteOutline, Edit, CheckBoxOutlineBlank, CheckBox, Draw)
  • Color system: MUI alpha() utility for transparency overlays
  • State: useReducer (no external store)
  • Bilingual: All labels in Thai + English throughout

Verification Checklist (for Claude reviewer)

Structural

  • [ ] File renders without runtime errors at ?target=OrCountSection
  • [ ] 12 standard items displayed in table
  • [ ] 4 phase tabs (Initial/1st Count/Closing/Final) clickable and switch content
  • [ ] 2 verification sections (The First Procedure / Pre-Implant — Closing Count)
  • [ ] Attestation section with 2 nurse dropdown selects

Functional

  • [ ] Total, Scrub, and Circulator number inputs are editable
  • [ ] Match column shows when all 3 values agree, on mismatch, when total=0
  • [ ] Discrepancy alert appears when any item has mismatched counts
  • [ ] Clicking N/A/Corrected/Uncorrected toggles correctly (click again to deselect)
  • [ ] Setting any item to “Uncorrected” reveals surgeon notification block
  • [ ] Surgeon notification checkboxes toggle independently
  • [ ] Signature field appears only when checkbox is checked
  • [ ] Surgeon notification block hides when all items return to N/A/Corrected
  • [ ] Nurse dropdown selection stores Thai nurse name as attestation
  • [ ] Both nurses selected → “count verified” success alert
  • [ ] Phase tab shows green checkmark when both nurses attested

Multi-Operation

  • [ ] Seed Demo creates 2 tabs (Lap Chole + Appendectomy)
  • [ ] Tabs switch operations correctly
  • [ ] Add Operation dialog creates new tab
  • [ ] Remove operation (X button) removes tab (minimum 1 enforced)
  • [ ] Summary chips appear when >1 operations

Custom Items

  • [ ] AddItemRow (EN + TH fields) visible at bottom of table
  • [ ] Typing name and clicking “+ Add” adds row to table
  • [ ] Enter key also triggers add
  • [ ] Custom items show red delete icon in Match column
  • [ ] Standard items do NOT show delete icon
  • [ ] Reset clears custom items

Data Integrity

  • [ ] Each operation maintains independent state (items, phases, attestations, verification)
  • [ ] Verification state is per-section per-operation (not shared)
  • [ ] Attestation is per-phase per-role per-operation
  • [ ] Switching phases preserves count data in other phases
Ask Anything