diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index e2e3459c..866fc803 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -1,7 +1,6 @@ import { BrowserRouter as Router, Routes, Route, Navigate } from 'react-router-dom'; import Layout from './components/Layout.tsx'; import Dashboard from './pages/Dashboard.tsx'; -import StoreDashboard from './pages/StoreDashboard.tsx'; import BaseMenu from './pages/BaseMenu.tsx'; import Products from './pages/Products.tsx'; import Orders from './pages/Orders.tsx'; @@ -48,7 +47,6 @@ function App() { }> } /> } /> - } /> {/* Sale */} } /> diff --git a/frontend/src/components/Sidebar.tsx b/frontend/src/components/Sidebar.tsx index 409501af..9794e8ec 100644 --- a/frontend/src/components/Sidebar.tsx +++ b/frontend/src/components/Sidebar.tsx @@ -40,7 +40,6 @@ interface MenuItem { const menuItems: MenuItem[] = [ { title: 'Dashboard', icon: Gauge, path: '/dashboard' }, - { title: 'Store Dashboard', icon: LayoutGrid, path: '/store-dashboard' }, { title: 'Sale', icon: Receipt, @@ -97,7 +96,7 @@ const menuItems: MenuItem[] = [ icon: Store, subMenu: [ { title: 'Terminals', path: '/stores/terminals' }, - { title: 'Managers', path: '/stores/managers' }, + { title: 'Managers', path: '/stores/staffs' }, { title: 'Staffs', path: '/stores/staffs' }, { title: 'Stalls', path: '/stores/stalls' } ] @@ -131,7 +130,6 @@ const Sidebar = () => { // Map title to permission ID const permissionMap: Record = { 'Dashboard': 'dashboard', - 'Store Dashboard': 'dashboard', 'Sale': 'sale', 'Customers': 'customers', 'Purchases': 'purchases', diff --git a/frontend/src/pages/Dashboard.tsx b/frontend/src/pages/Dashboard.tsx index 1b02a183..ad088302 100644 --- a/frontend/src/pages/Dashboard.tsx +++ b/frontend/src/pages/Dashboard.tsx @@ -10,7 +10,8 @@ import { BarChart3, MessageSquare, Flame, - TrendingUp + TrendingUp, + UserMinus } from 'lucide-react'; import { AreaChart, @@ -29,6 +30,7 @@ import { motion } from 'framer-motion'; const Dashboard = () => { const navigate = useNavigate(); const [activeTab, setActiveTab] = useState('Sales'); + const [dashboardMode, setDashboardMode] = useState<'business' | 'store'>('business'); const [timeRange, setTimeRange] = useState('Today'); const [customDates, setCustomDates] = useState({ from: '', to: '' }); const [data, setData] = useState(null); @@ -36,7 +38,6 @@ const Dashboard = () => { const toLocalISOString = (date: Date) => { const tzo = -date.getTimezoneOffset(), - dif = tzo >= 0 ? '+' : '-', pad = (num: number) => { const norm = Math.floor(Math.abs(num)); return (norm < 10 ? '0' : '') + norm; @@ -136,9 +137,12 @@ const Dashboard = () => { const { stats, storeOverview, hourlySales, insights, trendingItems } = data; - const pieData = [ - { name: 'Full Payment', value: stats.periodRevenue, color: '#8b5cf6' }, - { name: 'Credit', value: 0, color: '#fbbf24' } + const pieData = dashboardMode === 'business' ? [ + { name: 'RITZ Spend', value: stats.periodRevenue, color: '#8b5cf6' }, + { name: 'Other', value: 0, color: '#fbbf24' } + ] : [ + { name: 'Store Revenue', value: stats.periodStoreRevenue, color: '#8b5cf6' }, + { name: 'Other', value: 0, color: '#fbbf24' } ]; return ( @@ -150,7 +154,7 @@ const Dashboard = () => { -

Dashboard

+

Dashboard Overview

Good morning, {(() => { @@ -160,7 +164,7 @@ const Dashboard = () => {

i - The default time settings for the merchant view are from 12:00 AM to 11:59 PM. + Combined metrics from both the Business (Ritz tokens) and Store performance parameters.

@@ -180,10 +184,31 @@ const Dashboard = () => { View Full Report - + {/* Mode Toggles */} +
+ + +
+ {/* Main Stats Grid */}
{/* Sales Chart Section */} @@ -207,7 +232,9 @@ const Dashboard = () => {
- {timeRange}'s Revenue + + {timeRange}'s {dashboardMode === 'business' ? 'Circulation' : 'Revenue'} +
@@ -222,7 +249,12 @@ const Dashboard = () => { - v >= 1000 ? `🅡${v / 1000}k` : `🅡${v}`} /> + dashboardMode === 'business' ? (v >= 1000 ? `🅡${v / 1000}k` : `🅡${v}`) : (v >= 1000 ? `₹${v / 1000}k` : `₹${v}`)} + /> @@ -234,7 +266,9 @@ const Dashboard = () => {
-

Total Revenue

+

+ {dashboardMode === 'business' ? 'Total Spent' : 'Total Revenue'} +

@@ -260,9 +294,13 @@ const Dashboard = () => {
-

🅡{(stats.periodRevenue || 0).toLocaleString()}

+

+ {dashboardMode === 'business' ? `🅡${(stats.periodRevenue || 0).toLocaleString()}` : `₹${(stats.periodStoreRevenue || 0).toLocaleString()}`} +

{timeRange === 'Today' ? 'Today' : timeRange}

-

Total: 🅡{(stats.totalSales || 0).toLocaleString()}

+

+ Total: {dashboardMode === 'business' ? `🅡${(stats.totalSales || 0).toLocaleString()}` : `₹${(stats.totalStoreRevenue || 0).toLocaleString()}`} +

{pieData.map(item => ( @@ -311,7 +349,7 @@ const Dashboard = () => {
{/* Total Orders Card */} -
+
@@ -319,8 +357,8 @@ const Dashboard = () => {

Total Orders

-

{stats.activeOrders}

-
+

{stats.activeOrders}

+
@@ -336,6 +374,19 @@ const Dashboard = () => {

₹{stats.periodExpenses.toLocaleString()}

+ + {/* Restricted Accounts Card */} +
+
+
+ +
+

Restricted Accounts

+
+
+

{stats?.suspendedUserCount || 0}

+
+
diff --git a/frontend/src/pages/StoreDashboard.tsx b/frontend/src/pages/StoreDashboard.tsx deleted file mode 100644 index 7feca2ad..00000000 --- a/frontend/src/pages/StoreDashboard.tsx +++ /dev/null @@ -1,438 +0,0 @@ -import { apiFetch } from '../api'; -import { useState, useEffect } from 'react'; -import { - ChevronRight, - ShoppingBag, - Wallet, - ArrowRight, - RotateCcw, - Star, - UserMinus -} from 'lucide-react'; -import { - AreaChart, - Area, - XAxis, - YAxis, - CartesianGrid, - Tooltip, - ResponsiveContainer, - PieChart, - Pie, - Cell -} from 'recharts'; -import { motion } from 'framer-motion'; - - -const StoreDashboard = () => { - const [activeTab, setActiveTab] = useState('Sales'); - const [timeRange, setTimeRange] = useState('Today'); - const [customDates, setCustomDates] = useState({ from: '', to: '' }); - const [stats, setStats] = useState({ - totalSales: 0, - activeOrders: 0, - dailyCustomers: 0, - revenueGrowth: 0, - suspendedUserCount: 0 - }); - const [trendingItems, setTrendingItems] = useState([]); - const [salesData, setSalesData] = useState([]); - const [insights, setInsights] = useState([]); - const [isLoading, setIsLoading] = useState(true); - - const formatCurrency = (val: any) => { - const num = Number(val); - return isNaN(num) ? '0' : num.toLocaleString(); - }; - - const toLocalISOString = (date: Date) => { - const tzo = -date.getTimezoneOffset(), - pad = (num: number) => { - const norm = Math.floor(Math.abs(num)); - return (norm < 10 ? '0' : '') + norm; - }; - return date.getFullYear() + - '-' + pad(date.getMonth() + 1) + - '-' + pad(date.getDate()) + - 'T' + pad(date.getHours()) + - ':' + pad(date.getMinutes()) + - ':' + pad(date.getSeconds()) + - '.' + pad(date.getMilliseconds()); - }; - - const getRangeDates = (range: string) => { - const now = new Date(); - const start = new Date(); - const end = new Date(); - - // Set end to end of today - end.setHours(23, 59, 59, 999); - - switch (range) { - case 'Today': - start.setHours(0, 0, 0, 0); - break; - case 'Yesterday': - start.setDate(now.getDate() - 1); - start.setHours(0, 0, 0, 0); - end.setDate(now.getDate() - 1); - end.setHours(23, 59, 59, 999); - break; - case 'Week': - start.setDate(now.getDate() - 7); - start.setHours(0, 0, 0, 0); - break; - case '30 Days': - start.setDate(now.getDate() - 30); - start.setHours(0, 0, 0, 0); - break; - case 'Custom': - if (customDates.from && customDates.to) { - const from = new Date(customDates.from); - from.setHours(0, 0, 0, 0); - const to = new Date(customDates.to); - to.setHours(23, 59, 59, 999); - return { from: toLocalISOString(from), to: toLocalISOString(to) }; - } - return null; - default: - start.setHours(0, 0, 0, 0); - } - return { from: toLocalISOString(start), to: toLocalISOString(end) }; - }; - - useEffect(() => { - const fetchStats = async () => { - try { - setIsLoading(true); - const range = getRangeDates(timeRange); - if (!range) { - setIsLoading(false); - return; - } - const params = new URLSearchParams(); - params.append('from', range.from); - params.append('to', range.to); - - const response = await apiFetch(`/api/dashboard/stats?${params.toString()}`); - if (response.ok) { - const data = await response.json(); - console.log('Dashboard data received successfully:', data); - - if (data.stats) { - setStats({ - totalSales: data.stats.periodStoreRevenue, - activeOrders: data.stats.activeOrders, - dailyCustomers: data.stats.dailyCustomers, - revenueGrowth: data.stats.growth, - suspendedUserCount: data.stats.suspendedUserCount - }); - } - - if (data.storeOverview && data.storeOverview.length > 0) { - const ritStore = data.storeOverview.find((s: any) => s.name === 'Tillo Canteen'); - if (ritStore) { - setStats(prev => ({ - ...prev, - totalSales: data.stats.periodStoreRevenue, - activeOrders: ritStore.orders, - dailyCustomers: ritStore.orders * 0.9, - })); - } - } - - if (data.trendingItems) setTrendingItems(data.trendingItems); - if (data.hourlySales) setSalesData(data.hourlySales); - if (data.insights) setInsights(data.insights); - } - } catch (error) { - console.error('Error fetching dashboard stats:', error); - } finally { - setIsLoading(false); - } - }; - fetchStats(); - }, [timeRange, customDates]); - - const pieData = [ - { name: 'Full Payment', value: Number(stats.totalSales) || 0, color: '#8b5cf6' }, - { name: 'Credit', value: 0, color: '#fbbf24' } - ]; - - if (isLoading) { - return ( -
- - Analyzing Store Data... - -
- ); - } - - - return ( -
- {/* Top Header */} -
-
-
- -

Store Dashboard

-
-

- Good morning, {(() => { - const saved = localStorage.getItem('systemUser'); - return saved ? JSON.parse(saved).name : 'Partner'; - })()} -

-
- -
- {/* Action buttons or profile placeholder can go here if needed later */} -
-
- - {/* Main Stats Grid */} -
- {/* Sales Chart Section */} -
-
- {['Sales', 'Payments'].map(tab => ( - - ))} -
- -
- - - - - - - - - - - v >= 1000 ? `R${v / 1000}k` : `R${v}`} /> - - - - -
-
- - {/* Total Sales Gauge */} -
-
- - - - {pieData.map((entry, index) => ( - - ))} - - - -
-

₹{formatCurrency(stats.totalSales)}

-
-
-
-
- Full-Payment -
-
-
- Credit -
-
-
-
- - {/* Right Stats Column */} -
- {/* Filters */} -
-
- {['Yesterday', 'Today', 'Week', '30 Days', 'Custom'].map(range => ( - - ))} -
- {timeRange === 'Custom' && ( -
- setCustomDates({ ...customDates, from: e.target.value })} - className="flex-1 bg-white border border-slate-200 rounded-lg px-2 py-1.5 text-[10px] font-bold text-slate-600 outline-none focus:border-[#003317]" - /> - to - setCustomDates({ ...customDates, to: e.target.value })} - className="flex-1 bg-white border border-slate-200 rounded-lg px-2 py-1.5 text-[10px] font-bold text-slate-600 outline-none focus:border-[#003317]" - /> -
- )} -
- - {/* Total Orders Card */} -
-
-
- -
-

Total Sales

-
-
-

{stats.activeOrders}

-
-
-
- - {/* Restricted Accounts Card */} -
-
-
- -
-

Restricted Accounts

-
-
-

{stats?.suspendedUserCount || 0}

-
-
- - {/* Expenses Card */} -
-
-
- -
-

Expenses

-
-
-

₹0

-
-
-
-
- - {/* Bottom Section */} -
- {/* Trending Items */} -
-
-
-

Trending Items

-
- -
-
-
- - -
-
- -
- - - - - - - - - {trendingItems.map((item, idx) => ( - - - - - ))} - -
ItemsSold Quantity
-
-
- {item.imageUrl ? ( - {item.name} - ) : ( -
- )} -
-
-

{item.category}

-

{item.name}

-
-
-
- {item.orderCount} -
-
-
- - {/* Store Insights */} -
-

Store Insights

- -
- {insights.map((insight, idx) => ( -
-
- -
-

{insight.text}

-
- ))} -
- -
- -
-
-
-
- ); -}; - -export default StoreDashboard;