A full-stack hospital platform where patients find and pay for doctors online, doctors run their schedules and consultations, and admins run the hospital — one system, three roles, real payments.
This repository is the Next.js frontend. The REST API lives in its companion repository:
Jinna89/Hospital-Doctor-Management-System (Express · Prisma · PostgreSQL), deployed at
https://hospital-management-system-ten-ivory.vercel.app/api/v1.
- Highlights
- Quick demo
- Features by role
- Tech stack
- Architecture
- Getting started
- Scripts
- Project structure
- Routes
- Payments
- Quality
- Three fixed roles — Patient, Doctor, Admin — enforced at the route level (Next.js middleware) and in the UI.
- Real payments only. Booking creates a
PENDING_PAYMENTappointment, then hands off to SSLCommerz (test mode). No cash-on-delivery, no "mark as paid" button. - Real API only. No mock data anywhere; every screen reads from the live backend.
- One-click demo login for all three roles on the login page.
- URL-synced state. Search, filters, sorting and pagination live in the query string, so any view is bookmarkable and shareable.
- Fast by default. Server Components for static pages, per-route
loading.tsxskeletons,error.tsxboundaries, and Recharts lazy-loaded so charts never block first paint. - Strict TypeScript (no
any), ESLint + Prettier, shared UI primitives.
Open /login and press one of the Quick demo login buttons, or sign in manually:
| Role | Password | |
|---|---|---|
| Admin | admin@hospital.test |
Admin@12345 |
| Doctor | dr.rahman@hospital.test |
Doctor@12345 |
| Patient | demo.patient@medicare-hms.test |
DemoPatient@123 |
These accounts are created by the backend seed script. Change them before any non-demo deployment.
- Search doctors by name (server-side), filter by specialty, sort by name / rating / fee
- Pick a date and an available time slot, then book
- Pay through SSLCommerz and land on a success or cancel page that shows the real appointment status
- Review appointments (with cancellation), prescriptions, lab reports and payment history
- Edit profile
- Dashboard of assigned appointments with status updates
- Guided consultation workflow: chief complaint → diagnosis & notes → prescription → lab test requests → complete
- Weekly schedule and leave management
- Earnings and monthly consultation analytics
- Profile and availability settings
- Overview dashboard with platform stats and a 30-day revenue chart
- Manage users: filter by role, verify or reject doctors, suspend or reactivate accounts
- Reports and audit logs with filters and pagination
- Profile and settings
Home, About, Services, Pricing, FAQ, Contact, plus Login and Register, a custom 404, a global error boundary, and SEO metadata, sitemap and robots.txt.
| Concern | Choice |
|---|---|
| Framework | Next.js 15 (App Router), React 19, TypeScript |
| Styling / UI | Tailwind CSS v4, shadcn/ui-style components on Radix UI, Lucide icons |
| Server state | TanStack Query |
| Client state | Zustand (persisted auth store) |
| Forms | React Hook Form + Zod |
| HTTP | Axios with Bearer injection and de-duplicated refresh-on-401 |
| Auth | Backend-issued JWT (access + refresh) with a role cookie for middleware gates |
| Charts | Recharts (lazy-loaded) |
| Notifications | Sonner |
| Payments | SSLCommerz (test mode), redirect-based |
Palette: #091540 navy · #1B2CC1 royal · #7692FF periwinkle · #ABD2FA sky.
Browser ──▶ middleware.ts ──▶ App Router page
│ reads hms_role cookie │
│ redirects by role ▼
│ TanStack Query hook
▼ │
/login?redirect=… ▼
lib/api/* (typed service functions)
│
▼
apiClient (axios + interceptors)
│
▼
REST API /api/v1 (Express)
- Service layer.
src/lib/api/*returns typedApiSuccess<T>values. A response interceptor rejects failures, so pages readdata?.dataand letonErrortoast problems. - Route protection. Middleware cannot read
localStorage, so login also sets a lightweighthms_rolecookie used only for redirects. The JWT in the persisted store is the source of truth for API calls, and the backend re-validates every request. - Shared components.
DataTable,StatCard,StatusBadge,SearchInput,PaginationBar,EmptyState,ConfirmDialogandPageHeaderare reused across all dashboards. - Hooks.
useAuth,useDebounce,usePaginationanduseQueryState(URL-synced state).
Requirements: Node.js 20+ (22 recommended) and npm.
git clone <this-repo-url>
cd hospital-frontend
npm install
cp .env.example .env.local # already points at the deployed API
npm run dev # http://localhost:3000| Variable | Default | Purpose |
|---|---|---|
NEXT_PUBLIC_API_URL |
https://hospital-management-system-ten-ivory.vercel.app/api/v1 |
Backend base URL |
NEXT_PUBLIC_SITE_URL |
https://medicare-hms.example.com |
Canonical URL for metadata & sitemap |
Start the API from the backend repo (npm run dev, port 5000), then set
NEXT_PUBLIC_API_URL=http://localhost:5000/api/v1 in .env.local.
| Command | What it does |
|---|---|
npm run dev |
Start the dev server |
npm run build |
Production build |
npm start |
Serve the production build |
npm run lint |
ESLint |
npm run typecheck |
tsc --noEmit |
npm run format |
Prettier (write) |
npm run check |
Lint + typecheck + format check — the pre-commit gate |
src/
├── app/ # routes: public, auth, patient, doctor, admin, payment
├── components/
│ ├── ui/ # shadcn-style primitives (button, form, table, dialog…)
│ ├── shared/ # DataTable, StatCard, StatusBadge, SearchInput…
│ ├── charts/ # lazy-loaded Recharts components
│ ├── layout/ # SiteHeader, SiteFooter, DashboardShell
│ └── providers/ # TanStack Query provider
├── hooks/ # useAuth, useDebounce, usePagination, useQueryState
├── lib/
│ ├── api/ # typed service functions per backend resource
│ ├── api-client.ts # axios instance + auth refresh interceptor
│ └── demo-accounts.ts # one-click demo login
├── store/ # Zustand auth store
├── types/ # API contract types
└── middleware.ts # role-based route protection
| Area | Routes |
|---|---|
| Public | /, /about, /services, /pricing, /faq, /contact, /login, /register |
| Patient | /patient, /patient/doctors, /patient/doctors/[id], /patient/appointments, /patient/appointments/[id], /patient/prescriptions, /patient/prescriptions/[id], /patient/lab-reports, /patient/payments, /patient/profile |
| Doctor | /doctor, /doctor/appointments/[id], /doctor/schedule, /doctor/earnings, /doctor/profile |
| Admin | /admin, /admin/users, /admin/reports, /admin/profile |
| Payment | /payment/success, /payment/cancel |
- The patient books a slot, which creates an appointment in
PENDING_PAYMENT. - The frontend calls
POST /payments/initiate; the backend creates the SSLCommerz session using the server-side fee snapshot and returns a gateway URL. - The browser is redirected to SSLCommerz to pay.
- SSLCommerz redirects back to
/payment/successor/payment/cancel, which load the appointment's real status from the API.
The client never sends an amount and never declares a payment successful; the backend verifies every transaction independently.
- Strict TypeScript, no
any - ESLint (Next.js config) and Prettier enforced via
npm run check loading.tsxskeletons anderror.tsxboundaries on every data route- Accessible forms with inline Zod validation messages and toast feedback
- Backend: 117 integration tests against an embedded PostgreSQL
- Jinna — github.com/Jinna89
- Facebook Md Nur Rahman and Code with Jinna
- LikedIn Jinna89
- YouTube Code with Jinna