A full-stack retail intelligence dashboard built with Next.js 16, designed to help grocery store chains manage inventory, forecast demand, and keep shelves stocked β all in one place
FreshMart is an internal operations tool for a fictional grocery retail chain with 25 store locations across India. The platform gives store managers and regional directors a real-time view into sales performance, stock levels, and demand trends β without needing to dig through spreadsheets or wait for end-of-week reports.
Think of it as the command center for a mid-to-large retail operation: you walk in, see what's running low, what's selling fast, which store is crushing it this week, and what needs attention before it becomes a problem.
Dashboard β A personalized welcome screen that greets the manager by name, shows today's sales vs. target, forecast accuracy, stockout risk, and a breakdown of top-performing stores across the network.
Products Inventory β Browse all 17+ products across Dairy, Produce, Bakery, and Pantry categories. Filter by category or stock status, search by name, and click any product for a detailed modal showing a 7-day demand forecast, demand driver breakdown, and stock level visualization.
Alerts & Notifications β A live alerts feed sorted by severity (critical, warning, info). Cards are color-coded and dismissible. The header bell icon opens a slide-out notification panel with mark-as-read and clear-all functionality.
Insights & Analytics β Weekly performance charts, a demand heatmap by category and day, a category performance scatter plot, and an "Opportunities" section that surfaces revenue growth ideas with estimated impact.
Analytics Page β Forecast accuracy trends over time, sales distribution by category (pie chart), and key performance metrics like inventory turnover and waste reduction.
Settings β Full store profile management, notification preferences per alert type, auto-reorder configuration, and security options. All backed by local state (no API calls needed to explore).
Store Selector β The sidebar includes a dropdown to switch between all 25 Indian city stores, updating every dashboard metric in real time.
Profile Panel β Slide-out panel showing manager info, performance summary, and quick links to Store Settings and Inventory Preferences β each with their own dedicated panels.
| Layer | Choice | Why |
|---|---|---|
| Framework | Next.js 16 (App Router) | File-based routing, RSC support, fast builds |
| Language | TypeScript | Type safety across the entire codebase |
| Styling | Tailwind CSS v4 | Utility-first, fast iteration |
| UI Components | shadcn/ui + Radix UI | Accessible, unstyled primitives |
| Charts | Recharts | Flexible, React-native charting |
| Icons | Lucide React | Consistent, clean icon set |
| State | React Context + useState | Lightweight, no external store needed |
| Analytics | Vercel Analytics | Zero-config page view tracking |
| Fonts | Geist (Next.js native) | Clean, modern sans-serif |
βββ app/
β βββ dashboard/ # Main dashboard page
β βββ products/ # Product inventory grid + modals
β βββ alerts/ # Alert management
β βββ insights/ # Deep analytics + heatmap
β βββ analytics/ # Charts and performance metrics
β βββ settings/ # Store config and preferences
β βββ login/ # Admin login page
β βββ layout.tsx # Root layout with providers
β βββ globals.css # Theme variables + base styles
β
βββ components/
β βββ app-layout.tsx # Sidebar + header shell
β βββ product-card.tsx # Individual product card with sparkline
β βββ product-detail-modal.tsx # Full product deep-dive
β βββ notification-panel.tsx # Slide-out notifications
β βββ profile-panel.tsx # Slide-out user profile
β βββ inventory-preferences.tsx # Category-level inventory config
β βββ store-settings.tsx # Store operational settings
β βββ home-page.tsx # Public landing page
β βββ admin-login.tsx # Login form with validation
β βββ ui/ # shadcn/ui component library
β
βββ lib/
β βββ data.ts # All mock data, types, and interfaces
β βββ store-context.tsx # Global store state (React Context)
β βββ utils.ts # cn() helper + currency formatter
β
βββ hooks/
βββ use-mobile.ts
βββ use-toast.ts
Prerequisites: Node.js 20.9.0 or higher, npm or pnpm.
# Clone the repo
git clone https://github.com/your-username/freshmart-dashboard.git
cd freshmart-dashboard
# Install dependencies
npm install
# Start the dev server
npm run devOpen http://localhost:3000 and you'll land on the public homepage. Hit Admin Login and use:
Email: admin@freshmart.com
Password: admin123
That drops you straight into the dashboard for the Hyderabad Central store.
npm run dev # Local dev server at localhost:3000
npm run build # Production build
npm run start # Serve the production build
npm run lint # ESLint checkEverything runs on mock data defined in lib/data.ts. There's no database or external API β the app is entirely self-contained and works offline.
Here's what's included:
- 25 stores across India (Hyderabad, Mumbai, Delhi, Bengaluru, Chennai, and more), each with real metrics like forecast accuracy, stockout rates, sales targets, and staff counts
- 17 products across 4 categories, complete with current/required stock levels, demand trend arrays (for sparklines), pricing, turnover rates, and risk badges
- Mock alerts covering stockout risks, demand spikes, and informational notices
- Mock notifications with read/unread state and type-based styling
- Category heatmap data showing demand by day of week
- Inventory preferences with per-category thresholds and auto-reorder config
The StoreProvider wraps the whole app and makes the currently selected store available anywhere via useStore(). Switching stores in the sidebar immediately updates all dashboard figures.
Theme: The app uses a warm, earthy color palette inspired by fresh produce and natural grocery aesthetics β deep forest green (#2d5016) as the primary, burnt orange (#e67e22) as the accent, and off-white backgrounds. The sidebar stays dark green while the main content area stays light, creating a clear visual hierarchy.
Dark mode quirk: The .dark class in globals.css is actually overridden to use the light grocery theme β this was an intentional design choice so the app feels warm and retail-appropriate rather than techy-dark.
Sparklines on product cards: Each product card renders a tiny inline SVG chart using raw path calculations β no extra chart library needed for these. They update based on the demandTrend array in the product data.
Slide-out panels: Notifications, profile, store settings, and inventory preferences all use fixed-position slide-in panels rather than modals β keeps the main content visible and feels more like a native app sidebar.
AppLayout β The main shell. Handles the sidebar (with store selector and nav), the top header (with notification bell and profile avatar), mobile toggle, and renders child page content in the scrollable main area.
ProductCard β Renders a single product tile with category badge, image, stock progress bar, price/turnover stats, an inline sparkline chart, and a status badge. Clicking opens the detail modal.
ProductDetailModal β A Dialog component that shows a product's full stats: a Recharts line chart for 7-day demand forecast, a horizontal bar breakdown of demand drivers (base demand, weekend boost, seasonal, promotional), and metadata chips.
InventoryPreferencesPanel β A comprehensive settings panel for per-store inventory rules. Covers low stock thresholds, auto-reorder triggers, supplier preferences, delivery frequency, overstock protection, and category-level rules for each of the 6 product categories.
A few things are wired up visually but don't persist beyond the session:
- Save Settings β The settings page UI is complete but saving writes to local React state only (no localStorage or API)
- Real auth β Login validates against a hardcoded credential; no JWT or session management
- Search on the products page filters the visible list but doesn't persist across navigation
- Alert dismiss state resets on page refresh
If you're extending this into a real product, the natural next steps would be hooking up a backend (Supabase or a REST API), adding proper auth (NextAuth.js works well here), and replacing the mock data with live database queries.
All CSS variables live in app/globals.css under the .dark selector (yes, even though it's a light theme β see the design note above). To change the brand colors:
.dark {
--primary: #2d5016; /* sidebar, primary buttons */
--accent: #e67e22; /* highlights, badges, rings */
--background: #faf8f6; /* main content area */
--sidebar: #2d5016; /* sidebar background */
}Open lib/data.ts and add an entry to the mockStores array:
{
id: 'store-26',
name: 'FreshMart Surat West',
city: 'Surat',
region: 'West',
status: 'online',
salesTarget: 45000,
actualSales: 47200,
forecastAccuracy: 93.1,
stockoutRate: 1.2,
overstockRate: 1.8,
averageStock: 86,
topProduct: 'Organic Milk',
staffCount: 24,
lastUpdated: new Date(),
managerName: 'Priya Mehta',
managerPhone: '+91-9876543235',
}It'll automatically appear in the sidebar dropdown and get included in all network-wide calculations.
In lib/data.ts, add to mockProducts:
{
id: '18',
name: 'Alphonso Mangoes - 1kg',
category: 'Produce',
image: 'https://images.unsplash.com/photo-...?w=400&h=400&fit=crop',
currentStock: 120,
requiredStock: 200,
status: 'attention',
trend: 'up',
demandTrend: [80, 95, 110, 125, 140, 130, 120],
price: 5.49,
turnoverRate: 13.2,
}It'll show up on the Products page immediately with a working sparkline, stock bar, and clickable detail modal.
MIT β use it, fork it, ship it. No attribution required, though it's always appreciated.
Built with Next.js, shadcn/ui, Recharts, and Tailwind CSS. Product images sourced from Unsplash. Icons by Lucide.