code optimization

This commit is contained in:
jaanvi 2025-04-01 18:39:17 +05:30
parent dc327f97fc
commit 57160520fb
45 changed files with 1566 additions and 1158 deletions

View file

@ -0,0 +1,340 @@
import React, { useState } from "react";
import {
Box,
Button,
Typography,
Modal,
InputAdornment,
styled,
} from "@mui/material";
import CloseIcon from "@mui/icons-material/Close";
import Visibility from "@mui/icons-material/Visibility";
import VisibilityOff from "@mui/icons-material/VisibilityOff";
import { useForm, Controller } from "react-hook-form";
import { CustomIconButton, CustomTextField } from "../AddUserModal/styled.css";
interface FormData {
name: string;
email: string;
password: string;
registeredAddress: string;
phone: string; // Added phone field
}
interface AddAdminModalProps {
open: boolean;
handleClose: () => void;
handleCreate: (data: FormData) => void;
}
const AddAdminModal: React.FC<AddAdminModalProps> = ({
open,
handleClose,
handleCreate,
}) => {
const [showPassword, setShowPassword] = useState(false);
const {
control,
handleSubmit,
formState: { errors },
reset,
} = useForm<FormData>({
defaultValues: {
name: "",
email: "",
password: "",
registeredAddress: "",
phone: "", // Initialize phone field
},
});
const onSubmit = (data: FormData) => {
handleCreate(data);
handleClose();
reset();
};
const togglePasswordVisibility = () => {
setShowPassword((prev) => !prev);
};
return (
<Modal
open={open}
onClose={(e, reason) => {
if (reason === "backdropClick") {
return;
}
handleClose();
}}
aria-labelledby="add-admin-modal"
>
<Box
sx={{
position: "absolute",
top: "50%",
left: "50%",
transform: "translate(-50%, -50%)",
width: 600,
bgcolor: "background.paper",
boxShadow: 24,
p: 3,
borderRadius: 2,
}}
>
{/* Header */}
<Box
sx={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
}}
>
<Typography variant="h6" fontWeight={600}>
Add Admin
</Typography>
<CustomIconButton onClick={handleClose}>
<CloseIcon />
</CustomIconButton>
</Box>
{/* Horizontal Line */}
<Box sx={{ borderBottom: "1px solid #ddd", my: 2 }} />
{/* Form */}
<form onSubmit={handleSubmit(onSubmit)}>
{/* First Row - Admin Name & Email */}
<Box sx={{ display: "flex", gap: 2, mb: 2 }}>
<Box
sx={{
display: "flex",
flexDirection: "column",
flex: 1,
}}
>
<Typography variant="body2" fontWeight={500}>
Admin Name
</Typography>
<Controller
name="name"
control={control}
rules={{
required: "Admin Name is required",
minLength: {
value: 3,
message:
"Minimum 3 characters required",
},
maxLength: {
value: 30,
message:
"Maximum 30 characters allowed",
},
}}
render={({ field }) => (
<CustomTextField
{...field}
required
placeholder="Enter Admin Name"
fullWidth
size="small"
error={!!errors.name}
helperText={errors.name?.message}
/>
)}
/>
</Box>
<Box
sx={{
display: "flex",
flexDirection: "column",
flex: 1,
}}
>
<Typography variant="body2" fontWeight={500}>
Email
</Typography>
<Controller
name="email"
control={control}
rules={{
required: "Email is required",
pattern: {
value: /\S+@\S+\.\S+/,
message:
"Please enter a valid email address.",
},
}}
render={({ field }) => (
<CustomTextField
{...field}
error={!!errors.email}
helperText={errors.email?.message}
type="email"
placeholder="Email"
required
fullWidth
/>
)}
/>
</Box>
</Box>
{/* Second Row - Password, Phone, Address */}
<Box sx={{ display: "flex", gap: 2 }}>
<Box
sx={{
display: "flex",
flexDirection: "column",
flex: 1,
}}
>
<Typography variant="body2" fontWeight={500}>
Password
</Typography>
<Controller
name="password"
control={control}
rules={{
required: "Password is required",
minLength: {
value: 6,
message:
"Password must be at least 6 characters",
},
}}
render={({ field }) => (
<CustomTextField
{...field}
required
placeholder="Enter Password"
type={
showPassword ? "text" : "password"
}
fullWidth
size="small"
error={!!errors.password}
helperText={errors.password?.message}
slotProps={{
input: {
endAdornment: (
<InputAdornment position="end">
<CustomIconButton
onClick={
togglePasswordVisibility
}
edge="end"
>
{showPassword ? (
<VisibilityOff />
) : (
<Visibility />
)}
</CustomIconButton>
</InputAdornment>
),
},
}}
/>
)}
/>
</Box>
<Box
sx={{
display: "flex",
flexDirection: "column",
flex: 1,
}}
>
<Typography variant="body2" fontWeight={500}>
Phone
</Typography>
<Controller
name="phone"
control={control}
rules={{
required: "Phone number is required",
pattern: {
value: /^[0-9]{10}$/,
message:
"Enter a valid 10-digit phone number",
},
}}
render={({ field }) => (
<CustomTextField
{...field}
required
placeholder="Enter Phone Number"
fullWidth
size="small"
error={!!errors.phone}
helperText={errors.phone?.message}
/>
)}
/>
</Box>
<Box
sx={{
display: "flex",
flexDirection: "column",
flex: 1,
}}
>
<Typography variant="body2" fontWeight={500}>
Address
</Typography>
<Controller
name="registeredAddress"
control={control}
rules={{
required: "Address is required",
}}
render={({ field }) => (
<CustomTextField
{...field}
required
placeholder="Enter Address"
fullWidth
size="small"
error={!!errors.registeredAddress}
helperText={
errors.registeredAddress?.message
}
/>
)}
/>
</Box>
</Box>
{/* Submit Button */}
<Box
sx={{
display: "flex",
justifyContent: "flex-end",
mt: 3,
}}
>
<Button
type="submit"
sx={{
backgroundColor: "#52ACDF",
color: "white",
borderRadius: "8px",
width: "117px",
"&:hover": { backgroundColor: "#439BC1" },
}}
>
Add Admin
</Button>
</Box>
</form>
</Box>
</Modal>
);
};
export default AddAdminModal;

View file

@ -20,10 +20,7 @@ import {
} from "../../redux/slices/bookSlice.ts"; } from "../../redux/slices/bookSlice.ts";
import { AppDispatch, RootState } from "../../redux/store/store.ts"; import { AppDispatch, RootState } from "../../redux/store/store.ts";
import { toast } from "sonner"; import { toast } from "sonner";
import { import { CustomIconButton, CustomTextField } from "../AddUserModal/styled.css";
CustomIconButton,
CustomTextField,
} from "../AddEditUserModel/styled.css.tsx";
import { getAllStations } from "../../redux/slices/stationSlice.ts"; import { getAllStations } from "../../redux/slices/stationSlice.ts";
import { fetchAvailableSlots } from "../../redux/slices/slotSlice.ts"; import { fetchAvailableSlots } from "../../redux/slices/slotSlice.ts";
@ -186,11 +183,14 @@ export default function AddBookingModal({
value >= today || value >= today ||
"Date cannot be in the past", "Date cannot be in the past",
})} })}
InputLabelProps={{ slotProps={{
shrink: true, inputLabel: {
shrink: true,
},
htmlInput: {
min: today,
},
}} }}
// Setting minimum date to today
inputProps={{ min: today }}
/> />
</Box> </Box>
</Box> </Box>
@ -346,114 +346,6 @@ export default function AddBookingModal({
})} })}
/> />
</Box> </Box>
{/* <Box sx={{ flex: 1 }}>
<Typography variant="body2" fontWeight={500}>
{" Time Slot "}
</Typography>
<Controller
control={control}
name="timeSlot"
render={({ field }) => (
<FormControl
fullWidth
size="small"
error={!!errors.timeSlot}
>
<InputLabel>
Select Time Slot
</InputLabel>
<Select
{...field}
label="Time Slot"
multiple // Allow multiple selections
value={field.value || []} // Ensure the value is an array, even if it's empty
onChange={(e) =>
field.onChange(e.target.value)
} // Ensure the selected value is updated properly
>
{availableSlots.map(
(slot, index) => {
const start = dayjs(
slot.startTime
);
const end = dayjs(
slot.endTime
);
// Function to generate half-hour time slots between start and end time
const generateHalfHourSlots =
(
startTime: dayjs.Dayjs,
endTime: dayjs.Dayjs
) => {
const slots = [];
let currentTime =
startTime;
while (
currentTime.isBefore(
endTime
)
) {
const nextTime =
currentTime.add(
30,
"minute"
);
slots.push({
id: `${currentTime.format(
"HH:mm"
)}-${nextTime.format(
"HH:mm"
)}`,
label: `${currentTime.format(
"hh:mm A"
)} - ${nextTime.format(
"hh:mm A"
)}`,
});
currentTime =
nextTime;
}
return slots;
};
// Generate half-hour slots for the current available slot
const halfHourSlots =
generateHalfHourSlots(
start,
end
);
return halfHourSlots.map(
(slot, slotIndex) => (
<MenuItem
key={`${index}-${slotIndex}`}
value={slot.id}
>
{slot.label}
</MenuItem>
)
);
}
)}
</Select>
{errors.timeSlot && (
<Typography
color="error"
variant="body2"
sx={{ mt: 1 }}
>
{errors.timeSlot.message}
</Typography>
)}
</FormControl>
)}
rules={{ required: "Time Slot is required" }}
/>
</Box> */}
</Box> </Box>
{/* Submit Button */} {/* Submit Button */}

View file

@ -4,10 +4,7 @@ import CloseIcon from "@mui/icons-material/Close";
import Visibility from "@mui/icons-material/Visibility"; import Visibility from "@mui/icons-material/Visibility";
import VisibilityOff from "@mui/icons-material/VisibilityOff"; import VisibilityOff from "@mui/icons-material/VisibilityOff";
import { useForm, Controller } from "react-hook-form"; import { useForm, Controller } from "react-hook-form";
import { import { CustomIconButton, CustomTextField } from "../AddUserModal/styled.css";
CustomIconButton,
CustomTextField,
} from "../AddEditUserModel/styled.css.tsx";
//By Jaanvi : Edit Model :: 11-feb-25 //By Jaanvi : Edit Model :: 11-feb-25
interface AddEditCategoryModalProps { interface AddEditCategoryModalProps {
@ -292,24 +289,26 @@ const AddEditCategoryModal: React.FC<AddEditCategoryModalProps> = ({
: "primary" : "primary"
} }
size="small" size="small"
InputProps={{ slotProps={{
endAdornment: ( input: {
<InputAdornment position="end"> endAdornment: (
<CustomIconButton <InputAdornment position="end">
aria-label="toggle password visibility" <CustomIconButton
onClick={ aria-label="toggle password visibility"
togglePasswordVisibility onClick={
} togglePasswordVisibility
edge="end" }
> edge="end"
{showPassword ? ( >
<VisibilityOff /> {showPassword ? (
) : ( <VisibilityOff />
<Visibility /> ) : (
)} <Visibility />
</CustomIconButton> )}
</InputAdornment> </CustomIconButton>
), </InputAdornment>
),
},
}} }}
error={!!errors.password} error={!!errors.password}
helperText={ helperText={

View file

@ -1,222 +0,0 @@
import React, { useEffect, useState } from "react";
import { useForm, SubmitHandler } from "react-hook-form";
import { Dialog, DialogActions, DialogContent, DialogTitle, Button, TextField, MenuItem, Select, InputLabel, FormControl, FormHelperText, Box } from "@mui/material";
import { useDropzone } from 'react-dropzone';
// Define the types for form data
interface FormData {
exerciseName: string;
description: string;
primMuscleTargeted: string;
secMuscleTargeted?: string;
repsOrduration: string;
sets: string;
restBetweenSets?: string;
difficultyLevel: "beginner" | "intermediate" | "advanced";
formTips?: string;
modificationOptions?: string;
equipmentNeeded?: string;
videoLink?: string;
audioInstructions?: string;
restTimeAfterExercise?: string;
totalTimeForExercise?: string;
progressTracking?: string;
motivationalTips?: string;
exerciseImage?: File | null;
}
interface AddEditExerciseModalProps {
open: boolean;
handleClose: () => void;
editRow: any;
preview: string;
setPreview: string;
}
const AddEditExerciseModal: React.FC<AddEditExerciseModalProps> = ({ open, handleClose, editRow ,preview,setPreview}) => {
const { handleSubmit, register, formState: { errors }, setValue, reset, getValues} = useForm<FormData>();
const { getRootProps, getInputProps } = useDropzone({
accept: 'image/*, .gif',
onDrop: (acceptedFiles) => {
if (acceptedFiles && acceptedFiles.length > 0) {
setValue('exerciseImage', acceptedFiles[0]);
handlePreview(acceptedFiles[0])
}
},
});
console.log("Imageeeee" , getValues('exerciseImage'))
// State to store the preview URL of the uploaded file
const [selectedFile, setSelectedFile] = useState<File | null>(null);
useEffect(() => {
if (editRow) {
setValue('exerciseName', editRow.exerciseName);
setValue('description', editRow.description);
setValue('primMuscleTargeted', editRow.primMuscleTargeted);
setValue('secMuscleTargeted', editRow.secMuscleTargeted);
setValue('repsOrduration', editRow.repsOrduration);
setValue('sets', editRow.sets);
setValue('restBetweenSets', editRow.restBetweenSets);
setValue('difficultyLevel', editRow.difficultyLevel);
if (editRow.exerciseImage) {
setValue('exerciseImage', editRow.exerciseImage);
setPreview(editRow.exerciseImage);
setSelectedFile(editRow.exerciseImage);
}
} else {
reset();
setPreview(null);
setSelectedFile(null);
}
}, [editRow, setValue, reset,setPreview]);
const onSubmit: SubmitHandler<FormData> = (data: FormData) => {
console.log(data);
reset();
setPreview(null);
handleClose();
};
const handlePreview = (file: File | null) => {
if (file) {
setValue('exerciseImage', file);
setPreview(URL.createObjectURL(file));
setSelectedFile(file);
} else {
setPreview(null);
setSelectedFile(null);
}
};
const handleClearFile = () => {
setPreview(null);
setSelectedFile(null);
setValue('exerciseImage', null);
};
return (
<Dialog open={open} onClose={handleClose} fullWidth maxWidth="md">
<DialogTitle>Create Exercise</DialogTitle>
<DialogContent>
<form onSubmit={handleSubmit(onSubmit)}>
<Box sx={{ display: "grid", gap: 2 }}>
{/* Exercise Name */}
<TextField
fullWidth
label="Exercise Name"
variant="outlined"
{...register("exerciseName", { required: "Exercise name is required" })}
error={!!errors.exerciseName}
helperText={errors.exerciseName?.message}
/>
{/* Description */}
<TextField
fullWidth
label="Description"
variant="outlined"
multiline
rows={4}
{...register("description", { required: "Description is required" })}
error={!!errors.description}
helperText={errors.description?.message}
/>
{/* Primary Muscles Targeted */}
<TextField
fullWidth
label="Primary Muscles Targeted"
variant="outlined"
{...register("primMuscleTargeted", { required: "Primary muscles are required" })}
error={!!errors.primMuscleTargeted}
helperText={errors.primMuscleTargeted?.message}
/>
{/* Secondary Muscles Targeted */}
<TextField
fullWidth
label="Secondary Muscles Targeted"
variant="outlined"
{...register("secMuscleTargeted")}
/>
{/* Reps/Duration */}
<TextField
fullWidth
label="Reps/Duration"
variant="outlined"
{...register("repsOrduration", { required: "Reps or duration is required" })}
error={!!errors.repsOrduration}
helperText={errors.repsOrduration?.message}
/>
{/* Sets */}
<TextField
fullWidth
label="Sets"
variant="outlined"
{...register("sets", { required: "Sets are required" })}
error={!!errors.sets}
helperText={errors.sets?.message}
/>
{/* Rest Between Sets */}
<TextField
fullWidth
label="Rest Between Sets"
variant="outlined"
{...register("restBetweenSets")}
/>
{/* Difficulty Level */}
<FormControl fullWidth error={!!errors.difficultyLevel}>
<InputLabel>Difficulty Level</InputLabel>
<Select
defaultValue={editRow?.difficultyLevel || ''}
label="Difficulty Level"
{...register("difficultyLevel", { required: "Difficulty level is required" })}
>
<MenuItem value="beginner">Beginner</MenuItem>
<MenuItem value="intermediate">Intermediate</MenuItem>
<MenuItem value="advanced">Advanced</MenuItem>
</Select>
{errors.difficultyLevel && <FormHelperText>{errors.difficultyLevel.message}</FormHelperText>}
</FormControl>
{/* Image/GIF Upload */}
<Box {...getRootProps()} sx={{ border: '2px dashed', padding: 2, width: '100%', marginBottom: 2 }}>
<input {...getInputProps()} onChange={(e) => handlePreview(e.target.files?.[0] || null)} />
<p>Drag & drop an image or GIF here, or click to select</p>
</Box>
{/* Preview the uploaded image or GIF */}
{preview && (
<Box sx={{ textAlign: 'center', marginBottom: 2 }}>
<p>Preview:</p>
<img src={preview} alt="Exercise Preview" style={{ maxWidth: '100%', maxHeight: 300, objectFit: 'contain' }} />
<p>{selectedFile?.name || selectedFile.split("/").pop()}</p>
<Button variant="outlined" color="secondary" onClick={handleClearFile} sx={{ marginTop: 1 }}>
Remove File
</Button>
</Box>
)}
</Box>
</form>
</DialogContent>
<DialogActions>
<Button onClick={handleClose} color="secondary">
Cancel
</Button>
<Button onClick={handleSubmit(onSubmit)} color="primary" variant="contained">
Submit
</Button>
</DialogActions>
</Dialog>
);
};
export default AddEditExerciseModal;

View file

@ -1,82 +0,0 @@
import React,{useEffect} from "react";
import { Button, Dialog, DialogActions, DialogContent, DialogTitle, TextField } from "@mui/material";
import { useForm, Controller } from "react-hook-form";
interface AddEditTagsModalProps {
open: boolean;
handleClose: () => void;
editRow:any;
}
interface FormData {
tag: string;
}
const AddEditTagsModal: React.FC<AddEditTagsModalProps> = ({ open, handleClose,editRow }) => {
const { control, handleSubmit, formState: { errors },setValue,reset } = useForm<FormData>({
defaultValues: {
tag: "",
},
});
const onSubmit = (data: FormData) => {
console.log(data.tag);
handleClose();
reset();
};
useEffect(() => {
if (editRow) {
setValue('tag', editRow.name);
} else {
reset();
}
}, [editRow, setValue, reset]);
return (
<>
<Dialog
open={open}
onClose={handleClose}
maxWidth="md"
fullWidth
PaperProps={{
component: 'form',
onSubmit: handleSubmit(onSubmit),
}}
>
<DialogTitle>{editRow ? "Edit" : 'Add'} Tag</DialogTitle>
<DialogContent>
<Controller
name="tag"
control={control}
rules={{
required: "Tag Name is required",
}}
render={({ field }) => (
<TextField
{...field}
autoFocus
required
margin="dense"
label="Add Tag Name"
type="text"
fullWidth
variant="standard"
error={!!errors.tag}
helperText={errors.tag?.message}
/>
)}
/>
</DialogContent>
<DialogActions>
<Button onClick={handleClose}>Cancel</Button>
<Button type="submit">Save</Button>
</DialogActions>
</Dialog>
</>
);
};
export default AddEditTagsModal;

View file

@ -1,382 +0,0 @@
import React, { useEffect, useState } from "react";
import {
Box,
Button,
Typography,
TextField,
Modal,
IconButton,
InputAdornment,
styled,
} from "@mui/material";
import CloseIcon from "@mui/icons-material/Close";
import Visibility from "@mui/icons-material/Visibility";
import VisibilityOff from "@mui/icons-material/VisibilityOff";
import { useForm, Controller } from "react-hook-form";
import { CustomIconButton, CustomTextField } from "./styled.css.tsx";
interface FormData {
name: string;
email: string;
password: string;
phone: string;
}
interface AddUserModalProps {
open: boolean;
handleClose: () => void;
handleCreate: (data: FormData) => void;
handleUpdate: (
id: string,
name: string,
email: string,
phone: string,
) => void;
editRow: any;
}
const AddUserModal: React.FC<AddUserModalProps> = ({
open,
handleClose,
handleCreate,
handleUpdate,
editRow,
}) => {
const [showPassword, setShowPassword] = useState(false);
const {
control,
handleSubmit,
formState: { errors },
reset,
setValue,
} = useForm<FormData>({
defaultValues: {
name: "",
email: "",
phone: "",
},
});
useEffect(() => {
if (editRow) {
setValue("name", editRow.name);
setValue("email", editRow.email);
setValue("phone", editRow.phone);
} else {
reset();
}
}, [editRow, setValue,reset]);
const onSubmit = (data: FormData) => {
if (editRow) {
handleUpdate(
editRow.id,
data.name,
data.email,
data.phone
);
} else {
handleCreate(data);
}
handleClose();
reset();
};
const togglePasswordVisibility = () => {
setShowPassword((prev) => !prev);
};
return (
<Modal
open={open}
onClose={(e, reason) => {
if (reason === "backdropClick") {
return;
}
handleClose(); // Close modal when clicking cross or cancel
}}
aria-labelledby="add-user-modal"
>
<Box
sx={{
position: "absolute",
top: "50%",
left: "50%",
transform: "translate(-50%, -50%)",
width: 600, // Adjusted the width for a wider modal
bgcolor: "background.paper",
boxShadow: 24,
p: 3,
borderRadius: 2,
}}
>
{/* Header */}
<Box
sx={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
}}
>
<Typography variant="h6" fontWeight={600}>
{editRow ? "Edit User" : "Add User"}
</Typography>
<CustomIconButton onClick={handleClose}>
<CloseIcon />
</CustomIconButton>
</Box>
{/* Horizontal Line */}
<Box sx={{ borderBottom: "1px solid #ddd", my: 2 }} />
{/* Form */}
<form onSubmit={handleSubmit(onSubmit)}>
{/* Input Fields */}
<Box
sx={{
display: "flex",
flexDirection: "column",
gap: 2,
}}
>
{/* First Row - Two Inputs */}
<Box sx={{ display: "flex", gap: 2 }}>
<Box
sx={{
display: "flex",
flexDirection: "column",
width: "100%",
}}
>
<Typography variant="body2" fontWeight={500}>
User Name
</Typography>
<Controller
name="name"
control={control}
rules={{
required: "User Name is required",
minLength: {
value: 3,
message:
"Minimum 3 characters required",
},
maxLength: {
value: 30,
message:
"Maximum 30 characters allowed",
},
pattern: {
value: /^[A-Za-z\s]+$/, // Only letters and spaces are allowed
message:
"User Name must only contain letters and spaces",
},
}}
render={({ field }) => (
<CustomTextField
{...field}
required
placeholder="Enter User Name"
fullWidth
size="small"
error={!!errors.name}
helperText={errors.name?.message}
/>
)}
/>
</Box>
<Box
sx={{
display: "flex",
flexDirection: "column",
width: "100%",
}}
>
<Typography variant="body2" fontWeight={500}>
Email
</Typography>
<Controller
name="email"
control={control}
rules={{
required: "Email is required",
pattern: {
value: /\S+@\S+\.\S+/,
message:
"Please enter a valid email address.",
},
}}
render={({ field }) => (
<CustomTextField
{...field}
error={!!errors.email}
helperText={errors.email?.message}
id="email"
type="email"
placeholder="Email"
required
fullWidth
color={
errors.email
? "error"
: "primary"
}
/>
)}
/>
</Box>
</Box>
{/* Second Row - Two Inputs */}
<Box sx={{ display: "flex", gap: 2 }}>
{!editRow && ( <Box
sx={{
display: "flex",
flexDirection: "column",
width: "100%",
}}
>
<Typography variant="body2" fontWeight={500}>
Password
</Typography>
<Controller
name="password"
control={control}
rules={{
required: "Password is required",
minLength: {
value: 6,
message:
"Password must be at least 6 characters long.",
},
pattern: {
value: /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{6,}$/,
message:
"Password must contain at least one uppercase letter, one lowercase letter, one number, and one special character.",
},
}}
render={({ field }) => (
<CustomTextField
{...field}
required
placeholder="Enter Password"
type={
showPassword
? "text"
: "password"
}
id="password"
fullWidth
color={
errors.password
? "error"
: "primary"
}
size="small"
InputProps={{
endAdornment: (
<InputAdornment position="end">
<CustomIconButton
aria-label="toggle password visibility"
onClick={
togglePasswordVisibility
}
edge="end"
>
{showPassword ? (
<VisibilityOff />
) : (
<Visibility />
)}
</CustomIconButton>
</InputAdornment>
),
}}
error={!!errors.password}
helperText={
errors.password?.message
}
/>
)}
/>
</Box>)}
<Box
sx={{
display: "flex",
flexDirection: "column",
width: "100%",
}}
>
<Typography variant="body2" fontWeight={500}>
Phone Number
</Typography>
<Controller
name="phone"
control={control}
rules={{
required: "Phone number is required",
pattern: {
value: /^[0-9]*$/,
message: "Only numbers are allowed",
},
minLength: {
value: 6,
message:
"Phone number must be at least 6 digits",
},
maxLength: {
value: 14,
message:
"Phone number must be at most 14 digits",
},
}}
render={({ field }) => (
<CustomTextField
{...field}
required
placeholder="Enter Phone Number"
size="small"
error={!!errors.phone}
helperText={errors.phone?.message}
/>
)}
/>
</Box>
</Box>
</Box>
{/* Submit Button */}
<Box
sx={{
display: "flex",
justifyContent: "flex-end",
width: "100%",
mt: 3,
}}
>
<Button
type="submit"
sx={{
backgroundColor: "#52ACDF",
color: "white",
borderRadius: "8px",
width: "117px",
"&:hover": { backgroundColor: "#439BC1" },
}}
>
{editRow ? "Update User" : "Add User"}
</Button>
</Box>
</form>
</Box>
</Modal>
);
};
export default AddUserModal;

View file

@ -1,11 +0,0 @@
import React from 'react'
const AddEditWorkoutModal = () => {
return (
<div>
</div>
)
}
export default AddEditWorkoutModal

View file

@ -15,10 +15,7 @@ import CloseIcon from "@mui/icons-material/Close";
import { Visibility, VisibilityOff } from "@mui/icons-material"; import { Visibility, VisibilityOff } from "@mui/icons-material";
import { useDispatch, useSelector } from "react-redux"; import { useDispatch, useSelector } from "react-redux";
import { addManager, managerList } from "../../redux/slices/managerSlice.ts"; import { addManager, managerList } from "../../redux/slices/managerSlice.ts";
import { import { CustomIconButton, CustomTextField } from "../AddUserModal/styled.css";
CustomIconButton,
CustomTextField,
} from "../AddEditUserModel/styled.css.tsx";
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import { RootState } from "../../redux/reducers.ts"; import { RootState } from "../../redux/reducers.ts";
import { stationList } from "../../redux/slices/stationSlice.ts"; import { stationList } from "../../redux/slices/stationSlice.ts";
@ -258,24 +255,26 @@ export default function AddManagerModal({
: "primary" : "primary"
} }
size="small" size="small"
InputProps={{ slotProps={{
endAdornment: ( input: {
<InputAdornment position="end"> endAdornment: (
<CustomIconButton <InputAdornment position="end">
aria-label="toggle password visibility" <CustomIconButton
onClick={ aria-label="toggle password visibility"
togglePasswordVisibility onClick={
} togglePasswordVisibility
edge="end" }
> edge="end"
{showPassword ? ( >
<VisibilityOff /> {showPassword ? (
) : ( <VisibilityOff />
<Visibility /> ) : (
)} <Visibility />
</CustomIconButton> )}
</InputAdornment> </CustomIconButton>
), </InputAdornment>
),
},
}} }}
error={!!errors.password} error={!!errors.password}
helperText={errors.password?.message} helperText={errors.password?.message}

View file

@ -48,8 +48,10 @@ const AddSlotModal = ({ open, handleClose, handleAddSlot }: any) => {
type="date" type="date"
fullWidth fullWidth
margin="normal" margin="normal"
InputLabelProps={{ slotProps={{
shrink: true, inputLabel: {
shrink: true,
},
}} }}
error={!!errors.date} error={!!errors.date}
helperText={errors.date?.message} helperText={errors.date?.message}
@ -64,8 +66,10 @@ const AddSlotModal = ({ open, handleClose, handleAddSlot }: any) => {
type="time" type="time"
fullWidth fullWidth
margin="normal" margin="normal"
InputLabelProps={{ slotProps={{
shrink: true, inputLabel: {
shrink: true,
},
}} }}
error={!!errors.startHour} error={!!errors.startHour}
helperText={errors.startHour?.message} helperText={errors.startHour?.message}
@ -106,20 +110,19 @@ const AddSlotModal = ({ open, handleClose, handleAddSlot }: any) => {
<Button onClick={handleClose} color="secondary"> <Button onClick={handleClose} color="secondary">
Cancel Cancel
</Button> </Button>
<Button <Button
type="submit" type="submit"
sx={{ sx={{
backgroundColor: "#52ACDF", backgroundColor: "#52ACDF",
color: "white", color: "white",
borderRadius: "8px", borderRadius: "8px",
width: "100px", width: "100px",
"&:hover": { backgroundColor: "#439BC1" }, "&:hover": { backgroundColor: "#439BC1" },
}} }}
> >
Add Booking Add Booking
</Button> </Button>
</DialogActions> </DialogActions>
</form> </form>
</DialogContent> </DialogContent>

View file

@ -20,10 +20,7 @@ import {
fetchVehicleBrands, fetchVehicleBrands,
vehicleList, vehicleList,
} from "../../redux/slices/VehicleSlice.ts"; // Adjust this import path accordingly } from "../../redux/slices/VehicleSlice.ts"; // Adjust this import path accordingly
import { import { CustomIconButton, CustomTextField } from "../AddUserModal/styled.css";// Assuming custom styled components
CustomIconButton,
CustomTextField,
} from "../AddEditUserModel/styled.css.tsx"; // Assuming custom styled components
export default function AddStationModal({ export default function AddStationModal({
open, open,
@ -262,7 +259,7 @@ export default function AddStationModal({
}} }}
> >
<Typography variant="body2" fontWeight={500}> <Typography variant="body2" fontWeight={500}>
Select Vehicle Brands Vehicle Brand
</Typography> </Typography>
<FormControl fullWidth> <FormControl fullWidth>
<InputLabel>Choose Brands</InputLabel> <InputLabel>Choose Brands</InputLabel>
@ -270,10 +267,53 @@ export default function AddStationModal({
multiple multiple
value={selectedBrands} value={selectedBrands}
onChange={handleBrandChange} onChange={handleBrandChange}
renderValue={(selected) => renderValue={(selected) => {
(selected as string[]).join(", ") const selectedArray =
} selected as string[];
label="Choose Brands" const displayNames =
selectedArray.slice(0, 1); // First 2 brands
const moreCount =
selectedArray.length - 1;
return (
<Box
sx={{
display: "flex",
alignItems: "center",
gap: 1,
}}
>
{displayNames.map(
(id, index) => {
const brand =
vehicleBrands.find(
(b) =>
b.id ===
id
);
return (
<Typography
key={index}
variant="body2"
>
{brand
? brand.name
: ""}
</Typography>
);
}
)}
{moreCount > 0 && (
<Typography
variant="body2"
color="textSecondary"
>
+{moreCount} more
</Typography>
)}
</Box>
);
}}
> >
{vehicleBrands.length > 0 ? ( {vehicleBrands.length > 0 ? (
vehicleBrands.map((brand) => ( vehicleBrands.map((brand) => (
@ -315,16 +355,49 @@ export default function AddStationModal({
<Typography variant="body2" fontWeight={500}> <Typography variant="body2" fontWeight={500}>
Vehicle Name Vehicle Name
</Typography> </Typography>
<FormControl fullWidth> <FormControl fullWidth>
<InputLabel>Choose Vehicles</InputLabel> <InputLabel>Choose Vehicles</InputLabel>
<Select <Select
multiple multiple
value={selectedVehicles} value={selectedVehicles}
onChange={handleVehicleChange} onChange={handleVehicleChange}
renderValue={(selected) => renderValue={(selected) => {
(selected as string[]).join(", ") const selectedArray =
} selected as string[];
const displayNames =
selectedArray.slice(0, 1); // First 2 vehicles
const moreCount =
selectedArray.length - 1;
return (
<Box
sx={{
display: "flex",
alignItems: "center",
gap: 1,
}}
>
{displayNames.map(
(name, index) => (
<Typography
key={index}
variant="body2"
>
{name}
</Typography>
)
)}
{moreCount > 0 && (
<Typography
variant="body2"
color="textSecondary"
>
+{moreCount} more
</Typography>
)}
</Box>
);
}}
> >
{filteredVehicles.length > 0 ? ( {filteredVehicles.length > 0 ? (
filteredVehicles.map((vehicle) => ( filteredVehicles.map((vehicle) => (

View file

@ -0,0 +1,324 @@
import React, { useState } from "react";
import {
Box,
Button,
Typography,
Modal,
InputAdornment,
styled,
} from "@mui/material";
import CloseIcon from "@mui/icons-material/Close";
import Visibility from "@mui/icons-material/Visibility";
import VisibilityOff from "@mui/icons-material/VisibilityOff";
import { useForm, Controller } from "react-hook-form";
import { CustomIconButton, CustomTextField } from "./styled.css.tsx";
interface FormData {
name: string;
email: string;
password: string;
phone: string;
}
interface AddUserModalProps {
open: boolean;
handleClose: () => void;
handleCreate: (data: FormData) => void;
}
const AddUserModal: React.FC<AddUserModalProps> = ({
open,
handleClose,
handleCreate,
}) => {
const [showPassword, setShowPassword] = useState(false);
const {
control,
handleSubmit,
formState: { errors },
reset,
} = useForm<FormData>({
defaultValues: {
name: "",
email: "",
password: "",
phone: "",
},
});
const onSubmit = (data: FormData) => {
handleCreate(data);
handleClose();
reset();
};
const togglePasswordVisibility = () => {
setShowPassword((prev) => !prev);
};
return (
<Modal
open={open}
onClose={(e, reason) => {
if (reason === "backdropClick") {
return;
}
handleClose();
}}
aria-labelledby="add-user-modal"
>
<Box
sx={{
position: "absolute",
top: "50%",
left: "50%",
transform: "translate(-50%, -50%)",
width: 600,
bgcolor: "background.paper",
boxShadow: 24,
p: 3,
borderRadius: 2,
}}
>
{/* Header */}
<Box
sx={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
}}
>
<Typography variant="h6" fontWeight={600}>
Add User
</Typography>
<CustomIconButton onClick={handleClose}>
<CloseIcon />
</CustomIconButton>
</Box>
{/* Horizontal Line */}
<Box sx={{ borderBottom: "1px solid #ddd", my: 2 }} />
{/* Form */}
<form onSubmit={handleSubmit(onSubmit)}>
{/* First Row - User Name & Email */}
<Box sx={{ display: "flex", gap: 2, mb: 2 }}>
<Box
sx={{
display: "flex",
flexDirection: "column",
flex: 1,
}}
>
<Typography variant="body2" fontWeight={500}>
User Name
</Typography>
<Controller
name="name"
control={control}
rules={{
required: "User Name is required",
minLength: {
value: 3,
message:
"Minimum 3 characters required",
},
maxLength: {
value: 30,
message:
"Maximum 30 characters allowed",
},
}}
render={({ field }) => (
<CustomTextField
{...field}
required
placeholder="Enter User Name"
fullWidth
size="small"
error={!!errors.name}
helperText={errors.name?.message}
/>
)}
/>
</Box>
<Box
sx={{
display: "flex",
flexDirection: "column",
flex: 1,
}}
>
<Typography variant="body2" fontWeight={500}>
Email
</Typography>
<Controller
name="email"
control={control}
rules={{
required: "Email is required",
pattern: {
value: /\S+@\S+\.\S+/,
message:
"Please enter a valid email address.",
},
}}
render={({ field }) => (
<CustomTextField
{...field}
error={!!errors.email}
helperText={errors.email?.message}
type="email"
placeholder="Email"
required
fullWidth
color={
errors.email ? "error" : "primary"
}
/>
)}
/>
</Box>
</Box>
{/* Second Row - Password & Phone Number */}
<Box sx={{ display: "flex", gap: 2 }}>
<Box
sx={{
display: "flex",
flexDirection: "column",
flex: 1,
}}
>
<Typography variant="body2" fontWeight={500}>
Password
</Typography>
<Controller
name="password"
control={control}
rules={{
required: "Password is required",
minLength: {
value: 6,
message:
"Password must be at least 6 characters long.",
},
}}
render={({ field }) => (
<CustomTextField
{...field}
required
placeholder="Enter Password"
type={
showPassword ? "text" : "password"
}
fullWidth
color={
errors.password
? "error"
: "primary"
}
size="small"
slotProps={{
input: {
endAdornment: (
<InputAdornment position="end">
<CustomIconButton
aria-label="toggle password visibility"
onClick={
togglePasswordVisibility
}
edge="end"
>
{showPassword ? (
<VisibilityOff />
) : (
<Visibility />
)}
</CustomIconButton>
</InputAdornment>
),
},
}}
error={!!errors.password}
helperText={errors.password?.message}
/>
)}
/>
</Box>
<Box
sx={{
display: "flex",
flexDirection: "column",
flex: 1,
}}
>
<Typography variant="body2" fontWeight={500}>
Phone Number
</Typography>
<Controller
name="phone"
control={control}
rules={{
required: "Phone number is required",
pattern: {
value: /^[0-9]*$/,
message: "Only numbers are allowed",
},
minLength: {
value: 6,
message:
"Phone number must be at least 6 digits",
},
maxLength: {
value: 14,
message:
"Phone number must be at most 14 digits",
},
}}
render={({ field }) => (
<CustomTextField
{...field}
required
placeholder="Enter Phone Number"
size="small"
error={!!errors.phone}
helperText={errors.phone?.message}
/>
)}
/>
</Box>
</Box>
{/* Submit Button */}
<Box
sx={{
display: "flex",
justifyContent: "flex-end",
width: "100%",
mt: 3,
}}
>
<Button
type="submit"
sx={{
backgroundColor: "#52ACDF",
color: "white",
borderRadius: "8px",
width: "117px",
"&:hover": { backgroundColor: "#439BC1" },
}}
>
Add User
</Button>
</Box>
</form>
</Box>
</Modal>
);
};
export default AddUserModal;

View file

@ -6,10 +6,7 @@ import {
Modal, Modal,
} from "@mui/material"; } from "@mui/material";
import CloseIcon from "@mui/icons-material/Close"; import CloseIcon from "@mui/icons-material/Close";
import { import { CustomIconButton, CustomTextField } from "../AddUserModal/styled.css";
CustomIconButton,
CustomTextField,
} from "../AddEditUserModel/styled.css.tsx";
export default function AddVehicleModal({ export default function AddVehicleModal({
open, open,
handleClose, handleClose,

View file

@ -11,7 +11,6 @@ import DashboardRoundedIcon from "@mui/icons-material/DashboardRounded";
import ColorModeIconDropdown from "../../shared-theme/ColorModeIconDropdown"; import ColorModeIconDropdown from "../../shared-theme/ColorModeIconDropdown";
import MenuButton from "../MenuButton"; import MenuButton from "../MenuButton";
import SideMenuMobile from "../SideMenuMobile"; import SideMenuMobile from "../SideMenuMobile";
import NotificationsRoundedIcon from "@mui/icons-material/NotificationsRounded";
const Toolbar = styled(MuiToolbar)({ const Toolbar = styled(MuiToolbar)({
width: "100%", width: "100%",

View file

@ -10,7 +10,6 @@ import {
import { styled } from "@mui/system"; import { styled } from "@mui/system";
import { import {
fetchAvailableSlots, fetchAvailableSlots,
availableSlots,
} from "../../redux/slices/slotSlice"; // Update with the correct import path } from "../../redux/slices/slotSlice"; // Update with the correct import path
const SlotButton = styled(Button)<{ selected: boolean }>(({ selected }) => ({ const SlotButton = styled(Button)<{ selected: boolean }>(({ selected }) => ({
@ -38,7 +37,7 @@ const AvailableSlotsModal = ({
const { availableSlots, loading, error } = useSelector( const { availableSlots, loading, error } = useSelector(
(state: any) => state.slotReducer.availableSlots (state: any) => state.slotReducer.availableSlots
); // Adjust selector path ); // Adjust selector path
const [selectedSlot, setSelectedSlot] = useState<availableSlots | null>( const [selectedSlot, setSelectedSlot] = useState<typeof availableSlots | null>(
null null
); );
@ -49,7 +48,7 @@ const AvailableSlotsModal = ({
} }
}, [open, dispatch]); }, [open, dispatch]);
const handleSlotSelect = (slot: availableSlots) => { const handleSlotSelect = (slot: typeof availableSlots) => {
setSelectedSlot(slot); // Update the selected slot setSelectedSlot(slot); // Update the selected slot
}; };
@ -79,7 +78,7 @@ const AvailableSlotsModal = ({
<div style={{ color: "red" }}>Error: {error}</div> <div style={{ color: "red" }}>Error: {error}</div>
) : Array.isArray(availableSlots) && ) : Array.isArray(availableSlots) &&
availableSlots.length > 0 ? ( availableSlots.length > 0 ? (
availableSlots.map((slot: availableSlots) => ( availableSlots.map((slot: availableSlots) => (
<SlotButton <SlotButton
key={slot?.id} key={slot?.id}
onClick={() => handleSlotSelect(slot)} onClick={() => handleSlotSelect(slot)}

View file

@ -1,25 +1,28 @@
import * as React from 'react'; import * as React from "react";
import Card from '@mui/material/Card'; import Card from "@mui/material/Card";
import CardContent from '@mui/material/CardContent'; import CardContent from "@mui/material/CardContent";
import Button from '@mui/material/Button'; import Button from "@mui/material/Button";
import Typography from '@mui/material/Typography'; import Typography from "@mui/material/Typography";
import AutoAwesomeRoundedIcon from '@mui/icons-material/AutoAwesomeRounded'; import AutoAwesomeRoundedIcon from "@mui/icons-material/AutoAwesomeRounded";
export default function CardAlert() { export default function CardAlert() {
return ( return (
<Card variant="outlined" sx={{ m: 1.5, p: 1.5 }}> <Card variant="outlined" sx={{ m: 1.5, p: 1.5 }}>
<CardContent> <CardContent>
<AutoAwesomeRoundedIcon fontSize="small" /> <AutoAwesomeRoundedIcon fontSize="small" />
<Typography gutterBottom sx={{ fontWeight: 600 }}> <Typography gutterBottom sx={{ fontWeight: 600 }}>
Plan about to expire Plan about to expire
</Typography> </Typography>
<Typography variant="body2" sx={{ mb: 2, color: 'text.secondary' }}> <Typography
Enjoy 10% off when renewing your plan today. variant="body2"
</Typography> sx={{ mb: 2, color: "text.secondary" }}
<Button variant="contained" size="small" fullWidth> >
Get the discount Enjoy 10% off when renewing your plan today.
</Button> </Typography>
</CardContent> <Button variant="contained" size="small" fullWidth>
</Card> Get the discount
); </Button>
</CardContent>
</Card>
);
} }

View file

@ -30,7 +30,7 @@ import VehicleViewModal from "../Modals/VehicleViewModal/index.tsx";
import SearchIcon from "@mui/icons-material/Search"; import SearchIcon from "@mui/icons-material/Search";
import TuneIcon from "@mui/icons-material/Tune"; import TuneIcon from "@mui/icons-material/Tune";
import { CustomIconButton } from "../AddEditUserModel/styled.css.tsx"; import { CustomIconButton } from "../AddUserModal/styled.css";
import ManagerViewModal from "../Modals/ViewManagerModal/index.tsx"; import ManagerViewModal from "../Modals/ViewManagerModal/index.tsx";
import UserViewModal from "../Modals/UserViewModal/index.tsx"; import UserViewModal from "../Modals/UserViewModal/index.tsx";
import { deleteUser, userList } from "../../redux/slices/userSlice.ts"; import { deleteUser, userList } from "../../redux/slices/userSlice.ts";
@ -299,12 +299,14 @@ const CustomTable: React.FC<CustomTableProps> = ({
opacity: 1, opacity: 1,
}, },
}} }}
InputProps={{ slotProps={{
startAdornment: ( input: {
<InputAdornment position="start"> startAdornment: (
<SearchIcon sx={{ color: "#52ACDF" }} /> <InputAdornment position="start">
</InputAdornment> <SearchIcon sx={{ color: "#52ACDF" }} />
), </InputAdornment>
),
},
}} }}
value={searchQuery} value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)} onChange={(e) => setSearchQuery(e.target.value)}
@ -502,36 +504,22 @@ const CustomTable: React.FC<CustomTableProps> = ({
id="menu" id="menu"
open={open} open={open}
onClose={handleClose} onClose={handleClose}
onClick={handleClose} transformOrigin={{ horizontal: "right", vertical: "top" }}
transformOrigin={{ anchorOrigin={{ horizontal: "right", vertical: "bottom" }}
horizontal: "right",
vertical: "top",
}}
anchorOrigin={{
horizontal: "right",
vertical: "bottom",
}}
sx={{ sx={{
[`& .${paperClasses.root}`]: { [`& .${paperClasses.root}`]: {
padding: 0, padding: 0,
}, },
"& .MuiList-root": { "& .MuiList-root": {
background: "#272727", // Remove any divider under menu items background: "#272727",
}, },
}} }}
> >
<Box <div style={{ display: "flex", flexDirection: "column" }}>
sx={{
display: "flex",
flexDirection: "column",
justifyContent: "flex-start",
}}
>
<Button <Button
variant="text" variant="text"
onClick={(e) => { onClick={(e) => {
e.stopPropagation(); e.stopPropagation();
// setSelectedRow(row);
setViewModal(true); setViewModal(true);
}} }}
color="primary" color="primary"
@ -544,6 +532,7 @@ const CustomTable: React.FC<CustomTableProps> = ({
> >
View View
</Button> </Button>
{viewModal && tableType === "admin" && ( {viewModal && tableType === "admin" && (
<ViewModal <ViewModal
handleView={() => handleView={() =>
@ -554,16 +543,6 @@ const CustomTable: React.FC<CustomTableProps> = ({
id={selectedRow?.id} id={selectedRow?.id}
/> />
)} )}
{viewModal && tableType === "vehicle" && (
<VehicleViewModal
handleView={() =>
handleViewButton(selectedRow?.id)
}
open={viewModal}
setViewModal={setViewModal}
id={selectedRow?.id}
/>
)}
{viewModal && tableType === "manager" && ( {viewModal && tableType === "manager" && (
<ManagerViewModal <ManagerViewModal
handleView={() => handleView={() =>
@ -574,8 +553,9 @@ const CustomTable: React.FC<CustomTableProps> = ({
id={selectedRow?.id} id={selectedRow?.id}
/> />
)} )}
{viewModal && tableType === "user" && (
<UserViewModal {viewModal && tableType === "vehicle" && (
<VehicleViewModal
handleView={() => handleView={() =>
handleViewButton(selectedRow?.id) handleViewButton(selectedRow?.id)
} }
@ -594,10 +574,28 @@ const CustomTable: React.FC<CustomTableProps> = ({
id={selectedRow?.id} id={selectedRow?.id}
/> />
)} )}
{viewModal && tableType === "user" && (
<UserViewModal
handleView={() =>
handleViewButton(selectedRow?.id)
}
open={viewModal}
setViewModal={setViewModal}
id={selectedRow?.id}
/>
)}
{/* Edit Button */}
<Button <Button
variant="text" variant="text"
onClick={() => setModalOpen(true)} onClick={(e) => {
e.stopPropagation();
setModalOpen(true);
if (selectedRow) {
setModalOpen(true); // Only open if a row is selected
setRowData(selectedRow);
}
}}
color="primary" color="primary"
sx={{ sx={{
justifyContent: "flex-start", justifyContent: "flex-start",
@ -607,6 +605,7 @@ const CustomTable: React.FC<CustomTableProps> = ({
> >
Edit Edit
</Button> </Button>
{tableType === "role" && ( {tableType === "role" && (
<Button <Button
variant="text" variant="text"
@ -626,6 +625,7 @@ const CustomTable: React.FC<CustomTableProps> = ({
: "Activate"} : "Activate"}
</Button> </Button>
)} )}
{tableType === "station" && ( {tableType === "station" && (
<Button <Button
variant="text" variant="text"
@ -646,6 +646,7 @@ const CustomTable: React.FC<CustomTableProps> = ({
</Button> </Button>
)} )}
{/* Delete Button */}
<Button <Button
variant="text" variant="text"
onClick={(e) => { onClick={(e) => {
@ -661,7 +662,7 @@ const CustomTable: React.FC<CustomTableProps> = ({
> >
Delete Delete
</Button> </Button>
</Box> </div>
</Menu> </Menu>
)} )}
{/* Modals */} {/* Modals */}

View file

@ -0,0 +1,237 @@
import React, { useEffect } from "react";
import { Box, Button, Typography, Modal } from "@mui/material";
import CloseIcon from "@mui/icons-material/Close";
import { useForm, Controller } from "react-hook-form";
import { CustomIconButton, CustomTextField } from "../AddUserModal/styled.css";
interface EditAdminModalProps {
open: boolean;
handleClose: () => void;
handleUpdate: (
id: number,
name: string,
email: string,
phone: string,
registeredAddress: string
) => void;
editRow: any;
}
interface FormData {
name: string;
email: string;
phone: string;
registeredAddress: string;
}
const EditAdminModal: React.FC<EditAdminModalProps> = ({
open,
handleClose,
handleUpdate,
editRow,
}) => {
const {
control,
handleSubmit,
formState: { errors },
setValue,
reset,
} = useForm<FormData>({
defaultValues: {
name: "",
email: "",
phone: "",
registeredAddress: "",
},
});
useEffect(() => {
if (editRow) {
setValue("name", editRow.name);
setValue("email", editRow.email);
setValue("phone", editRow.phone);
setValue(
"registeredAddress",
editRow.Admins?.[0]?.registeredAddress || ""
);
} else {
reset();
}
}, [editRow, setValue, reset]);
const onSubmit = (data: FormData) => {
if (editRow) {
handleUpdate(
editRow.id,
data.name,
data.email,
data.phone,
data.registeredAddress
);
}
handleClose();
reset();
};
return (
<Modal
open={open}
onClose={(e, reason) => {
if (reason === "backdropClick") return;
handleClose();
}}
aria-labelledby="edit-admin-modal"
>
<Box
component="form"
onSubmit={handleSubmit(onSubmit)}
sx={{
position: "absolute",
top: "50%",
left: "50%",
transform: "translate(-50%, -50%)",
width: 400,
bgcolor: "background.paper",
boxShadow: 24,
p: 3,
borderRadius: 2,
}}
>
{/* Header */}
<Box
sx={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
}}
>
<Typography variant="h6" fontWeight={600}>
Edit Admin
</Typography>
<CustomIconButton onClick={handleClose}>
<CloseIcon />
</CustomIconButton>
</Box>
{/* Horizontal Line */}
<Box sx={{ borderBottom: "1px solid #ddd", my: 2 }} />
{/* Input Fields */}
<Box sx={{ display: "flex", flexDirection: "column", gap: 2 }}>
{/* Name */}
<Box sx={{ display: "flex", flexDirection: "column" }}>
<Typography variant="body2" fontWeight={500} mb={0.5}>
Full Name
</Typography>
<Controller
name="name"
control={control}
rules={{ required: "Name is required" }}
render={({ field }) => (
<CustomTextField
{...field}
fullWidth
placeholder="Enter Full Name"
size="small"
error={!!errors.name}
helperText={errors.name?.message}
/>
)}
/>
</Box>
{/* Email */}
<Box sx={{ display: "flex", flexDirection: "column" }}>
<Typography variant="body2" fontWeight={500} mb={0.5}>
Email
</Typography>
<Controller
name="email"
control={control}
rules={{ required: "Email is required" }}
render={({ field }) => (
<CustomTextField
{...field}
type="email"
fullWidth
placeholder="Enter Email"
size="small"
error={!!errors.email}
helperText={errors.email?.message}
/>
)}
/>
</Box>
{/* Phone */}
<Box sx={{ display: "flex", flexDirection: "column" }}>
<Typography variant="body2" fontWeight={500} mb={0.5}>
Phone Number
</Typography>
<Controller
name="phone"
control={control}
rules={{ required: "Phone number is required" }}
render={({ field }) => (
<CustomTextField
{...field}
fullWidth
placeholder="Enter Phone Number"
size="small"
error={!!errors.phone}
helperText={errors.phone?.message}
/>
)}
/>
</Box>
{/* Address */}
<Box sx={{ display: "flex", flexDirection: "column" }}>
<Typography variant="body2" fontWeight={500} mb={0.5}>
Address
</Typography>
<Controller
name="registeredAddress"
control={control}
rules={{ required: "Address is required" }}
render={({ field }) => (
<CustomTextField
{...field}
fullWidth
placeholder="Enter Address"
size="small"
error={!!errors.registeredAddress}
helperText={
errors.registeredAddress?.message
}
/>
)}
/>
</Box>
</Box>
{/* Submit Button */}
<Box
sx={{ display: "flex", justifyContent: "flex-end", mt: 3 }}
>
<Button
type="submit"
sx={{
backgroundColor: "#52ACDF",
color: "white",
borderRadius: "8px",
width: "117px",
"&:hover": { backgroundColor: "#439BC1" },
}}
>
Update Admin
</Button>
</Box>
</Box>
</Modal>
);
};
export default EditAdminModal;

View file

@ -10,10 +10,7 @@ import CloseIcon from "@mui/icons-material/Close";
import { useForm, Controller } from "react-hook-form"; import { useForm, Controller } from "react-hook-form";
import { useDispatch } from "react-redux"; import { useDispatch } from "react-redux";
import { managerList, updateManager } from "../../redux/slices/managerSlice.ts"; // Import the updateManager action import { managerList, updateManager } from "../../redux/slices/managerSlice.ts"; // Import the updateManager action
import { import { CustomIconButton, CustomTextField } from "../AddUserModal/styled.css";// Custom styled components
CustomIconButton,
CustomTextField,
} from "../AddEditUserModel/styled.css.tsx"; // Custom styled components
import { AppDispatch } from "../../redux/store/store.ts"; import { AppDispatch } from "../../redux/store/store.ts";
interface EditManagerModalProps { interface EditManagerModalProps {
@ -224,26 +221,6 @@ const EditManagerModal: React.FC<EditManagerModalProps> = ({
)} )}
/> />
</Box> </Box>
{/* <Box sx={{ flex: "1 1 48%" }}>
<Typography variant="body2" fontWeight={500} mb={0.5}>
StationId
</Typography>
<Controller
name="stationId"
control={control}
rules={{ required: "StationId is required" }}
render={({ field }) => (
<CustomTextField
{...field}
fullWidth
placeholder="Enter Station Id"
size="small"
error={!!errors.stationId}
helperText={errors.stationId?.message}
/>
)}
/>
</Box> */}
</Box> </Box>
{/* Submit Button */} {/* Submit Button */}
@ -259,7 +236,7 @@ const EditManagerModal: React.FC<EditManagerModalProps> = ({
width: "117px", width: "117px",
"&:hover": { backgroundColor: "#439BC1" }, "&:hover": { backgroundColor: "#439BC1" },
}} }}
disabled={loading} // Disable the button during loading state disabled={loading}
> >
{loading ? ( {loading ? (
<CircularProgress size={24} color="inherit" /> <CircularProgress size={24} color="inherit" />

View file

@ -13,10 +13,7 @@ import {
updateSlot, updateSlot,
fetchAvailableSlots, fetchAvailableSlots,
} from "../../redux/slices/slotSlice.ts"; // Update with correct action } from "../../redux/slices/slotSlice.ts"; // Update with correct action
import { import { CustomIconButton, CustomTextField } from "../AddUserModal/styled.css"; // Custom styled components
CustomIconButton,
CustomTextField,
} from "../AddEditUserModel/styled.css.tsx"; // Custom styled components
import { AppDispatch } from "../../redux/store/store.ts"; import { AppDispatch } from "../../redux/store/store.ts";
interface EditSlotModalProps { interface EditSlotModalProps {
@ -148,27 +145,6 @@ const EditSlotModal: React.FC<EditSlotModalProps> = ({
{/* Input Fields */} {/* Input Fields */}
<Box sx={{ display: "flex", flexWrap: "wrap", gap: 2 }}> <Box sx={{ display: "flex", flexWrap: "wrap", gap: 2 }}>
{/* Date */}
{/* <Box sx={{ flex: "1 1 100%" }}>
<Typography variant="body2" fontWeight={500} mb={0.5}>
Date
</Typography>
<Controller
name="date"
control={control}
rules={{ required: "Date is required" }}
render={({ field }) => (
<CustomTextField
{...field}
type="date"
fullWidth
size="small"
error={!!errors.date}
helperText={errors.date?.message}
/>
)}
/>
</Box> */}
{/* Start Time */} {/* Start Time */}
<Box sx={{ flex: "1 1 48%" }}> <Box sx={{ flex: "1 1 48%" }}>

View file

@ -23,7 +23,7 @@ import {
import { import {
CustomIconButton, CustomIconButton,
CustomTextField, CustomTextField,
} from "../AddEditUserModel/styled.css.tsx"; // Assuming custom styled components } from "../AddUserModal/styled.css"; // Assuming custom styled components
interface FormData { interface FormData {
name: string; name: string;
@ -121,7 +121,7 @@ const EditStationModal: React.FC<EditStationModalProps> = ({
const onSubmit = (data: FormData) => { const onSubmit = (data: FormData) => {
const vehicleIds = vehicles const vehicleIds = vehicles
.filter((vehicle) => selectedVehicles.includes(vehicle.name)) .filter((vehicle) => selectedVehicles.includes(vehicle.name))
.map((vehicle) => vehicle.id); .map((vehicle) => Number(vehicle.id));
handleUpdate( handleUpdate(
editRow.id, editRow.id,
@ -135,6 +135,8 @@ const EditStationModal: React.FC<EditStationModalProps> = ({
//setSelectedBrands([]); // Reset brands after submit //setSelectedBrands([]); // Reset brands after submit
setSelectedVehicles([]); // Reset selected vehicles setSelectedVehicles([]); // Reset selected vehicles
}; };
console.log("editRow:", editRow);
return ( return (
<Modal <Modal
@ -311,6 +313,52 @@ const EditStationModal: React.FC<EditStationModalProps> = ({
value={selectedBrands} value={selectedBrands}
onChange={handleBrandChange} onChange={handleBrandChange}
label="Choose Brands" label="Choose Brands"
renderValue={(selected) => {
const selectedArray =
selected as string[];
const displayNames =
selectedArray.slice(0, 1); // First 2 brand names
const moreCount =
selectedArray.length - 1; // Remaining brands
return (
<Box
sx={{
display: "flex",
alignItems: "center",
gap: 1,
}}
>
{displayNames.map(
(id, index) => {
const brand =
vehicleBrands.find(
(b) =>
b.id === id
);
return (
<Typography
key={index}
variant="body2"
>
{brand
? brand.name
: ""}
</Typography>
);
}
)}
{moreCount > 0 && (
<Typography
variant="body2"
color="textSecondary"
>
+{moreCount} more
</Typography>
)}
</Box>
);
}}
> >
{vehicleBrands.length > 0 ? ( {vehicleBrands.length > 0 ? (
vehicleBrands.map((brand) => ( vehicleBrands.map((brand) => (
@ -336,6 +384,8 @@ const EditStationModal: React.FC<EditStationModalProps> = ({
</Select> </Select>
</FormControl> </FormControl>
</Box> </Box>
{/* </Box>
<Box sx={{ display: "flex", gap: 2 }}> */}
<Box <Box
sx={{ sx={{
display: "flex", display: "flex",
@ -352,9 +402,43 @@ const EditStationModal: React.FC<EditStationModalProps> = ({
multiple multiple
value={selectedVehicles} value={selectedVehicles}
onChange={handleCheckboxChange} onChange={handleCheckboxChange}
renderValue={(selected) => renderValue={(selected) => {
(selected as string[]).join(", ") const selectedArray =
} selected as string[];
const displayNames =
selectedArray.slice(0, 1); // First 2 names
const moreCount =
selectedArray.length - 1; // Count of remaining items
return (
<Box
sx={{
display: "flex",
alignItems: "center",
gap: 1,
}}
>
{displayNames.map(
(name, index) => (
<Typography
key={index}
variant="body2"
>
{name}
</Typography>
)
)}
{moreCount > 0 && (
<Typography
variant="body2"
color="textSecondary"
>
+{moreCount} more
</Typography>
)}
</Box>
);
}}
> >
{filteredVehicles.length > 0 ? ( {filteredVehicles.length > 0 ? (
filteredVehicles.map((vehicle) => ( filteredVehicles.map((vehicle) => (
@ -378,6 +462,7 @@ const EditStationModal: React.FC<EditStationModalProps> = ({
</MenuItem> </MenuItem>
)} )}
</Select> </Select>
<FormHelperText> <FormHelperText>
{errors.allowedCarIds {errors.allowedCarIds
? errors.allowedCarIds.message ? errors.allowedCarIds.message
@ -388,8 +473,6 @@ const EditStationModal: React.FC<EditStationModalProps> = ({
</Box> </Box>
</Box> </Box>
{/* Submit Button */} {/* Submit Button */}
<Box <Box
sx={{ display: "flex", justifyContent: "flex-end", mt: 3 }} sx={{ display: "flex", justifyContent: "flex-end", mt: 3 }}

View file

@ -0,0 +1,211 @@
import React, { useEffect } from "react";
import { Box, Button, Typography, Modal } from "@mui/material";
import CloseIcon from "@mui/icons-material/Close";
import { useForm, Controller } from "react-hook-form";
import {
CustomIconButton,
CustomTextField,
} from "../AddUserModal/styled.css";
interface EditUserModalProps {
open: boolean;
handleClose: () => void;
handleUpdate: (
id: number,
name: string,
email: string,
phone: string,
) => void;
editRow: any;
}
interface FormData {
name: string;
email: string;
phone: string;
}
const EditUserModal: React.FC<EditUserModalProps> = ({
open,
handleClose,
handleUpdate,
editRow,
}) => {
const {
control,
handleSubmit,
formState: { errors },
setValue,
reset,
} = useForm<FormData>({
defaultValues: {
name: "",
email: "",
phone: "",
},
});
// Set values if editRow is provided
useEffect(() => {
if (editRow) {
setValue("name", editRow.name);
setValue("email", editRow.email);
setValue("phone", editRow.phone);
} else {
reset();
}
}, [editRow, setValue, reset]);
const onSubmit = (data: FormData) => {
if (editRow) {
handleUpdate(
editRow.id,
data.name,
data.email,
data.phone,
);
}
handleClose(); // Close the modal
reset(); // Reset the form fields
};
return (
<Modal
open={open}
onClose={(e, reason) => {
if (reason === "backdropClick") {
return;
}
handleClose();
}}
aria-labelledby="edit-user-modal"
>
<Box
component="form"
onSubmit={handleSubmit(onSubmit)}
sx={{
position: "absolute",
top: "50%",
left: "50%",
transform: "translate(-50%, -50%)",
width: 400,
bgcolor: "background.paper",
boxShadow: 24,
p: 3,
borderRadius: 2,
}}
>
{/* Header */}
<Box
sx={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
}}
>
<Typography variant="h6" fontWeight={600}>
Edit User
</Typography>
<CustomIconButton onClick={handleClose}>
<CloseIcon />
</CustomIconButton>
</Box>
{/* Horizontal Line */}
<Box sx={{ borderBottom: "1px solid #ddd", my: 2 }} />
{/* Input Fields */}
<Box sx={{ display: "flex", flexDirection: "column", gap: 2 }}>
{/* Name */}
<Box sx={{ display: "flex", flexDirection: "column" }}>
<Typography variant="body2" fontWeight={500} mb={0.5}>
Full Name
</Typography>
<Controller
name="name"
control={control}
rules={{ required: "Name is required" }}
render={({ field }) => (
<CustomTextField
{...field}
fullWidth
placeholder="Enter Full Name"
size="small"
error={!!errors.name}
helperText={errors.name?.message}
/>
)}
/>
</Box>
{/* Email */}
<Box sx={{ display: "flex", flexDirection: "column" }}>
<Typography variant="body2" fontWeight={500} mb={0.5}>
Email
</Typography>
<Controller
name="email"
control={control}
rules={{ required: "Email is required" }}
render={({ field }) => (
<CustomTextField
{...field}
type="email"
fullWidth
placeholder="Enter Email"
size="small"
error={!!errors.email}
helperText={errors.email?.message}
/>
)}
/>
</Box>
{/* Phone */}
<Box sx={{ display: "flex", flexDirection: "column" }}>
<Typography variant="body2" fontWeight={500} mb={0.5}>
Phone Number
</Typography>
<Controller
name="phone"
control={control}
rules={{ required: "Phone number is required" }}
render={({ field }) => (
<CustomTextField
{...field}
fullWidth
placeholder="Enter Phone Number"
size="small"
error={!!errors.phone}
helperText={errors.phone?.message}
/>
)}
/>
</Box>
</Box>
{/* Submit Button */}
<Box
sx={{ display: "flex", justifyContent: "flex-end", mt: 3 }}
>
<Button
type="submit"
sx={{
backgroundColor: "#52ACDF",
color: "white",
borderRadius: "8px",
width: "117px",
"&:hover": { backgroundColor: "#439BC1" },
}}
>
Update User
</Button>
</Box>
</Box>
</Modal>
);
};
export default EditUserModal;

View file

@ -11,7 +11,7 @@ import { updateVehicle } from "../../redux/slices/VehicleSlice";
import { import {
CustomIconButton, CustomIconButton,
CustomTextField, CustomTextField,
} from "../AddEditUserModel/styled.css.tsx"; } from "../AddUserModal/styled.css";
interface EditVehicleModalProps { interface EditVehicleModalProps {
open: boolean; open: boolean;
handleClose: () => void; handleClose: () => void;

View file

@ -5,17 +5,11 @@ import Box from "@mui/material/Box";
import Typography from "@mui/material/Typography"; import Typography from "@mui/material/Typography";
import InputBase from "@mui/material/InputBase"; import InputBase from "@mui/material/InputBase";
import SearchIcon from "@mui/icons-material/Search"; import SearchIcon from "@mui/icons-material/Search";
import Divider from "@mui/material/Divider";
import MenuButton from "../MenuButton";
import ArrowDropDownIcon from "@mui/icons-material/ArrowDropDown";
import NotificationsRoundedIcon from "@mui/icons-material/NotificationsRounded";
import SideMenu from "../SideMenu/sideMenu";
import { useDispatch, useSelector } from "react-redux"; import { useDispatch, useSelector } from "react-redux";
import { AppDispatch, RootState } from "../../redux/store/store"; import { AppDispatch, RootState } from "../../redux/store/store";
import { fetchAdminProfile } from "../../redux/slices/profileSlice"; import { fetchAdminProfile } from "../../redux/slices/profileSlice";
import OptionsMenu from "../OptionsMenu"; import OptionsMenu from "../OptionsMenu";
import NotificationsNoneIcon from "@mui/icons-material/NotificationsNone"; import NotificationsNoneIcon from "@mui/icons-material/NotificationsNone";
import ColorModeIconDropdown from "../../shared-theme/ColorModeIconDropdown";
export default function Header() { export default function Header() {
const [showNotifications, setShowNotifications] = React.useState(false); const [showNotifications, setShowNotifications] = React.useState(false);
@ -36,7 +30,7 @@ export default function Header() {
width: "100%", width: "100%",
// height: "84px", // height: "84px",
// backgroundColor: "#1C1C1C", // backgroundColor: "#1C1C1C",
padding: { xs: "20px 12px", sm: "20px 24px" }, // Adjust padding based on screen size // error on this padding: { xs: "20px 12px", sm: "20px 24px" },
display: "flex", display: "flex",
alignItems: "center", alignItems: "center",
justifyContent: "space-between", justifyContent: "space-between",

View file

@ -1,20 +1,11 @@
import * as React from "react";
import Grid from "@mui/material/Grid2"; import Grid from "@mui/material/Grid2";
import Box from "@mui/material/Box"; import Box from "@mui/material/Box";
import Stack from "@mui/material/Stack";
import Typography from "@mui/material/Typography"; import Typography from "@mui/material/Typography";
import Copyright from "../../pages/Dashboard/internals/components/Copyright";
import ChartUserByCountry from "../ChartUserByCountry";
import CustomizedTreeView from "../CustomizedTreeView";
import CustomizedDataGrid from "../CustomizedDataGrid";
import HighlightedCard from "../HighlightedCard";
import PageViewsBarChart from "../PageViewsBarChart";
import SessionsChart from "../SessionsChart/sessionChart"; import SessionsChart from "../SessionsChart/sessionChart";
import StatCard, { StatCardProps } from "../StatCard/statCard"; import StatCard, { StatCardProps } from "../StatCard/statCard";
import ResourcesPieChart from "../ResourcePieChart/resourcePieChart"; import ResourcesPieChart from "../ResourcePieChart/resourcePieChart";
import { BarChart } from "@mui/icons-material";
import RoundedBarChart from "../barChartCard/barChartCard"; import RoundedBarChart from "../barChartCard/barChartCard";
import { LineHighlightPlot } from "@mui/x-charts";
import LineChartCard from "../LineChartCard/lineChartCard"; import LineChartCard from "../LineChartCard/lineChartCard";
const data: StatCardProps[] = [ const data: StatCardProps[] = [

View file

@ -4,15 +4,11 @@ import ListItemButton from "@mui/material/ListItemButton";
import ListItemIcon from "@mui/material/ListItemIcon"; import ListItemIcon from "@mui/material/ListItemIcon";
import ListItemText from "@mui/material/ListItemText"; import ListItemText from "@mui/material/ListItemText";
import Stack from "@mui/material/Stack"; import Stack from "@mui/material/Stack";
import HomeRoundedIcon from "@mui/icons-material/HomeRounded";
import AnalyticsRoundedIcon from "@mui/icons-material/AnalyticsRounded";
import FormatListBulletedIcon from "@mui/icons-material/FormatListBulleted";
import { Link, useLocation } from "react-router-dom"; import { Link, useLocation } from "react-router-dom";
import { useSelector } from "react-redux"; import { useSelector } from "react-redux";
import { RootState } from "../../redux/store/store"; import { RootState } from "../../redux/store/store";
import DashboardOutlinedIcon from "@mui/icons-material/DashboardOutlined"; import DashboardOutlinedIcon from "@mui/icons-material/DashboardOutlined";
import ManageAccountsOutlinedIcon from "@mui/icons-material/ManageAccountsOutlined"; import ManageAccountsOutlinedIcon from "@mui/icons-material/ManageAccountsOutlined";
import EvStationOutlinedIcon from "@mui/icons-material/EvStationOutlined";
import EvStationIcon from "@mui/icons-material/EvStation"; import EvStationIcon from "@mui/icons-material/EvStation";
import BookOnlineOutlinedIcon from "@mui/icons-material/BookOnlineOutlined"; import BookOnlineOutlinedIcon from "@mui/icons-material/BookOnlineOutlined";
import ChecklistSharpIcon from "@mui/icons-material/ChecklistSharp"; import ChecklistSharpIcon from "@mui/icons-material/ChecklistSharp";

View file

@ -1,5 +1,6 @@
import { Box, Button, Modal, Typography } from "@mui/material"; import { Box, Button, IconButton, Modal, Typography } from "@mui/material";
import CloseIcon from "@mui/icons-material/Close"; import CloseIcon from "@mui/icons-material/Close";
import { CustomIconButton } from "../../AddUserModal/styled.css";
type Props = { type Props = {
open: boolean; open: boolean;
@ -14,7 +15,7 @@ const style = {
left: "50%", left: "50%",
transform: "translate(-50%, -50%)", transform: "translate(-50%, -50%)",
width: 330, width: 330,
bgcolor: "background.paper", bgcolor: "#272727",
borderRadius: 1.5, borderRadius: 1.5,
boxShadow: 24, boxShadow: 24,
p: 3, p: 3,
@ -47,17 +48,22 @@ export default function DeleteModal({
Delete Record Delete Record
</Typography> </Typography>
<Box <Box
onClick={() => setDeleteModal(false)}
sx={{ sx={{
cursor: "pointer", cursor: "pointer",
display: "flex", display: "flex",
alignItems: "center", alignItems: "center",
justifyContent: "flex-end", // Aligns the close icon to the right justifyContent: "flex-end",
marginTop: -3.5, marginTop: -3.5,
}} }}
> >
<CloseIcon /> <CustomIconButton
onClick={() => setDeleteModal(false)}
aria-label="Close"
>
<CloseIcon />
</CustomIconButton>
</Box> </Box>
<Typography <Typography
id="modal-modal-description" id="modal-modal-description"
sx={{ mt: 2 }} sx={{ mt: 2 }}

View file

@ -1,5 +1,6 @@
import { Box, Button, Modal, Typography } from "@mui/material"; import { Box, Button, Modal, Typography } from "@mui/material";
import CloseIcon from "@mui/icons-material/Close"; import CloseIcon from "@mui/icons-material/Close";
import { CustomIconButton } from "../../AddUserModal/styled.css";
type Props = { type Props = {
open: boolean; open: boolean;
@ -13,7 +14,7 @@ const style = {
left: "50%", left: "50%",
transform: "translate(-50%, -50%)", transform: "translate(-50%, -50%)",
width: 330, width: 330,
bgcolor: "background.paper", bgcolor: "#272727",
borderRadius: 1.5, borderRadius: 1.5,
boxShadow: 24, boxShadow: 24,
p: 3, p: 3,
@ -35,13 +36,16 @@ export default function LogoutModal({
return ( return (
<Modal <Modal
open={open} open={open}
onClose={(e, reason) => onClose={(event, reason) => {
reason !== "backdropClick" && setLogoutModal(false) if (reason !== "backdropClick") {
} // Prevent closing on backdrop click setLogoutModal(false);
}
}}
aria-labelledby="modal-modal-title" aria-labelledby="modal-modal-title"
aria-describedby="modal-modal-description" aria-describedby="modal-modal-description"
disableEscapeKeyDown // Prevent closing with the ESC key
BackdropProps={{ BackdropProps={{
onClick: (e) => e.stopPropagation(), // Stop propagation on backdrop click to prevent closing the modal invisible: true, // Use to control backdrop visibility
}} }}
> >
<Box sx={style}> <Box sx={style}>
@ -61,14 +65,18 @@ export default function LogoutModal({
> >
<Box sx={{ flex: 1, textAlign: "center" }}>Logout</Box> <Box sx={{ flex: 1, textAlign: "center" }}>Logout</Box>
<Box <Box
onClick={() => setLogoutModal(false)}
sx={{ sx={{
cursor: "pointer", cursor: "pointer",
display: "flex", display: "flex",
alignItems: "center", alignItems: "center",
}} }}
> >
<CloseIcon /> <CustomIconButton
onClick={() => setLogoutModal(false)}
aria-label="Close"
>
<CloseIcon />
</CustomIconButton>
</Box> </Box>
</Box> </Box>
</Typography> </Typography>

View file

@ -1,14 +1,15 @@
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import { Box, Modal, Typography, Divider, Grid } from "@mui/material"; import { Box, Modal, Typography, Divider, Grid, Chip } from "@mui/material";
import CloseIcon from "@mui/icons-material/Close"; import CloseIcon from "@mui/icons-material/Close";
import { useSelector } from "react-redux"; import { useSelector } from "react-redux";
import { RootState } from "../../../redux/reducers"; import { RootState } from "../../../redux/reducers";
import { CustomIconButton } from "../../AddUserModal/styled.css";
type Props = { type Props = {
open: boolean; open: boolean;
setViewModal: Function; setViewModal: Function;
handleView: (id: string | undefined) => void; handleView: (id: number | undefined) => void;
id?: string | undefined; id?: number | undefined;
}; };
const style = { const style = {
@ -64,16 +65,12 @@ export default function StationViewModal({ open, setViewModal, id }: Props) {
<Box sx={{ flex: 1, textAlign: "center" }}> <Box sx={{ flex: 1, textAlign: "center" }}>
{selectedStation?.name || "Station"}'s Details {selectedStation?.name || "Station"}'s Details
</Box> </Box>
<Box <CustomIconButton
onClick={() => setViewModal(false)} onClick={() => setViewModal(false)}
sx={{ aria-label="Close"
cursor: "pointer",
display: "flex",
alignItems: "center",
}}
> >
<CloseIcon /> <CloseIcon />
</Box> </CustomIconButton>
</Box> </Box>
</Typography> </Typography>
@ -109,12 +106,52 @@ export default function StationViewModal({ open, setViewModal, id }: Props) {
<Typography variant="body1"> <Typography variant="body1">
<strong>Status:</strong> <strong>Status:</strong>
<Typography variant="body2"> <Typography variant="body2">
{selectedStation.status === "available" {selectedStation.status === 1
? "Available" ? "Available"
: "Not Available"} : "Not Available"}
</Typography> </Typography>
</Typography> </Typography>
</Grid> </Grid>
{/* Display Vehicles */}
<Grid item xs={12}>
<Typography variant="body1">
<strong>Vehicles:</strong>
</Typography>
<Box
sx={{
display: "flex",
flexWrap: "wrap",
gap: 1,
marginTop: 1,
}}
>
{selectedStation.allowedCars &&
selectedStation.allowedCars.length > 0 ? (
selectedStation.allowedCars.map(
(car: any, index: number) => (
<Typography
key={car.id || index}
variant="body2"
sx={{
color: "#FFFFFF",
fontWeight: 500,
}}
>
{car.name}{","}
</Typography>
)
)
) : (
<Typography
variant="body2"
color="text.secondary"
>
No vehicles available
</Typography>
)}
</Box>
</Grid>
</Grid> </Grid>
) : ( ) : (
<Typography align="center"> <Typography align="center">

View file

@ -7,7 +7,7 @@ import { RootState } from "../../../redux/reducers";
type Props = { type Props = {
open: boolean; open: boolean;
setViewModal: Function; setViewModal: Function;
handleView: (id: string | undefined) => void; handleView: (id: number | undefined) => void;
id?: number | undefined; id?: number | undefined;
}; };

View file

@ -59,9 +59,10 @@ export default function SideMenu() {
sx={{ sx={{
display: "flex", display: "flex",
flexDirection: "row", flexDirection: "row",
justifyContent:"center",
alignItems: "center", alignItems: "center",
pt: 2, pt: 2,
pl: 2,
}} }}
> >
<img <img
@ -69,7 +70,7 @@ export default function SideMenu() {
alt="Logo" alt="Logo"
style={{ style={{
justifyContent: "center", justifyContent: "center",
width: open ? "200px" : "60px", // Adjust width depending on open state width: open ? "120px" : "60px", // Adjust width depending on open state
height: "auto", height: "auto",
transition: "width 0.5s ease", // Smooth transition for width change transition: "width 0.5s ease", // Smooth transition for width change
}} }}

View file

@ -1,13 +1,8 @@
import * as React from "react";
import { useTheme } from "@mui/material/styles";
import Box from "@mui/material/Box";
import Card from "@mui/material/Card"; import Card from "@mui/material/Card";
import CardContent from "@mui/material/CardContent"; import CardContent from "@mui/material/CardContent";
import Chip from "@mui/material/Chip";
import Stack from "@mui/material/Stack";
import Typography from "@mui/material/Typography"; import Typography from "@mui/material/Typography";
import { SparkLineChart } from "@mui/x-charts/SparkLineChart";
import { areaElementClasses } from "@mui/x-charts/LineChart";
export type StatCardProps = { export type StatCardProps = {
title: string; title: string;

View file

@ -20,7 +20,7 @@ import { useDispatch, useSelector } from "react-redux";
import { createRole } from "../../redux/slices/roleSlice"; // Import the createRole action import { createRole } from "../../redux/slices/roleSlice"; // Import the createRole action
import { AppDispatch, RootState } from "../../redux/store/store"; // Assuming this is the path to your store file import { AppDispatch, RootState } from "../../redux/store/store"; // Assuming this is the path to your store file
import { toast } from "sonner"; import { toast } from "sonner";
import { CustomTextField } from "../../components/AddEditUserModel/styled.css.tsx"; import { CustomTextField } from "../../components/AddUserModal/styled.css";
// Define the data structure for permission // Define the data structure for permission
interface Permission { interface Permission {
module: string; module: string;

View file

@ -28,7 +28,8 @@ export default function AdminList() {
dispatch(adminList()); dispatch(adminList());
}, [dispatch]); }, [dispatch]);
const handleClickOpen = () => { const handleClickOpen = (row: any) => {
setRowData(row);
setRowData(null); // Reset row data when opening for new admin setRowData(null); // Reset row data when opening for new admin
setModalOpen(true); setModalOpen(true);
}; };
@ -123,6 +124,7 @@ export default function AdminList() {
setModalOpen={setModalOpen} setModalOpen={setModalOpen}
tableType="admin" tableType="admin"
handleClickOpen={handleClickOpen} handleClickOpen={handleClickOpen}
editRow={rowData}
/> />
<AddEditCategoryModal <AddEditCategoryModal
open={modalOpen} open={modalOpen}

View file

@ -21,7 +21,7 @@ import ForgotPassword from "./ForgotPassword.tsx";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
import { Visibility, VisibilityOff } from "@mui/icons-material"; import { Visibility, VisibilityOff } from "@mui/icons-material";
import { Card, SignInContainer } from "./styled.css.tsx"; import { Card, SignInContainer } from "./styled.css.tsx";
import { CustomIconButton } from "../../../components/AddEditUserModel/styled.css.tsx"; import { CustomIconButton } from "../../../components/AddUserModal/styled.css.tsx";
import { AppDispatch } from "../../../redux/store/store.ts"; import { AppDispatch } from "../../../redux/store/store.ts";
interface ILoginForm { interface ILoginForm {
email: string; email: string;

View file

@ -8,7 +8,7 @@ import {
IconButton, IconButton,
Button, Button,
} from "@mui/material"; } from "@mui/material";
import { CustomTextField } from "../../components/AddEditUserModel/styled.css.tsx"; import { CustomTextField } from "../../components/AddUserModal/styled.css.tsx";
import AddCircleIcon from "@mui/icons-material/AddCircle"; import AddCircleIcon from "@mui/icons-material/AddCircle";
import DeleteIcon from "@mui/icons-material/Delete"; import DeleteIcon from "@mui/icons-material/Delete";
import CalendarTodayRoundedIcon from "@mui/icons-material/CalendarTodayRounded"; import CalendarTodayRoundedIcon from "@mui/icons-material/CalendarTodayRounded";

View file

@ -1,5 +1,4 @@
import React, { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { Box, Button, TextField, Typography } from "@mui/material";
import CustomTable, { Column } from "../../components/CustomTable/customTable"; import CustomTable, { Column } from "../../components/CustomTable/customTable";
import AddManagerModal from "../../components/AddManagerModal/addManagerModal"; import AddManagerModal from "../../components/AddManagerModal/addManagerModal";
import EditManagerModal from "../../components/EditManagerModal/editManagerModal"; import EditManagerModal from "../../components/EditManagerModal/editManagerModal";
@ -15,13 +14,11 @@ import { useForm } from "react-hook-form";
export default function ManagerList() { export default function ManagerList() {
const [addModalOpen, setAddModalOpen] = useState<boolean>(false); const [addModalOpen, setAddModalOpen] = useState<boolean>(false);
const [editModalOpen, setEditModalOpen] = useState<boolean>(false); const [editModalOpen, setEditModalOpen] = useState<boolean>(false);
const [editRow, setEditRow] = useState<any>(null);
const { reset } = useForm(); const { reset } = useForm();
const [deleteModal, setDeleteModal] = useState<boolean>(false); const [deleteModal, setDeleteModal] = useState<boolean>(false);
const [viewModal, setViewModal] = useState<boolean>(false); const [viewModal, setViewModal] = useState<boolean>(false);
const [rowData, setRowData] = useState<any | null>(null); const [rowData, setRowData] = useState<any | null>(null);
const [searchTerm, setSearchTerm] = useState("");
const dispatch = useDispatch<AppDispatch>(); const dispatch = useDispatch<AppDispatch>();
const managers = useSelector( const managers = useSelector(
(state: RootState) => state.managerReducer.managers (state: RootState) => state.managerReducer.managers
@ -65,7 +62,7 @@ export default function ManagerList() {
// Handle updating an existing manager // Handle updating an existing manager
const handleUpdate = async ( const handleUpdate = async (
id: string, id: number,
name: string, name: string,
email: string, email: string,
phone: string, phone: string,
@ -100,14 +97,6 @@ export default function ManagerList() {
{ id: "action", label: "Action", align: "center" }, { id: "action", label: "Action", align: "center" },
]; ];
// Filter managers based on search term
// const filteredManagers = managers?.filter(
// (manager) =>
// manager.name?.toLowerCase().includes(searchTerm.toLowerCase()) ||
// manager.email?.toLowerCase().includes(searchTerm.toLowerCase()) ||
// manager.phone?.toLowerCase().includes(searchTerm.toLowerCase())
// );
const categoryRows = managers?.length const categoryRows = managers?.length
? managers.map((manager, index) => { ? managers.map((manager, index) => {
const station = manager?.chargingStation; // Correct access to the ChargingStation data const station = manager?.chargingStation; // Correct access to the ChargingStation data

View file

@ -13,10 +13,9 @@ import {
import { AppDispatch, RootState } from "../../redux/store/store"; import { AppDispatch, RootState } from "../../redux/store/store";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
import AddEditRolePage from "../AddEditRolePage"; import AddEditRolePage from "../AddEditRolePage";
import SearchIcon from "@mui/icons-material/Search";
export default function RoleList() { export default function RoleList() {
const [modalOpen, setModalOpen] = useState(false);
const { reset } = useForm(); const { reset } = useForm();
const [deleteModal, setDeleteModal] = React.useState<boolean>(false); const [deleteModal, setDeleteModal] = React.useState<boolean>(false);
@ -120,3 +119,4 @@ export default function RoleList() {
</> </>
); );
} }

View file

@ -1,4 +1,4 @@
import { Chip } from "@mui/material";
import AddStationModal from "../../components/AddStationModal/addStationModal"; import AddStationModal from "../../components/AddStationModal/addStationModal";
import CustomTable, { Column } from "../../components/CustomTable/customTable"; import CustomTable, { Column } from "../../components/CustomTable/customTable";
import EditStationModal from "../../components/EditStationModal/editSationModal"; import EditStationModal from "../../components/EditStationModal/editSationModal";
@ -17,13 +17,11 @@ import { useForm } from "react-hook-form";
export default function StationList() { export default function StationList() {
const [addModalOpen, setAddModalOpen] = useState<boolean>(false); const [addModalOpen, setAddModalOpen] = useState<boolean>(false);
const [editModalOpen, setEditModalOpen] = useState<boolean>(false); const [editModalOpen, setEditModalOpen] = useState<boolean>(false);
const [editRow, setEditRow] = useState<any>(null);
const { reset } = useForm(); const { reset } = useForm();
const [deleteModal, setDeleteModal] = useState<boolean>(false); const [deleteModal, setDeleteModal] = useState<boolean>(false);
const [viewModal, setViewModal] = useState<boolean>(false); const [viewModal, setViewModal] = useState<boolean>(false);
const [rowData, setRowData] = useState<any | null>(null); const [rowData, setRowData] = useState<any | null>(null);
const [searchTerm, setSearchTerm] = useState("");
const dispatch = useDispatch<AppDispatch>(); const dispatch = useDispatch<AppDispatch>();
const vehicles = useSelector( const vehicles = useSelector(
@ -64,7 +62,7 @@ export default function StationList() {
}; };
const handleUpdate = async ( const handleUpdate = async (
id: string, id: number,
name: string, name: string,
registeredAddress: string, registeredAddress: string,
totalSlots: number, totalSlots: number,

View file

@ -6,17 +6,17 @@ import CustomTable, { Column } from "../../components/CustomTable/customTable";
import { useDispatch, useSelector } from "react-redux"; import { useDispatch, useSelector } from "react-redux";
import { createUser, updateUser, userList } from "../../redux/slices/userSlice"; import { createUser, updateUser, userList } from "../../redux/slices/userSlice";
import { AppDispatch, RootState } from "../../redux/store/store"; import { AppDispatch, RootState } from "../../redux/store/store";
import { string } from "prop-types"; import AddUserModal from "../../components/AddUserModal/addUserModal";
import { adminList, updateAdmin } from "../../redux/slices/adminSlice"; import EditUserModal from "../../components/EditUserModal/editUserModal";
import AddUserModal from "../../components/AddEditUserModel";
export default function UserList() { export default function UserList() {
const [modalOpen, setModalOpen] = useState(false); const [addModalOpen, setAddModalOpen] = useState<boolean>(false);
const [editModalOpen, setEditModalOpen] = useState<boolean>(false);
const [rowData, setRowData] = useState<any | null>(null);
const [deleteModal, setDeleteModal] = useState<boolean>(false);
const [viewModal, setViewModal] = useState<boolean>(false);
const { reset } = useForm(); const { reset } = useForm();
const [deleteModal, setDeleteModal] = React.useState<boolean>(false);
const [viewModal, setViewModal] = React.useState<boolean>(false);
const [rowData, setRowData] = React.useState<any | null>(null);
const dispatch = useDispatch<AppDispatch>(); const dispatch = useDispatch<AppDispatch>();
@ -28,11 +28,12 @@ export default function UserList() {
const handleClickOpen = () => { const handleClickOpen = () => {
setRowData(null); // Reset row data when opening for new admin setRowData(null); // Reset row data when opening for new admin
setModalOpen(true); setAddModalOpen(true);
}; };
const handleCloseModal = () => { const handleCloseModal = () => {
setModalOpen(false); setAddModalOpen(false);
setEditModalOpen(false);
setRowData(null); setRowData(null);
reset(); reset();
}; };
@ -52,7 +53,7 @@ export default function UserList() {
}; };
const handleUpdate = async ( const handleUpdate = async (
id: string, id: number,
name: string, name: string,
email: string, email: string,
phone: string phone: string
@ -64,6 +65,7 @@ export default function UserList() {
name, name,
email, email,
phone, phone,
}) })
); );
await dispatch(userList()); await dispatch(userList());
@ -77,39 +79,21 @@ export default function UserList() {
{ id: "name", label: "Name" }, { id: "name", label: "Name" },
{ id: "email", label: "Email" }, { id: "email", label: "Email" },
{ id: "phone", label: "Phone" }, { id: "phone", label: "Phone" },
// { id: "location", label: "Location" },
// { id: "managerAssigned", label: "ManagerAssigned" },
// { id: "vehicle", label: "Vehicle" },
{ id: "action", label: "Action", align: "center" }, { id: "action", label: "Action", align: "center" },
]; ];
const categoryRows = users?.length
? users.map((user, index) => ({
id: user.id,
srno: index + 1,
name: user.name,
email: user.email,
phone: user.phone || "NA", // Ensures it's a string
}))
: [];
const categoryRows = users?.length
? users?.map(function (
user: {
id: string;
name: string;
email: string;
phone: string;
// location?: string;
// managerAssigned?: string;
// vehicle?: string;
},
index: number
) {
return {
id: user?.id,
srno: index + 1,
name: user?.name,
email: user?.email,
phone: user?.phone,
// location: user?.location,
// managerAssigned: user?.managerAssigned,
// vehicle: user?.vehicle,
};
})
: [];
return ( return (
<> <>
@ -121,14 +105,19 @@ export default function UserList() {
setViewModal={setViewModal} setViewModal={setViewModal}
viewModal={viewModal} viewModal={viewModal}
setRowData={setRowData} setRowData={setRowData}
setModalOpen={setModalOpen}
tableType="user" tableType="user"
handleClickOpen={handleClickOpen} handleClickOpen={handleClickOpen}
setModalOpen={() => setEditModalOpen(true)}
/> />
<AddUserModal <AddUserModal
open={modalOpen} open={addModalOpen}
handleClose={handleCloseModal} handleClose={handleCloseModal}
handleCreate={handleCreate} handleCreate={handleCreate}
/>
<EditUserModal
open={editModalOpen}
handleClose={handleCloseModal}
handleUpdate={handleUpdate} handleUpdate={handleUpdate}
editRow={rowData} editRow={rowData}
/> />

View file

@ -58,7 +58,7 @@ export default function VehicleList() {
}; };
const handleUpdate = async ( const handleUpdate = async (
id: string, id: number,
name: string, name: string,
company: string, company: string,
modelName: string, modelName: string,
@ -93,24 +93,13 @@ export default function VehicleList() {
{ id: "action", label: "Action", align: "center" }, { id: "action", label: "Action", align: "center" },
]; ];
// const filteredVehicles = vehicles?.filter(
// (vehicle) =>
// vehicle.name?.toLowerCase().includes(searchTerm.toLowerCase()) ||
// vehicle.company?.toLowerCase().includes(searchTerm.toLowerCase()) ||
// vehicle.modelName
// ?.toLowerCase()
// .includes(searchTerm.toLowerCase()) ||
// vehicle.chargeType
// ?.toLowerCase()
// .includes(searchTerm.toLowerCase()) ||
// vehicle.imageUrl?.toLowerCase().includes(searchTerm.toLowerCase())
// );
const categoryRows = vehicles?.length const categoryRows = vehicles?.length
? vehicles?.map( ? vehicles?.map(
( (
vehicle: { vehicle: {
id: string; id: number;
name: string; name: string;
company: string; company: string;
modelName: string; modelName: string;

View file

@ -9,7 +9,7 @@ interface VehicleBrand {
interface Vehicle { interface Vehicle {
brandId?: string; brandId?: string;
id: string; id: number;
name: string; name: string;
company: string; company: string;
modelName: string; modelName: string;

View file

@ -5,8 +5,7 @@ import { toast } from "sonner";
// Define the Manager interface based on the payload // Define the Manager interface based on the payload
interface Manager { interface Manager {
Manager: any; id: number;
id: string;
name: string; name: string;
email: string; email: string;
phone: string; phone: string;
@ -74,7 +73,7 @@ export const addManager = createAsyncThunk<
// Update Manager (Async Thunk) // Update Manager (Async Thunk)
export const updateManager = createAsyncThunk< export const updateManager = createAsyncThunk<
Manager, Manager,
{ id: string; managerData: Manager }, { id: number; managerData: Manager },
{ rejectValue: string } { rejectValue: string }
>("updateManager", async ({ id, managerData }, { rejectWithValue }) => { >("updateManager", async ({ id, managerData }, { rejectWithValue }) => {
if (!id) { if (!id) {

View file

@ -5,7 +5,7 @@ import { toast } from "sonner";
// Define TypeScript types // Define TypeScript types
interface Station { interface Station {
id: string; id: number;
name: string; name: string;
registeredAddress: string; registeredAddress: string;
totalSlots: number; totalSlots: number;

View file

@ -5,14 +5,12 @@ import { toast } from "sonner";
// Define TypeScript types // Define TypeScript types
interface User { interface User {
id: string; id: number;
name: string; name: string;
email: string; email: string;
phone?: string; phone?: string;
// location?: string;
// managerAssigned?: string;
// vehicle?: string;
password: string;
} }
interface UserState { interface UserState {