Case study · 2026

ClinicARE

A hospital runs on lists — patients, beds, appointments, invoices. ClinicARE is the admin system that keeps all four in one place, fast enough to use during a shift.

Open live demoRead the source

login admin · password 123

11
screens shipped
9
domain modules
920
seeded records
2
UI languages
clinicare.islomjon.uz
ClinicARE dashboard — counters, patient statistics chart and the appointment list

Dashboard · light theme · the interface ships in Russian and Uzbek

Dashboard · light theme · the interface ships in Russian and Uzbek

Built to be judged on the boring parts

Anyone can render a chart. Clinic software lives or dies on the fifteenth minute of use: filtering 150 patients, sharing a filtered view with a colleague, staying logged in through a long shift.

Problem

Small clinics track admissions in spreadsheets. Records get duplicated, bed availability is a phone call, and nobody can say how many patients came in last month without counting rows by hand.

Approach

One register per entity, one table component behind all of them, and every list view addressable by URL — so a filtered screen is a link you can paste into a chat.

Outcome

Nine modules and eleven screens running on a mock API with 920 seeded records, so the demo behaves like production: real pagination, real sorting, real latency.

Shareable state

The URL is the table's memory

Page, page size, sort column, sort direction, search text and every column filter live in the query string — never in component state. Reload the tab and the view survives; send the link and your colleague sees the same rows. One useDataTableQuery hook drives all nine tables.

clinicare.islomjon.uz
ClinicARE patient register — sortable, searchable and filterable data table

Patient register · the same table engine renders all nine modules

Patient register · the same table engine renders all nine modules

Modules

Nine registers, one grammar

Every module reads the same way: a header with the primary action, a filterable table, a create/edit modal and a delete confirmation. Learn one screen and you know all nine.

Dashboard

Four live counters, a patient curve switchable between weekly, monthly and yearly, today's appointments and the recent patient register.

Appointments

Book a patient with a doctor, a date and a note. Scheduled, completed and cancelled states are filterable from the column header.

130 records

Rooms

Bed inventory by type — VIP, ICU, Regular — with availability, occupancy and maintenance status.

110 records

Payments

Invoices tied to a patient and the treating doctor, with amount, note and paid / pending / cancelled state.

200 records

Doctors

The medical roster: specialty, contact details and availability, each row editable in place.

80 records

Patients

The master register — name, gender, date of birth, address, phone, emergency contact and blood type.

150 records

Inpatients

Who is admitted, in which room, since when — the bridge between the patient register and the bed inventory.

150 records

Users & access

Staff accounts across four roles — Admin, Doctor, Staff, Nurse — feeding the permission checks that build the sidebar.

100 records

Settings & help

Eight settings tabs — account, general, preferences, language, notifications, linked accounts, billing, plans — plus a searchable FAQ.

Small screens

The same system in a pocket

The sidebar becomes a drawer, tables scroll horizontally and every create/edit form reflows to a single column — the modal keeps its validation, its date picker and its required-field markers down to 360px.

  • One layout, no separate mobile build
  • Keyboard focus stays visible on every control
  • prefers-reduced-motion is respected
ClinicARE on a phone — the new patient form as a full-screen modal

Create patient · the modal reflows to a single column on small screens

Under the hood

Decisions the demo is built on

The parts a client never sees in a screenshot and feels every day.

Session handling

Expired tokens refresh without a flicker

When a request comes back 401, the axios layer refreshes the access token once and replays the failed request. Requests that fail while a refresh is in flight queue up and resume with the new token instead of firing a refresh each.

  • A dashboard with six parallel queries triggers one refresh, not six
  • Each request retries at most once — no loops
  • Refresh failure is the only path to a forced logout
Demo data

A mock backend that behaves like a real one

A Service Worker intercepts every request in the browser and answers it from seeded datasets — 920 records generated from a fixed seed, so the demo looks identical on every machine and every reload.

  • Lists are paginated, sorted, searched and filtered server-side
  • Create, update and delete persist for the session
  • Swapping in a real API means changing one base URL
Architecture

The menu generates the router

Sidebar groups and route definitions are built from the same navigation array, so a screen can never appear in one and be missing from the other. Route strings live in exactly one file.

  • A route cannot exist without a permission
  • Renaming a route is a one-line change
  • Folders follow bulletproof-react: a feature owns its page, columns, modals and route
Fit & finish

Two languages, three themes, no drift

Every visible string comes from a translation file — around 500 keys per language, Russian and Uzbek, switched from the header without a reload. Theme follows light, dark or the operating system, applied before first paint.

  • Ant Design tokens and Tailwind utilities read the same colour variables
  • The app never flashes white on a dark screen
  • Adding a third language is one JSON file, not a search across the codebase

Stack

Current versions, no legacy shims

Typechecking runs as part of the production build, so a type error fails the deploy rather than reaching the browser.

  • React 19
  • TypeScript
  • Vite
  • Ant Design 6
  • Tailwind CSS 4
  • React Router 7
  • TanStack Query
  • Zustand
  • Recharts
  • MSW
  • i18next
  • react-hook-form
  • axios
  • dayjs
  • ru · uz

Need an admin panel your team will actually use?

ClinicARE is one example. I build internal tools, dashboards and data-heavy interfaces — from the first wireframe to the deployed build.