A modern, responsive patient directory web application built with Next.js, React, and Tailwind CSS. Browse, search, filter, sort, and export patient records with a polished UI featuring dark/light theme support.
- 🔄 Dual View Modes — Switch between detailed table view and responsive card grid view with smooth animated transitions
- 🔍 Smart Search — Debounced full-text search across patient name, medical issue, email, address, and phone number
- 🏷️ Filter by Medical Issue — Checkbox-based filter dropdown with active filter chips
- 📊 Flexible Sorting — Sort by Name, Age, ID, or Medical Issue with ascending/descending toggle
- 📄 Pagination — Full page navigation with Previous/Next buttons and numbered pages
- 📥 PDF Export — Download the current patient list as a formatted PDF with headers and filters
- 🌓 Dark / Light Theme — Toggle between themes with localStorage persistence and system preference detection
- ⚡ Loading Skeletons — Pulse-animated skeleton placeholders for both table and card views
- 📱 Responsive Design — Fully responsive layout from mobile to desktop (1-4 column card grid)
| Layer | Technology |
|---|---|
| Framework | Next.js 16 (App Router) |
| Language | TypeScript 5 |
| UI Library | React 19 |
| Styling | Tailwind CSS 4 |
| PDF Export | jsPDF + jspdf-autotable |
| Linting | ESLint 9 + eslint-config-next |
assignment/
├── app/
│ ├── api/
│ │ └── patients/
│ │ └── route.ts # GET /api/patients — paginated, filterable API
│ ├── components/
│ │ ├── CardView.tsx # Card grid view
│ │ ├── FilterPanel.tsx # Standalone filter panel
│ │ ├── Pagination.tsx # Page navigation
│ │ ├── PatientAvatar.tsx # Color-coded initials avatar
│ │ ├── SearchBar.tsx # Search input + inline filter dropdown
│ │ ├── Skeletons.tsx # Loading skeletons (table + card)
│ │ ├── SortControls.tsx # Sort-by buttons
│ │ ├── TableView.tsx # Table view
│ │ ├── ThemeProvider.tsx # Dark/light theme context + provider
│ │ └── ThemeToggle.tsx # Theme toggle button (sun/moon)
│ ├── hooks/
│ │ ├── useDebounce.ts # Generic debounce hook
│ │ └── usePatients.ts # Data-fetching hook with filter/sort/pagination
│ ├── lib/
│ │ ├── exportPdf.ts # PDF generation with jsPDF
│ │ └── types.ts # TypeScript interfaces + constants
│ ├── globals.css # Tailwind imports + custom animations + dark mode
│ ├── layout.tsx # Root layout with ThemeProvider
│ └── page.tsx # Main page (PatientDirectory)
├── data/
│ └── patients.json # Mock patient data (~100 records)
├── public/ # Static assets
├── .gitignore
├── eslint.config.mjs
├── next.config.ts
├── package.json
├── postcss.config.mjs
├── tsconfig.json
└── README.md
- Node.js 18.17 or later
- npm, yarn, pnpm, or bun
# Clone the repository
git clone <repository-url>
cd assignment
# Install dependencies
npm installnpm run devOpen http://localhost:3000 in your browser.
npm run build
npm startnpm run lintReturns paginated patient data with optional filtering and sorting.
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
page |
number | 1 |
Page number |
limit |
number | 10 |
Items per page (max 100) |
search |
string | — | Search across name, issue, email, address, phone |
medicalIssue |
string | — | Comma-separated list of medical issues |
sortBy |
string | patient_id |
Field to sort by (patient_id, patient_name, age, medical_issue) |
sortOrder |
string | asc |
asc or desc |
Response:
{
"patients": [
{
"patient_id": 1,
"patient_name": "John Doe",
"age": 45,
"photo_url": null,
"contact": [
{
"address": "123 Main St",
"number": "+1234567890",
"email": "john@example.com"
}
],
"medical_issue": "fever"
}
],
"total": 100,
"page": 1,
"limit": 10,
"totalPages": 10
}- Table View: Displays 10 patients per page in a sortable table with clickable column headers
- Card View: Displays 12 patients per page in a responsive grid (1-4 columns based on screen size)
- Real-time search with 300ms debounce to optimize API calls
- Multi-select medical issue filter with visual chips
- Active filter count badge
- Clear individual filters via chip close buttons
- System preference detection on first visit
- Manual toggle between light and dark modes
- Preference persisted in localStorage
- Smooth transitions between themes
- Exports current filtered/sorted patient list
- Includes header with timestamp
- Shows active filters and search terms
- Formatted table with page numbers
The application supports the following medical issues with color-coded badges:
- Fever
- Headache
- Sore Throat
- Sprained Ankle
- Rash
- Ear Infection
- Sinusitis
- Allergic Reaction
- Stomach Ache
- Broken Arm
The easiest way to deploy this Next.js app is to use the Vercel Platform.
Check out the Next.js deployment documentation for more details.
This project is private and proprietary.
This is a private project. Contributions are not currently accepted.
Built with ❤️ using Next.js and Tailwind CSS