Table UI changes and manager , charging station modals ui chnaged

This commit is contained in:
jaanvi 2025-04-22 18:34:59 +05:30
parent f353befab5
commit b2945a83f5
14 changed files with 784 additions and 437 deletions

View file

@ -8,7 +8,6 @@ import {
InputAdornment,
Select,
MenuItem,
InputLabel,
FormControl,
} from "@mui/material";
import CloseIcon from "@mui/icons-material/Close";
@ -21,12 +20,7 @@ import { RootState } from "../../redux/reducers.ts";
import { stationList } from "../../redux/slices/stationSlice.ts";
import { autofillFix } from "../../shared-theme/customizations/autoFill.tsx";
export default function AddManagerModal({
open,
handleClose,
handleAddManager,
// Assume the stations prop contains a list of station objects with 'id' and 'name'
}) {
export default function AddManagerModal({ open, handleClose }) {
const dispatch = useDispatch();
const {
control,
@ -34,7 +28,10 @@ export default function AddManagerModal({
handleSubmit,
formState: { errors },
reset,
} = useForm();
clearErrors,
} = useForm({
mode: "onChange", // Trigger validation on change for real-time feedback
});
const [showPassword, setShowPassword] = useState(false);
const stations = useSelector(
(state: RootState) => state?.stationReducer.stations
@ -46,7 +43,6 @@ export default function AddManagerModal({
// Handle form submission
const onSubmit = async (data: any) => {
// Retrieve the stationId based on the stationName selected
const selectedStation = stations.find(
(station) => station.name === data.stationName
);
@ -55,22 +51,29 @@ export default function AddManagerModal({
email: data.email,
phone: data.phone,
password: data.password,
stationId: selectedStation?.id, // Send stationId here
stationId: selectedStation?.id,
};
try {
// Dispatch the addManager action
await dispatch(addManager(managerData));
dispatch(managerList());
handleClose(); // Close modal after successful addition
reset(); // Reset form fields
clearErrors(); // Clear errors on successful submission
reset(); // Reset form fields on successful submission
handleClose(); // Close modal
} catch (error) {
console.error("Error adding manager:", error);
}
};
// Handle modal close, clearing errors and resetting form
const handleModalClose = () => {
clearErrors(); // Clear errors when closing via close icon
reset(); // Reset form fields when closing via close icon
handleClose(); // Close modal
};
const togglePasswordVisibility = (e: React.MouseEvent) => {
e.preventDefault(); // Prevent focus loss
e.preventDefault();
setShowPassword((prev) => !prev);
};
@ -79,9 +82,9 @@ export default function AddManagerModal({
open={open}
onClose={(e, reason) => {
if (reason === "backdropClick") {
return;
return; // Prevent closing on backdrop click
}
handleClose(); // Close modal when clicking cross or cancel
handleModalClose();
}}
aria-labelledby="add-manager-modal"
>
@ -92,7 +95,7 @@ export default function AddManagerModal({
left: "50%",
transform: "translate(-50%, -50%)",
width: 400,
bgcolor: "background.paper",
bgcolor: "#000000",
boxShadow: 24,
p: 3,
borderRadius: 2,
@ -106,10 +109,15 @@ export default function AddManagerModal({
alignItems: "center",
}}
>
<Typography variant="h6" fontWeight={600} fontSize={"16px"}>
<Typography
variant="h6"
fontWeight={600}
fontSize={"16px"}
color="#D0E1E9"
>
Add Manager
</Typography>
<CustomIconButton onClick={handleClose}>
<CustomIconButton onClick={handleModalClose}>
<CloseIcon />
</CustomIconButton>
</Box>
@ -122,7 +130,11 @@ export default function AddManagerModal({
{/* Manager Name */}
<Box sx={{ display: "flex", gap: 2, mb: 2 }}>
<Box sx={{ flex: 1, ...autofillFix }}>
<Typography variant="body2" fontWeight={500}>
<Typography
variant="body2"
fontWeight={500}
color="#D0E1E9"
>
Manager Name
</Typography>
<CustomTextField
@ -159,7 +171,11 @@ export default function AddManagerModal({
{/* Station Dropdown */}
<Box sx={{ display: "flex", gap: 2, mb: 2 }}>
<Box sx={{ flex: 1 }}>
<Typography variant="body2" fontWeight={500}>
<Typography
variant="body2"
fontWeight={500}
color="#D0E1E9"
>
Select Station
</Typography>
<FormControl
@ -167,48 +183,57 @@ export default function AddManagerModal({
size="small"
error={!!errors.stationName}
>
<Select
{...register("stationName", {
<Controller
name="stationName"
control={control}
rules={{
required: "Station Name is required",
})}
sx={{ marginTop: 1 }}
displayEmpty
defaultValue=""
renderValue={(selected) => {
if (!selected) {
return (
<Typography color="text.secondary">
Choose Station
</Typography>
);
}
return selected;
}}
MenuProps={{
PaperProps: {
style: {
maxHeight: 224,
},
},
}}
>
{Array.isArray(stations) &&
stations.length > 0 ? (
stations.map((station) => (
<MenuItem
key={station.id}
value={station.name}
>
{station.name}
</MenuItem>
))
) : (
<MenuItem disabled>
No stations available
</MenuItem>
render={({ field }) => (
<Select
{...field}
onChange={(e) =>
field.onChange(e.target.value)
} // Update form state
value={field.value || ""} // Ensure controlled value
sx={{ marginTop: 1 }}
displayEmpty
renderValue={(selected) => {
if (!selected) {
return (
<Typography color="text.secondary">
Choose Station
</Typography>
);
}
return selected;
}}
MenuProps={{
PaperProps: {
style: {
maxHeight: 224,
},
},
}}
>
{Array.isArray(stations) &&
stations.length > 0 ? (
stations.map((station) => (
<MenuItem
key={station.id}
value={station.name}
>
{station.name}
</MenuItem>
))
) : (
<MenuItem disabled>
No stations available
</MenuItem>
)}
</Select>
)}
</Select>
/>
{errors.stationName && (
<Typography
color="error"
@ -226,7 +251,11 @@ export default function AddManagerModal({
<Box sx={{ display: "flex", gap: 2, mb: 2 }}>
{/* Email */}
<Box sx={{ flex: 1, ...autofillFix }}>
<Typography variant="body2" fontWeight={500}>
<Typography
variant="body2"
fontWeight={500}
color="#D0E1E9"
>
Email
</Typography>
<CustomTextField
@ -243,7 +272,8 @@ export default function AddManagerModal({
required: "Email is required",
pattern: {
value: /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/,
message: "Invalid email address",
message:
"Please enter a valid email address (e.g., example@domain.com).",
},
})}
/>
@ -251,7 +281,11 @@ export default function AddManagerModal({
{/* Password */}
<Box sx={{ flex: 1, ...autofillFix }}>
<Typography variant="body2" fontWeight={500}>
<Typography
variant="body2"
fontWeight={500}
color="#D0E1E9"
>
Password
</Typography>
<Controller
@ -319,7 +353,11 @@ export default function AddManagerModal({
{/* Phone Number */}
<Box sx={{ display: "flex", gap: 2, mb: 2 }}>
<Box sx={{ flex: 1, ...autofillFix }}>
<Typography variant="body2" fontWeight={500}>
<Typography
variant="body2"
fontWeight={500}
color="#D0E1E9"
>
Phone Number
</Typography>
<CustomTextField
@ -343,7 +381,7 @@ export default function AddManagerModal({
if (value.length > 14) {
return "Phone number must be at most 14 digits";
}
return true; // No errors
return true;
},
})}
/>
@ -361,12 +399,12 @@ export default function AddManagerModal({
<Button
type="submit"
sx={{
backgroundColor: "#52ACDF",
color: "white",
backgroundColor: "#D0E1E9",
color: "#000000",
borderRadius: "8px",
fontSize: "16px",
width: "117px",
"&:hover": { backgroundColor: "#439BC1" },
width: "125px",
"&:hover": { backgroundColor: "#DFECF1" },
}}
>
Add Manager

View file

@ -35,6 +35,7 @@ export default function AddStationModal({
handleSubmit,
formState: { errors },
reset,
clearErrors,
} = useForm();
const dispatch = useDispatch();
@ -83,7 +84,11 @@ export default function AddStationModal({
.filter((vehicle) => selectedVehicles.includes(vehicle.name))
.map((vehicle) => vehicle.id);
};
const handleModalClose = () => {
clearErrors();
reset();
handleClose();
};
const onSubmit = (data: any) => {
const vehicleIds = getVehicleIds(); // Get the ids of the selected vehicles
@ -95,7 +100,7 @@ export default function AddStationModal({
};
handleAddStation(payload);
handleClose(); // Close modal after adding
handleClose();
reset();
setSelectedVehicles([]);
setSelectedBrands([]); // Reset selected brands after submission
@ -119,7 +124,7 @@ export default function AddStationModal({
left: "50%",
transform: "translate(-50%, -50%)",
width: 400,
bgcolor: "background.paper",
bgcolor: "#000000",
boxShadow: 24,
p: 3,
borderRadius: 2,
@ -133,10 +138,15 @@ export default function AddStationModal({
alignItems: "center",
}}
>
<Typography variant="h6" fontWeight={600} fontSize={"16px"}>
<Typography
variant="h6"
fontWeight={600}
fontSize={"16px"}
color="#D0E1E9"
>
Add Charging Station
</Typography>
<CustomIconButton onClick={handleClose}>
<CustomIconButton onClick={handleModalClose}>
<CloseIcon />
</CustomIconButton>
</Box>
@ -163,7 +173,11 @@ export default function AddStationModal({
...autofillFix,
}}
>
<Typography variant="body2" fontWeight={500}>
<Typography
variant="body2"
fontWeight={500}
color="#D0E1E9"
>
Station Name
</Typography>
<CustomTextField
@ -199,7 +213,11 @@ export default function AddStationModal({
...autofillFix,
}}
>
<Typography variant="body2" fontWeight={500}>
<Typography
variant="body2"
fontWeight={500}
color="#D0E1E9"
>
Station Location
</Typography>
<CustomTextField
@ -215,7 +233,7 @@ export default function AddStationModal({
}
{...register("registeredAddress", {
required:
"Registered Address is required",
"Station Location is required",
})}
/>
</Box>
@ -230,7 +248,11 @@ export default function AddStationModal({
width: "100%",
}}
>
<Typography variant="body2" fontWeight={500}>
<Typography
variant="body2"
fontWeight={500}
color="#D0E1E9"
>
Total Slots
</Typography>
<CustomTextField
@ -270,6 +292,7 @@ export default function AddStationModal({
variant="body2"
fontWeight={500}
sx={{ mb: 1 }}
color="#D0E1E9"
>
Vehicle Brand
</Typography>
@ -283,7 +306,7 @@ export default function AddStationModal({
renderValue={(selected) => {
if (selected.length === 0) {
return (
<Typography color="text.secondary">
<Typography color="#D0E1E9">
Choose Brands
</Typography>
);
@ -316,6 +339,7 @@ export default function AddStationModal({
<Typography
key={index}
variant="body2"
color="#454545"
>
{brand
? brand.name
@ -328,7 +352,7 @@ export default function AddStationModal({
{moreCount > 0 && (
<Typography
variant="body2"
color="textSecondary"
color="#454545"
>
+{moreCount} more
</Typography>
@ -385,6 +409,7 @@ export default function AddStationModal({
variant="body2"
fontWeight={500}
sx={{ mb: 1 }}
color="#D0E1E9"
>
Vehicle Name
</Typography>
@ -402,7 +427,7 @@ export default function AddStationModal({
renderValue={(selected) => {
if (selected.length === 0) {
return (
<Typography color="text.secondary">
<Typography color="#454545">
{selectedBrands.length ===
0
? "Select brand first"
@ -433,6 +458,7 @@ export default function AddStationModal({
<Typography
key={index}
variant="body2"
color="#454545"
>
{name}
</Typography>
@ -441,7 +467,7 @@ export default function AddStationModal({
{moreCount > 0 && (
<Typography
variant="body2"
color="textSecondary"
color="#454545"
>
+{moreCount} more
</Typography>
@ -501,12 +527,12 @@ export default function AddStationModal({
<Button
type="submit"
sx={{
backgroundColor: "#52ACDF",
color: "white",
backgroundColor: "#D0E1E9",
color: "#000000",
borderRadius: "8px",
fontSize: "16px",
width: "117px",
"&:hover": { backgroundColor: "#439BC1" },
"&:hover": { backgroundColor: "#DFECF1" },
}}
>
Add Station

View file

@ -9,6 +9,7 @@ export const CustomIconButton = styled(IconButton)({
backgroundColor: "transparent",
border: "none",
},
color: "#D0E1E9",
});
// Custom TextField with different placeholder color

View file

@ -92,7 +92,7 @@ export default function AddVehicleModal({
left: "50%",
transform: "translate(-50%, -50%)",
width: 400,
bgcolor: "background.paper",
bgcolor: "#000000",
boxShadow: 24,
p: 3,
borderRadius: 2,
@ -106,7 +106,12 @@ export default function AddVehicleModal({
alignItems: "center",
}}
>
<Typography variant="h6" fontWeight={600} fontSize={"16px"}>
<Typography
variant="h6"
fontWeight={600}
fontSize={"16px"}
color="#D0E1E9"
>
Add Vehicle
</Typography>
<CustomIconButton onClick={handleClose}>
@ -133,6 +138,7 @@ export default function AddVehicleModal({
variant="body2"
fontWeight={500}
mb={0.5}
color="#D0E1E9"
>
Vehicle Name
</Typography>
@ -183,6 +189,7 @@ export default function AddVehicleModal({
variant="body2"
fontWeight={500}
mb={0.5}
color="#D0E1E9"
>
Company
</Typography>
@ -226,6 +233,7 @@ export default function AddVehicleModal({
variant="body2"
fontWeight={500}
mb={0.5}
color="#D0E1E9"
>
Model Name
</Typography>
@ -259,6 +267,7 @@ export default function AddVehicleModal({
variant="body2"
fontWeight={500}
mb={0.5}
color="#D0E1E9"
>
Charge Type
</Typography>
@ -290,17 +299,22 @@ export default function AddVehicleModal({
...autofillFix,
}}
>
<Typography variant="body2" fontWeight={500} mb={0.5}>
<Typography
variant="body2"
fontWeight={500}
mb={0.5}
color="#D0E1E9"
>
Upload Image
</Typography>
<Button
component="label"
sx={{
backgroundColor: "#52ACDF",
color: "white",
backgroundColor: "#D0E1E9",
color: "#000000",
borderRadius: "8px",
width: "100%",
"&:hover": { backgroundColor: "#52ACDF" },
"&:hover": { backgroundColor: "#DFECF1" },
}}
>
Choose Image
@ -346,12 +360,12 @@ export default function AddVehicleModal({
<Button
type="submit"
sx={{
backgroundColor: "#52ACDF",
color: "white",
backgroundColor: "#D0E1E9",
color: "#00000",
borderRadius: "8px",
fontSize:"16px",
fontSize: "16px",
width: "117px",
"&:hover": { backgroundColor: "#439BC1" },
"&:hover": { backgroundColor: "#DFECF1" },
}}
>
Add Vehicle

View file

@ -6,86 +6,126 @@ import TableCell, { tableCellClasses } from "@mui/material/TableCell";
import TableContainer from "@mui/material/TableContainer";
import TableHead from "@mui/material/TableHead";
import TableRow from "@mui/material/TableRow";
import Paper, { paperClasses } from "@mui/material/Paper";
import { adminList, deleteAdmin } from "../../redux/slices/adminSlice.ts";
import { vehicleList, deleteVehicle } from "../../redux/slices/VehicleSlice.ts";
import { deleteManager, managerList } from "../../redux/slices/managerSlice.ts";
import { useDispatch, useSelector } from "react-redux";
import Paper from "@mui/material/Paper";
import {
Box,
Button,
InputAdornment,
Menu,
IconButton,
Pagination,
TextField,
Typography,
IconButton,
Menu,
MenuItem,
} from "@mui/material";
import MoreVertIcon from "@mui/icons-material/MoreVert";
import VisibilityIcon from "@mui/icons-material/Visibility";
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 DeleteModal from "../Modals/DeleteModal/index.tsx";
import SearchIcon from "@mui/icons-material/Search";
import ArrowUpwardIcon from "@mui/icons-material/ArrowUpward";
import ArrowDownwardIcon from "@mui/icons-material/ArrowDownward";
import { useDispatch, useSelector } from "react-redux";
import { AppDispatch, RootState } from "../../redux/store/store.ts";
import DeleteModal from "../Modals/DeleteModal/index.tsx";
import ViewModal from "../Modals/ViewModal/index.tsx";
import VehicleViewModal from "../Modals/VehicleViewModal/index.tsx";
import SearchIcon from "@mui/icons-material/Search";
import TuneIcon from "@mui/icons-material/Tune";
import { CustomIconButton } from "../AddUserModal/styled.css";
import ManagerViewModal from "../Modals/ViewManagerModal/index.tsx";
import ManagerViewModal from "../Modals/ViewManagerModal/";
import UserViewModal from "../Modals/UserViewModal/index.tsx";
import StationViewModal from "../Modals/StationViewModal/index.tsx";
import { adminList, deleteAdmin } from "../../redux/slices/adminSlice.ts";
import { vehicleList, deleteVehicle } from "../../redux/slices/VehicleSlice.ts";
import { deleteManager, managerList } from "../../redux/slices/managerSlice.ts";
import { deleteUser, userList } from "../../redux/slices/userSlice.ts";
import { deleteStation, stationList } from "../../redux/slices/stationSlice.ts";
import StationViewModal from "../Modals/StationViewModal/index.tsx";
import {
deleteSlot,
fetchAvailableSlots,
} from "../../redux/slices/slotSlice.ts";
import { bookingList, deleteBooking } from "../../redux/slices/bookSlice.ts";
import AddCircleIcon from "@mui/icons-material/AddCircle";
import {
deleteStationDetails,
stationDetailList,
} from "../../redux/slices/managerStationSlice.ts";
import { CustomIconButton } from "../AddUserModal/styled.css.tsx";
import { autofillFix } from "../../shared-theme/customizations/autoFill.tsx";
import ArrowUpwardIcon from "@mui/icons-material/ArrowUpward";
import ArrowDownwardIcon from "@mui/icons-material/ArrowDownward";
import { deleteStationDetails, stationDetailList } from "../../redux/slices/managerStationSlice.ts";
import ManagerStationDetails from "../../pages/ManagerStationDetails/index.tsx";
// Styled components for customization
// Styled Components
const StyledTableCell = styled(TableCell)(({ theme }) => ({
[`&.${tableCellClasses.body}`]: {
fontSize: "16px",
borderBottom: "1px solid rgba(87, 85, 85, 0.53)",
color: "#000000",
backgroundColor: "#D0E1E9",
},
[`&.${tableCellClasses.head}`]: {
backgroundColor: "#000000",
color: "#D0E1E9",
fontWeight: 600,
fontSize: "16px",
padding: "12px 16px",
borderBottom: "none",
//borderRight: "1px solid rgba(141, 135, 135, 0.51)",
position: "sticky",
top: 0,
zIndex: 10,
transition: "background-color 0.2s ease",
"&:hover": {
backgroundColor: "#2A2A2A",
cursor: "pointer",
},
// Make the "Action" header cell sticky
"&.action-cell": {
right: 0,
zIndex: 11, // Higher z-index to ensure it stays above other headers
boxShadow: "-4px 0 8px rgba(0, 0, 0, 0.1)",
},
},
[`&.${tableCellClasses.body}`]: {
fontSize: "16px",
padding: "12px 16px",
borderBottom: "1px solid rgba(255, 255, 255, 0.1)",
color: "#333333",
transition: "background-color 0.2s ease",
// Make the "Action" body cell sticky
"&.action-cell": {
position: "sticky",
right: 0,
zIndex: 2,
boxShadow: "-4px 0 8px rgba(0, 0, 0, 0.1)",
backgroundColor: "#DFECF1", // Match row background
"&:hover": {
backgroundColor: "#D0E1E9", // Match row hover background
},
},
},
}));
const StyledTableRow = styled(TableRow)(({ theme }) => ({
backgroundColor: "#D0E1E9",
"& td, th": {
backgroundColor: "#DFECF1",
transition: "background-color 0.2s ease",
"&:hover": {
backgroundColor: "#D0E1E9",
},
"& td, & th": {
borderColor: "#454545",
borderWidth: "1px",
borderBottom: "1px solid #454545",
color: "#000000",
backgroundColor: "#D0E1E9",
},
}));
const StyledTableContainer = styled(TableContainer)(({ theme }) => ({
borderRadius: "12px",
boxShadow: "0 4px 12px rgba(0, 0, 0, 0.1)",
"&::-webkit-scrollbar": {
height: "6px",
},
"&::-webkit-scrollbar-track": {
background: "#D0E1E9",
},
"&::-webkit-scrollbar-thumb": {
background: "#000000",
borderRadius: "3px",
},
}));
// Interfaces
export interface Column {
id: string;
label: string;
align?: "left" | "center" | "right";
}
interface Row {
@ -102,11 +142,16 @@ interface CustomTableProps {
setViewModal: Function;
deleteModal: boolean;
handleStatusToggle?: (id: string, currentStatus: number | boolean) => void;
tableType: string; // Adding tableType prop to change header text dynamically
tableType: string;
handleClickOpen?: () => void;
statusField?: string; // Optional field to indicate the status column
statusValue?: boolean; // Optional normalized status value
statusField?: string;
statusValue?: boolean;
}
// Sorting State Interface
interface SortConfig {
key: string;
direction: "asc" | "desc" | null;
}
const CustomTable: React.FC<CustomTableProps> = ({
@ -123,18 +168,19 @@ const CustomTable: React.FC<CustomTableProps> = ({
handleClickOpen,
}) => {
const dispatch = useDispatch<AppDispatch>();
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
const [selectedRow, setSelectedRow] = React.useState<Row | null>(null);
const [searchQuery, setSearchQuery] = React.useState("");
const [currentPage, setCurrentPage] = React.useState(1);
const [sortConfig, setSortConfig] = React.useState<SortConfig>({
key: "",
direction: null,
});
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
const [menuRow, setMenuRow] = React.useState<Row | null>(null);
const usersPerPage = 10;
const { user } = useSelector((state: RootState) => state?.profileReducer);
const open = Boolean(anchorEl);
const [sortOrder, setSortOrder] = React.useState<"asc" | "desc" | null>(
null
);
// ... [imports remain the same, no changes needed] ...
// Helper Functions
const getTitleByType = (type: string) => {
const titles: { [key: string]: string } = {
admin: "Admins",
@ -143,9 +189,9 @@ const CustomTable: React.FC<CustomTableProps> = ({
manager: "Managers",
"all-managers": "Managers",
vehicle: "Vehicles",
station: "Charging Station",
"external-station": "Charging Station",
booking: "Booking",
station: "Charging Stations",
"external-station": "Charging Stations",
booking: "Bookings",
slots: "Slots",
"all-available-slots": "Available Slots",
"manager-station": "Station Details",
@ -196,23 +242,76 @@ const CustomTable: React.FC<CustomTableProps> = ({
return true;
};
const handleClick = (event: React.MouseEvent<HTMLElement>, row: Row) => {
setAnchorEl(event.currentTarget);
setSelectedRow(row);
setRowData(row);
};
const handleClose = () => {
setAnchorEl(null);
};
const isImage = (value: any) => {
if (typeof value === "string") {
return value.startsWith("http") || value.startsWith("data:image"); // Check for URL or base64 image
return value.startsWith("http") || value.startsWith("data:image");
}
return false;
};
// Sorting Logic
const handleSort = (key: string) => {
setSortConfig((prev) => {
if (prev.key === key) {
if (prev.direction === "asc") return { key, direction: "desc" };
if (prev.direction === "desc") return { key, direction: null };
return { key, direction: "asc" };
}
return { key, direction: "asc" };
});
};
const sortedRows = React.useMemo(() => {
if (!sortConfig.key || !sortConfig.direction) return [...rows];
return [...rows].sort((a, b) => {
const aValue = a[sortConfig.key];
const bValue = b[sortConfig.key];
if (aValue == null && bValue == null) return 0;
if (aValue == null) return sortConfig.direction === "asc" ? 1 : -1;
if (bValue == null) return sortConfig.direction === "asc" ? -1 : 1;
if (typeof aValue === "number" && typeof bValue === "number") {
return sortConfig.direction === "asc"
? aValue - bValue
: bValue - aValue;
}
const aStr = String(aValue).toLowerCase();
const bStr = String(bValue).toLowerCase();
return sortConfig.direction === "asc"
? aStr.localeCompare(bStr)
: bStr.localeCompare(aStr);
});
}, [rows, sortConfig]);
// Filtering Logic
const filteredRows = sortedRows.filter((row) => {
if (!searchQuery.trim()) return true;
const lowerCaseQuery = searchQuery.toLowerCase().trim();
return (
(row.name && row.name.toLowerCase().includes(lowerCaseQuery)) ||
(row.registeredAddress &&
row.registeredAddress.toLowerCase().includes(lowerCaseQuery)) ||
(row.stationName &&
row.stationName.toLowerCase().includes(lowerCaseQuery))
);
});
// Pagination Logic
const indexOfLastRow = currentPage * usersPerPage;
const indexOfFirstRow = indexOfLastRow - usersPerPage;
const currentRows = filteredRows.slice(indexOfFirstRow, indexOfLastRow);
const handlePageChange = (
_event: React.ChangeEvent<unknown>,
value: number
) => {
setCurrentPage(value);
};
// Action Handlers
const handleDeleteButton = (id: string | undefined) => {
if (!id) {
console.error("ID not found", id);
@ -221,36 +320,34 @@ const CustomTable: React.FC<CustomTableProps> = ({
switch (tableType) {
case "admin":
dispatch(deleteAdmin(id || ""));
dispatch(deleteAdmin(id));
break;
case "vehicle":
dispatch(deleteVehicle(id || ""));
dispatch(deleteVehicle(id));
break;
case "manager":
dispatch(deleteManager(id || ""));
dispatch(deleteManager(id));
break;
case "user":
dispatch(deleteUser(id || ""));
dispatch(deleteUser(id));
break;
case "station":
dispatch(deleteStation(id || ""));
dispatch(deleteStation(id));
break;
case "slots":
dispatch(deleteSlot(id || ""));
dispatch(deleteSlot(id));
break;
case "booking":
dispatch(deleteBooking(id || ""));
dispatch(deleteBooking(id));
break;
case "manager-station":
dispatch(deleteStationDetails(id || ""));
dispatch(deleteStationDetails(id));
break;
default:
console.error("Unknown table type:", tableType);
return;
}
setDeleteModal(false); // Close the modal only after deletion
handleClose();
setDeleteModal(false);
};
const handleViewButton = (id: string | undefined) => {
@ -284,62 +381,55 @@ const CustomTable: React.FC<CustomTableProps> = ({
console.error("Unknown table type:", tableType);
return;
}
setViewModal(false);
};
const handleToggleStatus = () => {
if (selectedRow) {
handleStatusToggle?.(selectedRow.id, !selectedRow.statusValue); // Toggle the boolean statusValue
}
handleClose();
};
const handleSort = () => {
setSortOrder((prevSortOrder) =>
prevSortOrder === "asc" ? "desc" : "asc"
);
};
const handleEditButton = (row: Row) => {
setModalOpen(true);
setRowData(row);
};
const sortedRows = React.useMemo(() => {
let sorted = [...rows];
if (sortOrder) {
sorted.sort((a, b) => {
if (a.name < b.name) return sortOrder === "asc" ? -1 : 1;
if (a.name > b.name) return sortOrder === "asc" ? 1 : -1;
return 0;
});
// Menu Handlers
const handleMenuOpen = (event: React.MouseEvent<HTMLElement>, row: Row) => {
setAnchorEl(event.currentTarget);
setMenuRow(row);
};
const handleMenuClose = () => {
setAnchorEl(null);
setMenuRow(null);
};
const handleMenuAction = (action: string) => {
if (!menuRow) return;
switch (action) {
case "view":
setSelectedRow(menuRow);
setViewModal(true);
break;
case "edit":
handleEditButton(menuRow);
break;
case "delete":
setDeleteModal(true);
setSelectedRow(menuRow);
break;
default:
break;
}
return sorted;
}, [rows, sortOrder]);
const filteredRows = sortedRows.filter((row) => {
if (!searchQuery.trim()) return true;
const lowerCaseQuery = searchQuery.toLowerCase().trim();
return (
(row.name && row.name.toLowerCase().includes(lowerCaseQuery)) ||
(row.registeredAddress &&
row.registeredAddress.toLowerCase().includes(lowerCaseQuery)) ||
(row.stationName &&
row.stationName.toLowerCase().includes(lowerCaseQuery))
);
});
const indexOfLastRow = currentPage * usersPerPage;
const indexOfFirstRow = indexOfLastRow - usersPerPage;
const currentRows = filteredRows.slice(indexOfFirstRow, indexOfLastRow);
const handlePageChange = (
_event: React.ChangeEvent<unknown>,
value: number
) => {
setCurrentPage(value);
handleMenuClose();
};
return (
<Box sx={{ width: "100%", padding: "24px", borderRadius: "12px" }}>
<Box
sx={{
width: "100%",
padding: "24px",
backgroundColor: "#D0E1E9",
borderRadius: "12px",
}}
>
{/* Header Section */}
<Box
sx={{
display: "flex",
@ -353,48 +443,47 @@ const handleToggleStatus = () => {
>
<Typography
sx={{
color: "#000000",
fontWeight: 600,
fontSize: "30px",
letterSpacing: "-0.5px",
}}
>
{getTitleByType(tableType)}
</Typography>
{/* Right Side: Search + Add */}
<Box
sx={{
display: "flex",
alignItems: "center",
gap: 2,
flexWrap: "wrap",
justifyContent: "flex-end",
}}
>
<TextField
variant="outlined"
placeholder="Search"
sx={{
width: { xs: "100%", sm: "300px", md: "300px" },
input: { color: "#454545" },
width: { xs: "100%", sm: "300px" },
...autofillFix,
"& .MuiOutlinedInput-root": {
borderRadius: "12px",
height: "44px",
"& fieldset": { borderColor: "#454545" },
"&:hover fieldset": { borderColor: "#454545" },
borderRadius: "8px",
height: "40px",
backgroundColor: "#FFFFFF",
"& fieldset": { borderColor: "#D1D5DB" },
"&:hover fieldset": { borderColor: "#9CA3AF" },
"&.Mui-focused fieldset": {
borderColor: "#52ACDF",
borderColor: "#3B82F6",
},
},
"& .MuiInputBase-input::placeholder": {
color: "#454545",
opacity: 1,
"& .MuiInputBase-input": {
fontSize: "14px",
color: "#1A1A1A",
},
}}
InputProps={{
startAdornment: (
<InputAdornment position="start">
<SearchIcon sx={{ color: "#454545" }} />
<SearchIcon sx={{ color: "#6B7280" }} />
</InputAdornment>
),
}}
@ -402,16 +491,21 @@ const handleToggleStatus = () => {
onChange={(e) => setSearchQuery(e.target.value)}
/>
{/* Conditionally show Add Button */}
{shouldShowAddButton(user?.userType, tableType) && (
<Button
sx={{
backgroundColor: "#000000",
color: "white",
minWidth: "115px",
fontSize: "16px",
paddingX: 2,
"&:hover": { backgroundColor: "#000000" },
color: "#FFFFFF",
fontWeight: 600,
fontSize: "14px",
padding: "8px 16px",
borderRadius: "8px",
textTransform: "none",
"&:hover": {
backgroundColor: "#454545",
boxShadow: "0 2px 8px rgba(0, 0, 0, 0.15)",
},
transition: "all 0.2s ease",
}}
onClick={handleClickOpen}
>
@ -422,33 +516,58 @@ const handleToggleStatus = () => {
</Box>
{/* Table Section */}
<TableContainer
component={Paper}
sx={{
marginTop: "24px",
borderRadius: "12px",
overflow: "auto",
maxWidth: "100%",
"&::-webkit-scrollbar": {
height: "3px",
},
"&::-webkit-scrollbar-track": {
background: "#1C1C1C",
},
"&::-webkit-scrollbar-thumb": {
background: "#52ACDF",
borderRadius: "4px",
},
}}
>
<StyledTableContainer>
<Table sx={{ minWidth: "750px", tableLayout: "auto" }}>
<TableHead>
{" "}
<TableRow>
{columns.map((column) => (
<StyledTableCell key={column.id}>
{column.label}
<StyledTableCell
key={column.id}
align={column.align}
onClick={
column.id !== "action"
? () => handleSort(column.id)
: undefined
}
sx={{
cursor:
column.id !== "action"
? "pointer"
: "default",
}}
className={
column.id === "action"
? "action-cell"
: undefined
} // Add action-cell class
>
<Box
sx={{
display: "flex",
alignItems: "center",
gap: 1,
}}
>
{column.label}
{column.id !== "action" &&
sortConfig.key === column.id &&
sortConfig.direction &&
(sortConfig.direction === "asc" ? (
<ArrowUpwardIcon
sx={{
fontSize: "16px",
color: "#FFFFFF",
}}
/>
) : (
<ArrowDownwardIcon
sx={{
fontSize: "16px",
color: "#FFFFFF",
}}
/>
))}
</Box>
</StyledTableCell>
))}
</TableRow>
@ -458,88 +577,156 @@ const handleToggleStatus = () => {
<StyledTableRow>
<StyledTableCell
colSpan={columns.length}
sx={{
textAlign: "center",
padding: "32px 0",
}}
sx={{ textAlign: "center", py: 4 }}
>
{getEmptyMessage(tableType)}
<Typography
sx={{
color: "#6B7280",
fontSize: "16px",
}}
>
{getEmptyMessage(tableType)}
</Typography>
</StyledTableCell>
</StyledTableRow>
) : (
currentRows.map((row, rowIndex) => (
<StyledTableRow key={rowIndex}>
{columns.map((column) => (
// In CustomTable.tsx, update the status column rendering logic inside the TableBody
<StyledTableCell
key={column.id}
sx={{
color: "#000000",
backgroundColor: "#D0E1E9",
...(column.id === "action" && {
position: "sticky",
right: 0,
zIndex: 2,
boxShadow:
"-5px 0 5px -2px rgba(0,0,0,0.15)",
}),
}}
align={column.align}
className={
column.id === "action"
? "action-cell"
: undefined
} // Add action-cell class
>
{column.id === "action" ? (
<>
<Box>
<CustomIconButton
onClick={() => {
setSelectedRow(row);
setViewModal(true);
}}
>
<VisibilityIcon
sx={{
color: "#454545",
"&:hover": {
color: "#6B7280",
},
}}
/>
</CustomIconButton>
<CustomIconButton
onClick={() =>
handleEditButton(
onClick={(e) =>
handleMenuOpen(
e,
row
)
}
>
<EditIcon
sx={{
sx={{
color: "#6B7280",
"&:hover": {
color: "#454545",
"&:hover": {
color: "#6B7280",
},
}}
/>
</CustomIconButton>
<CustomIconButton
onClick={() => {
setDeleteModal(
true
);
setSelectedRow(row);
},
transition:
"color 0.2s ease",
}}
>
<DeleteIcon
sx={{
color: "#454545",
"&:hover": {
color: "#6B7280",
},
}}
/>
<MoreVertIcon />
</CustomIconButton>
</>
<Menu
anchorEl={anchorEl}
open={
Boolean(anchorEl) &&
menuRow === row
}
onClose={
handleMenuClose
}
anchorOrigin={{
vertical: "top",
horizontal: "right",
}}
transformOrigin={{
vertical: "top",
horizontal: "right",
}}
PaperProps={{
sx: {
borderRadius:
"8px",
boxShadow:
"0 2px 8px rgba(0, 0, 0, 0.15)",
},
}}
>
<MenuItem
onClick={() =>
handleMenuAction(
"view"
)
}
sx={{
color: "#000000",
fontSize:
"16px",
display: "flex",
alignItems:
"center",
gap: 1,
}}
>
<VisibilityIcon
sx={{
fontSize:
"18px",
color: "#454545",
}}
/>
View
</MenuItem>
<MenuItem
onClick={() =>
handleMenuAction(
"edit"
)
}
sx={{
color: "#000000",
fontSize:
"16px",
display: "flex",
alignItems:
"center",
gap: 1,
}}
>
<EditIcon
sx={{
fontSize:
"18px",
color: "#454545",
}}
/>
Edit
</MenuItem>
<MenuItem
onClick={() =>
handleMenuAction(
"delete"
)
}
sx={{
color: "#000000",
fontSize:
"14px",
display: "flex",
alignItems:
"center",
gap: 1,
}}
>
<DeleteIcon
sx={{
fontSize:
"18px",
color: "#454545",
}}
/>
Delete
</MenuItem>
</Menu>
</Box>
) : row.statusField &&
column.id === row.statusField ? ( // Check if statusField matches the column
column.id === row.statusField ? (
<Button
variant="outlined"
onClick={(e) => {
@ -548,26 +735,25 @@ const handleToggleStatus = () => {
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",
fontSize: "12px",
fontWeight: 600,
borderRadius: "6px",
color: row.statusValue
? "#10B981"
: "#EF4444",
borderColor:
row.statusValue
? "#10B981"
: "#EF4444",
padding: "4px 12px",
"&:hover": {
borderColor:
"#000000",
backgroundColor:
"transparent",
row.statusValue
? "rgba(16, 185, 129, 0.1)"
: "rgba(239, 68, 68, 0.1)",
},
"&::before": {
content: '""',
@ -580,7 +766,7 @@ const handleToggleStatus = () => {
backgroundColor:
row.statusValue
? "#10B981"
: "#EF4444", // Green for true, red for false
: "#EF4444",
},
}}
>
@ -593,8 +779,8 @@ const handleToggleStatus = () => {
src={row[column.id]}
alt="Row"
style={{
width: "50px",
height: "50px",
width: "40px",
height: "40px",
borderRadius: "50%",
objectFit: "cover",
}}
@ -609,7 +795,8 @@ const handleToggleStatus = () => {
)}
</TableBody>
</Table>
</TableContainer>
</StyledTableContainer>
{/* Pagination */}
<Box sx={{ display: "flex", justifyContent: "flex-end", mt: 3 }}>
<Pagination
@ -618,16 +805,21 @@ const handleToggleStatus = () => {
onChange={handlePageChange}
sx={{
"& .MuiPaginationItem-root": {
color: "#000000",
color: "#1A1A1A",
fontSize: "16px",
},
"& .Mui-selected": {
backgroundColor: "#000000",
color: "#FFFFFF",
"&:hover": {
backgroundColor: "#000000",
},
},
}}
/>
</Box>
{/* Modals */}
{viewModal && tableType === "admin" && (
<ViewModal
handleView={() => handleViewButton(selectedRow?.id)}
@ -644,7 +836,6 @@ const handleToggleStatus = () => {
id={selectedRow?.id}
/>
)}
{viewModal && tableType === "vehicle" && (
<VehicleViewModal
handleView={() => handleViewButton(selectedRow?.id)}
@ -669,26 +860,6 @@ const handleToggleStatus = () => {
id={selectedRow?.id}
/>
)}
{tableType === "role" && (
<Button
variant="text"
onClick={(e) => {
e.stopPropagation();
handleToggleStatus();
}}
color="secondary"
sx={{
justifyContent: "flex-start",
py: 0,
fontWeight: "bold",
}}
>
{selectedRow?.statusValue === 1 ? "Deactivate" : "Activate"}
</Button>
)}
{/* Modals */}
{deleteModal && (
<DeleteModal
handleDelete={() => handleDeleteButton(selectedRow?.id)}

View file

@ -10,7 +10,7 @@ import CloseIcon from "@mui/icons-material/Close";
import { useForm, Controller } from "react-hook-form";
import { useDispatch } from "react-redux";
import { managerList, updateManager } from "../../redux/slices/managerSlice.ts"; // Import the updateManager action
import { CustomIconButton, CustomTextField } from "../AddUserModal/styled.css";// Custom styled components
import { CustomIconButton, CustomTextField } from "../AddUserModal/styled.css"; // Custom styled components
import { AppDispatch } from "../../redux/store/store.ts";
interface EditManagerModalProps {
@ -114,7 +114,7 @@ const EditManagerModal: React.FC<EditManagerModalProps> = ({
left: "50%",
transform: "translate(-50%, -50%)",
width: 400,
bgcolor: "background.paper",
bgcolor: "#000000",
boxShadow: 24,
p: 3,
borderRadius: 2,
@ -128,7 +128,7 @@ const EditManagerModal: React.FC<EditManagerModalProps> = ({
alignItems: "center",
}}
>
<Typography variant="h6" fontWeight={600}>
<Typography variant="h6" fontWeight={600} color="#D0E1E9">
Edit Manager
</Typography>
<CustomIconButton onClick={handleClose}>
@ -143,7 +143,12 @@ const EditManagerModal: React.FC<EditManagerModalProps> = ({
<Box sx={{ display: "flex", flexWrap: "wrap", gap: 2 }}>
{/* Manager Name */}
<Box sx={{ flex: "1 1 48%" }}>
<Typography variant="body2" fontWeight={500} mb={0.5}>
<Typography
variant="body2"
fontWeight={500}
mb={0.5}
color="#D0E1E9"
>
Manager Name
</Typography>
<Controller
@ -172,7 +177,6 @@ const EditManagerModal: React.FC<EditManagerModalProps> = ({
placeholder="Enter Manager Name"
size="small"
sx={{ marginTop: 1 }}
error={!!errors.name}
helperText={errors.name?.message}
/>
@ -182,13 +186,25 @@ const EditManagerModal: React.FC<EditManagerModalProps> = ({
{/* Email */}
<Box sx={{ flex: "1 1 48%" }}>
<Typography variant="body2" fontWeight={500} mb={0.5}>
<Typography
variant="body2"
fontWeight={500}
mb={0.5}
color="#D0E1E9"
>
Email
</Typography>
<Controller
name="email"
control={control}
rules={{ required: "Email is required" }}
rules={{
required: "Email is required",
pattern: {
value: /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/,
message:
"Please enter a valid email address (e.g., example@domain.com).",
},
}}
render={({ field }) => (
<CustomTextField
{...field}
@ -196,7 +212,6 @@ const EditManagerModal: React.FC<EditManagerModalProps> = ({
placeholder="Enter Email"
size="small"
sx={{ marginTop: 1 }}
error={!!errors.email}
helperText={errors.email?.message}
/>
@ -206,7 +221,12 @@ const EditManagerModal: React.FC<EditManagerModalProps> = ({
{/* Phone Number */}
<Box sx={{ flex: "1 1 48%" }}>
<Typography variant="body2" fontWeight={500} mb={0.5}>
<Typography
variant="body2"
fontWeight={500}
mb={0.5}
color="#D0E1E9"
>
Phone Number
</Typography>
<Controller
@ -234,7 +254,6 @@ const EditManagerModal: React.FC<EditManagerModalProps> = ({
placeholder="Enter Phone Number"
size="small"
sx={{ marginTop: 1 }}
error={!!errors.phone}
helperText={errors.phone?.message}
/>
@ -250,11 +269,11 @@ const EditManagerModal: React.FC<EditManagerModalProps> = ({
<Button
type="submit"
sx={{
backgroundColor: "#52ACDF",
color: "white",
backgroundColor: "#D0E1E9",
color: "#000000",
borderRadius: "8px",
width: "117px",
"&:hover": { backgroundColor: "#439BC1" },
width: "125px",
"&:hover": { backgroundColor: "#DFECF1" },
whiteSpace: "pre",
}}
disabled={loading}

View file

@ -55,6 +55,7 @@ const EditStationModal: React.FC<EditStationModalProps> = ({
setValue,
reset,
formState: { errors },
register,
} = useForm<FormData>({
defaultValues: {
name: "",
@ -197,7 +198,7 @@ const EditStationModal: React.FC<EditStationModalProps> = ({
left: "50%",
transform: "translate(-50%, -50%)",
width: 400,
bgcolor: "background.paper",
bgcolor: "#000000",
boxShadow: 24,
p: 3,
borderRadius: 2,
@ -211,7 +212,12 @@ const EditStationModal: React.FC<EditStationModalProps> = ({
alignItems: "center",
}}
>
<Typography variant="h6" fontWeight={600} fontSize={"16px"}>
<Typography
variant="h6"
fontWeight={600}
fontSize={"16px"}
color="#D0E1E9"
>
Edit Charging Station
</Typography>
<CustomIconButton onClick={handleClose}>
@ -237,6 +243,7 @@ const EditStationModal: React.FC<EditStationModalProps> = ({
variant="body2"
fontWeight={500}
mb={0.5}
color="#D0E1E9"
>
Station Name
</Typography>
@ -256,6 +263,20 @@ const EditStationModal: React.FC<EditStationModalProps> = ({
? errors.name.message
: ""
}
{...register("name", {
required:
"Station Name is required",
minLength: {
value: 3,
message:
"Minimum 3 characters required",
},
maxLength: {
value: 30,
message:
"Maximum 30 characters allowed",
},
})}
/>
)}
/>
@ -271,6 +292,7 @@ const EditStationModal: React.FC<EditStationModalProps> = ({
variant="body2"
fontWeight={500}
mb={0.5}
color="#D0E1E9"
>
Station Location
</Typography>
@ -291,6 +313,10 @@ const EditStationModal: React.FC<EditStationModalProps> = ({
.message
: ""
}
{...register("registeredAddress", {
required:
"Station Location is required",
})}
/>
)}
/>
@ -310,6 +336,7 @@ const EditStationModal: React.FC<EditStationModalProps> = ({
variant="body2"
fontWeight={500}
mb={0.5}
color="#D0E1E9"
>
Total Slots
</Typography>
@ -330,6 +357,15 @@ const EditStationModal: React.FC<EditStationModalProps> = ({
? errors.totalSlots.message
: ""
}
{...register("totalSlots", {
required:
"Total Slots are required",
min: {
value: 1,
message:
"At least 1 slot is required",
},
})}
/>
)}
/>
@ -345,7 +381,11 @@ const EditStationModal: React.FC<EditStationModalProps> = ({
width: "100%",
}}
>
<Typography variant="body2" fontWeight={500}>
<Typography
variant="body2"
fontWeight={500}
color="#D0E1E9"
>
Select Vehicle Brands
</Typography>
<FormControl fullWidth>
@ -385,6 +425,7 @@ const EditStationModal: React.FC<EditStationModalProps> = ({
<Typography
key={index}
variant="body2"
color="#454545"
>
{brand
? brand.name
@ -396,7 +437,7 @@ const EditStationModal: React.FC<EditStationModalProps> = ({
{moreCount > 0 && (
<Typography
variant="body2"
color="textSecondary"
color="#454545"
>
+{moreCount} more
</Typography>
@ -438,7 +479,11 @@ const EditStationModal: React.FC<EditStationModalProps> = ({
width: "100%",
}}
>
<Typography variant="body2" fontWeight={500}>
<Typography
variant="body2"
fontWeight={500}
color="#D0E1E9"
>
Vehicle Name
</Typography>
<FormControl fullWidth>
@ -471,6 +516,7 @@ const EditStationModal: React.FC<EditStationModalProps> = ({
<Typography
key={index}
variant="body2"
color="#454545"
>
{name}
</Typography>
@ -479,7 +525,7 @@ const EditStationModal: React.FC<EditStationModalProps> = ({
{moreCount > 0 && (
<Typography
variant="body2"
color="textSecondary"
color="#454545"
>
+{moreCount} more
</Typography>
@ -528,12 +574,12 @@ const EditStationModal: React.FC<EditStationModalProps> = ({
<Button
type="submit"
sx={{
backgroundColor: "#52ACDF",
color: "white",
backgroundColor: "#D0E1E9",
color: "#000000",
borderRadius: "8px",
fontSize:"16px",
width: "117px",
"&:hover": { backgroundColor: "#439BC1" },
fontSize: "16px",
width: "150px",
"&:hover": { backgroundColor: "#DFECF1" },
}}
>
Update Station

View file

@ -15,14 +15,27 @@ const style = {
left: "50%",
transform: "translate(-50%, -50%)",
width: 330,
bgcolor: "#272727",
bgcolor: "#000000",
color: "#D0E1E9",
borderRadius: 1.5,
boxShadow: 24,
p: 3,
};
const btnStyle = { py: 1, px: 5, width: "50%", textTransform: "capitalize" };
const btnStyle = {
py: 1,
px: 5,
width: "50%",
textTransform: "capitalize",
backgroundColor: "#D0E1E9",
color: "#000000",
};
const btnStyleCancel = {
py: 1,
px: 5,
width: "50%",
textTransform: "capitalize",
};
export default function DeleteModal({
open,
setDeleteModal,
@ -52,8 +65,9 @@ export default function DeleteModal({
cursor: "pointer",
display: "flex",
alignItems: "center",
justifyContent: "flex-end",
justifyContent: "flex-end",
marginTop: -3.5,
}}
>
<CustomIconButton
@ -89,10 +103,10 @@ export default function DeleteModal({
Cancel
</Button>
<Button
variant="contained"
type="button"
color="primary"
sx={btnStyle}
variant="contained"
color="error"
sx={btnStyleCancel}
onClick={() => handleDelete(id || "")}
>
Delete

View file

@ -18,7 +18,7 @@ const style = {
left: "50%",
transform: "translate(-50%, -50%)",
width: 400,
bgcolor: "background.paper",
bgcolor: "#000000",
borderRadius: 2,
boxShadow: "0px 4px 20px rgba(0, 0, 0, 0.15)",
p: 4,
@ -62,7 +62,10 @@ export default function StationViewModal({ open, setViewModal, id }: Props) {
width: "100%",
}}
>
<Box sx={{ flex: 1, textAlign: "center" }}>
<Box
sx={{ flex: 1, textAlign: "center" }}
color="#D0E1E9"
>
{selectedStation?.name || "Station"}'s Details
</Box>
<CustomIconButton
@ -79,33 +82,33 @@ export default function StationViewModal({ open, setViewModal, id }: Props) {
{selectedStation ? (
<Grid container spacing={2} sx={{ width: "80%" }}>
<Grid item xs={6}>
<Typography variant="body1">
<Typography variant="body1" color="#D0E1E9">
<strong>Station Name:</strong>{" "}
<Typography variant="body2">
<Typography variant="body2" color="#D0E1E9">
{selectedStation.name}
</Typography>
</Typography>
</Grid>
<Grid item xs={6}>
<Typography variant="body1">
<Typography variant="body1" color="#D0E1E9">
<strong>Station Location:</strong>{" "}
<Typography variant="body2">
<Typography variant="body2" color="#D0E1E9">
{selectedStation.registeredAddress}
</Typography>
</Typography>
</Grid>
<Grid item xs={6}>
<Typography variant="body1">
<Typography variant="body1" color="#D0E1E9">
<strong>Total Slots:</strong>
<Typography variant="body2">
<Typography variant="body2" color="#D0E1E9">
{selectedStation.totalSlots}
</Typography>
</Typography>
</Grid>
<Grid item xs={6}>
<Typography variant="body1">
<Typography variant="body1" color="#D0E1E9">
<strong>Status:</strong>
<Typography variant="body2">
<Typography variant="body2" color="#D0E1E9">
{selectedStation.status === 1
? "Available"
: "Not Available"}
@ -115,7 +118,7 @@ export default function StationViewModal({ open, setViewModal, id }: Props) {
{/* Display Vehicles */}
<Grid item xs={12}>
<Typography variant="body1">
<Typography variant="body1" color="#D0E1E9">
<strong>Vehicles:</strong>
</Typography>
<Box
@ -125,6 +128,7 @@ export default function StationViewModal({ open, setViewModal, id }: Props) {
gap: 1,
marginTop: 1,
}}
color="#D0E1E9"
>
{selectedStation.allowedCars &&
selectedStation.allowedCars.length > 0 ? (
@ -138,15 +142,13 @@ export default function StationViewModal({ open, setViewModal, id }: Props) {
fontWeight: 500,
}}
>
{car.name}{","}
{car.name}
{","}
</Typography>
)
)
) : (
<Typography
variant="body2"
color="text.secondary"
>
<Typography variant="body2" color="#D0E1E9">
No vehicles available
</Typography>
)}

View file

@ -17,7 +17,7 @@ const style = {
left: "50%",
transform: "translate(-50%, -50%)",
width: 400,
bgcolor: "background.paper",
bgcolor: "#000000",
borderRadius: 2,
boxShadow: "0px 4px 20px rgba(0, 0, 0, 0.15)",
p: 4,
@ -61,7 +61,13 @@ export default function VehicleViewModal({ open, setViewModal, id }: Props) {
width: "100%",
}}
>
<Box sx={{ flex: 1, textAlign: "center" }}>
<Box
sx={{
flex: 1,
textAlign: "center",
color: "#D0E1E9",
}}
>
{selectedVehicle?.name || "Vehicle"}'s Details
</Box>
<Box
@ -82,39 +88,43 @@ export default function VehicleViewModal({ open, setViewModal, id }: Props) {
{selectedVehicle ? (
<Grid container spacing={2} sx={{ width: "80%" }}>
<Grid item xs={6}>
<Typography variant="body1">
<Typography variant="body1" color="#D0E1E9">
<strong>Name:</strong>{" "}
<Typography variant="body2">
<Typography variant="body2" color="#D0E1E9">
{selectedVehicle.name}
</Typography>
</Typography>
</Grid>
<Grid item xs={6}>
<Typography variant="body1">
<Typography variant="body1" color="#D0E1E9">
<strong>Company:</strong>{" "}
<Typography variant="body2">
<Typography variant="body2" color="#D0E1E9">
{selectedVehicle.company}
</Typography>
</Typography>
</Grid>
<Grid item xs={6}>
<Typography variant="body1">
<Typography variant="body1" color="#D0E1E9">
<strong>Model Name:</strong>
<Typography variant="body2">
<Typography variant="body2" color="#D0E1E9">
{selectedVehicle.modelName}
</Typography>
</Typography>
</Grid>
<Grid item xs={6}>
<Typography variant="body1">
<Typography variant="body1" color="#D0E1E9">
<strong>Charge Type:</strong>
<Typography variant="body2">
<Typography variant="body2" color="#D0E1E9">
{selectedVehicle.chargeType}
</Typography>
</Typography>
</Grid>
<Grid item xs={12}>
<Typography variant="body1" gutterBottom>
<Typography
variant="body1"
gutterBottom
color="#D0E1E9"
>
<strong>Image:</strong>
</Typography>
{selectedVehicle.imageUrl ? (
@ -139,7 +149,7 @@ export default function VehicleViewModal({ open, setViewModal, id }: Props) {
}}
/>
) : (
<Typography variant="body2">
<Typography variant="body2" color="#D0E1E9">
No image available
</Typography>
)}

View file

@ -17,7 +17,7 @@ const style = {
left: "50%",
transform: "translate(-50%, -50%)",
width: 400,
bgcolor: "background.paper",
bgcolor: "#000000",
borderRadius: 2,
boxShadow: "0px 4px 20px rgba(0, 0, 0, 0.15)",
p: 4,
@ -32,10 +32,9 @@ export default function ManagerViewModal({ open, setViewModal, id }: Props) {
(state: RootState) => state.managerReducer
);
const [selectedManager, setSelectedManager] = useState<any>(null);
useEffect(() => {
if (id) {
const manager = managers.find((manager) => manager.id === id);
setSelectedManager(manager || null);
}
@ -62,7 +61,13 @@ export default function ManagerViewModal({ open, setViewModal, id }: Props) {
width: "100%",
}}
>
<Box sx={{ flex: 1, textAlign: "center" }}>
<Box
sx={{
flex: 1,
textAlign: "center",
color: "#D0E1E9",
}}
>
{selectedManager?.name || "Manager"}'s Details
</Box>
<Box
@ -71,6 +76,7 @@ export default function ManagerViewModal({ open, setViewModal, id }: Props) {
cursor: "pointer",
display: "flex",
alignItems: "center",
color: "#D0E1E9",
}}
>
<CloseIcon />
@ -83,42 +89,42 @@ export default function ManagerViewModal({ open, setViewModal, id }: Props) {
{selectedManager ? (
<Grid container spacing={2} sx={{ width: "80%" }}>
<Grid item xs={6}>
<Typography variant="body1">
<Typography variant="body1" color="#D0E1E9">
<strong>Name:</strong>
<Typography variant="body2">
<Typography variant="body2" color="#D0E1E9">
{selectedManager.name}
</Typography>
</Typography>
</Grid>
<Grid item xs={6}>
<Typography variant="body1">
<Typography variant="body1" color="#D0E1E9">
<strong>Email:</strong>
<Typography variant="body2">
<Typography variant="body2" color="#D0E1E9">
{selectedManager.email}
</Typography>
</Typography>
</Grid>
<Grid item xs={6}>
<Typography variant="body1">
<Typography variant="body1" color="#D0E1E9">
<strong>Phone:</strong>
<Typography variant="body2">
<Typography variant="body2" color="#D0E1E9">
{selectedManager.phone}
</Typography>
</Typography>
</Grid>
<Grid item xs={6}>
<Typography variant="body1">
<Typography variant="body1" color="#D0E1E9">
<strong>Station Location:</strong>
<Typography variant="body2">
<Typography variant="body2" color="#D0E1E9">
{selectedManager.chargingStation
?.registeredAddress || "Not Available"}
</Typography>
</Typography>
</Grid>
<Grid item xs={6}>
<Typography variant="body1">
<Typography variant="body1" color="#D0E1E9">
<strong>Station Name:</strong>
<Typography variant="body2">
<Typography variant="body2" color="#D0E1E9">
{selectedManager.chargingStation?.name ||
"Not Available"}
</Typography>

View file

@ -1,4 +1,3 @@
import * as React from "react";
import { ThemeProvider, Theme, createTheme } from "@mui/material/styles";
import type { ThemeOptions } from "@mui/material/styles";
@ -28,7 +27,7 @@ export default function AppTheme(props: AppThemeProps) {
paper: "#D0E1E9", // Dark cards
},
text: {
primary: "#000000", // Already matches the image
primary: "#454545", // Already matches the image
secondary: "#272727", // Already matches the image
},
success: {
@ -55,6 +54,7 @@ export default function AppTheme(props: AppThemeProps) {
body2: {
fontSize: "0.875rem",
color: "#b0b0b0",
fontWeight: 300,
},
},
cssVariables: {

View file

@ -1,7 +1,7 @@
export const autofillFix = {
"& input:-webkit-autofill": {
WebkitBoxShadow: "0 0 0 1000px transparent inset !important",
WebkitTextFillColor: "white !important",
WebkitTextFillColor: "#454545 !important",
transition: "background-color 5000s ease-in-out 0s",
},
"& input:-webkit-autofill:hover": {
@ -15,12 +15,12 @@ export const autofillFix = {
},
"& input:-moz-autofill": {
boxShadow: "0 0 0 1000px transparent inset !important",
MozTextFillColor: "white !important",
MozTextFillColor: "#454545 !important",
transition: "background-color 5000s ease-in-out 0s",
},
"& input:autofill": {
boxShadow: "0 0 0 1000px transparent inset !important",
textFillColor: "transparent !important",
textFillColor: "#454545 !important",
transition: "background-color 5000s ease-in-out 0s",
},
};

View file

@ -385,7 +385,7 @@ export const inputsCustomizations: Components<Theme> = {
input: {
"&::placeholder": {
opacity: 0.7,
color: gray[500],
color: gray[600],
},
},
},