FluidCalc — Clinical Fluid & IV Calculator
iOS app for nurses and clinicians to track fluid balance and perform bedside calculations in real time.
More screenshots
Overview
FluidCalc is a production iOS app built for critical care and ward nurses who need fast, accurate fluid tracking and clinical calculations at the bedside. It replaces paper tally charts and mental arithmetic with a structured, safety-aware tool that works fully offline.
The app ships on the Apple App Store via TestFlight CI, is installable as a PWA on any device, and is built to clinical safety standards — including weight-relative balance thresholds, anuria alerts, and ARDS grading.
Features
Fluid Balance Tracking
- Log intake (IV fluids, oral, blood products, TPN) and output (urine, drainage, blood loss, NG aspirate) with timestamps
- Real-time net balance with colour-coded status: normal / caution / critical
- Weight-relative thresholds (3 ml/kg, 8 ml/kg) when patient weight is known; flat thresholds (200 ml, 500 ml) as fallback
- Anuria detection with clinical alert when urine output falls below threshold
- Up to 4 simultaneous patient slots with instant switching
- 10-step undo stack per patient
- Shift PDF export with handoff notes and page numbers
- CSV export for documentation
- Virtual list rendering for shifts with 50+ entries (no jank)
19 Clinical Calculators
Grouped by specialty:
| Category | Calculators |
|---|---|
| Fluid / Renal | IV Drip Rate, Urine Output, Maintenance Fluid, Free Water Deficit, Corrected Sodium, FENa, Creatinine Clearance (CG), Osmolality |
| Cardiac | MAP, QTc (Bazett) |
| Respiratory | ABG Interpreter (full acid-base disorder classification, compensation adequacy, P/F ratio, ARDS grading) |
| Nutrition | Harris-Benedict REE, BSA (DuBois) |
| Paediatric | Paediatric Weight (age-based), Paediatric Dehydration |
| Burns / Trauma | Parkland Formula |
| Pharmacology | Drug Dose (weight-based), Medication Infusion Rate, Intraoperative Fluid Planner, Anion Gap |
Clinical Safety
- Division-by-zero guards on all calculations
- Critical value alerts with
aria-liveannouncements (pH, QTc, MAP, FENa, anion gap) - ABG interpreter classifies primary disorder, compensation, and flags life-threatening derangements
- DOMPurify sanitisation on all free-text inputs
- Duplicate entry detection
Technical Stack
| Layer | Technology |
|---|---|
| Framework | Next.js 16 (App Router, static export) |
| Language | TypeScript 5 (strict) |
| UI | React 19, Tailwind CSS 4 |
| State | Zustand 5 with localStorage persistence and versioned migrations |
| Native wrapper | Capacitor 8 (iOS) |
| PDF export | jsPDF (static import, no lazy loading) |
| Virtualisation | @tanstack/react-virtual (entry lists > 50 items) |
| Testing | Vitest, @testing-library/react — 131 tests |
| CI/CD | Codemagic (TestFlight), Vercel (web preview) |
| i18n | Custom context with 8 languages, navigator.language detection, regex-cached plural rules |
Design System
Built on a custom Precision Instrument design language — dark-first, clinical, and typographically precise:
- Fonts: Instrument Serif (headings) · DM Sans (body/UI) · Geist Mono (all clinical numbers)
- Colours:
#0F1117surface ·#4FC3F7primary ·#4CAF82success ·#F5A623warning ·#EF5350critical - All numeric outputs use
font-variant-numeric: tabular-numsso values never jump width - 8px spacing grid · 48px minimum tap targets throughout · iOS safe-area insets on every header and nav bar
- Light theme support with full CSS variable theming
Architecture Highlights
- No backend — the entire app is a static export. All state lives in
localStorage, serialised with customDatehydration to survive JSON round-trips. - Versioned store migrations — each breaking state shape change increments a version and runs a migration on hydration, so users never lose data across app updates.
- i18n without a library — a hand-rolled context reads
navigator.language, loads JSON message files dynamically, and caches plural-form regex per locale. Supports EN, DE, FR, ES, HI, RO, PT, AR. - Shallow selectors everywhere — Zustand
useShallowprevents re-renders on unrelated state changes across the entry list, summary, and patient switcher. - Static jsPDF import — eagerly imported at module level to avoid a 300ms+ lazy-load stall when a nurse first hits "Export PDF" mid-shift.
Internationalisation
8 languages: English, German, French, Spanish, Hindi, Romanian, Portuguese, Arabic. Locale is detected from the browser, persisted to localStorage, and applied without a flash on mount. All clinical alerts, error messages, and ARIA labels are translated.
Testing
131 unit and integration tests covering:
- All 19 clinical calculation functions (including edge cases and zero-guards)
- Store mutations, serialisation, and migration logic
- Validation helpers (DOMPurify, duplicate detection, time validation)
- UI quality assertions (tap target sizes, ARIA roles, toast behaviour)