From 99e3f8c9f9f8e7a3b273401a64efce288ea915b4 Mon Sep 17 00:00:00 2001 From: jaanvi Date: Thu, 24 Apr 2025 18:26:22 +0530 Subject: [PATCH] manager modal changes, dashboard apis implemented and add dashboard page for user created --- .../AddManagerModal/addManagerModal.tsx | 13 +- src/components/MainGrid/adminGrid.tsx | 105 ++++++++ src/components/MainGrid/mainGrid.tsx | 125 ++++++++- src/components/MainGrid/managerGrid.tsx | 77 ++++++ src/components/MainGrid/userDashboard.tsx | 248 ++++++++++++++++++ src/components/MenuContent/index.tsx | 8 +- .../RoleBasedRedirect/roleBasedRedirect.tsx | 19 ++ src/components/barChartCard/barChartCard.tsx | 7 +- src/pages/Dashboard/index.tsx | 66 +++-- src/redux/slices/dashboardSlice.ts | 14 +- src/router.tsx | 1 + 11 files changed, 639 insertions(+), 44 deletions(-) create mode 100644 src/components/MainGrid/adminGrid.tsx create mode 100644 src/components/MainGrid/managerGrid.tsx create mode 100644 src/components/MainGrid/userDashboard.tsx create mode 100644 src/components/RoleBasedRedirect/roleBasedRedirect.tsx diff --git a/src/components/AddManagerModal/addManagerModal.tsx b/src/components/AddManagerModal/addManagerModal.tsx index e3cfdf2..f91bd46 100644 --- a/src/components/AddManagerModal/addManagerModal.tsx +++ b/src/components/AddManagerModal/addManagerModal.tsx @@ -57,9 +57,9 @@ export default function AddManagerModal({ open, handleClose }) { try { await dispatch(addManager(managerData)); dispatch(managerList()); - clearErrors(); - reset(); - handleClose(); + clearErrors(); + reset(); + handleClose(); } catch (error) { console.error("Error adding manager:", error); } @@ -67,8 +67,8 @@ export default function AddManagerModal({ open, handleClose }) { // Handle modal close, clearing errors and resetting form const handleModalClose = () => { - clearErrors(); - reset(); + clearErrors(); + reset(); handleClose(); }; @@ -348,6 +348,9 @@ export default function AddManagerModal({ open, handleClose }) { togglePasswordVisibility } edge="end" + sx={{ + color: "#000000", + }} > {showPassword ? ( diff --git a/src/components/MainGrid/adminGrid.tsx b/src/components/MainGrid/adminGrid.tsx new file mode 100644 index 0000000..7af0102 --- /dev/null +++ b/src/components/MainGrid/adminGrid.tsx @@ -0,0 +1,105 @@ +import React, { useEffect } from "react"; +import Grid from "@mui/material/Grid"; +import Box from "@mui/material/Box"; +import Typography from "@mui/material/Typography"; +import SessionsChart from "../SessionsChart/sessionChart"; +import ResourcesPieChart from "../ResourcePieChart/resourcePieChart"; +import RoundedBarChart from "../barChartCard/barChartCard"; +import LineChartCard from "../LineChartCard/lineChartCard"; +import { AppDispatch, RootState } from "../../redux/store/store"; +import { useDispatch, useSelector } from "react-redux"; +import { fetchDashboardData } from "../../redux/slices/dashboardSlice"; +import AppTheme from "../../shared-theme/AppTheme"; +import StatCard from "../StatCard/statCard"; + +export default function AdminGrid() { + const dispatch = useDispatch(); + const { totalManagers, totalUsers, totalStations, loading, error } = + useSelector((state: RootState) => state.dashboardReducer); + + useEffect(() => { + dispatch(fetchDashboardData()); + }, [dispatch]); + + // Fallback defaults if data is undefined + const data = { + totalManagers: totalManagers ?? 12, + totalUsers: totalUsers ?? 24, + totalStations: totalStations ?? 8, + }; + + const statCards = [ + { title: "Total Managers", value: data.totalManagers }, + { title: "Total Users", value: data.totalUsers }, + { title: "Total Stations", value: data.totalStations }, + ]; + + return ( + + theme.palette.background.default, + }} + > + {/* Header */} + + Admin Dashboard + + + + {statCards.map((card, index) => ( + + + + ))} + + + {/* Charts */} + + + + + + + + + + + + + + + + + ); +} diff --git a/src/components/MainGrid/mainGrid.tsx b/src/components/MainGrid/mainGrid.tsx index a1aefae..49d0a67 100644 --- a/src/components/MainGrid/mainGrid.tsx +++ b/src/components/MainGrid/mainGrid.tsx @@ -1,3 +1,120 @@ +// import React, { useEffect } from "react"; +// import Grid from "@mui/material/Grid"; +// import Box from "@mui/material/Box"; +// import Typography from "@mui/material/Typography"; +// import SessionsChart from "../SessionsChart/sessionChart"; +// import ResourcesPieChart from "../ResourcePieChart/resourcePieChart"; +// import RoundedBarChart from "../barChartCard/barChartCard"; +// import LineChartCard from "../LineChartCard/lineChartCard"; +// import { AppDispatch, RootState } from "../../redux/store/store"; +// import { useDispatch, useSelector } from "react-redux"; +// import { fetchDashboardData } from "../../redux/slices/dashboardSlice"; +// import AppTheme from "../../shared-theme/AppTheme"; // Import the custom theme +// import StatCard from "../StatCard/statCard"; // Adjusted import for consistency + +// export default function MainGrid() { +// const dispatch = useDispatch(); +// const { +// totalAdmins, +// totalManagers, +// totalUsers, +// totalStations, + +// } = useSelector((state: RootState) => state.dashboardReducer); +// const userType = useSelector( +// (state: RootState) => state.profileReducer.user?.userType +// ); +// useEffect(() => { +// dispatch(fetchDashboardData()); +// }, [dispatch]); + +// const data = { +// totalAdmins: totalAdmins ?? 86, +// totalManagers: totalManagers ?? 12, +// totalUsers: totalUsers ?? 24, +// totalStations: totalStations ?? 8, +// }; + +// const getStatCards = () => { +// switch (userType) { +// case "superadmin": +// return [ +// { title: "Total Admins", value: data.totalAdmins }, +// { title: "Total Managers", value: data.totalManagers }, +// { title: "Total Users", value: data.totalUsers }, +// { title: "Total Stations", value: data.totalStations }, +// ]; +// case "admin": +// return [ +// { title: "Total Managers", value: data.totalManagers }, +// { title: "Total Users", value: data.totalUsers }, +// { title: "Total Stations", value: data.totalStations }, +// ]; +// case "manager": +// return [ +// { title: "Total Users", value: data.totalUsers }, + +// ]; + +// default: +// return []; +// } +// }; +// return ( +// +// theme.palette.background.default, +// }} +// > +// {/* Dashboard Header */} +// +// Dashboard +// + +// {/* Grid Layout */} +// +// {/* Statistic Cards */} +// {getStatCards().map((card, index) => ( +// +// +// +// ))} + +// {/* Charts */} +// {userType !== "user" && ( +// <> +// +// +// +// +// +// + +// +// +// + +// +// +// +// +// )} +// +// +// +// ); +// } import React, { useEffect } from "react"; import Grid from "@mui/material/Grid"; import Box from "@mui/material/Box"; @@ -50,20 +167,18 @@ export default function MainGrid() { maxWidth: "1800px", mx: "auto", px: { xs: 2, sm: 1, md: 0 }, - background: (theme) => theme.palette.background.default, // #DFECF1 from theme + background: (theme) => theme.palette.background.default, }} > {/* Dashboard Header */} - Dashboard + Dashboard {/* Grid Layout */} diff --git a/src/components/MainGrid/managerGrid.tsx b/src/components/MainGrid/managerGrid.tsx new file mode 100644 index 0000000..5cab860 --- /dev/null +++ b/src/components/MainGrid/managerGrid.tsx @@ -0,0 +1,77 @@ +import React, { useEffect } from "react"; +import Grid from "@mui/material/Grid"; +import Box from "@mui/material/Box"; +import Typography from "@mui/material/Typography"; +import SessionsChart from "../SessionsChart/sessionChart"; +import ResourcesPieChart from "../ResourcePieChart/resourcePieChart"; +import RoundedBarChart from "../barChartCard/barChartCard"; +import LineChartCard from "../LineChartCard/lineChartCard"; +import { AppDispatch, RootState } from "../../redux/store/store"; +import { useDispatch, useSelector } from "react-redux"; +import { fetchDashboardData } from "../../redux/slices/dashboardSlice"; +import AppTheme from "../../shared-theme/AppTheme"; +import StatCard from "../StatCard/statCard"; + +export default function ManagerGrid() { + const dispatch = useDispatch(); + const { totalUsers, totalStations } = useSelector( + (state: RootState) => state.dashboardReducer + ); + + useEffect(() => { + dispatch(fetchDashboardData()); + }, [dispatch]); + + const statCards = [{ title: "Total Users", value: totalUsers ?? 24 }]; + + return ( + + theme.palette.background.default, + }} + > + {/* Header */} + + Dashboard + + + {/* Stat Cards - Centered */} + + {statCards.map((card, index) => ( + + + + ))} + + + {/* Charts */} + + + + + + + + + + + + + + ); +} diff --git a/src/components/MainGrid/userDashboard.tsx b/src/components/MainGrid/userDashboard.tsx new file mode 100644 index 0000000..8aac5b6 --- /dev/null +++ b/src/components/MainGrid/userDashboard.tsx @@ -0,0 +1,248 @@ +import React, { useEffect } from "react"; +import { Box, Grid, Typography, Divider, Avatar, Chip } from "@mui/material"; +import { + EvStation, + AccessTime, + DirectionsCar, + BookOnline, +} from "@mui/icons-material"; +import { useDispatch, useSelector } from "react-redux"; +import { fetchDashboardData } from "../../redux/slices/dashboardSlice"; +import { AppDispatch, RootState } from "../../redux/store/store"; +import { BarChart } from "@mui/x-charts/BarChart"; +import { LineChart } from "@mui/x-charts/LineChart"; +import AppTheme from "../../shared-theme/AppTheme"; +import StatCard from "../StatCard/statCard"; + +export default function UserDashboard() { + const dispatch = useDispatch(); + const { user } = useSelector((state: RootState) => state.profileReducer); + const { totalStations } = useSelector( + (state: RootState) => state.dashboardReducer + ); + + useEffect(() => { + dispatch(fetchDashboardData()); + }, [dispatch]); + + const statCards = [ + { + title: "Active Bookings", + value: 2, + icon: , + }, + { + title: "Nearby Stations", + value: totalStations || 8, + icon: , + }, + { + title: "Charges This Month", + value: 15, + icon: , + }, + { + title: "Available Slots", + value: 4, + icon: , + }, + ]; + + const upcomingBookings = [ + { title: "Indian EV Station - Slot 1", time: "Apr 25, 6:00 PM" }, + { title: "Mumbai EV Station - Slot 3", time: "Apr 26, 2:00 PM" }, + ]; + + const recentSessions = [ + { + station: "Indian EV Station", + time: "Yesterday at 3:00 PM", + duration: "1h 30m", + }, + { + station: "Delhi EV Station", + time: "Apr 22, 5:00 PM", + duration: "2h", + }, + ]; + + const barChartData = [ + { category: "Station A", bookings: 5 }, + { category: "Station B", bookings: 3 }, + { category: "Station C", bookings: 8 }, + ]; + + const lineChartData = [ + { date: "2025-04-01", charges: 5 }, + { date: "2025-04-02", charges: 6 }, + { date: "2025-04-03", charges: 4 }, + { date: "2025-04-04", charges: 7 }, + { date: "2025-04-05", charges: 5 }, + ]; + + return ( + + + {/* Greeting */} + + {/* + {user?.name?.charAt(0).toUpperCase() || "U"} + */} + + + Welcome back, {user?.name || "User"}! + + + Here’s a quick snapshot of your EV activity. + + + + + {/* Stat Cards */} + + {statCards.map((card, index) => ( + + + + ))} + + + {/* Charts */} + + + + + Bookings by Station + + + + + + + + + Daily Charges + + + + + + + + {/* Bookings & Sessions */} + + + + + Upcoming Bookings + + + {upcomingBookings.map((booking, idx) => ( + + + {booking.title} + + + } + label={booking.time} + sx={{ + bgcolor: "#000000", + color: "#D0E1E9 !important", + "& .MuiChip-label": { + color: "#D0E1E9 !important", + }, + }} + /> + + ))} + + + + + + Recent Charging Sessions + + + {recentSessions.map((session, idx) => ( + + + {session.station} + + + {session.time} • {session.duration} + + + ))} + + + + + + ); +} diff --git a/src/components/MenuContent/index.tsx b/src/components/MenuContent/index.tsx index 492f9a4..a2a9974 100644 --- a/src/components/MenuContent/index.tsx +++ b/src/components/MenuContent/index.tsx @@ -89,17 +89,17 @@ export default function MenuContent({ hidden }: PropType) { userRole === "manager" && { text: "Station Details", icon: , - url: "/panel/manager-station-details", // Placeholder for now + url: "/panel/manager-station-details", }, userRole === "user" && { text: "Available Slots", icon: , - url: "/panel/all-available-slots", // Placeholder for now + url: "/panel/all-available-slots", }, userRole === "user" && { text: "Near By Stations", icon: , - url: "/panel/external-station-list", // Placeholder for now + url: "/panel/external-station-list", }, ]; @@ -119,7 +119,7 @@ export default function MenuContent({ hidden }: PropType) { { + const userType = useSelector( + (state: RootState) => state.profileReducer.user?.userType + ); + + if (userType === "user") { + return ; + } + + // Optional: route others to dashboard or their own start page + return ; +}; + +export default RoleBasedRedirect; diff --git a/src/components/barChartCard/barChartCard.tsx b/src/components/barChartCard/barChartCard.tsx index e667a36..689122d 100644 --- a/src/components/barChartCard/barChartCard.tsx +++ b/src/components/barChartCard/barChartCard.tsx @@ -84,11 +84,12 @@ export default function RoundedBarChart() { const chartSetting = getChartSettings(); // Data transformation for BarChart - const chartData = topStations.map((station) => ({ - name: station?.ChargingStation?.name, - count: parseInt(station.count, 10), // Ensure count is a number + const chartData = (topStations ?? []).map((station) => ({ + name: station?.ChargingStation?.name ?? "Unknown Station", + count: parseInt(station?.count ?? "0", 10), })); + return ( = ({ disableCustomTheme = false, }) => { + + const userType = useSelector( + (state: RootState) => state.profileReducer.user?.userType + ); + + + const renderGrid = () => { + switch (userType?.toLowerCase()) { + case "superadmin": + return ; + case "admin": + return ; + case "manager": + return ; + case "user": + return ; + + default: + return ( + + + Access Denied: You do not have permission to view + this dashboard. + + + ); + } + }; + return ( - {!disableCustomTheme ? ( - <> - - - ) : ( - - )} + {!disableCustomTheme && renderGrid()} ); }; diff --git a/src/redux/slices/dashboardSlice.ts b/src/redux/slices/dashboardSlice.ts index f4bc836..ace0259 100644 --- a/src/redux/slices/dashboardSlice.ts +++ b/src/redux/slices/dashboardSlice.ts @@ -18,13 +18,13 @@ interface TopStation { } interface DashboardState { - totalAdmins: number; - totalManagers: number; - totalUsers: number; - totalStations: number; - carPortCounts: CarPortCount[]; - topStations: TopStation[]; - totalBookings: number; + totalAdmins?: number; + totalManagers?: number; + totalUsers?: number; + totalStations?: number; + carPortCounts?: CarPortCount[]; + topStations?: TopStation[]; + totalBookings?: number; loading: boolean; error: string | null; } diff --git a/src/router.tsx b/src/router.tsx index b78f394..5d3d935 100644 --- a/src/router.tsx +++ b/src/router.tsx @@ -62,6 +62,7 @@ export default function AppRouter() { {/* Dashboard Routes */} }> + } />}