GitHunt
PO

poal98-hakim/real-time-dashboard

Responsive real-time dashboard built with Next.js 15, TailwindCSS & TypeScript. Features include API polling, customizable widgets, theme support and a scalable multi-layer architecture.

Real-Time Dashboard

A responsive, real-time dashboard built with Next.js 15, React 19, TypeScript, and Tailwind CSS. It features live data polling, a customizable widget grid, theme switching, and persistent user layout.

Deployment

Features

  • Real-time updates: 5-second polling with pause/resume and manual refresh
  • Customizable layout: drag, resize, add/remove widgets; persistent via localStorage
  • Theme switching: light/dark with cookie persistence; server-generated tokens
  • Rich widgets: line and bar charts, table with pagination/selection, map with markers
  • Typed boundaries: Zod validation (server-side) + Result pattern for safe error handling
  • User feedback: toast notifications on failures; friendly error messages

User Journey

  1. Landing

    • The header shows “Reset to default”, an “Edit mode” switch, and the theme toggle.
    • The subheader shows “Last updated …”, a pause/resume polling button, a manual refresh, and an “Add widget” menu when widgets are available to add.
  2. Live data

    • Data auto-refreshes every 5 seconds via the DashboardRepository. The subheader’s timestamp updates using a relative “from now” label.
    • Users can pause/resume polling or click refresh for an immediate update.
    • Errors show as toasts with a user-friendly message while keeping previous data visible.
  3. Customizing the dashboard

    • Toggle “Edit mode” to enable dragging/resizing widgets (react-grid-layout) and reveal remove buttons on each card.
    • Remove a widget from its card; re-add it via the “Add widget” menu in the subheader.
    • Layout changes persist automatically to localStorage.
  4. Theme and persistence

    • Toggle light/dark via the header button. Preference is stored in a cookie; CSS tokens are generated server-side and applied inline.

Architecture & Design

Layered framework-agnostic architecture for separation of concerns and testability:

  1. Services

    • src/services/dashboard/dashboard.ts calls the Next API route (by default NEXT_PUBLIC_API_PATH=/api/dashboard).
    • HTTP communication uses native fetch with simple timeout handling. Service returns Result<DashboardDTO>.
    • DTO type is shared from server schemas. Validation happens in the API route (see API Layer).
  2. Repositories (Centralized State)

    • DashboardRepository (src/repositories/dashboard) owns polling, loading state, lastUpdatedAt, and normalized data (PM — Presentation Model). It publishes toasts on failures.
    • LayoutRepository (src/repositories/layout) owns grid layout, edit mode, and persistence with zustand + persist to localStorage.
    • NotificationsRepository drives toasts.
  3. Presenters (Mapping to VM for UI/Business logic)

    • WidgetGridPresenter hydrates initial PM into the DashboardRepository, manages polling start/stop, and maps PM -> VM for widgets.
    • HeaderPresenter toggles edit mode and layout reset;
    • SubHeaderPresenter toggles polling, refreshes data, and computes “addable” widgets.
  4. UI Components (Pure React)

    • Widget grid uses react-grid-layout (src/components/WidgetGrid). Charts use recharts, maps use react-leaflet.
    • Theming: tokens generated server-side (src/server/theme) with a small cookie-driven action layer; CSS variables injected via <style> in src/app/layout.tsx.
  5. API Layer (Next.js Route)

    • src/app/api/dashboard/route.ts proxies to https://dashboard-api-dusky.vercel.app/api/get.
    • Validates upstream response with Zod (src/server/schemas/dashboard.schema.ts) and returns a guaranteed shape.
    • Keeps secrets server-side and avoids CORS issues from the client.

Key design decisions:

  • Result + server-side Zod: safer IO and uniform, user-friendly errors.
  • Repositories as single sources of truth: polling, persistence, and view subscriptions centralized.
  • Presenters isolate view-specific transforms and reduce component complexity.
  • Proxied API route protects tokens and centralizes backend config.
  • Server-generated theme tokens ensure consistent design with minimal runtime cost.
  • Charts are dynamically imported in WidgetGrid and chart animations are disabled to reduce jank during polling
  • Fetch initial dashboard data on the server and WidgetGridPresenter.setInitialData(pm) hydrates the DashboardRepository in a useLayoutEffect before first paint to avoid flicker.

Tech Stack

  • Next.js 15, React 19, TypeScript
  • Zustand for state; Zod for schema validation
  • Native fetch for HTTP; React Grid Layout for drag/resize
  • Recharts for charts; React Leaflet + Leaflet for maps
  • Vitest + Testing Library for tests

Setup

Prerequisites:

  • Node.js
  • npm
  1. Install dependencies
npm install
  1. Configure environment

Create .env.local in the project root:

NEXT_PUBLIC_API_PATH=/api/dashboard
API_PATH=https://dashboard-api-dusky.vercel.app/api/get
API_TOKEN=your_api_token_here
# Optional: return randomized stub data instead of calling upstream API
# USE_STUBS=true

Notes:

  • API_TOKEN is used by the Next.js route to call the upstream API.
  • Set USE_STUBS=true to serve randomized demo data on each request (skips upstream fetch).
  1. Run the app
npm run dev
  1. Build and start (production)
npm run build
npm start
  1. Lint
npm run lint

Testing

This project uses Vitest.

npm test

Created few tests for showcasing:

  • src/integration-tests/homeFlow.test.ts: black-box integration of the home flow. It verifies presenter–repository interactions, polling toggles, layout add/remove behaviors, and “last updated” timing labels.
  • src/components/SubHeader/SubHeader.test.tsx: UI tests for the react component.

Languages

TypeScript96.1%CSS3.3%JavaScript0.6%

Contributors

Created August 29, 2025
Updated September 12, 2025
poal98-hakim/real-time-dashboard | GitHunt