dev-jaanvi #1
BIN
public/tablet-img.png
Normal file
BIN
public/tablet-img.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 148 KiB |
|
@ -203,17 +203,15 @@ const CustomTable: React.FC<CustomTableProps> = ({
|
||||||
handleClose();
|
handleClose();
|
||||||
};
|
};
|
||||||
|
|
||||||
const filteredRows = rows.filter((row) => {
|
const filteredRows = rows.filter((row) => {
|
||||||
if (!searchQuery.trim()) return true; // Return all rows if searchQuery is empty or whitespace
|
if (!searchQuery.trim()) return true; // Return all rows if searchQuery is empty or whitespace
|
||||||
const lowerCaseQuery = searchQuery.toLowerCase().trim();
|
const lowerCaseQuery = searchQuery.toLowerCase().trim();
|
||||||
return (
|
return (
|
||||||
(row.name && row.name.toLowerCase().includes(lowerCaseQuery)) ||
|
(row.name && row.name.toLowerCase().includes(lowerCaseQuery)) ||
|
||||||
(row.registeredAddress &&
|
(row.registeredAddress &&
|
||||||
row.registeredAddress.toLowerCase().includes(lowerCaseQuery))
|
row.registeredAddress.toLowerCase().includes(lowerCaseQuery))
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const indexOfLastRow = currentPage * usersPerPage;
|
const indexOfLastRow = currentPage * usersPerPage;
|
||||||
const indexOfFirstRow = indexOfLastRow - usersPerPage;
|
const indexOfFirstRow = indexOfLastRow - usersPerPage;
|
||||||
|
@ -248,13 +246,15 @@ const filteredRows = rows.filter((row) => {
|
||||||
{(() => {
|
{(() => {
|
||||||
switch (tableType) {
|
switch (tableType) {
|
||||||
case "admin":
|
case "admin":
|
||||||
return "Admin";
|
return "Admins";
|
||||||
case "role":
|
case "role":
|
||||||
return "Roles";
|
return "Roles";
|
||||||
case "user":
|
case "user":
|
||||||
return "Users";
|
return "Users";
|
||||||
case "manager":
|
case "manager":
|
||||||
return "Managers";
|
return "Managers";
|
||||||
|
case "all-managers":
|
||||||
|
return "Managers";
|
||||||
case "vehicle":
|
case "vehicle":
|
||||||
return "Vehicles";
|
return "Vehicles";
|
||||||
case "station":
|
case "station":
|
||||||
|
@ -264,7 +264,9 @@ const filteredRows = rows.filter((row) => {
|
||||||
case "booking":
|
case "booking":
|
||||||
return "Booking";
|
return "Booking";
|
||||||
case "slots":
|
case "slots":
|
||||||
return "Slot";
|
return "Slots";
|
||||||
|
case "all-available-slots":
|
||||||
|
return "Available Slots";
|
||||||
default:
|
default:
|
||||||
return "List";
|
return "List";
|
||||||
}
|
}
|
||||||
|
@ -326,8 +328,13 @@ const filteredRows = rows.filter((row) => {
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{!(
|
{!(
|
||||||
user?.userType === "user" &&
|
(user?.userType === "user" &&
|
||||||
(tableType === "slots" )) && (
|
tableType === "all-available-slots") ||
|
||||||
|
(user?.userType === "superadmin" &&
|
||||||
|
tableType === "all-managers") ||
|
||||||
|
(user?.userType === "superadmin" &&
|
||||||
|
tableType === "user")
|
||||||
|
) && (
|
||||||
<Button
|
<Button
|
||||||
sx={{
|
sx={{
|
||||||
backgroundColor: "#52ACDF",
|
backgroundColor: "#52ACDF",
|
||||||
|
|
|
@ -38,7 +38,7 @@ export default function MenuContent({ hidden }: PropType) {
|
||||||
userRole === "superadmin" && {
|
userRole === "superadmin" && {
|
||||||
text: "Manager",
|
text: "Manager",
|
||||||
icon: <ManageAccountsOutlinedIcon />,
|
icon: <ManageAccountsOutlinedIcon />,
|
||||||
url: "/panel/manager-list",
|
url: "/panel/all-managers-list",
|
||||||
},
|
},
|
||||||
userRole === "superadmin" && {
|
userRole === "superadmin" && {
|
||||||
text: "User",
|
text: "User",
|
||||||
|
@ -89,7 +89,7 @@ export default function MenuContent({ hidden }: PropType) {
|
||||||
userRole === "user" && {
|
userRole === "user" && {
|
||||||
text: "Available Slots",
|
text: "Available Slots",
|
||||||
icon: <ChecklistSharpIcon />,
|
icon: <ChecklistSharpIcon />,
|
||||||
url: "/panel/slot-list", // Placeholder for now
|
url: "/panel/all-available-slots", // Placeholder for now
|
||||||
},
|
},
|
||||||
userRole === "user" && {
|
userRole === "user" && {
|
||||||
text: "Near By Stations",
|
text: "Near By Stations",
|
||||||
|
|
|
@ -84,12 +84,13 @@ export default function AdminList() {
|
||||||
{ id: "email", label: "Email" },
|
{ id: "email", label: "Email" },
|
||||||
{ id: "phone", label: "Phone" },
|
{ id: "phone", label: "Phone" },
|
||||||
{ id: "registeredAddress", label: "Address" },
|
{ id: "registeredAddress", label: "Address" },
|
||||||
{ id: "userType", label: "Role" },
|
// { id: "userType", label: "Role" },
|
||||||
|
|
||||||
{ id: "action", label: "Action", align: "center" },
|
{ id: "action", label: "Action", align: "center" },
|
||||||
];
|
];
|
||||||
|
|
||||||
const categoryRows = admins?.map(
|
const categoryRows = admins
|
||||||
|
?.filter((admin) => admin?.userType === "admin").map(
|
||||||
(
|
(
|
||||||
admin: {
|
admin: {
|
||||||
id: string;
|
id: string;
|
||||||
|
|
54
src/pages/AllMangersList/index.tsx
Normal file
54
src/pages/AllMangersList/index.tsx
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
import { useEffect } from "react";
|
||||||
|
import CustomTable, { Column } from "../../components/CustomTable/customTable";
|
||||||
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
|
import { RootState, AppDispatch } from "../../redux/store/store";
|
||||||
|
import { AllmanagerList,} from "../../redux/slices/managerSlice";
|
||||||
|
|
||||||
|
export default function ManagerList() {
|
||||||
|
const dispatch = useDispatch<AppDispatch>();
|
||||||
|
const managers = useSelector(
|
||||||
|
(state: RootState) => state.managerReducer.managers
|
||||||
|
);
|
||||||
|
|
||||||
|
// Fetch manager list on component mount
|
||||||
|
useEffect(() => {
|
||||||
|
dispatch(AllmanagerList());
|
||||||
|
}, [dispatch]);
|
||||||
|
|
||||||
|
// Columns for the manager table
|
||||||
|
const categoryColumns: Column[] = [
|
||||||
|
{ id: "srno", label: "Sr No" },
|
||||||
|
{ id: "name", label: "Name" },
|
||||||
|
{ id: "email", label: "Email" },
|
||||||
|
{ id: "phone", label: "Phone" },
|
||||||
|
{ id: "stationName", label: "Station Name" },
|
||||||
|
{ id: "registeredAddress", label: "Station Location" },
|
||||||
|
];
|
||||||
|
|
||||||
|
// Prepare rows for the table
|
||||||
|
const categoryRows = managers?.length
|
||||||
|
? managers.map((manager, index) => {
|
||||||
|
const station = manager?.chargingStation;
|
||||||
|
return {
|
||||||
|
id: manager.id,
|
||||||
|
srno: index + 1,
|
||||||
|
name: manager.name,
|
||||||
|
email: manager.email,
|
||||||
|
phone: manager.phone ?? "NA",
|
||||||
|
stationName: station?.name ?? "NA",
|
||||||
|
registeredAddress: station?.registeredAddress ?? "NA",
|
||||||
|
};
|
||||||
|
})
|
||||||
|
: [];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{/* Display manager list */}
|
||||||
|
<CustomTable
|
||||||
|
columns={categoryColumns}
|
||||||
|
rows={categoryRows}
|
||||||
|
tableType="all-managers"
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
67
src/pages/AvailableSlotsList/index.tsx
Normal file
67
src/pages/AvailableSlotsList/index.tsx
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
import CustomTable, { Column } from "../../components/CustomTable/customTable";
|
||||||
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
|
import { RootState, AppDispatch } from "../../redux/store/store";
|
||||||
|
|
||||||
|
import {
|
||||||
|
fetchAvailableSlots,
|
||||||
|
|
||||||
|
} from "../../redux/slices/slotSlice";
|
||||||
|
import dayjs from "dayjs";
|
||||||
|
|
||||||
|
export default function EVSlotList() {
|
||||||
|
|
||||||
|
|
||||||
|
const dispatch = useDispatch<AppDispatch>();
|
||||||
|
const availableSlots = useSelector(
|
||||||
|
(state: RootState) => state?.slotReducer.availableSlots
|
||||||
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
dispatch(fetchAvailableSlots());
|
||||||
|
}, [dispatch]);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const slotColumns: Column[] = [
|
||||||
|
{ id: "srno", label: "Sr No" },
|
||||||
|
{ id: "name", label: "Station Name" },
|
||||||
|
{ id: "stationId", label: "Station Id" },
|
||||||
|
{ id: "date", label: "Date" },
|
||||||
|
{ id: "startTime", label: "Start Time" },
|
||||||
|
{ id: "endTime", label: "End Time" },
|
||||||
|
{ id: "isAvailable", label: "Is Available", align: "center" },
|
||||||
|
|
||||||
|
];
|
||||||
|
|
||||||
|
const slotRows = availableSlots?.length
|
||||||
|
? availableSlots.map((slot, index) => {
|
||||||
|
const formattedDate = dayjs(slot?.date).format("YYYY-MM-DD");
|
||||||
|
const startTime = dayjs(slot?.startTime).format("HH:mm");
|
||||||
|
const endTime = dayjs(slot?.endTime).format("HH:mm");
|
||||||
|
|
||||||
|
return {
|
||||||
|
srno: index + 1,
|
||||||
|
id: slot?.id ?? "NA",
|
||||||
|
stationId: slot?.stationId ?? "NA",
|
||||||
|
name: slot?.ChargingStation?.name ?? "NA",
|
||||||
|
date: formattedDate ?? "NA",
|
||||||
|
startTime: startTime ?? "NA",
|
||||||
|
endTime: endTime ?? "NA",
|
||||||
|
isAvailable: slot?.isAvailable ? "Yes" : "No",
|
||||||
|
};
|
||||||
|
})
|
||||||
|
: [];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<CustomTable
|
||||||
|
columns={slotColumns}
|
||||||
|
rows={slotRows}
|
||||||
|
tableType="all-available-slots"
|
||||||
|
|
||||||
|
/>
|
||||||
|
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
|
@ -5,7 +5,7 @@ import { RootState, AppDispatch } from "../../redux/store/store";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import {
|
import {
|
||||||
createSlot,
|
createSlot,
|
||||||
fetchAvailableSlots,
|
fetchManagersSlots,
|
||||||
updateSlot,
|
updateSlot,
|
||||||
} from "../../redux/slices/slotSlice";
|
} from "../../redux/slices/slotSlice";
|
||||||
import AddSlotModal from "../../components/AddSlotModal/addSlotModal";
|
import AddSlotModal from "../../components/AddSlotModal/addSlotModal";
|
||||||
|
@ -24,7 +24,7 @@ export default function EVSlotList() {
|
||||||
);
|
);
|
||||||
const { user } = useSelector((state: RootState) => state?.profileReducer);
|
const { user } = useSelector((state: RootState) => state?.profileReducer);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
dispatch(fetchAvailableSlots());
|
dispatch(fetchManagersSlots());
|
||||||
}, [dispatch]);
|
}, [dispatch]);
|
||||||
|
|
||||||
const handleClickOpen = () => {
|
const handleClickOpen = () => {
|
||||||
|
@ -46,7 +46,7 @@ export default function EVSlotList() {
|
||||||
}) => {
|
}) => {
|
||||||
try {
|
try {
|
||||||
await dispatch(createSlot(data));
|
await dispatch(createSlot(data));
|
||||||
await dispatch(fetchAvailableSlots());
|
await dispatch(fetchManagersSlots());
|
||||||
handleCloseModal();
|
handleCloseModal();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error adding slot", error);
|
console.error("Error adding slot", error);
|
||||||
|
@ -74,7 +74,7 @@ export default function EVSlotList() {
|
||||||
})
|
})
|
||||||
).unwrap();
|
).unwrap();
|
||||||
|
|
||||||
await dispatch(fetchAvailableSlots());
|
await dispatch(fetchManagersSlots());
|
||||||
handleCloseModal();
|
handleCloseModal();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Update failed", error);
|
console.error("Update failed", error);
|
||||||
|
@ -83,7 +83,7 @@ export default function EVSlotList() {
|
||||||
|
|
||||||
const slotColumns: Column[] = [
|
const slotColumns: Column[] = [
|
||||||
{ id: "srno", label: "Sr No" },
|
{ id: "srno", label: "Sr No" },
|
||||||
{ id: "name", label: "Station Name" },
|
{ id: "stationName", label: "Station Name" },
|
||||||
{ id: "stationId", label: "Station Id" },
|
{ id: "stationId", label: "Station Id" },
|
||||||
{ id: "date", label: "Date" },
|
{ id: "date", label: "Date" },
|
||||||
{ id: "startTime", label: "Start Time" },
|
{ id: "startTime", label: "Start Time" },
|
||||||
|
@ -104,7 +104,7 @@ export default function EVSlotList() {
|
||||||
srno: index + 1,
|
srno: index + 1,
|
||||||
id: slot?.id ?? "NA",
|
id: slot?.id ?? "NA",
|
||||||
stationId: slot?.stationId ?? "NA",
|
stationId: slot?.stationId ?? "NA",
|
||||||
name: slot?.ChargingStation?.name ?? "NA",
|
stationName: slot?.stationName?? "NA",
|
||||||
date: formattedDate ?? "NA",
|
date: formattedDate ?? "NA",
|
||||||
startTime: startTime ?? "NA",
|
startTime: startTime ?? "NA",
|
||||||
endTime: endTime ?? "NA",
|
endTime: endTime ?? "NA",
|
||||||
|
|
|
@ -1,7 +1,44 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { Box, Button, Container, Grid, Typography } from "@mui/material";
|
import {
|
||||||
|
Box,
|
||||||
|
Button,
|
||||||
|
Card,
|
||||||
|
CardContent,
|
||||||
|
Container,
|
||||||
|
Grid,
|
||||||
|
Typography,
|
||||||
|
} from "@mui/material";
|
||||||
import { useNavigate } from "react-router-dom"; // Import useNavigate for navigation
|
import { useNavigate } from "react-router-dom"; // Import useNavigate for navigation
|
||||||
import SearchIcon from "@mui/icons-material/Search";
|
import SearchIcon from "@mui/icons-material/Search";
|
||||||
|
import EvStationIcon from "@mui/icons-material/EvStation";
|
||||||
|
import BatteryChargingFullIcon from "@mui/icons-material/BatteryChargingFull";
|
||||||
|
import LocationOnIcon from "@mui/icons-material/LocationOn";
|
||||||
|
const features = [
|
||||||
|
{
|
||||||
|
icon: <EvStationIcon fontSize="large" />,
|
||||||
|
title: "Seamless Charging Experience",
|
||||||
|
description:
|
||||||
|
"Find and book EV charging stations effortlessly with DigiEv's smart platform.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: <BatteryChargingFullIcon fontSize="large" />,
|
||||||
|
title: "Real-Time Availability",
|
||||||
|
description:
|
||||||
|
"Check live station availability and optimize your route for an efficient charge.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: <LocationOnIcon fontSize="large" />,
|
||||||
|
title: "Widespread Network",
|
||||||
|
description:
|
||||||
|
"Access a vast network of EV stations across multiple locations with ease.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: <SearchIcon fontSize="large" />, // New feature icon
|
||||||
|
title: "Smart Search Functionality",
|
||||||
|
description:
|
||||||
|
"Find EV stations nearby with advanced filters for location, availability, and pricing.",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
const LandingPage = () => {
|
const LandingPage = () => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
@ -13,7 +50,6 @@ const LandingPage = () => {
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
|
|
||||||
background: `
|
background: `
|
||||||
linear-gradient(135deg, #0D0D0D 20%, #1C1E22 80%),
|
linear-gradient(135deg, #0D0D0D 20%, #1C1E22 80%),
|
||||||
radial-gradient(circle at 30%, rgb(241, 201, 119) 100%, rgba(255, 204, 102, 0) 50%)
|
radial-gradient(circle at 30%, rgb(241, 201, 119) 100%, rgba(255, 204, 102, 0) 50%)
|
||||||
|
@ -21,6 +57,8 @@ const LandingPage = () => {
|
||||||
color: "white",
|
color: "white",
|
||||||
minHeight: "100vh",
|
minHeight: "100vh",
|
||||||
fontFamily: "Inter",
|
fontFamily: "Inter",
|
||||||
|
//display: "flex", // Ensures the children align correctly
|
||||||
|
//flexDirection: "column",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{/* Navbar */}
|
{/* Navbar */}
|
||||||
|
@ -57,8 +95,8 @@ const LandingPage = () => {
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
type="button" // Changed to "button" to avoid form submission
|
type="button"
|
||||||
onClick={handleLoginClick} // Trigger navigation on click
|
onClick={handleLoginClick}
|
||||||
sx={{
|
sx={{
|
||||||
backgroundColor: "#52ACDF",
|
backgroundColor: "#52ACDF",
|
||||||
color: "white",
|
color: "white",
|
||||||
|
@ -174,15 +212,18 @@ const LandingPage = () => {
|
||||||
|
|
||||||
<Container
|
<Container
|
||||||
maxWidth="lg"
|
maxWidth="lg"
|
||||||
|
|
||||||
sx={{
|
sx={{
|
||||||
|
// width: "1320px",
|
||||||
|
// height: "239px",
|
||||||
|
width: "100%",
|
||||||
position: "relative",
|
position: "relative",
|
||||||
boxShadow: "0px 8px 20px rgba(166, 210, 235, 0.5)", // Bluish box shadow
|
boxShadow: "0px 8px 20px rgba(166, 210, 235, 0.2)", // Bluish box shadow
|
||||||
background:
|
background:
|
||||||
"linear-gradient(135deg, rgba(82, 172, 223, 0.2), rgba(0,0,0,0.3))",
|
"linear-gradient(135deg, rgba(82, 172, 223, 0.2), rgba(0,0,0,0.3))",
|
||||||
borderRadius: "16px",
|
borderRadius: "16px",
|
||||||
py: 4,
|
py: 4,
|
||||||
px: 3,
|
px: 3,
|
||||||
|
mt: 15,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Grid container spacing={4} textAlign="center">
|
<Grid container spacing={4} textAlign="center">
|
||||||
|
@ -193,11 +234,18 @@ const LandingPage = () => {
|
||||||
fontWeight={600}
|
fontWeight={600}
|
||||||
fontSize={"80px"}
|
fontSize={"80px"}
|
||||||
lineHeight={"100px"}
|
lineHeight={"100px"}
|
||||||
fontFamily={"Inter"}
|
fontFamily={"Poppins"}
|
||||||
>
|
>
|
||||||
50+
|
50+
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography variant="body2" color="#FFFFFF">
|
<Typography
|
||||||
|
variant="body2"
|
||||||
|
color="#FFFFFF"
|
||||||
|
fontFamily={"Inter"}
|
||||||
|
fontWeight={400}
|
||||||
|
fontSize={"16px"}
|
||||||
|
lineHeight={"22px"}
|
||||||
|
>
|
||||||
Successful Digital Transformations
|
Successful Digital Transformations
|
||||||
</Typography>
|
</Typography>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
@ -208,11 +256,18 @@ const LandingPage = () => {
|
||||||
fontWeight={600}
|
fontWeight={600}
|
||||||
fontSize={"80px"}
|
fontSize={"80px"}
|
||||||
lineHeight={"100px"}
|
lineHeight={"100px"}
|
||||||
fontFamily={"Inter"}
|
fontFamily={"Poppins"}
|
||||||
>
|
>
|
||||||
100%
|
100%
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography variant="body2" color="#FFFFFF">
|
<Typography
|
||||||
|
variant="body2"
|
||||||
|
color="#FFFFFF"
|
||||||
|
fontFamily={"Inter"}
|
||||||
|
fontWeight={400}
|
||||||
|
fontSize={"16px"}
|
||||||
|
lineHeight={"22px"}
|
||||||
|
>
|
||||||
Client Satisfaction
|
Client Satisfaction
|
||||||
</Typography>
|
</Typography>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
@ -223,11 +278,18 @@ const LandingPage = () => {
|
||||||
fontWeight={600}
|
fontWeight={600}
|
||||||
fontSize={"80px"}
|
fontSize={"80px"}
|
||||||
lineHeight={"100px"}
|
lineHeight={"100px"}
|
||||||
fontFamily={"Inter"}
|
fontFamily={"Poppins"}
|
||||||
>
|
>
|
||||||
20+
|
20+
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography variant="body2" color="#FFFFFF">
|
<Typography
|
||||||
|
variant="body2"
|
||||||
|
color="#FFFFFF"
|
||||||
|
fontFamily={"Inter"}
|
||||||
|
fontWeight={400}
|
||||||
|
fontSize={"16px"}
|
||||||
|
lineHeight={"22px"}
|
||||||
|
>
|
||||||
Global Partnerships
|
Global Partnerships
|
||||||
</Typography>
|
</Typography>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
@ -239,16 +301,160 @@ const LandingPage = () => {
|
||||||
fontWeight={600}
|
fontWeight={600}
|
||||||
fontSize={"80px"}
|
fontSize={"80px"}
|
||||||
lineHeight={"100px"}
|
lineHeight={"100px"}
|
||||||
fontFamily={"Inter"}
|
fontFamily={"Poppins"}
|
||||||
>
|
>
|
||||||
10+
|
10+
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography variant="body2" color="#FFFFFF">
|
<Typography
|
||||||
|
variant="body2"
|
||||||
|
color="#FFFFFF"
|
||||||
|
fontFamily={"Inter"}
|
||||||
|
fontWeight={400}
|
||||||
|
fontSize={"16px"}
|
||||||
|
lineHeight={"22px"}
|
||||||
|
>
|
||||||
Years of Innovation
|
Years of Innovation
|
||||||
</Typography>
|
</Typography>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Container>
|
</Container>
|
||||||
|
|
||||||
|
<Container
|
||||||
|
maxWidth="lg"
|
||||||
|
sx={{
|
||||||
|
minHeight: "100vh",
|
||||||
|
textAlign: "center",
|
||||||
|
// width: "1320px",
|
||||||
|
// height: "349.82px",
|
||||||
|
width: "100%",
|
||||||
|
boxShadow: "0px 8px 20px rgba(166, 210, 235, 0.2)", // Bluish box shadow
|
||||||
|
background:
|
||||||
|
"linear-gradient(135deg, rgba(82, 172, 223, 0.2), rgba(0,0,0,0.3))",
|
||||||
|
borderRadius: "16px",
|
||||||
|
py: 4,
|
||||||
|
px: 3,
|
||||||
|
mt: 10,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography
|
||||||
|
variant="h4"
|
||||||
|
fontWeight={600}
|
||||||
|
fontFamily={"Inter"}
|
||||||
|
fontSize={"40px"}
|
||||||
|
lineHeight={"100%"}
|
||||||
|
color="#FFFFFF"
|
||||||
|
>
|
||||||
|
Welcome to <span style={{ color: "#52ACDF" }}>DigiEv</span>{" "}
|
||||||
|
- Your EV Charging Partner
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
<Typography variant="h6" mt={1} fontWeight={600}>
|
||||||
|
Simplifying Electric Vehicle Charging
|
||||||
|
</Typography>
|
||||||
|
<Typography
|
||||||
|
variant="body1"
|
||||||
|
mt={2}
|
||||||
|
maxWidth="600px"
|
||||||
|
mx="auto"
|
||||||
|
fontFamily={"Inter"}
|
||||||
|
fontSize={"20px"}
|
||||||
|
fontWeight={400}
|
||||||
|
lineHeight={"100%"}
|
||||||
|
color="#D9D8D8"
|
||||||
|
>
|
||||||
|
DigiEv helps EV owners locate, book, and manage their
|
||||||
|
charging needs efficiently. With our intuitive platform, you
|
||||||
|
can ensure a smooth and hassle-free charging experience.
|
||||||
|
</Typography>
|
||||||
|
<Box mt={5}>
|
||||||
|
<img
|
||||||
|
src="/tablet-img.png"
|
||||||
|
alt="DigiEv Dashboard"
|
||||||
|
style={{
|
||||||
|
width: "80%",
|
||||||
|
maxWidth: "800px",
|
||||||
|
borderRadius: "10px",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
<Grid
|
||||||
|
container
|
||||||
|
spacing={4}
|
||||||
|
justifyContent="center"
|
||||||
|
alignItems="center"
|
||||||
|
mt={2}
|
||||||
|
>
|
||||||
|
{features.map((feature, index) => (
|
||||||
|
<Grid item xs={12} sm={6} md={3} key={index}>
|
||||||
|
<Card
|
||||||
|
sx={{
|
||||||
|
boxShadow:
|
||||||
|
"0px 8px 20px rgba(166, 210, 235, 0.2)", // Bluish box shadow
|
||||||
|
background:
|
||||||
|
"linear-gradient(135deg, rgba(82, 172, 223, 0.2), rgba(0,0,0,0.3))",
|
||||||
|
borderRadius: "18px",
|
||||||
|
width: "247px", // Fixed width
|
||||||
|
height: "200px", // Fixed height
|
||||||
|
display: "flex", // Flexbox for centering content
|
||||||
|
flexDirection: "column",
|
||||||
|
alignItems: "center",
|
||||||
|
justifyContent: "center",
|
||||||
|
textAlign: "center",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<CardContent
|
||||||
|
sx={{
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
alignItems: "center",
|
||||||
|
justifyContent: "center",
|
||||||
|
height: "100%", // Fills the parent card
|
||||||
|
textAlign: "center",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: "flex",
|
||||||
|
justifyContent: "center", // Centers the icon horizontally
|
||||||
|
alignItems: "center", // Centers the icon vertically
|
||||||
|
mt: 1,
|
||||||
|
mb: 2,
|
||||||
|
color: "#D9D8D8",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{feature.icon}
|
||||||
|
</Box>
|
||||||
|
<Typography
|
||||||
|
variant="h6"
|
||||||
|
sx={{
|
||||||
|
color: "#52ACDF",
|
||||||
|
fontFamily: "Inter",
|
||||||
|
fontWeight: 600,
|
||||||
|
fontSize: "18px", // Slightly reduced to fit uniformly
|
||||||
|
lineHeight: "160%",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{feature.title}
|
||||||
|
</Typography>
|
||||||
|
<Typography
|
||||||
|
variant="body2"
|
||||||
|
sx={{
|
||||||
|
color: "#D9D8D8",
|
||||||
|
fontFamily: "Inter",
|
||||||
|
fontWeight: 400,
|
||||||
|
fontSize: "14px",
|
||||||
|
lineHeight: "20px",
|
||||||
|
mt: 1,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{feature.description}
|
||||||
|
</Typography>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</Grid>
|
||||||
|
))}
|
||||||
|
</Grid>
|
||||||
|
</Container>
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -20,7 +20,7 @@ export default function UserList() {
|
||||||
const dispatch = useDispatch<AppDispatch>();
|
const dispatch = useDispatch<AppDispatch>();
|
||||||
|
|
||||||
const users = useSelector((state: RootState) => state.userReducer.users);
|
const users = useSelector((state: RootState) => state.userReducer.users);
|
||||||
|
const { user } = useSelector((state: RootState) => state?.profileReducer);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
dispatch(userList());
|
dispatch(userList());
|
||||||
}, [dispatch]);
|
}, [dispatch]);
|
||||||
|
@ -78,7 +78,9 @@ export default function UserList() {
|
||||||
{ id: "email", label: "Email" },
|
{ id: "email", label: "Email" },
|
||||||
{ id: "phone", label: "Phone" },
|
{ id: "phone", label: "Phone" },
|
||||||
|
|
||||||
{ id: "action", label: "Action", align: "center" },
|
...(user?.userType === "admin"
|
||||||
|
? [{ id: "action", label: "Action", align: "center" as const }]
|
||||||
|
: []),
|
||||||
];
|
];
|
||||||
const categoryRows = users?.length
|
const categoryRows = users?.length
|
||||||
? users.map((user, index) => ({
|
? users.map((user, index) => ({
|
||||||
|
|
|
@ -13,9 +13,10 @@ interface User {
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Admin {
|
interface Admin {
|
||||||
|
Admins: any;
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
role: string;
|
userType: string;
|
||||||
email: string;
|
email: string;
|
||||||
phone: string;
|
phone: string;
|
||||||
registeredAddress: string;
|
registeredAddress: string;
|
||||||
|
|
|
@ -46,7 +46,25 @@ export const managerList = createAsyncThunk<
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
export const AllmanagerList = createAsyncThunk<
|
||||||
|
Manager[],
|
||||||
|
void,
|
||||||
|
{ rejectValue: string }
|
||||||
|
>("fetchAllManagers", async (_, { rejectWithValue }) => {
|
||||||
|
try {
|
||||||
|
const token = localStorage?.getItem("authToken");
|
||||||
|
if (!token) throw new Error("No token found");
|
||||||
|
|
||||||
|
const response = await http.get("/all-manager-list");
|
||||||
|
if (!response.data?.data) throw new Error("Invalid API response");
|
||||||
|
return response.data.data;
|
||||||
|
} catch (error: any) {
|
||||||
|
toast.error("Error Fetching Managers: " + error.message);
|
||||||
|
return rejectWithValue(
|
||||||
|
error?.response?.data?.message || "An error occurred"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
// Create Manager (Async Thunk)
|
// Create Manager (Async Thunk)
|
||||||
export const addManager = createAsyncThunk<
|
export const addManager = createAsyncThunk<
|
||||||
Manager,
|
Manager,
|
||||||
|
@ -132,6 +150,21 @@ const managerSlice = createSlice({
|
||||||
state.loading = false;
|
state.loading = false;
|
||||||
state.error = action.payload || "Failed to fetch managers";
|
state.error = action.payload || "Failed to fetch managers";
|
||||||
})
|
})
|
||||||
|
.addCase(AllmanagerList.pending, (state) => {
|
||||||
|
state.loading = true;
|
||||||
|
state.error = null;
|
||||||
|
})
|
||||||
|
.addCase(
|
||||||
|
AllmanagerList.fulfilled,
|
||||||
|
(state, action: PayloadAction<Manager[]>) => {
|
||||||
|
state.loading = false;
|
||||||
|
state.managers = action.payload;
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.addCase(AllmanagerList.rejected, (state, action) => {
|
||||||
|
state.loading = false;
|
||||||
|
state.error = action.payload || "Failed to fetch managers";
|
||||||
|
})
|
||||||
|
|
||||||
// Add Manager
|
// Add Manager
|
||||||
.addCase(addManager.pending, (state) => {
|
.addCase(addManager.pending, (state) => {
|
||||||
|
|
|
@ -10,7 +10,7 @@ interface Slot {
|
||||||
startTime: string;
|
startTime: string;
|
||||||
endTime: string;
|
endTime: string;
|
||||||
isAvailable: boolean;
|
isAvailable: boolean;
|
||||||
|
stationName:string;
|
||||||
ChargingStation: { name: string };
|
ChargingStation: { name: string };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,7 +50,27 @@ export const fetchAvailableSlots = createAsyncThunk<
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
export const fetchManagersSlots = createAsyncThunk<
|
||||||
|
Slot[],
|
||||||
|
void,
|
||||||
|
{ rejectValue: string }
|
||||||
|
>("fetchManagersSlots", async (_, { rejectWithValue }) => {
|
||||||
|
try {
|
||||||
|
const token = localStorage?.getItem("authToken");
|
||||||
|
if (!token) throw new Error("No token found");
|
||||||
|
|
||||||
|
const response = await http.get("/manager-slots");
|
||||||
|
|
||||||
|
if (!response.data?.data) throw new Error("Invalid API response");
|
||||||
|
|
||||||
|
return response.data.data;
|
||||||
|
} catch (error: any) {
|
||||||
|
toast.error("Error Fetching Profile" + error);
|
||||||
|
return rejectWithValue(
|
||||||
|
error?.response?.data?.message || "An error occurred"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
export const createSlot = createAsyncThunk<
|
export const createSlot = createAsyncThunk<
|
||||||
Slot,
|
Slot,
|
||||||
{
|
{
|
||||||
|
@ -152,6 +172,22 @@ const slotSlice = createSlice({
|
||||||
state.error =
|
state.error =
|
||||||
action.payload || "Failed to fetch available slots";
|
action.payload || "Failed to fetch available slots";
|
||||||
})
|
})
|
||||||
|
.addCase(fetchManagersSlots.pending, (state) => {
|
||||||
|
state.loading = true;
|
||||||
|
state.error = null;
|
||||||
|
})
|
||||||
|
.addCase(
|
||||||
|
fetchManagersSlots.fulfilled,
|
||||||
|
(state, action: PayloadAction<Slot[]>) => {
|
||||||
|
state.loading = false;
|
||||||
|
state.availableSlots = action.payload;
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.addCase(fetchManagersSlots.rejected, (state, action) => {
|
||||||
|
state.loading = false;
|
||||||
|
state.error =
|
||||||
|
action.payload || "Failed to fetch available slots";
|
||||||
|
})
|
||||||
.addCase(createSlot.pending, (state) => {
|
.addCase(createSlot.pending, (state) => {
|
||||||
state.loading = true;
|
state.loading = true;
|
||||||
})
|
})
|
||||||
|
|
|
@ -24,7 +24,8 @@ const EVSlotManagement = lazy(() => import("./pages/EVSlotManagement"));
|
||||||
const BookingList = lazy(() => import("./pages/BookingList"));
|
const BookingList = lazy(() => import("./pages/BookingList"));
|
||||||
const EvSlotList = lazy(() => import("./pages/EvSlotList"));
|
const EvSlotList = lazy(() => import("./pages/EvSlotList"));
|
||||||
const ExternalStationList = lazy(() => import("./pages/ExternalStationList/externalStationList.tsx"));
|
const ExternalStationList = lazy(() => import("./pages/ExternalStationList/externalStationList.tsx"));
|
||||||
|
const AllManagersList = lazy(() => import("./pages/AllMangersList"));
|
||||||
|
const AvailableSlotsList = lazy(() => import("./pages/AvailableSlotsList"));
|
||||||
interface ProtectedRouteProps {
|
interface ProtectedRouteProps {
|
||||||
// caps: string[];
|
// caps: string[];
|
||||||
component: React.ReactNode;
|
component: React.ReactNode;
|
||||||
|
@ -44,7 +45,7 @@ export default function AppRouter() {
|
||||||
<Suspense fallback={<LoadingComponent />}>
|
<Suspense fallback={<LoadingComponent />}>
|
||||||
<BaseRoutes>
|
<BaseRoutes>
|
||||||
{/* Default Route */}
|
{/* Default Route */}
|
||||||
<Route path="" element={<LandingPage /> } />
|
<Route path="" element={<LandingPage />} />
|
||||||
|
|
||||||
{/* Auth Routes */}
|
{/* Auth Routes */}
|
||||||
<Route path="">
|
<Route path="">
|
||||||
|
@ -117,6 +118,18 @@ export default function AppRouter() {
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
<Route
|
||||||
|
path="all-managers-list"
|
||||||
|
element={
|
||||||
|
<ProtectedRoute component={<AllManagersList />} />
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<Route
|
||||||
|
path="all-available-slots"
|
||||||
|
element={
|
||||||
|
<ProtectedRoute component={<AvailableSlotsList />} />
|
||||||
|
}
|
||||||
|
/>
|
||||||
</Route>
|
</Route>
|
||||||
|
|
||||||
{/* Catch-all Route */}
|
{/* Catch-all Route */}
|
||||||
|
|
Loading…
Reference in a new issue