A full-stack admin dashboard template built with React 19 + MUI + Redux Toolkit on the frontend and FastAPI on the backend. All backend data is stored in-memory (mock) so the project runs with zero database setup.
| Layer | Technology |
|---|---|
| Frontend framework | React 19, TypeScript, Vite |
| UI library | MUI v7 (Material UI) + MUI X Tree View |
| State management | Redux Toolkit + React Redux |
| Routing | React Router v7 |
| Charts | Recharts, D3.js |
| Maps | React Leaflet, Leaflet Geoman (drawing) |
| Tables | Material React Table v3 |
| File handling | react-dropzone, react-pdf, xlsx (SheetJS), mammoth, react-avatar-editor |
| Styling | MUI theming + Tailwind CSS v4 |
| Backend | FastAPI (Python) |
| Auth | JWT (HS256, 24-hour tokens) |
cd backend
pip install fastapi uvicorn python-jose[cryptography] pydantic
uvicorn main:app --reload
# Runs on http://localhost:8000
# Interactive API docs: http://localhost:8000/docscd frontend
npm install
npm run dev
# Runs on http://localhost:5173| Password | Role | |
|---|---|---|
| admin@example.com | password123 | admin |
| editor@example.com | password123 | editor |
ReactAdminTemplate/
├── backend/
│ ├── main.py # FastAPI app, CORS, router registration
│ └── routes/
│ ├── auth.py # JWT login endpoint
│ ├── users.py # User CRUD + /me profile endpoints
│ ├── maps.py # History markers, GeoJSON, presets, drawn shapes
│ └── files.py # File upload / download / metadata CRUD
│
└── frontend/src/
├── app/
│ └── store.ts # Redux store (6 slices registered)
├── features/
│ ├── auth/authSlice.ts
│ ├── theme/themeSlice.ts
│ ├── charts/chartsSlice.ts
│ ├── users/usersSlice.ts
│ ├── maps/mapsSlice.ts
│ └── files/filesSlice.ts
├── pages/
│ ├── Landing.tsx
│ ├── SignIn.tsx
│ ├── Dashboard.tsx
│ ├── Typography.tsx
│ ├── charts/Charts.tsx
│ ├── charts/RidgelineChart.tsx
│ ├── users/Users.tsx
│ ├── users/UserAccount.tsx
│ ├── files/FileManager.tsx
│ ├── files/FileManager2.tsx
│ ├── maps/HistoryMap.tsx
│ ├── maps/GeoJsonMap.tsx
│ └── maps/CustomMap.tsx
├── components/common/
│ ├── FileDropzone.tsx
│ ├── fuctions.tsx # getStrength() password helper
│ ├── HadlingAvatars/
│ │ ├── AvatarDropzone.tsx
│ │ └── AvatarCropDialog.tsx
│ └── viewers/
│ ├── ImageViewer.tsx
│ ├── PdfViewer.tsx
│ ├── SpreadsheetViewer.tsx
│ └── DocViewer.tsx
└── routes/
└── routes.tsx # Route config object tree + flattenRoutes()
Public landing page. Displays the app name and a Sign In call-to-action button. No Redux state.
Two-panel authentication form.
- Left panel — demo video placeholder (hidden on mobile).
- Right panel — email + password form with show/hide password toggle.
- Pre-fills
admin@example.com / password123for quick demo access. - On success dispatches
signIn()and redirects to/dashboard. - Shows inline error from
state.auth.erroron failed login.
Overview page with static KPI widgets and a weekly visits chart.
- 4 stat cards — Total Users, Revenue, Orders, Growth (with positive/negative trend indicators).
- Weekly Visits bar chart — 7-day data rendered with Recharts.
- All data is local to the component; no API calls.
Design-system reference page. Showcases all MUI typography variants — h1–h6, subtitle1/2, body1/2, caption, overline. Static, no Redux.
- Bar chart — 7-month sales vs. revenue comparison (Recharts
BarChart). - Donut chart — Traffic-source breakdown (Recharts
PieChart). - Data from
chartsSlice(static mock, no API calls). - Orange colour palette matching the light theme.
- D3.js ridge-line density chart showing 6 monthly value distributions.
- Uses kernel density estimation (
kernelEpanechnikovbandwidth). - Generates 300 random normally-distributed values per category.
- Re-renders automatically on light/dark theme switch.
Full user management built on material-react-table.
Table capabilities:
- Global search, column filters, sortable columns, pagination (5 / 10 / 25 rows).
- Role column — colour-coded MUI
Chip:admin= red,editor= blue,viewer= grey. - Status column — MUI
Chip:active= green,inactive= grey. - Inline Edit and Delete action buttons per row.
- Add User toolbar button opens the create dialog.
UserDialog (add / edit modal):
| Field | Behaviour |
|---|---|
| Avatar | Toggle between letter-initials and uploaded photo; photo uses AvatarDropzone + crop dialog |
| Name | Free text |
| Validated against RFC 5322 pattern; error shown on blur | |
| Role | Select: admin, editor, viewer |
| Status | Select: active, inactive |
| Joined | Date picker |
| Password | Show/hide toggle; live LinearProgress strength bar (Weak / Fair / Good / Strong) |
Save is disabled until email is valid and (for new users) a password is provided.
Personal profile page for the signed-in user. Hidden from the sidebar navigation.
- Displays current name, email, and role (read-only chip).
- Avatar — toggle between letter avatar and photo; photo goes through the crop dialog before saving.
- New Password field with show/hide toggle.
- Submitting dispatches
updateProfile()→PUT /users/me.
Drag-and-drop file manager with folder organisation and real-time search.
Upload flow:
- Drop files onto the
FileDropzone(images, PDF, XLS/XLSX, DOC/DOCX, CSV, TXT). - A FileInfoDialog opens per file to collect description, tags (chip input), project, and folder.
- File content is base64-encoded (data-URL) and stored via
POST /files/.
Browse & navigate:
- Search bar — filters by filename, tags, and project in real-time. Active search spans all folders.
- Folder cards — clickable cards in the root view navigate into a named folder.
- Breadcrumbs — shows
All Files / folderNamewith a back link to root.
File cards:
- Images show a thumbnail preview; all other types show a colour-coded icon.
- Displays name, size, upload date, project label, description, and tags.
- Edit opens
EditDialogpre-filled with existing metadata. - Delete dispatches
deleteFile()immediately. - Click opens the appropriate type-specific viewer.
Viewers:
| File type | Viewer | Library |
|---|---|---|
| Image | ImageViewer |
react-avatar-editor — zoom + rotate sliders, view-only |
PdfViewer |
react-pdf — page-by-page navigation | |
| XLS / XLSX / CSV | SpreadsheetViewer |
xlsx (SheetJS) → sticky-header MUI Table |
| DOC / DOCX / TXT | DocViewer |
mammoth (DOCX → HTML) / atob (TXT → <pre>) |
Enhanced file manager with a MUI X SimpleTreeView sidebar replacing the folder-card navigation.
Tree panel (left, 240 px, sticky):
All Filesroot node — shows total file count; root node cannot be collapsed.- Folder child nodes — one per unique
foldervalue; shows name + file count badge. - Selecting a tree node instantly filters the right-side file grid.
- Search bar inside the panel; when a query is active the folder filter is suspended and results span all folders.
- A context label shows
Searching across all foldersorFolder: <name>depending on state.
Folder lock:
- Each folder node has a lock toggle button (🔒).
- Clicking it dispatches
toggleFolderLock(folderName)to the Redux store. - Locked folder — icon and label dim; lock button turns red.
- Files in a locked folder — Edit and Delete buttons are disabled; a lock icon appears in the card footer.
- Lock state is stored in
state.files.lockedFolders: string[]and persists for the session. - Upload dialog pre-fills the Folder field with the currently selected tree node.
World map displaying 15 global financial centres as circle markers.
- Marker colour = performance: green (positive change) → red (negative change).
- Click a marker → side panel shows city name, rate value, and % daily change.
- Data from
GET /maps/history.
Choropleth world map colouring 8 regions by a performance index (0–100).
- 5-step colour scale (light → dark as value increases).
- Click a polygon → side panel shows region name, value, population, GDP, and growth.
- Data from
GET /maps/geojson.
Interactive map combining drawing tools and preset location management.
Preset locations (side panel):
- Loads landmarks, airports, ports, and research sites from
GET /maps/custom. - Add / Edit / Delete presets with a dialog (name, type, description, coordinates).
- Clicking a preset centres and zooms the map to that location.
Drawing tools (Leaflet Geoman):
- Draw circles, rectangles, polygons, and polylines directly on the map.
- Edit and delete previously drawn shapes.
- Save Shapes — posts drawn shapes to
POST /maps/shapesand clears the local buffer. - Saved shapes are loaded on next visit via
GET /maps/shapes. - Edit and delete saved shapes via the shapes panel.
| Field | Type | Description |
|---|---|---|
token |
string | null |
JWT stored in localStorage |
user |
User | null |
{ id, name, email, role, avatar_mode, avatar_base64 } |
loading |
boolean |
Pending request indicator |
error |
string | null |
Last auth error message |
Reducers: signOut(), setUser(user)
Thunks: signIn({ email, password }), fetchCurrentUser(), updateProfile({ name?, email?, avatar_base64?, avatar_mode? })
| Field | Type | Description |
|---|---|---|
mode |
'light' | 'dark' |
Persisted to localStorage |
Reducers: toggleTheme(), setTheme(mode)
| Field | Type | Description |
|---|---|---|
barData |
BarDataPoint[] |
7 months × { month, sales, revenue } |
donutData |
DonutDataPoint[] |
4 traffic sources × { name, value } |
Static mock data; no thunks.
| Field | Type | Description |
|---|---|---|
list |
UserRow[] |
{ id, name, email, role, status, joined, avatar_mode?, avatar_base64? } |
loading |
boolean |
Fetch in-progress |
saving |
boolean |
Create/update/delete in-progress |
error |
string | null |
Thunks: fetchUsers(), createUser(payload), updateUser(user), deleteUser(id)
| Field | Type | Description |
|---|---|---|
markers |
HistoryMarker[] |
{ id, name, lat, lng, value, change, project } |
geoData |
GeoJSON | null |
8-region FeatureCollection |
customItems |
CustomMapItem[] |
Preset locations |
drawnShapes |
DrawnShape[] |
In-progress drawing buffer (local only) |
savedShapes |
StoredShape[] |
Shapes persisted on the backend |
Thunks: fetchHistoryMarkers, fetchGeoJson, fetchCustomMap, addPreset, updatePreset, deletePreset, fetchShapes, saveShapes, updateSavedShape, deleteSavedShape
Reducers: addDrawnShape, updateDrawnShape, removeDrawnShape, clearDrawnShapes
| Field | Type | Description |
|---|---|---|
list |
FileItem[] |
{ id, name, mime_type, size, description, tags, uploaded, project, folder, content_base64? } |
loading |
boolean |
Fetch in-progress |
saving |
boolean |
Upload/update/delete in-progress |
error |
string | null |
|
lockedFolders |
string[] |
Folder names currently locked in File Manager v2 |
Thunks: fetchFiles(), fetchFile(id), uploadFile(payload), updateFile({ id, description, tags, project, folder }), deleteFile(id)
Reducers: toggleFolderLock(folderName) — adds to / removes from lockedFolders
All endpoints (except /auth/login) require an Authorization: Bearer <token> header.
| Method | Path | Body | Response |
|---|---|---|---|
| POST | /auth/login |
{ email, password } |
{ access_token, token_type, user } |
| Method | Path | Description |
|---|---|---|
| GET | /users/me |
Current user profile |
| PUT | /users/me |
Update name, email, avatar |
| GET | /users/ |
List all users (10 seed entries) |
| POST | /users/ |
Create user (auto-increment ID) |
| PUT | /users/{id} |
Update user by ID |
| DELETE | /users/{id} |
Delete user by ID |
| Method | Path | Description |
|---|---|---|
| GET | /maps/history |
15 financial centre markers |
| GET | /maps/geojson |
8-region GeoJSON FeatureCollection |
| GET | /maps/custom |
List preset locations (12 seeds) |
| POST | /maps/custom |
Add preset location |
| PUT | /maps/custom/{id} |
Update preset location |
| DELETE | /maps/custom/{id} |
Delete preset location |
| GET | /maps/shapes |
List saved drawn shapes |
| POST | /maps/shapes |
Append new drawn shapes (accumulates) |
| PUT | /maps/shapes/{id} |
Update saved shape |
| DELETE | /maps/shapes/{id} |
Delete saved shape |
| Method | Path | Description |
|---|---|---|
| GET | /files/ |
List all files — content_base64 excluded |
| GET | /files/{id} |
Single file including content_base64 |
| POST | /files/ |
Upload file (full payload including base64) |
| PUT | /files/{id} |
Update description, tags, project, folder |
| DELETE | /files/{id} |
Delete file |
Drag-and-drop zone. Accepts: images, PDF, XLS/XLSX, DOC/DOCX, CSV, TXT.
Props: onFiles(files: File[]) => void
Single-image drop zone for avatar upload.
Props: onFile(objectUrl: string) => void, compact?: boolean
Crop/zoom/rotate dialog using react-avatar-editor. Calls onApply(base64) when confirmed.
Props: open, onClose, onApply(base64: string), image: string | null, title
Full-screen dialog. Zoom slider (0.5×–4×) + rotation slider (0°–360°). View-only, no save.
Props: open, onClose, src: string, title?: string
Dialog rendering a PDF via react-pdf. Previous/Next page navigation, shows current page number.
Props: open, onClose, src: string, title?: string
Dialog that parses XLS/XLSX/CSV using SheetJS and renders the first sheet as a sticky-header MUI Table (max height 500 px).
Props: open, onClose, src: string, fileName: string
Dialog for DOCX and TXT. DOCX → HTML via mammoth (rendered with dangerouslySetInnerHTML). TXT → decoded with atob and shown in a monospace <pre> block.
Props: open, onClose, src: string, mimeType: string, fileName: string
Scores a password 1–4 and returns { score, label, color } for the strength indicator bar.
| Score | Label | Colour |
|---|---|---|
| 1 | Weak | red |
| 2 | Fair | orange |
| 3 | Good | light green |
| 4 | Strong | dark green |
Routes are declared as a typed RouteConfig[] tree in routes/routes.tsx. The children field enables grouped sidebar items.
/ Landing (public)
/signin Sign In (public)
/dashboard Dashboard (nav)
/account User Account (hidden from nav)
/typography Typography (nav)
/charts ── group ── (nav)
/charts/barchart Bar & Donut Charts
/charts/ridgeline Ridgeline Chart
/users Users Table (nav)
/files ── group ── (nav)
/files/files1 File Manager
/files/files2 File Manager v2
/maps ── group ── (nav)
/maps/history History Map
/maps/geojson GeoJSON Map
/maps/custom Custom / Drawing Map
flattenRoutes(list) — recursively flattens the config tree into routable leaf nodes (nodes that have an element component). Used by the React Router setup.
Two colour modes, toggled via the header button. Mode is persisted to localStorage.
| Mode | Primary colour |
|---|---|
| Light | Orange #f97316 |
| Dark | Orange #f97316 (same accent, dark backgrounds) |