dev-jaanvi #1

Open
jaanvi wants to merge 155 commits from dev-jaanvi into main
15 changed files with 582 additions and 816 deletions
Showing only changes of commit f353befab5 - Show all commits

View file

@ -43,8 +43,15 @@ const AddSlotModal = ({ open, handleClose }: any) => {
}, [startHour]); }, [startHour]);
const onSubmit = (data: any) => { const onSubmit = (data: any) => {
const { date, startingDate, endingDate, startHour, endHour, duration } = const {
data; date,
startingDate,
endingDate,
startHour,
endHour,
duration,
stationId,
} = data;
const payload = isDateRange const payload = isDateRange
? { ? {
@ -55,6 +62,7 @@ const AddSlotModal = ({ open, handleClose }: any) => {
duration: parseInt(duration, 10), duration: parseInt(duration, 10),
durationUnit, // Include the duration unit (minutes or hours) durationUnit, // Include the duration unit (minutes or hours)
isAvailable, isAvailable,
stationId,
} }
: { : {
date, date,
@ -63,6 +71,7 @@ const AddSlotModal = ({ open, handleClose }: any) => {
duration: parseInt(duration, 10), duration: parseInt(duration, 10),
durationUnit, // Include the duration unit (minutes or hours) durationUnit, // Include the duration unit (minutes or hours)
isAvailable, isAvailable,
stationId,
}; };
dispatch(createSlot(payload)); dispatch(createSlot(payload));

View file

@ -5,7 +5,7 @@ export const CustomIconButton = styled(IconButton)({
"&:hover": { "&:hover": {
backgroundColor: "transparent", backgroundColor: "transparent",
}, },
"*:where([data-mui-color-scheme='dark']) &": { "*:where([data-mui-color-scheme='light']) &": {
backgroundColor: "transparent", backgroundColor: "transparent",
border: "none", border: "none",
}, },

View file

@ -22,6 +22,9 @@ import {
TextField, TextField,
Typography, Typography,
} from "@mui/material"; } from "@mui/material";
import EditIcon from "@mui/icons-material/Edit";
import DeleteIcon from "@mui/icons-material/Delete";
import VisibilityIcon from "@mui/icons-material/Visibility";
import MoreHorizRoundedIcon from "@mui/icons-material/MoreHorizRounded"; import MoreHorizRoundedIcon from "@mui/icons-material/MoreHorizRounded";
import DeleteModal from "../Modals/DeleteModal/index.tsx"; import DeleteModal from "../Modals/DeleteModal/index.tsx";
import { AppDispatch, RootState } from "../../redux/store/store.ts"; import { AppDispatch, RootState } from "../../redux/store/store.ts";
@ -51,38 +54,33 @@ import ManagerStationDetails from "../../pages/ManagerStationDetails/index.tsx";
const StyledTableCell = styled(TableCell)(({ theme }) => ({ const StyledTableCell = styled(TableCell)(({ theme }) => ({
[`&.${tableCellClasses.body}`]: { [`&.${tableCellClasses.body}`]: {
fontSize: "16px", fontSize: "16px",
borderBottom: "1px solid #454545", borderBottom: "1px solid rgba(87, 85, 85, 0.53)",
color: "#000000",
backgroundColor: "#D0E1E9",
}, },
[`&.${tableCellClasses.head}`]: { [`&.${tableCellClasses.head}`]: {
backgroundColor: "#454545", backgroundColor: "#000000",
color: theme.palette.common.white, color: "#D0E1E9",
borderBottom: "none", borderBottom: "none",
borderRight: "1px solid rgba(141, 135, 135, 0.51)", //borderRight: "1px solid rgba(141, 135, 135, 0.51)",
// transition: "border-color 0.3s ease",
position: "sticky", position: "sticky",
top: 0, top: 0,
zIndex: 10, zIndex: 10,
// "&:hover": {
// borderRight: "3px solid rgba(112, 109, 109, 0.8)",
// },p
}, },
})); }));
const StyledTableRow = styled(TableRow)(({ theme }) => ({ const StyledTableRow = styled(TableRow)(({ theme }) => ({
"&:nth-of-type(odd)": { backgroundColor: "#D0E1E9",
backgroundColor: theme.palette.action.hover,
},
"&:nth-of-type(even)": {
backgroundColor: theme.palette.action.hover,
},
"& td, th": { "& td, th": {
borderColor: "#454545", // Applying border color to both td and th borderColor: "#454545",
borderWidth: "1px", // Set border width to ensure it appears borderWidth: "1px",
borderBottom: "1px solid #454545", borderBottom: "1px solid #454545",
color: "#000000",
backgroundColor: "#D0E1E9",
}, },
})); }));
export interface Column { export interface Column {
id: string; id: string;
label: string; label: string;
@ -103,9 +101,11 @@ interface CustomTableProps {
viewModal: boolean; viewModal: boolean;
setViewModal: Function; setViewModal: Function;
deleteModal: boolean; deleteModal: boolean;
handleStatusToggle?: (id: string, currentStatus: number) => void; handleStatusToggle?: (id: string, currentStatus: number | boolean) => void;
tableType: string; // Adding tableType prop to change header text dynamically tableType: string; // Adding tableType prop to change header text dynamically
handleClickOpen?: () => void; handleClickOpen?: () => void;
statusField?: string; // Optional field to indicate the status column
statusValue?: boolean; // Optional normalized status value
} }
@ -133,6 +133,69 @@ const CustomTable: React.FC<CustomTableProps> = ({
const [sortOrder, setSortOrder] = React.useState<"asc" | "desc" | null>( const [sortOrder, setSortOrder] = React.useState<"asc" | "desc" | null>(
null null
); );
// ... [imports remain the same, no changes needed] ...
const getTitleByType = (type: string) => {
const titles: { [key: string]: string } = {
admin: "Admins",
role: "Roles",
user: "Users",
manager: "Managers",
"all-managers": "Managers",
vehicle: "Vehicles",
station: "Charging Station",
"external-station": "Charging Station",
booking: "Booking",
slots: "Slots",
"all-available-slots": "Available Slots",
"manager-station": "Station Details",
};
return titles[type] || "List";
};
const getAddButtonLabel = (type: string) => {
const labels: { [key: string]: string } = {
admin: "Admin",
role: "Role",
user: "User",
manager: "Manager",
vehicle: "Vehicle",
station: "Charging Station",
booking: "Booking",
slots: "Slot",
"external-station": "Location",
"manager-station": "Station Details",
};
return labels[type] || "Item";
};
const getEmptyMessage = (type: string) => {
const messages: { [key: string]: string } = {
admin: "No admins found",
role: "No roles found",
user: "No users found",
manager: "No managers found",
vehicle: "No vehicles found",
station: "No charging stations found",
"external-station": "No charging stations found",
booking: "No bookings found",
slots: "No slots found",
"all-available-slots": "No available slots found",
};
return messages[type] || "No data available";
};
const shouldShowAddButton = (userType: string, tableType: string) => {
if (
(userType === "user" && tableType === "all-available-slots") ||
(userType === "superadmin" && tableType === "all-managers") ||
(userType === "superadmin" && tableType === "user")
) {
return false;
}
return true;
};
const handleClick = (event: React.MouseEvent<HTMLElement>, row: Row) => { const handleClick = (event: React.MouseEvent<HTMLElement>, row: Row) => {
setAnchorEl(event.currentTarget); setAnchorEl(event.currentTarget);
setSelectedRow(row); setSelectedRow(row);
@ -224,21 +287,22 @@ const CustomTable: React.FC<CustomTableProps> = ({
setViewModal(false); setViewModal(false);
}; };
const handleToggleStatus = () => {
const handleToggleStatus = () => {
if (selectedRow) { if (selectedRow) {
// Toggle the opposite of current status handleStatusToggle?.(selectedRow.id, !selectedRow.statusValue); // Toggle the boolean statusValue
const newStatus = selectedRow.statusValue === 1 ? 0 : 1;
handleStatusToggle?.(selectedRow.id, newStatus);
} }
handleClose(); handleClose();
}; };
const handleSort = () => { const handleSort = () => {
setSortOrder((prevSortOrder) => setSortOrder((prevSortOrder) =>
prevSortOrder === "asc" ? "desc" : "asc" prevSortOrder === "asc" ? "desc" : "asc"
); );
}; };
const handleEditButton = (row: Row) => {
setModalOpen(true);
setRowData(row);
};
const sortedRows = React.useMemo(() => { const sortedRows = React.useMemo(() => {
let sorted = [...rows]; let sorted = [...rows];
@ -257,15 +321,12 @@ const CustomTable: React.FC<CustomTableProps> = ({
return ( return (
(row.name && row.name.toLowerCase().includes(lowerCaseQuery)) || (row.name && row.name.toLowerCase().includes(lowerCaseQuery)) ||
(row.registeredAddress && (row.registeredAddress &&
row.registeredAddress row.registeredAddress.toLowerCase().includes(lowerCaseQuery)) ||
.toLowerCase()
.includes(lowerCaseQuery)) ||
(row.stationName && (row.stationName &&
row.stationName.toLowerCase().includes(lowerCaseQuery)) row.stationName.toLowerCase().includes(lowerCaseQuery))
); );
}); });
const indexOfLastRow = currentPage * usersPerPage; const indexOfLastRow = currentPage * usersPerPage;
const indexOfFirstRow = indexOfLastRow - usersPerPage; const indexOfFirstRow = indexOfLastRow - usersPerPage;
const currentRows = filteredRows.slice(indexOfFirstRow, indexOfLastRow); const currentRows = filteredRows.slice(indexOfFirstRow, indexOfLastRow);
@ -278,194 +339,94 @@ const CustomTable: React.FC<CustomTableProps> = ({
}; };
return ( return (
<Box sx={{ width: "100%", padding: "24px", borderRadius: "12px" }}>
<Box <Box
sx={{ sx={{
width: { xs: "100%", sm: "100%" }, display: "flex",
margin: "0 auto", flexDirection: { xs: "column", md: "row" },
padding: "24px", justifyContent: "space-between",
backgroundColor: "#1C1C1C", alignItems: { xs: "flex-start", md: "center" },
borderRadius: "12px", flexWrap: "wrap",
overflowX: "auto", mb: 3,
boxSizing: "border-box", gap: 2,
// Ensure CustomTable doesn't affect layout above it
position: "relative",
zIndex: 1,
}} }}
> >
<Typography <Typography
sx={{ sx={{
color: "#FFFFFF", color: "#000000",
fontWeight: 600, fontWeight: 600,
fontSize: "30px", fontSize: "30px",
}} }}
> >
{/* Dynamic title based on the page type */} {getTitleByType(tableType)}
{(() => {
switch (tableType) {
case "admin":
return "Admins";
case "role":
return "Roles";
case "user":
return "Users";
case "manager":
return "Managers";
case "all-managers":
return "Managers";
case "vehicle":
return "Vehicles";
case "station":
return "Charging Station";
case "external-station":
return "Charging Station";
case "booking":
return "Booking";
case "slots":
return "Slots";
case "all-available-slots":
return "Available Slots";
case "manager-station":
return "Station Details"
default:
return "List";
}
})()}
</Typography> </Typography>
{/* Search & Buttons Section */} {/* Right Side: Search + Add */}
<Box <Box
sx={{ sx={{
display: "flex", display: "flex",
flexDirection: { xs: "column", sm: "column", md: "row" }, alignItems: "center",
gap: { xs: "16px", sm: "16px", md: "0" }, gap: 2,
marginTop: "16px", flexWrap: "wrap",
alignItems: { xs: "stretch", sm: "stretch", md: "center" }, justifyContent: "flex-end",
width: "100%",
...autofillFix,
}} }}
> >
<TextField <TextField
variant="outlined" variant="outlined"
placeholder="Search" placeholder="Search"
sx={{ sx={{
width: { xs: "100%", sm: "100%", md: "380px" }, width: { xs: "100%", sm: "300px", md: "300px" },
borderRadius: "12px", input: { color: "#454545" },
input: { color: "#FFFFFF" },
backgroundColor: "#272727",
"& .MuiOutlinedInput-root": { "& .MuiOutlinedInput-root": {
borderRadius: "12px", borderRadius: "12px",
width: { xs: "100%", sm: "100%", md: "380px" },
height: "44px", height: "44px",
borderWidth: "1px", "& fieldset": { borderColor: "#454545" },
padding: "14px 12px 14px 12px", "&:hover fieldset": { borderColor: "#454545" },
"& fieldset": { borderColor: "#FFFFFF" },
"&:hover fieldset": { borderColor: "#FFFFFF" },
"&.Mui-focused fieldset": { "&.Mui-focused fieldset": {
borderColor: "#52ACDF", borderColor: "#52ACDF",
}, },
}, },
"& .MuiInputBase-input::placeholder": { "& .MuiInputBase-input::placeholder": {
color: "#D9D8D8", color: "#454545",
opacity: 1, opacity: 1,
}, },
}} }}
slotProps={{ InputProps={{
input: {
startAdornment: ( startAdornment: (
<InputAdornment position="start"> <InputAdornment position="start">
<SearchIcon sx={{ color: "#52ACDF" }} /> <SearchIcon sx={{ color: "#454545" }} />
</InputAdornment> </InputAdornment>
), ),
},
}} }}
value={searchQuery} value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)} onChange={(e) => setSearchQuery(e.target.value)}
/> />
<Box {/* Conditionally show Add Button */}
sx={{ {shouldShowAddButton(user?.userType, tableType) && (
display: "flex",
justifyContent: "flex-end",
width: "100%",
}}
>
{!(
(user?.userType === "user" &&
tableType === "all-available-slots") ||
(user?.userType === "superadmin" &&
tableType === "all-managers") ||
(user?.userType === "superadmin" &&
tableType === "user")
) && (
<Button <Button
sx={{ sx={{
backgroundColor: "#52ACDF", backgroundColor: "#000000",
color: "white", color: "white",
minWidth: "115px", // Start small but allow it to grow minWidth: "115px",
maxWidth: "250px", // Optional: limit it from being *too* wide
marginRight: "16px",
paddingX: "16px",
fontSize: "16px", fontSize: "16px",
whiteSpace: "nowrap", // Prevents text from wrapping paddingX: 2,
"&:hover": { backgroundColor: "#439BC1" }, "&:hover": { backgroundColor: "#000000" },
}} }}
onClick={handleClickOpen} onClick={handleClickOpen}
//startIcon={<AddCircleIcon />} // <-- this adds the icon!
> >
Add{" "} Add {getAddButtonLabel(tableType)}
{(() => {
switch (tableType) {
case "admin":
return "Admin";
case "role":
return "Role";
case "user":
return "User";
case "manager":
return "Manager";
case "vehicle":
return "Vehicle";
case "station":
return "Charging Station";
case "booking":
return "Booking";
case "slots":
return "Slot";
case "external-station":
return "Location";
case "manager-station":
return "Station Details"
default:
return "Item";
}
})()}
</Button> </Button>
)} )}
</Box> </Box>
{/* <IconButton
sx={{
width: "44px",
height: "44px",
borderRadius: "8px",
backgroundColor: "#1C1C1C",
color: "#52ACDF",
"&:hover": { backgroundColor: "#333333" },
"*:where([data-mui-color-scheme='dark']) &": {
backgroundColor: "#1C1C1C",
},
}}
>
<TuneIcon />
</IconButton> */}
</Box> </Box>
{/* Table Section */} {/* Table Section */}
<TableContainer <TableContainer
component={Paper} component={Paper}
sx={{ sx={{
marginTop: "24px", marginTop: "24px",
backgroundColor: "#1C1C1C",
borderRadius: "12px", borderRadius: "12px",
overflow: "auto", overflow: "auto",
maxWidth: "100%", maxWidth: "100%",
@ -480,144 +441,157 @@ const CustomTable: React.FC<CustomTableProps> = ({
borderRadius: "4px", borderRadius: "4px",
}, },
}} }}
> >
<Table sx={{ minWidth: "750px", tableLayout: "auto" }}> <Table sx={{ minWidth: "750px", tableLayout: "auto" }}>
<TableHead <TableHead>
sx={{
backgroundColor: "#272727",
borderBottom: "none",
".css-1ex4ubw-MuiTableCell-root.MuiTableCell-head ":
{
backgroundColor: "#272727",
borderBottom: "1px solid #454545",
},
}}
>
{" "} {" "}
<TableRow> <TableRow>
{columns.map((column) => ( {columns.map((column) => (
<StyledTableCell <StyledTableCell key={column.id}>
key={column.id}
sx={{
color: "#FFFFFF",
fontWeight: "600",
...(column.id === "action" && {
position: "sticky",
right: 0,
zIndex: 2,
backgroundColor: "#272727",
boxShadow:
"-5px 0 5px -2px rgba(0,0,0,0.15)",
borderBottom: "1px solid #454545",
}),
fontSize: "16px",
}}
>
{column.label} {column.label}
{column.id === "name" && (
<CustomIconButton
onClick={handleSort}
sx={{
marginLeft: "8px",
opacity: 0.4, // Initial transparency
transition:
"0px 0px 0px rgba(255, 255, 255, 0)",
"&:hover": {
opacity: 1,
},
"&:active": {
opacity: 1,
},
}}
>
{sortOrder === "asc" ? (
<ArrowUpwardIcon
sx={{ color: "#FFFFFF" }}
/>
) : (
<ArrowDownwardIcon
sx={{ color: "#FFFFFF" }}
/>
)}
</CustomIconButton>
)}
</StyledTableCell> </StyledTableCell>
))} ))}
</TableRow> </TableRow>
</TableHead> </TableHead>
<TableBody <TableBody>
sx={{
".MuiTableCell-root": {
backgroundColor: "#1C1C1C",
},
}}
>
{/* This is where the modification starts */}
{currentRows.length === 0 ? ( {currentRows.length === 0 ? (
<StyledTableRow> <StyledTableRow>
<StyledTableCell <StyledTableCell
colSpan={columns.length} colSpan={columns.length}
sx={{ sx={{
color: "#D9D8D8",
backgroundColor: "#272727",
textAlign: "center", textAlign: "center",
padding: "32px 0", padding: "32px 0",
}} }}
> >
{(() => { {getEmptyMessage(tableType)}
switch (tableType) {
case "admin":
return "No admins found";
case "role":
return "No roles found";
case "user":
return "No users found";
case "manager":
return "No managers found";
case "vehicle":
return "No vehicles found";
case "station":
return "No charging stations found";
case "external-station":
return "No charging stations found";
case "booking":
return "No bookings found";
case "slots":
return "No slots found";
case "all-available-slots":
return "No available slots found";
default:
return "No data available";
}
})()}
</StyledTableCell> </StyledTableCell>
</StyledTableRow> </StyledTableRow>
) : ( ) : (
currentRows.map((row, rowIndex) => ( currentRows.map((row, rowIndex) => (
<StyledTableRow key={rowIndex}> <StyledTableRow key={rowIndex}>
{columns.map((column) => ( {columns.map((column) => (
// In CustomTable.tsx, update the status column rendering logic inside the TableBody
<StyledTableCell <StyledTableCell
key={column.id} key={column.id}
sx={{ sx={{
color: "#D9D8D8", color: "#000000",
backgroundColor: "#272727", backgroundColor: "#D0E1E9",
...(column.id === "action" && { ...(column.id === "action" && {
position: "sticky", position: "sticky",
right: 0, right: 0,
zIndex: 2, zIndex: 2,
backgroundColor: "#272727",
boxShadow: boxShadow:
"-5px 0 5px -2px rgba(0,0,0,0.15)", "-5px 0 5px -2px rgba(0,0,0,0.15)",
}), }),
}} }}
> >
{isImage(row[column.id]) ? ( {column.id === "action" ? (
<>
<CustomIconButton
onClick={() => {
setSelectedRow(row);
setViewModal(true);
}}
>
<VisibilityIcon
sx={{
color: "#454545",
"&:hover": {
color: "#6B7280",
},
}}
/>
</CustomIconButton>
<CustomIconButton
onClick={() =>
handleEditButton(
row
)
}
>
<EditIcon
sx={{
color: "#454545",
"&:hover": {
color: "#6B7280",
},
}}
/>
</CustomIconButton>
<CustomIconButton
onClick={() => {
setDeleteModal(
true
);
setSelectedRow(row);
}}
>
<DeleteIcon
sx={{
color: "#454545",
"&:hover": {
color: "#6B7280",
},
}}
/>
</CustomIconButton>
</>
) : row.statusField &&
column.id === row.statusField ? ( // Check if statusField matches the column
<Button
variant="outlined"
onClick={(e) => {
e.stopPropagation();
setSelectedRow(row);
handleStatusToggle?.(
row.id,
!row.statusValue
); // Toggle the opposite of current statusValue
}}
color="primary"
sx={{
justifyContent:
"flex-start",
py: 0.5,
px: 1.5,
fontSize: "0.75rem",
fontWeight: "600",
borderRadius: "4px",
color: "#000000",
border: "1px solid #000000",
backgroundColor:
"transparent",
"&:hover": {
borderColor:
"#000000",
backgroundColor:
"transparent",
},
"&::before": {
content: '""',
display:
"inline-block",
width: "8px",
height: "8px",
borderRadius: "50%",
marginRight: "8px",
backgroundColor:
row.statusValue
? "#10B981"
: "#EF4444", // Green for true, red for false
},
}}
>
{row.statusValue
? "Available"
: "Not Available"}
</Button>
) : isImage(row[column.id]) ? (
<img <img
src={row[column.id]} src={row[column.id]}
alt="Row " alt="Row"
style={{ style={{
width: "50px", width: "50px",
height: "50px", height: "50px",
@ -625,28 +599,8 @@ const CustomTable: React.FC<CustomTableProps> = ({
objectFit: "cover", objectFit: "cover",
}} }}
/> />
) : column.id !== "action" ? (
row[column.id]
) : ( ) : (
<CustomIconButton row[column.id]
onClick={(e) => {
handleClick(e, row);
setRowData(row);
}}
sx={{
padding: 0,
minWidth: 0,
width: "auto",
height: "auto",
color: "#FFFFFF",
}}
>
<MoreHorizRoundedIcon
sx={{
fontSize: "24px",
}}
/>
</CustomIconButton>
)} )}
</StyledTableCell> </StyledTableCell>
))} ))}
@ -657,99 +611,26 @@ const CustomTable: React.FC<CustomTableProps> = ({
</Table> </Table>
</TableContainer> </TableContainer>
{/* Pagination */} {/* Pagination */}
<Box <Box sx={{ display: "flex", justifyContent: "flex-end", mt: 3 }}>
sx={{
display: "flex",
justifyContent: "flex-end",
alignItems: "center",
marginTop: "16px",
}}
>
{filteredRows.length > 0 && (
<>
<Typography
sx={{
color: "white",
fontSize: "16px",
fontWeight: 500,
marginRight: "8px", // optional spacing
}}
>
Page Number :
</Typography>
<Pagination <Pagination
count={Math.ceil( count={Math.ceil(filteredRows.length / usersPerPage)}
filteredRows.length / usersPerPage
)}
page={currentPage} page={currentPage}
onChange={handlePageChange} onChange={handlePageChange}
siblingCount={0}
boundaryCount={0}
sx={{ sx={{
"& .MuiPaginationItem-root": { "& .MuiPaginationItem-root": {
color: "white", color: "#000000",
borderRadius: "0px",
}, },
"& .MuiPaginationItem-page.Mui-selected": { "& .Mui-selected": {
backgroundColor: "transparent", backgroundColor: "#000000",
fontWeight: "bold",
fontSize: "16px",
color: "#FFFFFF", color: "#FFFFFF",
}, },
}} }}
/> />
</>
)}
</Box> </Box>
{/* Menu Actions */}
{open && (
<Menu
anchorEl={anchorEl}
id="menu"
open={open}
onClose={handleClose}
transformOrigin={{ horizontal: "right", vertical: "top" }}
anchorOrigin={{ horizontal: "right", vertical: "bottom" }}
sx={{
[`& .${paperClasses.root}`]: {
padding: 0,
},
"& .MuiList-root": {
background: "#272727",
},
}}
>
<div
style={{
display: "flex",
flexDirection: "column",
width: "80px",
}}
>
<Button
variant="text"
onClick={(e) => {
e.stopPropagation();
setViewModal(true);
}}
color="primary"
sx={{
justifyContent: "center",
py: 1,
fontWeight: "bold",
color: "#52ACDF",
fontSize: "16px",
}}
>
View
</Button>
{viewModal && tableType === "admin" && ( {viewModal && tableType === "admin" && (
<ViewModal <ViewModal
handleView={() => handleView={() => handleViewButton(selectedRow?.id)}
handleViewButton(selectedRow?.id)
}
open={viewModal} open={viewModal}
setViewModal={setViewModal} setViewModal={setViewModal}
id={selectedRow?.id} id={selectedRow?.id}
@ -757,9 +638,7 @@ const CustomTable: React.FC<CustomTableProps> = ({
)} )}
{viewModal && tableType === "manager" && ( {viewModal && tableType === "manager" && (
<ManagerViewModal <ManagerViewModal
handleView={() => handleView={() => handleViewButton(selectedRow?.id)}
handleViewButton(selectedRow?.id)
}
open={viewModal} open={viewModal}
setViewModal={setViewModal} setViewModal={setViewModal}
id={selectedRow?.id} id={selectedRow?.id}
@ -768,9 +647,7 @@ const CustomTable: React.FC<CustomTableProps> = ({
{viewModal && tableType === "vehicle" && ( {viewModal && tableType === "vehicle" && (
<VehicleViewModal <VehicleViewModal
handleView={() => handleView={() => handleViewButton(selectedRow?.id)}
handleViewButton(selectedRow?.id)
}
open={viewModal} open={viewModal}
setViewModal={setViewModal} setViewModal={setViewModal}
id={selectedRow?.id} id={selectedRow?.id}
@ -778,9 +655,7 @@ const CustomTable: React.FC<CustomTableProps> = ({
)} )}
{viewModal && tableType === "station" && ( {viewModal && tableType === "station" && (
<StationViewModal <StationViewModal
handleView={() => handleView={() => handleViewButton(selectedRow?.id)}
handleViewButton(selectedRow?.id)
}
open={viewModal} open={viewModal}
setViewModal={setViewModal} setViewModal={setViewModal}
id={selectedRow?.id} id={selectedRow?.id}
@ -788,39 +663,13 @@ const CustomTable: React.FC<CustomTableProps> = ({
)} )}
{viewModal && tableType === "user" && ( {viewModal && tableType === "user" && (
<UserViewModal <UserViewModal
handleView={() => handleView={() => handleViewButton(selectedRow?.id)}
handleViewButton(selectedRow?.id)
}
open={viewModal} open={viewModal}
setViewModal={setViewModal} setViewModal={setViewModal}
id={selectedRow?.id} id={selectedRow?.id}
/> />
)} )}
{/* Edit Button */}
<Button
variant="text"
onClick={(e) => {
e.stopPropagation();
setModalOpen(true);
if (selectedRow) {
setModalOpen(true); // Only open if a row is selected
setRowData(selectedRow);
}
handleClose();
}}
color="primary"
sx={{
justifyContent: "center",
py: 1,
fontWeight: "bold",
textTransform: "capitalize",
fontSize: "16px",
}}
>
Edit
</Button>
{tableType === "role" && ( {tableType === "role" && (
<Button <Button
variant="text" variant="text"
@ -835,54 +684,10 @@ const CustomTable: React.FC<CustomTableProps> = ({
fontWeight: "bold", fontWeight: "bold",
}} }}
> >
{selectedRow?.statusValue === 1 {selectedRow?.statusValue === 1 ? "Deactivate" : "Activate"}
? "Deactivate"
: "Activate"}
</Button> </Button>
)} )}
{tableType === "station" && (
<Button
variant="text"
onClick={(e) => {
e.stopPropagation();
handleToggleStatus();
}}
color="secondary"
sx={{
justifyContent: "flex-start",
py: 0,
fontWeight: "bold",
}}
>
{selectedRow?.statusValue === 1
? "Not Available"
: "Available"}
</Button>
)}
{/* Delete Button */}
<Button
variant="text"
// color="error"
onClick={(e) => {
e.stopPropagation();
setDeleteModal(true);
handleClose();
}}
sx={{
justifyContent: "center",
py: 1,
fontWeight: "bold",
fontSize: "16px",
color: "red !important",
}}
>
Delete
</Button>
</div>
</Menu>
)}
{/* Modals */} {/* Modals */}
{deleteModal && ( {deleteModal && (
<DeleteModal <DeleteModal

View file

@ -58,15 +58,11 @@ const EditSlotModal: React.FC<EditSlotModalProps> = ({
}); });
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [isAvailable, setIsAvailable] = useState<boolean>(
editRow?.isAvailable || false
);
useEffect(() => { useEffect(() => {
if (editRow) { if (editRow) {
setValue("startTime", editRow.startTime); setValue("startTime", editRow.startTime);
setValue("endTime", editRow.endTime); setValue("endTime", editRow.endTime);
setIsAvailable(editRow.isAvailable);
} else { } else {
reset(); reset();
} }
@ -77,24 +73,21 @@ const EditSlotModal: React.FC<EditSlotModalProps> = ({
setLoading(true); setLoading(true);
try { try {
const availabilityStatus = isAvailable ? true : false;
await dispatch( await dispatch(
updateSlot({ updateSlot({
id: editRow.id, // Slot ID// date: data.date, id: editRow.id,
startTime: data.startTime, startTime: data.startTime,
endTime: data.endTime, endTime: data.endTime,
isAvailable: availabilityStatus,
}) })
).unwrap(); ).unwrap();
dispatch(fetchManagersSlots()); dispatch(fetchManagersSlots());
handleClose(); // Close modal on success handleClose();
reset(); // Reset form fields after submit reset();
} catch (error) { } catch (error) {
console.error("Error updating slot:", error); console.error("Error updating slot:", error);
// Handle the error or show a toast message
} finally { } finally {
setLoading(false); // Stop loading state setLoading(false);
} }
} }
}; };
@ -106,7 +99,7 @@ const EditSlotModal: React.FC<EditSlotModalProps> = ({
if (reason === "backdropClick") { if (reason === "backdropClick") {
return; return;
} }
handleClose(); // Close modal when clicking cross or cancel handleClose();
}} }}
aria-labelledby="edit-slot-modal" aria-labelledby="edit-slot-modal"
> >
@ -119,7 +112,7 @@ const EditSlotModal: React.FC<EditSlotModalProps> = ({
left: "50%", left: "50%",
transform: "translate(-50%, -50%)", transform: "translate(-50%, -50%)",
width: 400, width: 400,
bgcolor: "background.paper", bgcolor: "#000000",
boxShadow: 24, boxShadow: 24,
p: 3, p: 3,
borderRadius: 2, borderRadius: 2,
@ -133,10 +126,18 @@ const EditSlotModal: React.FC<EditSlotModalProps> = ({
alignItems: "center", alignItems: "center",
}} }}
> >
<Typography variant="h6" fontWeight={600} fontSize={"16px"}> <Typography
variant="h6"
fontWeight={600}
fontSize={"16px"}
color="#D0E1E9"
>
Edit Slot Edit Slot
</Typography> </Typography>
<CustomIconButton onClick={handleClose}> <CustomIconButton
onClick={handleClose}
sx={{ "& .MuiSvgIcon-root": { color: "#FFFFFF" } }}
>
<CloseIcon /> <CloseIcon />
</CustomIconButton> </CustomIconButton>
</Box> </Box>
@ -148,7 +149,12 @@ const EditSlotModal: React.FC<EditSlotModalProps> = ({
<Box sx={{ display: "flex", flexWrap: "wrap", gap: 2 }}> <Box sx={{ display: "flex", flexWrap: "wrap", gap: 2 }}>
{/* Start Time */} {/* Start Time */}
<Box sx={{ flex: "1 1 48%" }}> <Box sx={{ flex: "1 1 48%" }}>
<Typography variant="body2" fontWeight={500} mb={0.5}> <Typography
variant="body2"
fontWeight={500}
mb={0.5}
color="#D0E1E9"
>
Start Time Start Time
</Typography> </Typography>
<Controller <Controller
@ -170,7 +176,12 @@ const EditSlotModal: React.FC<EditSlotModalProps> = ({
{/* End Time */} {/* End Time */}
<Box sx={{ flex: "1 1 48%" }}> <Box sx={{ flex: "1 1 48%" }}>
<Typography variant="body2" fontWeight={500} mb={0.5}> <Typography
variant="body2"
fontWeight={500}
mb={0.5}
color="#D0E1E9"
>
End Time End Time
</Typography> </Typography>
<Controller <Controller
@ -189,30 +200,6 @@ const EditSlotModal: React.FC<EditSlotModalProps> = ({
)} )}
/> />
</Box> </Box>
{/* Availability Toggle */}
<Box
display="flex"
alignItems="center"
justifyContent="space-between"
gap={2}
sx={{ flex: "1 1 100%" }}
>
<Button
onClick={() => {
const newAvailability = !isAvailable;
setIsAvailable(newAvailability); // Update local state
setValue("isAvailable", newAvailability); // Update form value for isAvailable
}}
variant={isAvailable ? "contained" : "outlined"}
color="primary"
>
{isAvailable ? "Available" : "Not Available"}
</Button>
{/* <Typography>
{isAvailable ? "Available" : "Not Available"}
</Typography> */}
</Box>
</Box> </Box>
{/* Submit Button */} {/* Submit Button */}
@ -222,12 +209,12 @@ const EditSlotModal: React.FC<EditSlotModalProps> = ({
<Button <Button
type="submit" type="submit"
sx={{ sx={{
backgroundColor: "#52ACDF", backgroundColor: "#D0E1E9",
color: "white", color: "#000000",
borderRadius: "8px", borderRadius: "8px",
fontSize:'16px', fontSize: "16px",
width: "117px", width: "117px",
"&:hover": { backgroundColor: "#439BC1" }, "&:hover": { backgroundColor: "#D0E1E9" },
}} }}
disabled={loading} // Disable the button during loading state disabled={loading} // Disable the button during loading state
> >

View file

@ -12,7 +12,6 @@ import { AppDispatch, RootState } from "../../redux/store/store";
import { fetchDashboardData } from "../../redux/slices/dashboardSlice"; import { fetchDashboardData } from "../../redux/slices/dashboardSlice";
import { Box } from "@mui/material"; import { Box } from "@mui/material";
function AreaGradient({ color, id }: { color: string; id: string }) { function AreaGradient({ color, id }: { color: string; id: string }) {
return ( return (
<defs> <defs>
@ -23,7 +22,7 @@ function AreaGradient({ color, id }: { color: string; id: string }) {
</defs> </defs>
); );
} }
const chartColor = " #111111"; const chartColor = " #111111";
export default function LineChartCard() { export default function LineChartCard() {
const theme = useTheme(); const theme = useTheme();
const isXsScreen = useMediaQuery(theme.breakpoints.down("sm")); const isXsScreen = useMediaQuery(theme.breakpoints.down("sm"));
@ -66,7 +65,7 @@ export default function LineChartCard() {
width: "100%", width: "100%",
height: "auto", height: "auto",
minHeight: { xs: "360px", sm: "400px", md: "444px" }, minHeight: { xs: "360px", sm: "400px", md: "444px" },
borderRadius: "16px", borderRadius: "30px",
border: "none", border: "none",
background: "#D0E1E9", background: "#D0E1E9",
}} }}
@ -156,7 +155,7 @@ export default function LineChartCard() {
{/* Line Chart */} {/* Line Chart */}
<Box sx={{ mt: 7.5 }}> <Box sx={{ mt: 7.5 }}>
<LineChart <LineChart
colors={[theme.palette.primary.main]} colors={[chartColor]}
xAxis={[ xAxis={[
{ {
scaleType: "point", scaleType: "point",
@ -170,7 +169,7 @@ export default function LineChartCard() {
curve: "linear", curve: "linear",
area: true, area: true,
data: chartData.map((data) => data.value), data: chartData.map((data) => data.value),
color: theme.palette.primary.main, color: "#000000",
}, },
]} ]}
height={getChartHeight()} height={getChartHeight()}

View file

@ -11,19 +11,18 @@ import { useDispatch, useSelector } from "react-redux";
import { useEffect } from "react"; import { useEffect } from "react";
import { fetchDashboardData } from "../../redux/slices/dashboardSlice"; import { fetchDashboardData } from "../../redux/slices/dashboardSlice";
const colorPalette = [ // const colorPalette = [
"hsla(202, 69%, 60%, 1)", // "hsla(202, 69%, 60%, 1)",
"hsl(204, 48.60%, 72.50%)", // "hsl(204, 48.60%, 72.50%)",
"hsl(214, 56.40%, 30.60%)", // "hsl(214, 56.40%, 30.60%)",
"hsl(222, 6.80%, 50.80%)", // "hsl(222, 6.80%, 50.80%)",
];
// const data = [
// { title: "Total Resources", value: 50, color: colorPalette[0] },
// { title: "Total Stations", value: 20, color: colorPalette[1] },
// { title: "Station Manager", value: 15, color: colorPalette[2] },
// { title: "Total Booth", value: 15, color: colorPalette[3] },
// ]; // ];
const colorPalette = [
"rgb(11, 13, 14)",
"hsl(204, 59.60%, 78.60%)",
"hsl(214, 77.50%, 13.90%)",
"hsl(222, 4.10%, 52.20%)",
];
export default function ResourcePieChart() { export default function ResourcePieChart() {
const theme = useTheme(); const theme = useTheme();
@ -31,20 +30,10 @@ export default function ResourcePieChart() {
const isSmScreen = useMediaQuery(theme.breakpoints.between("sm", "md")); const isSmScreen = useMediaQuery(theme.breakpoints.between("sm", "md"));
const dispatch = useDispatch<AppDispatch>(); const dispatch = useDispatch<AppDispatch>();
// // Fetch role and carPortCounts from Redux state
// const {user} = useSelector((state: RootState) => state.profileReducer); // Assuming user role is stored in Redux
const { carPortCounts } = useSelector( const { carPortCounts } = useSelector(
(state: RootState) => state.dashboardReducer (state: RootState) => state.dashboardReducer
); );
console.log("first", carPortCounts); console.log("first", carPortCounts);
// Static data for non-superadmin roles
// const staticCarPorts = [
// { carPort: "240V", count: 5 },
// { carPort: "120V", count: 3 },
// { carPort: "DCFC", count: 2 },
// { carPort: "Other", count: 7 },
// ];
useEffect(() => { useEffect(() => {
dispatch(fetchDashboardData()); dispatch(fetchDashboardData());
}, [dispatch]); }, [dispatch]);
@ -53,11 +42,6 @@ export default function ResourcePieChart() {
const dataToDisplay = carPortCounts; const dataToDisplay = carPortCounts;
// const dataToDisplay =
// user?.userType === "superadmin"
// ? carPortCounts.filter((entry) => entry.count > 0) // Exclude zero counts
// : staticCarPorts.filter((entry) => entry.count > 0);
// console.log("Filtered Data to Display:", dataToDisplay);
const getChartDimensions = () => { const getChartDimensions = () => {
if (isXsScreen) { if (isXsScreen) {
return { return {
@ -100,11 +84,9 @@ export default function ResourcePieChart() {
height: "auto", height: "auto",
minHeight: { xs: "320px", sm: "340px", md: "360px" }, minHeight: { xs: "320px", sm: "340px", md: "360px" },
padding: { xs: "12px", sm: "14px", md: "16px" }, padding: { xs: "12px", sm: "14px", md: "16px" },
borderRadius: "16px", borderRadius: "30px",
border: "none", border: "none",
// "*:where([data-mui-color-scheme='dark']) &": {
// backgroundColor: "#202020",
// },
background: "#D0E1E9", background: "#D0E1E9",
}} }}
> >
@ -114,12 +96,10 @@ export default function ResourcePieChart() {
<Typography <Typography
component="h2" component="h2"
variant="subtitle2" variant="subtitle2"
// color="#F2F2F2"
sx={{ sx={{
fontWeight: 600, fontWeight: 600,
fontSize: { xs: "12px", sm: "14px", md: "16px" }, fontSize: { xs: "12px", sm: "14px", md: "16px" },
lineHeight: "24px", lineHeight: "24px",
// color: "#FFFFFF",
marginBottom: { xs: 1, sm: 1.5, md: 2 }, marginBottom: { xs: 1, sm: 1.5, md: 2 },
}} }}
> >

View file

@ -27,12 +27,9 @@ export default function SessionsChart() {
height: "auto", height: "auto",
minHeight: { xs: "260px", sm: "270px", md: "290px" }, minHeight: { xs: "260px", sm: "270px", md: "290px" },
gap: "16px", gap: "16px",
borderRadius: "16px", borderRadius: "30px",
padding: { xs: "12px", sm: "16px", md: "20px" }, padding: { xs: "12px", sm: "16px", md: "20px" },
border: "none", border: "none",
// "*:where([data-mui-color-scheme='dark']) &": {
// backgroundColor: "#202020",
// },
background: "#D0E1E9", background: "#D0E1E9",
}} }}
> >

View file

@ -26,7 +26,7 @@ export default function StatCard({ title, value }: StatCardProps) {
sm: "14px", sm: "14px",
md: "10px", md: "10px",
}, },
borderRadius: "12px", borderRadius: "30px",
border: "none", border: "none",
gap: "24px", gap: "24px",
background: "#D0E1E9", background: "#D0E1E9",
@ -80,9 +80,9 @@ export default function StatCard({ title, value }: StatCardProps) {
sx={{ sx={{
fontWeight: 600, fontWeight: 600,
fontSize: { fontSize: {
xs: "24px", xs: "25px",
sm: "28px", sm: "30px",
md: "30px", md: "35px",
}, },
lineHeight: { lineHeight: {
xs: "28px", xs: "28px",

View file

@ -49,6 +49,7 @@ export default function RoundedBarChart() {
{ {
dataKey: "name", dataKey: "name",
scaleType: "band" as const, scaleType: "band" as const,
bandWidth: isXsScreen ? 8 : 15,
}, },
], ],
sx: { sx: {
@ -74,7 +75,7 @@ export default function RoundedBarChart() {
} else { } else {
return { return {
...baseSettings, ...baseSettings,
width: 500, width: 400,
height: 280, height: 280,
}; };
} }
@ -95,11 +96,8 @@ export default function RoundedBarChart() {
width: "100%", width: "100%",
height: "auto", height: "auto",
minHeight: { xs: "360px", sm: "400px", md: "444px" }, minHeight: { xs: "360px", sm: "400px", md: "444px" },
borderRadius: "16px", borderRadius: "30px",
border: "none", border: "none",
// "*:where([data-mui-color-scheme='dark']) &": {
// backgroundColor: "#202020",
// },
background: "#D0E1E9", background: "#D0E1E9",
}} }}
> >
@ -211,7 +209,7 @@ export default function RoundedBarChart() {
series={[ series={[
{ {
dataKey: "count", dataKey: "count",
color: "#52ACDF", color: "#000000",
}, },
]} ]}
layout="vertical" layout="vertical"

View file

@ -40,7 +40,7 @@ export default function Login(props: { disableCustomTheme?: boolean }) {
trigger, trigger,
} = useForm<ILoginForm>({ mode: "onChange" }); } = useForm<ILoginForm>({ mode: "onChange" });
const dispatch = useDispatch<AppDispatch>(); const dispatch = useDispatch<AppDispatch>();
const router = useNavigate(); const navigate = useNavigate();
const handleClickOpen = () => { const handleClickOpen = () => {
setOpen(true); setOpen(true);
@ -63,7 +63,7 @@ export default function Login(props: { disableCustomTheme?: boolean }) {
try { try {
const response = await dispatch(loginUser(data)).unwrap(); const response = await dispatch(loginUser(data)).unwrap();
if (response?.data?.token) { if (response?.data?.token) {
router("/panel/dashboard"); navigate("/panel/dashboard");
} }
} catch (error: any) { } catch (error: any) {
console.log("Login failed:", error); console.log("Login failed:", error);
@ -112,7 +112,7 @@ export default function Login(props: { disableCustomTheme?: boolean }) {
xs={12} xs={12}
md={5} md={5}
sx={{ sx={{
backgroundColor: "black", backgroundColor: "background.default", // Use theme's default background (#DFECF1)
display: "flex", display: "flex",
justifyContent: "center", justifyContent: "center",
alignItems: "center", alignItems: "center",
@ -144,7 +144,7 @@ export default function Login(props: { disableCustomTheme?: boolean }) {
<Typography <Typography
variant="h3" variant="h3"
sx={{ sx={{
color: "white", color: "text.primary", // Use theme's primary text color (#000000)
textAlign: "center", textAlign: "center",
fontSize: { fontSize: {
xs: "1.8rem", xs: "1.8rem",
@ -154,6 +154,8 @@ export default function Login(props: { disableCustomTheme?: boolean }) {
width: "100%", width: "100%",
mb: { xs: 2, md: 3 }, mb: { xs: 2, md: 3 },
mt: { xs: 0, md: 0 }, mt: { xs: 0, md: 0 },
fontFamily:
'"Publica Sans Round Medium", sans-serif',
}} }}
> >
Welcome Back! Welcome Back!
@ -171,11 +173,9 @@ export default function Login(props: { disableCustomTheme?: boolean }) {
maxWidth: "408px", maxWidth: "408px",
minHeight: { xs: "auto", md: "428px" }, minHeight: { xs: "auto", md: "428px" },
padding: { xs: "16px", sm: "20px", md: "24px" }, padding: { xs: "16px", sm: "20px", md: "24px" },
borderRadius: "9px", borderRadius: "8px", // Match theme's borderRadius
border: "none", backgroundColor: "#000000", // Use theme's paper color (#D0E1E9)
"*:where([data-mui-color-scheme='dark']) &": { borderColor: "divider", // Use theme's divider color (#E0E0E0)
backgroundColor: "#1E1E1E",
},
}} }}
> >
<Box <Box
@ -193,10 +193,13 @@ export default function Login(props: { disableCustomTheme?: boolean }) {
variant="h4" variant="h4"
sx={{ sx={{
textAlign: "center", textAlign: "center",
color: "white", color: "#D0E1E9",
fontSize: { xs: "20px", md: "24px" }, fontSize: { xs: "20px", md: "24px" },
fontFamily:
'"Publica Sans Round Medium", sans-serif',
}} }}
> >
{" "}
Login Login
</Typography> </Typography>
<Typography <Typography
@ -204,9 +207,11 @@ export default function Login(props: { disableCustomTheme?: boolean }) {
variant="subtitle2" variant="subtitle2"
sx={{ sx={{
textAlign: "center", textAlign: "center",
color: "#D9D8D8", color: "#D0E1E9", // Use theme's secondary text color (#272727)
fontSize: { xs: "14px", md: "16px" }, fontSize: { xs: "14px", md: "16px" },
mb: 1, mb: 1,
fontFamily:
'"Publica Sans Round Medium", sans-serif',
}} }}
> >
Log in with your email and password Log in with your email and password
@ -217,13 +222,14 @@ export default function Login(props: { disableCustomTheme?: boolean }) {
<FormLabel <FormLabel
htmlFor="email" htmlFor="email"
sx={{ sx={{
borderRadius: "8px",
fontSize: { fontSize: {
xs: "0.875rem", xs: "0.875rem",
sm: "1rem", sm: "1rem",
}, },
color: "white", color: "#D0E1E9",
mb: 0.5, mb: 0.5,
fontFamily:
'"Publica Sans Round Medium", sans-serif',
...autofillFix, ...autofillFix,
}} }}
> >
@ -269,46 +275,43 @@ export default function Login(props: { disableCustomTheme?: boolean }) {
}, },
alignItems: "center", alignItems: "center",
backgroundColor: backgroundColor:
"#1E1F1F", "background.paper", // Match card background
borderRadius: "8px",
}, },
}} }}
sx={{ sx={{
"& .MuiOutlinedInput-root": "& .MuiOutlinedInput-root":
{ {
backgroundColor:
"#1E1F1F",
borderRadius: "8px",
"& fieldset": { "& fieldset": {
borderColor: borderColor:
"#4b5255", "divider",
}, },
"&:hover fieldset": "&:hover fieldset":
{ {
borderColor: borderColor:
"#4b5255", "text.secondary",
}, },
"&.Mui-focused fieldset": "&.Mui-focused fieldset":
{ {
borderColor: borderColor:
"#4b5255", "primary.main",
}, },
}, },
"& input": { "& input": {
color: "white", color: "text.primary",
fontSize: { fontSize: {
xs: "0.875rem", xs: "0.875rem",
sm: "1rem", sm: "1rem",
}, },
fontFamily: fontFamily:
"Gilroy, sans-serif", '"Publica Sans Round Medium", sans-serif',
}, },
"& .MuiInputBase-input::placeholder": "& .MuiInputBase-input::placeholder":
{ {
color: "white", color: "text.secondary",
opacity: 1, opacity: 1,
fontFamily: fontFamily:
"Gilroy, sans-serif", '"Publica Sans Round Medium", sans-serif',
}, },
...autofillFix, ...autofillFix,
}} }}
@ -322,14 +325,14 @@ export default function Login(props: { disableCustomTheme?: boolean }) {
<FormLabel <FormLabel
htmlFor="password" htmlFor="password"
sx={{ sx={{
borderRadius: "8px",
fontSize: { fontSize: {
xs: "0.875rem", xs: "0.875rem",
sm: "1rem", sm: "1rem",
}, },
color: "white", color: "#D0E1E9",
fontFamily: "Gilroy, sans-serif",
mb: 0.5, mb: 0.5,
fontFamily:
'"Publica Sans Round Medium", sans-serif',
}} }}
> >
Password Password
@ -381,16 +384,18 @@ export default function Login(props: { disableCustomTheme?: boolean }) {
xs: "45px", xs: "45px",
md: "50px", md: "50px",
}, },
backgroundColor:
"background.paper",
borderRadius: "8px",
...autofillFix, ...autofillFix,
}, },
endAdornment: ( endAdornment: (
<InputAdornment position="end"> <InputAdornment position="end">
<CustomIconButton <CustomIconButton
aria-label="toggle password visibility" aria-label="toggle password visibility"
onClick={ onClick={
togglePasswordVisibility togglePasswordVisibility
} // Only the button triggers visibility toggle }
edge="end" edge="end"
> >
{showPassword ? ( {showPassword ? (
@ -405,35 +410,36 @@ export default function Login(props: { disableCustomTheme?: boolean }) {
sx={{ sx={{
"& .MuiOutlinedInput-root": "& .MuiOutlinedInput-root":
{ {
backgroundColor:
"#1E1F1F",
borderRadius: "8px",
"& fieldset": { "& fieldset": {
borderColor: borderColor:
"#4b5255", "divider",
}, },
"&:hover fieldset": "&:hover fieldset":
{ {
borderColor: borderColor:
"#4b5255", "text.secondary",
}, },
"&.Mui-focused fieldset": "&.Mui-focused fieldset":
{ {
borderColor: borderColor:
"#4b5255", "primary.main",
}, },
}, },
"& input": { "& input": {
color: "white", color: "text.primary",
fontSize: { fontSize: {
xs: "0.875rem", xs: "0.875rem",
sm: "1rem", sm: "1rem",
}, },
fontFamily:
'"Publica Sans Round Medium", sans-serif',
}, },
"& .MuiInputBase-input::placeholder": "& .MuiInputBase-input::placeholder":
{ {
color: "white", color: "text.secondary",
opacity: 1, opacity: 1,
fontFamily:
'"Publica Sans Round Medium", sans-serif',
}, },
}} }}
/> />
@ -446,7 +452,6 @@ export default function Login(props: { disableCustomTheme?: boolean }) {
sx={{ sx={{
display: "flex", display: "flex",
justifyContent: "space-between", justifyContent: "space-between",
color: "white",
alignItems: "center", alignItems: "center",
flexWrap: { xs: "wrap", sm: "nowrap" }, flexWrap: { xs: "wrap", sm: "nowrap" },
gap: 1, gap: 1,
@ -460,7 +465,8 @@ export default function Login(props: { disableCustomTheme?: boolean }) {
sx={{ sx={{
width: { xs: 16, md: 20 }, width: { xs: 16, md: 20 },
height: { xs: 16, md: 20 }, height: { xs: 16, md: 20 },
border: "2px solid #4b5255", border: "2px solid",
borderColor: "divider",
borderRadius: "4px", borderRadius: "4px",
backgroundColor: backgroundColor:
"transparent", "transparent",
@ -471,7 +477,8 @@ export default function Login(props: { disableCustomTheme?: boolean }) {
"&.Mui-checked": { "&.Mui-checked": {
backgroundColor: backgroundColor:
"transparent", "transparent",
borderColor: "#4b5255", borderColor:
"primary.main",
"&:hover": { "&:hover": {
backgroundColor: backgroundColor:
"transparent", "transparent",
@ -488,6 +495,9 @@ export default function Login(props: { disableCustomTheme?: boolean }) {
sm: "0.875rem", sm: "0.875rem",
md: "1rem", md: "1rem",
}, },
color: "#D0E1E9",
fontFamily:
'"Publica Sans Round Medium", sans-serif',
}} }}
> >
Remember me Remember me
@ -502,22 +512,20 @@ export default function Login(props: { disableCustomTheme?: boolean }) {
variant="body2" variant="body2"
sx={{ sx={{
alignSelf: "center", alignSelf: "center",
color: "#01579b", color: "#D0E1E9",
textDecoration: "none", textDecoration: "none",
fontSize: { fontSize: {
xs: "0.75rem", xs: "0.75rem",
sm: "0.875rem", sm: "0.875rem",
md: "1rem", md: "1rem",
}, },
fontFamily:
'"Publica Sans Round Medium", sans-serif',
}} }}
> >
Forgot password? Forgot password?
</Link> </Link>
</Box> </Box>
{/* <ForgotPassword
open={open}
handleClose={handleClose}
/> */}
{/* Login Button */} {/* Login Button */}
<Button <Button
@ -525,11 +533,11 @@ export default function Login(props: { disableCustomTheme?: boolean }) {
fullWidth fullWidth
disabled={!isValid} disabled={!isValid}
sx={{ sx={{
color: "#ffffff !important", color: "#000000",
fontWeight: 500, fontWeight: 500,
backgroundColor: "#52ACDF", backgroundColor: "#D0E1E9",
"&:hover": { "&:hover": {
backgroundColor: "#52ACDF", backgroundColor: "#D0E1E9",
}, },
padding: { xs: "8px 0", md: "10px 0" }, padding: { xs: "8px 0", md: "10px 0" },
mt: { xs: 2, md: 3 }, mt: { xs: 2, md: 3 },
@ -537,6 +545,8 @@ export default function Login(props: { disableCustomTheme?: boolean }) {
xs: "0.875rem", xs: "0.875rem",
md: "1rem", md: "1rem",
}, },
fontFamily:
'"Publica Sans Round Medium", sans-serif',
}} }}
> >
Login Login

View file

@ -6,6 +6,7 @@ import { useForm } from "react-hook-form";
import { import {
createSlot, createSlot,
fetchManagersSlots, fetchManagersSlots,
toggleStatus,
updateSlot, updateSlot,
} from "../../redux/slices/slotSlice"; } from "../../redux/slices/slotSlice";
import AddSlotModal from "../../components/AddSlotModal/addSlotModal"; import AddSlotModal from "../../components/AddSlotModal/addSlotModal";
@ -25,7 +26,6 @@ export default function EVSlotList() {
(state: RootState) => state?.slotReducer.availableSlots (state: RootState) => state?.slotReducer.availableSlots
); );
const { user } = useSelector((state: RootState) => state?.profileReducer); const { user } = useSelector((state: RootState) => state?.profileReducer);
console.log("bjbjhjh", availableSlots);
useEffect(() => { useEffect(() => {
dispatch(fetchManagersSlots()); dispatch(fetchManagersSlots());
}, [dispatch]); }, [dispatch]);
@ -101,7 +101,6 @@ console.log("bjbjhjh", availableSlots);
duration: duration, duration: duration,
}; };
// Dispatch action to create slot and refresh available slots
await dispatch(createSlot(payload)); await dispatch(createSlot(payload));
await dispatch(fetchManagersSlots()); await dispatch(fetchManagersSlots());
@ -116,8 +115,7 @@ console.log("bjbjhjh", availableSlots);
const handleUpdate = async ( const handleUpdate = async (
id: string, id: string,
startTime: string, startTime: string,
endTime: string, endTime: string
isAvailable: boolean
) => { ) => {
try { try {
// Convert times using dayjs // Convert times using dayjs
@ -136,7 +134,6 @@ console.log("bjbjhjh", availableSlots);
id, id,
startTime: formattedStartTime, startTime: formattedStartTime,
endTime: formattedEndTime, endTime: formattedEndTime,
isAvailable,
}) })
).unwrap(); ).unwrap();
@ -150,13 +147,17 @@ console.log("bjbjhjh", availableSlots);
} }
}; };
const handleStatusToggle = async (id: string, newStatus: boolean) => {
await dispatch(toggleStatus({ id, isAvailable: newStatus })); // Dispatch the action with the correct status
};
const slotColumns: Column[] = [ const slotColumns: Column[] = [
{ id: "srno", label: "Sr No" }, { id: "srno", label: "Sr No" },
{ id: "stationName", label: "Station Name" }, { id: "stationName", label: "Station Name" },
{ id: "date", label: "Date" }, { id: "date", label: "Date" },
{ id: "startTime", label: "Start Time" }, { id: "startTime", label: "Start Time" },
{ id: "endTime", label: "End Time" }, { id: "endTime", label: "End Time" },
{ id: "isAvailable", label: "Is Available", align: "center" }, { id: "isAvailable", label: "Status", align: "center" },
...(user?.userType === "manager" ...(user?.userType === "manager"
? [{ id: "action", label: "Action", align: "center" as const }] ? [{ id: "action", label: "Action", align: "center" as const }]
: []), : []),
@ -164,7 +165,6 @@ console.log("bjbjhjh", availableSlots);
const slotRows = availableSlots?.length const slotRows = availableSlots?.length
? availableSlots.map((slot, index) => { ? availableSlots.map((slot, index) => {
const startTime = dayjs( const startTime = dayjs(
slot?.startTime, slot?.startTime,
"YYYY-MM-DD hh:mm A" "YYYY-MM-DD hh:mm A"
@ -173,7 +173,6 @@ console.log("bjbjhjh", availableSlots);
"hh:mm A" "hh:mm A"
) )
: "Invalid"; : "Invalid";
const endTime = dayjs( const endTime = dayjs(
slot?.endTime, slot?.endTime,
"YYYY-MM-DD hh:mm A" "YYYY-MM-DD hh:mm A"
@ -190,7 +189,11 @@ console.log("bjbjhjh", availableSlots);
date: slot?.date ?? "NA", date: slot?.date ?? "NA",
startTime: startTime ?? "NA", startTime: startTime ?? "NA",
endTime: endTime ?? "NA", endTime: endTime ?? "NA",
isAvailable: slot?.isAvailable ? "Yes" : "No", isAvailable: slot?.isAvailable
? "Available"
: "Not Available",
statusValue: !!slot?.isAvailable, // Normalize to boolean (true/false)
statusField: "isAvailable", // I
}; };
}) })
: []; : [];
@ -208,7 +211,9 @@ console.log("bjbjhjh", availableSlots);
setModalOpen={() => setEditModalOpen(true)} setModalOpen={() => setEditModalOpen(true)}
tableType="slots" tableType="slots"
handleClickOpen={handleClickOpen} handleClickOpen={handleClickOpen}
handleStatusToggle={handleStatusToggle} // Pass handleStatusToggle as a prop
/> />
<AddSlotModal <AddSlotModal
open={addModalOpen} open={addModalOpen}
handleClose={handleCloseModal} handleClose={handleCloseModal}

View file

@ -86,19 +86,10 @@ export default function StationList() {
} }
}; };
const handleStatusToggle = async (id: string, newStatus: number) => { const handleStatusToggle = async (id: string, newStatus: boolean) => {
await dispatch(toggleStatus({ id, status: newStatus })); await dispatch(toggleStatus({ id, status: newStatus ? 1 : 0 })); // For stations, convert boolean to 1/0
}; };
// const filterStations = Array.isArray(stations)
// ? stations.filter((station) =>
// station.name
// .toLocaleLowerCase()
// .includes(searchTerm.toLowerCase())
// )
// : [];
// Mapping and formatting vehicles
const categoryRows = stations?.length const categoryRows = stations?.length
? stations?.map((station: any, index: number) => { ? stations?.map((station: any, index: number) => {
// Format the selected vehicles from the allowedCars array // Format the selected vehicles from the allowedCars array
@ -122,9 +113,8 @@ export default function StationList() {
registeredAddress: station.registeredAddress || "N/A", registeredAddress: station.registeredAddress || "N/A",
totalSlots: station.totalSlots, totalSlots: station.totalSlots,
vehicles: vehicleDisplay, // Add the formatted vehicle display here vehicles: vehicleDisplay, // Add the formatted vehicle display here
status: statusValue: station?.status === 1, // Normalize to boolean (true for 1, false for 0)
station.status === 1 ? "Available" : "Not Available", // Format status text statusField: "status", // Status value for toggling
statusValue: station.status, // Status value for toggling
}; };
}) })
: []; : [];

View file

@ -85,8 +85,7 @@ export const createSlot = createAsyncThunk<
endHour: string; endHour: string;
isAvailable: boolean; isAvailable: boolean;
duration: number; duration: number;
stationId:number; stationId: number;
}, },
{ rejectValue: string } { rejectValue: string }
>("slots/createSlot", async (payload, { rejectWithValue }) => { >("slots/createSlot", async (payload, { rejectWithValue }) => {
@ -114,7 +113,6 @@ export const updateSlot = createAsyncThunk<
id: string; id: string;
startTime: string; startTime: string;
endTime: string; endTime: string;
isAvailable: boolean;
}, },
{ rejectValue: string } { rejectValue: string }
>("slots/updateSlot", async ({ id, ...slotData }, { rejectWithValue }) => { >("slots/updateSlot", async ({ id, ...slotData }, { rejectWithValue }) => {
@ -134,7 +132,39 @@ export const updateSlot = createAsyncThunk<
); );
} }
}); });
export const toggleStatus = createAsyncThunk<
any,
{ id: string; isAvailable: boolean },
{ rejectValue: string }
>("slot/toggleStatus", async ({ id, isAvailable }, { rejectWithValue }) => {
try {
const response = await http.patch(`/update-availability/${id}`, {
isAvailable,
});
if (response.data.statusCode === 200) {
toast.success(
response.data.message || "Status updated successfully"
);
return {
responseData: response.data,
id,
isAvailable,
};
} else {
throw new Error(response.data.message || "Failed to update status");
}
} catch (error: any) {
toast.error(
"Error updating status: " + (error.message || "Unknown error")
);
return rejectWithValue(
error.response?.data?.message ||
error.message ||
"An error occurred"
);
}
});
export const deleteSlot = createAsyncThunk< export const deleteSlot = createAsyncThunk<
string, // Return type (id of deleted slot) string, // Return type (id of deleted slot)
string, string,
@ -193,16 +223,6 @@ const slotSlice = createSlice({
.addCase(createSlot.pending, (state) => { .addCase(createSlot.pending, (state) => {
state.loading = true; state.loading = true;
}) })
// .addCase(
// createSlot.fulfilled,
// (state, action: PayloadAction<Slot[]>) => {
// state.loading = false;
// // Add the new slots to both arrays
// state.slots.push(...action.payload);
// state.availableSlots.push(...action.payload);
// }
// )
.addCase( .addCase(
createSlot.fulfilled, createSlot.fulfilled,
(state, action: PayloadAction<Slot[]>) => { (state, action: PayloadAction<Slot[]>) => {
@ -254,6 +274,35 @@ const slotSlice = createSlice({
.addCase(deleteSlot.pending, (state) => { .addCase(deleteSlot.pending, (state) => {
state.loading = true; state.loading = true;
}) })
.addCase(toggleStatus.pending, (state) => {
state.loading = true;
})
.addCase(
toggleStatus.fulfilled,
(state, action: PayloadAction<any>) => {
state.loading = false;
const { id, isAvailable } = action.payload;
const stationIndex = state.availableSlots.findIndex(
(slot) => slot.id === id
);
if (stationIndex !== -1) {
state.availableSlots[stationIndex] = {
...state.availableSlots[stationIndex],
isAvailable: isAvailable,
};
}
}
)
.addCase(
toggleStatus.rejected,
(state, action: PayloadAction<string | undefined>) => {
state.loading = false;
state.error =
action.payload || "Failed to toggle station status";
}
)
.addCase( .addCase(
deleteSlot.fulfilled, deleteSlot.fulfilled,
(state, action: PayloadAction<string>) => { (state, action: PayloadAction<string>) => {

View file

@ -1,67 +1,4 @@
// import * as React from "react";
// import { ThemeProvider, Theme, createTheme } from "@mui/material/styles";
// import type { ThemeOptions } from "@mui/material/styles";
// import { inputsCustomizations } from "./customizations/inputs";
// import { dataDisplayCustomizations } from "./customizations/dataDisplay";
// import { feedbackCustomizations } from "./customizations/feedback";
// import { navigationCustomizations } from "./customizations/navigation";
// import { surfacesCustomizations } from "./customizations/surfaces";
// import { colorSchemes, shadows, shape } from "./themePrimitives";
// interface AppThemeProps {
// children: React.ReactNode;
// disableCustomTheme?: boolean;
// themeComponents?: ThemeOptions["components"];
// }
// export default function AppTheme(props: AppThemeProps) {
// const { children, disableCustomTheme, themeComponents } = props;
// const theme = React.useMemo(() => {
// return disableCustomTheme
// ? {}
// : createTheme({
// palette: {
// mode: "dark",
// background: {
// // default: "#ECF4FA",
// default: "#DFECF1",
// paper: "#1e1e1e",
// },
// text: {
// primary: "#111111",
// secondary: "#b0b0b0",
// },
// },
// typography: {
// fontFamily: "Gilroy",
// },
// cssVariables: {
// colorSchemeSelector: "data-mui-color-scheme",
// cssVarPrefix: "template",
// },
// shadows,
// shape,
// components: {
// ...inputsCustomizations,
// ...dataDisplayCustomizations,
// ...feedbackCustomizations,
// ...navigationCustomizations,
// ...surfacesCustomizations,
// ...themeComponents,
// },
// });
// }, [disableCustomTheme, themeComponents]);
// if (disableCustomTheme) {
// return <React.Fragment>{children}</React.Fragment>;
// }
// return (
// <ThemeProvider theme={theme} disableTransitionOnChange>
// {children}
// </ThemeProvider>
// );
// }
import * as React from "react"; import * as React from "react";
import { ThemeProvider, Theme, createTheme } from "@mui/material/styles"; import { ThemeProvider, Theme, createTheme } from "@mui/material/styles";
import type { ThemeOptions } from "@mui/material/styles"; import type { ThemeOptions } from "@mui/material/styles";

View file

@ -20,8 +20,8 @@ export const autofillFix = {
}, },
"& input:autofill": { "& input:autofill": {
boxShadow: "0 0 0 1000px transparent inset !important", boxShadow: "0 0 0 1000px transparent inset !important",
textFillColor: "white !important", textFillColor: "transparent !important",
transition: "background-color 5000s ease-in-out 0s", transition: "background-color 5000s ease-in-out 0s",
}, },
}; };