ProfilePage Edit api integration and Create EditProfile Modal

This commit is contained in:
jaanvi 2025-04-29 18:34:34 +05:30
parent e717d6c58c
commit 570faa40d4
5 changed files with 935 additions and 82 deletions

View file

@ -67,29 +67,27 @@ const StyledTableCell = styled(TableCell)(({ theme }) => ({
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
zIndex: 11,
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)",
borderBottom: "none",
color: "#333333",
transition: "background-color 0.2s ease",
fontWeight:500,
// Make the "Action" body cell sticky
fontWeight: 500,
"&.action-cell": {
position: "sticky",
right: 0,
zIndex: 2,
boxShadow: "-4px 0 8px rgba(0, 0, 0, 0.1)",
backgroundColor: "#DFECF1", // Match row background
backgroundColor: "#DFECF1",
"&:hover": {
backgroundColor: "#D0E1E9", // Match row hover background
backgroundColor: "#D0E1E9",
},
},
},
@ -100,11 +98,11 @@ const StyledTableRow = styled(TableRow)(({ theme }) => ({
"&:hover": {
backgroundColor: "#D0E1E9",
},
"& td, & th": {
borderColor: "#454545",
borderWidth: "1px",
borderBottom: "1px solid #454545",
},
// "& td, & th": {
// borderColor: "#454545",
// borderWidth: "1px",
// // borderBottom: "1px solid #454545",
// },
}));
const StyledTableContainer = styled(TableContainer)(({ theme }) => ({

View file

@ -0,0 +1,315 @@
import React, { useEffect, useState } 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 EditProfileModalProps {
open: boolean;
handleClose: () => void;
handleUpdate: (
name: string,
phone: string,
bio?: string,
profilePhoto?: string | null
) => void;
editUser: any;
}
interface FormData {
name: string;
phone: string;
bio?: string;
profilePhoto?: string | null;
}
const EditProfileModal: React.FC<EditProfileModalProps> = ({
open,
handleClose,
handleUpdate,
editUser,
}) => {
const {
control,
handleSubmit,
formState: { errors },
setValue,
reset,
} = useForm<FormData>();
const [imagePreview, setImagePreview] = useState<string | null>(null);
useEffect(() => {
if (editUser) {
setValue("name", editUser.name || "");
setValue("phone", editUser.phone || "");
setValue("bio", editUser.bio || "");
setImagePreview(editUser.profilePhoto || null);
}
}, [editUser, setValue]);
const handleImageChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const file = e.target.files?.[0];
if (file) {
const imageUrl = URL.createObjectURL(file);
setImagePreview(imageUrl);
setValue("profilePhoto", imageUrl);
}
};
const handleModalClose = () => {
handleClose();
};
const onSubmit = (data: FormData) => {
console.log("Form Data:-----", data);
handleUpdate(data.name, data.phone, data.bio, data.profilePhoto);
reset();
handleModalClose();
};
return (
<Modal
open={open}
onClose={(e, reason) => {
if (reason !== "backdropClick") handleModalClose();
}}
aria-labelledby="edit-profile-modal"
>
<Box
component="form"
onSubmit={handleSubmit(onSubmit)}
sx={{
position: "absolute",
top: "50%",
left: "50%",
transform: "translate(-50%, -50%)",
width: 500,
boxShadow: 24,
p: 0,
borderRadius: 2,
}}
>
{/* Header */}
<Box
sx={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
backgroundColor: "#000000",
color: "#D0E1E9",
padding: "20px 24px",
borderRadius: "10px 10px 0 0",
}}
>
<Typography variant="h6" fontWeight={600} fontSize="16px">
Edit Profile
</Typography>
<CustomIconButton onClick={handleModalClose}>
<CloseIcon />
</CustomIconButton>
</Box>
<Box
sx={{
backgroundColor: "#b5c4cb",
padding: "20px",
borderRadius: "0 0 10px 10px",
}}
>
<Box
sx={{
display: "flex",
flexDirection: "column",
gap: 2,
}}
>
{/* Name Field */}
<Box sx={{ display: "flex", flexDirection: "column" }}>
<Typography
variant="body2"
fontWeight={500}
color="#000000"
>
Full Name
</Typography>
<Controller
name="name"
control={control}
rules={{
required: "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]+$/,
message:
"Only letters and spaces allowed",
},
}}
render={({ field }) => (
<CustomTextField
{...field}
fullWidth
placeholder="Enter your name"
size="small"
sx={{ mt: 1 }}
error={!!errors.name}
helperText={errors.name?.message}
/>
)}
/>
</Box>
{/* Phone Field */}
<Box sx={{ display: "flex", flexDirection: "column" }}>
<Typography
variant="body2"
fontWeight={500}
color="#000000"
>
Phone Number
</Typography>
<Controller
name="phone"
control={control}
rules={{
required: "Phone number is required",
validate: (value) => {
if (!/^[0-9]*$/.test(value))
return "Only numbers are allowed";
if (value.length < 6)
return "Must be at least 6 digits";
if (value.length > 14)
return "Must be at most 14 digits";
return true;
},
}}
render={({ field }) => (
<CustomTextField
{...field}
fullWidth
placeholder="Enter phone number"
size="small"
sx={{ mt: 1 }}
error={!!errors.phone}
helperText={errors.phone?.message}
/>
)}
/>
</Box>
{/* Bio Field */}
<Box sx={{ display: "flex", flexDirection: "column" }}>
<Typography
variant="body2"
fontWeight={500}
color="#000000"
>
Bio
</Typography>
<Controller
name="bio"
control={control}
render={({ field }) => (
<CustomTextField
{...field}
fullWidth
placeholder="Add your bio details here..."
size="small"
sx={{ mt: 1 }}
/>
)}
/>
</Box>
{/* Upload Image */}
<Box sx={{ display: "flex", flexDirection: "column" }}>
<Typography
variant="body2"
fontWeight={500}
color="#000000"
>
Upload Profile Photo
</Typography>
<Button
component="label"
sx={{
backgroundColor: "#000000",
color: "#D0E1E9",
borderRadius: "8px",
mt: 1,
"&:hover": { backgroundColor: "#454545" },
}}
>
Choose Image
<input
type="file"
hidden
accept="image/*"
onChange={handleImageChange}
/>
</Button>
{imagePreview && (
<Box mt={2}>
<Typography variant="body2" color="#000000">
Preview (
{imagePreview.startsWith("blob")
? "New"
: "Existing"}
):
</Typography>
<img
src={imagePreview}
alt="Profile Preview"
style={{
maxWidth: "40%",
borderRadius: "8px",
}}
/>
</Box>
)}
</Box>
</Box>
{/* Footer */}
<Box
sx={{
display: "flex",
justifyContent: "flex-end",
mt: 3,
}}
>
<Button
type="submit"
sx={{
backgroundColor: "#000000",
color: "#D0E1E9",
borderRadius: "8px",
fontSize: "16px",
width: "140px",
"&:hover": { backgroundColor: "#454545" },
}}
>
Save Changes
</Button>
</Box>
</Box>
</Box>
</Modal>
);
};
export default EditProfileModal;

View file

@ -169,3 +169,435 @@ export default function ViewModal({ open, setViewModal, id }: Props) {
</Modal>
);
}
// import {
// Box,
// Button,
// Modal,
// Typography,
// Tabs,
// Tab,
// Divider,
// Grid,
// } from "@mui/material";
// import { AppDispatch, RootState } from "../../../redux/store/store";
// import { useDispatch, useSelector } from "react-redux";
// import { useEffect, useState } from "react";
// import CloseIcon from "@mui/icons-material/Close";
// import { managerList } from "../../../redux/slices/managerSlice";
// import {
// AsyncThunkAction,
// ThunkDispatch,
// UnknownAction,
// } from "@reduxjs/toolkit";
// type Props = {
// open: boolean;
// setViewModal: Function;
// handleView: (id: string | undefined) => void;
// id?: string;
// };
// interface TabPanelProps {
// children?: React.ReactNode;
// index: number;
// value: number;
// }
// const style = {
// position: "absolute",
// top: "50%",
// left: "50%",
// transform: "translate(-50%, -50%)",
// width: 600,
// borderRadius: 2,
// boxShadow: "0px 4px 20px rgba(0, 0, 0, 0.15)",
// p: 0,
// display: "flex",
// flexDirection: "column",
// alignItems: "center",
// };
// function TabPanel(props: TabPanelProps) {
// const { children, value, index, ...other } = props;
// return (
// <div
// role="tabpanel"
// hidden={value !== index}
// id={`tabpanel-${index}`}
// aria-labelledby={`tab-${index}`}
// {...other}
// >
// {value === index && <Box sx={{ p: 3 }}>{children}</Box>}
// </div>
// );
// }
// export default function ViewModal({ open, setViewModal, id }: Props) {
// const { admins } = useSelector((state: RootState) => state.adminReducer);
// const { managers } = useSelector(
// (state: RootState) => state.managerReducer
// );
// const [selectedAdmin, setSelectedAdmin] = useState<any>(null);
// const selectedManager = managers.find(
// (manager) => String(manager.id) === String(selectedAdmin?.id)
// );
// const dispatch = useDispatch();
// const [tabValue, setTabValue] = useState(0);
// useEffect(() => {
// if (id) {
// const admin = admins.find((admin) => admin.id === id);
// setSelectedAdmin(admin);
// }
// }, [id, admins]);
// useEffect(() => {
// if (open) {
// //dispatch(managerList());
// }
// }, [open, dispatch]);
// const handleTabChange = (event: React.SyntheticEvent, newValue: number) => {
// setTabValue(newValue);
// };
// return (
// <Modal
// open={open}
// aria-labelledby="modal-title"
// aria-describedby="modal-description"
// >
// <Box sx={style}>
// <Box
// sx={{
// display: "flex",
// justifyContent: "space-between",
// alignItems: "center",
// backgroundColor: "#000000",
// color: "#D0E1E9",
// padding: "20px 24px",
// borderRadius: "10px 10px 0 0",
// width: "100%",
// boxSizing: "border-box",
// }}
// >
// <Typography
// id="modal-title"
// variant="h5"
// fontWeight="bold"
// sx={{ width: "100%" }}
// >
// <Box
// sx={{
// display: "flex",
// alignItems: "center",
// justifyContent: "space-between",
// width: "100%",
// }}
// >
// <Box
// sx={{
// flex: 1,
// textAlign: "center",
// color: "#D0E1E9",
// }}
// >
// {selectedAdmin?.name || "Admin"}'s Details
// </Box>
// <Box
// onClick={() => setViewModal(false)}
// sx={{
// cursor: "pointer",
// display: "flex",
// alignItems: "center",
// color: "#D0E1E9",
// }}
// >
// <CloseIcon />
// </Box>
// </Box>
// </Typography>
// </Box>
// <Box sx={{ width: "100%", backgroundColor: "#b5c4cb" }}>
// <Tabs
// value={tabValue}
// onChange={handleTabChange}
// aria-label="admin details tabs"
// sx={{
// backgroundColor: "#000000",
// "& .MuiTabs-indicator": {
// backgroundColor: "#D0E1E9",
// },
// }}
// >
// <Tab
// label="Admin Details"
// sx={{
// color: "#D0E1E9",
// "&.Mui-selected": { color: "#D0E1E9" },
// }}
// />
// <Tab
// label="Manager Details"
// sx={{
// color: "#D0E1E9",
// "&.Mui-selected": { color: "#D0E1E9" },
// }}
// />
// <Tab
// label="Charging Stations"
// sx={{
// color: "#D0E1E9",
// "&.Mui-selected": { color: "#D0E1E9" },
// }}
// />
// <Tab
// label="User Details"
// sx={{
// color: "#D0E1E9",
// "&.Mui-selected": { color: "#D0E1E9" },
// }}
// />
// </Tabs>
// <TabPanel value={tabValue} index={0}>
// {selectedAdmin ? (
// <Grid container spacing={3}>
// <Grid item xs={6}>
// <Typography variant="body1" color="#000000">
// <strong>Name:</strong>
// <Typography
// variant="body2"
// color="#454545"
// >
// {selectedAdmin.name}
// </Typography>
// </Typography>
// </Grid>
// <Grid item xs={6}>
// <Typography variant="body1" color="#000000">
// <strong>Phone:</strong>
// <Typography
// variant="body2"
// color="#454545"
// >
// {selectedAdmin.phone}
// </Typography>
// </Typography>
// </Grid>
// <Grid item xs={6}>
// <Typography variant="body1" color="#000000">
// <strong>Email:</strong>
// <Typography
// variant="body2"
// color="#454545"
// >
// {selectedAdmin.email}
// </Typography>
// </Typography>
// </Grid>
// <Grid item xs={6}>
// <Typography variant="body1" color="#000000">
// <strong>Address:</strong>
// <Typography
// variant="body2"
// color="#454545"
// >
// {selectedAdmin?.Admins?.[0]
// ?.registeredAddress ?? "N/A"}
// </Typography>
// </Typography>
// </Grid>
// </Grid>
// ) : (
// <Typography align="center" color="#454545">
// No admin found with this ID
// </Typography>
// )}
// </TabPanel>
// <TabPanel value={tabValue} index={1}>
// {selectedManager ? (
// <Grid container spacing={3}>
// <Grid item xs={6}>
// <Typography variant="body1" color="#000000">
// <strong>Manager Name:</strong>
// <Typography
// variant="body2"
// color="#454545"
// >
// {selectedManager.name ?? "N/A"}
// </Typography>
// </Typography>
// </Grid>
// <Grid item xs={6}>
// <Typography variant="body1" color="#000000">
// <strong>Manager Email:</strong>
// <Typography
// variant="body2"
// color="#454545"
// >
// {selectedManager.email ?? "N/A"}
// </Typography>
// </Typography>
// </Grid>
// <Grid item xs={6}>
// <Typography variant="body1" color="#000000">
// <strong>Phone:</strong>
// <Typography
// variant="body2"
// color="#454545"
// >
// {selectedManager.phone ?? "N/A"}
// </Typography>
// </Typography>
// </Grid>
// <Grid item xs={6}>
// <Typography variant="body1" color="#000000">
// <strong>Station Name:</strong>
// <Typography
// variant="body2"
// color="#454545"
// >
// {selectedManager.chargingStation
// ?.name ?? "N/A"}
// </Typography>
// </Typography>
// </Grid>
// </Grid>
// ) : (
// <Typography align="center" color="#454545">
// No manager details available
// </Typography>
// )}
// </TabPanel>
// <TabPanel value={tabValue} index={2}>
// {selectedAdmin?.chargingStations?.length > 0 ? (
// <Grid container spacing={3}>
// {selectedAdmin.chargingStations.map(
// (station: any, index: number) => (
// <Grid item xs={12} key={index}>
// <Typography
// variant="body1"
// color="#000000"
// >
// <strong>
// Station {index + 1}:
// </strong>
// <Typography
// variant="body2"
// color="#454545"
// >
// Name:{" "}
// {station.name ?? "N/A"}
// </Typography>
// <Typography
// variant="body2"
// color="#454545"
// >
// Location:{" "}
// {station.location ?? "N/A"}
// </Typography>
// <Typography
// variant="body2"
// color="#454545"
// >
// Status:{" "}
// {station.status ?? "N/A"}
// </Typography>
// </Typography>
// {index <
// selectedAdmin.chargingStations
// .length -
// 1 && (
// <Divider sx={{ my: 2 }} />
// )}
// </Grid>
// )
// )}
// </Grid>
// ) : (
// <Typography align="center" color="#454545">
// No charging stations assigned
// </Typography>
// )}
// </TabPanel>
// <TabPanel value={tabValue} index={3}>
// {selectedAdmin?.users?.length > 0 ? (
// <Grid container spacing={3}>
// {selectedAdmin.users.map(
// (user: any, index: number) => (
// <Grid item xs={12} key={index}>
// <Typography
// variant="body1"
// color="#000000"
// >
// <strong>
// User {index + 1}:
// </strong>
// <Typography
// variant="body2"
// color="#454545"
// >
// Name: {user.name ?? "N/A"}
// </Typography>
// <Typography
// variant="body2"
// color="#454545"
// >
// Email: {user.email ?? "N/A"}
// </Typography>
// <Typography
// variant="body2"
// color="#454545"
// >
// Role: {user.role ?? "N/A"}
// </Typography>
// </Typography>
// {index <
// selectedAdmin.users.length -
// 1 && (
// <Divider sx={{ my: 2 }} />
// )}
// </Grid>
// )
// )}
// </Grid>
// ) : (
// <Typography align="center" color="#454545">
// No users assigned
// </Typography>
// )}
// </TabPanel>
// <Box
// sx={{
// display: "flex",
// justifyContent: "flex-end",
// p: 2,
// borderRadius: "0 0 10px 10px",
// }}
// >
// <Button
// onClick={() => setViewModal(false)}
// sx={{
// backgroundColor: "#000000",
// color: "#D0E1E9",
// borderRadius: "8px",
// fontSize: "16px",
// width: "117px",
// "&:hover": { backgroundColor: "#454545" },
// }}
// >
// Close
// </Button>
// </Box>
// </Box>
// </Box>
// </Modal>
// );
// }

View file

@ -1,4 +1,4 @@
import { useEffect } from "react";
import { useEffect, useState, useMemo } from "react";
import {
Container,
Typography,
@ -14,19 +14,60 @@ import {
} from "@mui/material";
import { useDispatch, useSelector } from "react-redux";
import { AppDispatch, RootState } from "../../redux/store/store";
import { fetchAdminProfile } from "../../redux/slices/profileSlice";
import {
fetchAdminProfile,
updateProfile,
} from "../../redux/slices/profileSlice";
import EditIcon from "@mui/icons-material/Edit";
import EditProfileModal from "../../components/Modals/EditProfileModal/editProfileModal";
import { CustomIconButton } from "../../components/AddUserModal/styled.css";
const ProfilePage = () => {
const dispatch = useDispatch<AppDispatch>();
const { user, isLoading } = useSelector(
(state: RootState) => state?.profileReducer
const { user, loading } = useSelector(
(state: RootState) => state.profileReducer
);
const [openEditModal, setOpenEditModal] = useState(false);
useEffect(() => {
dispatch(fetchAdminProfile());
}, [dispatch]);
if (isLoading) {
const handleOpenEditModal = () => {
setOpenEditModal(true);
};
const handleClose = () => {
setOpenEditModal(false);
};
const handleUpdate = (
name: string,
phone: string,
bio?: string,
profilePhoto?: string | null
) => {
console.log("Dispatching updateProfile...");
dispatch(updateProfile({ name, phone, bio, profilePhoto }));
};
// Memoizing the user data for optimization
const displayUser = useMemo(
() => ({
name: user?.name || "N/A",
email: user?.email || "N/A",
phone: user?.phone || "N/A",
bio: user?.bio || "No bio available.",
userType: user?.userType || "N/A",
profilePhoto: user?.profilePhoto || "/avatar.png", // Default image path
}),
[user]
);
// Show loading indicator if data is being fetched
if (loading) {
return (
<Box
sx={{
@ -42,12 +83,7 @@ const ProfilePage = () => {
}
return (
<Container
sx={{
py:1,
}}
>
<Container sx={{ py: 1 }}>
<Typography
variant="h4"
gutterBottom
@ -61,42 +97,68 @@ const ProfilePage = () => {
p: { xs: 2, sm: 3 },
mx: "auto",
backgroundColor: "#000000",
}}
// sx={{
// width: "1132px",
// height: "331px",
// gap: "24px",
// borderRadius: "12px",
// padding: "16px",
// maxWidth: "100%",
// margin: "0 auto",
// backgroundColor: "#1C1C1C",
// }}
>
<CardContent>
<Stack direction="column" spacing={2}>
<Stack direction="row" spacing={2} alignItems="center">
<Avatar
alt="User Avatar"
src="/avatar.png"
sx={{ width: 60, height: 60 }}
/>
<Stack
direction="row"
spacing={2}
alignItems="center"
position="relative"
>
<Box
position="relative"
sx={{
width: 60,
height: 60,
"&:hover .edit-icon": { opacity: 1 },
"&:hover .avatar-img": { opacity: 0.4 },
}}
>
<Avatar
alt="User Avatar"
src={displayUser.profilePhoto}
sx={{
width: 60,
height: 60,
transition: "opacity 0.3s",
}}
className="avatar-img"
/>
<CustomIconButton
onClick={handleOpenEditModal}
className="edit-icon"
sx={{
position: "absolute",
top: "50%",
left: "50%",
transform: "translate(-50%, -50%)",
color: "white",
opacity: 0,
transition: "opacity 0.3s",
}}
>
<EditIcon fontSize="small" />
</CustomIconButton>
</Box>
<Box>
<Typography
variant="body1"
sx={{ color: "#D0E1E9", fontWeight: 500 }}
>
{user?.name || "No Admin"}
{displayUser.name}
</Typography>
<Typography
variant="body2"
sx={{ color: "#D9D8D8" }}
>
{user?.userType || "N/A"}
{displayUser.userType}
</Typography>
</Box>
</Stack>
<Divider
flexItem
sx={{ backgroundColor: "rgba(32, 32, 32, 0.5)" }}
@ -117,80 +179,72 @@ const ProfilePage = () => {
>
Personal Information
</Typography>
{/* <Link
<Link
component="button"
variant="body1"
href="/edit-profile"
color="#52ACDF"
onClick={handleOpenEditModal}
>
Edit
</Link> */}
</Link>
</Stack>
<Grid container spacing={3} >
<Grid container spacing={3}>
<Grid item xs={12} sm={4}>
<Typography
variant="body2"
sx={{
color: "#D0E1E9",
fontWeight: 500,
fontSize: "16px",
}}
sx={{ color: "#D0E1E9", fontWeight: 500 }}
>
Full Name:
</Typography>
<Typography variant="body2" color="#D9D8D8">
{user?.name || "N/A"}
{displayUser.name}
</Typography>
</Grid>
<Grid item xs={12} sm={4}>
<Typography
variant="body2"
sx={{
color: "#D0E1E9",
fontWeight: 500,
fontSize: "16px",
}}
sx={{ color: "#D0E1E9", fontWeight: 500 }}
>
Phone:
</Typography>
<Typography variant="body2" color="#D9D8D8">
{user?.phone || "N/A"}
{displayUser.phone}
</Typography>
</Grid>
<Grid item xs={12} sm={4}>
<Typography
variant="body2"
sx={{
color: "#D0E1E9",
fontWeight: 500,
fontSize: "16px",
}}
sx={{ color: "#D0E1E9", fontWeight: 500 }}
>
Email:
</Typography>
<Typography variant="body2" color="#D9D8D8">
{user?.email || "N/A"}
{displayUser.email}
</Typography>
</Grid>
<Grid item xs={12} sm={4}>
<Typography
variant="body2"
sx={{
color: "#D0E1E9",
fontWeight: 500,
fontSize: "16px",
}}
sx={{ color: "#D0E1E9", fontWeight: 500 }}
>
Bio:
</Typography>
<Typography variant="body2" color="#D9D8D8">
{user?.bio || "No bio available."}
{displayUser.bio}
</Typography>
</Grid>
</Grid>
</Stack>
</CardContent>
</Card>
<EditProfileModal
open={openEditModal}
handleClose={handleClose}
handleUpdate={handleUpdate} // Passing the handleUpdate function to the modal
editUser={user} // Pass the current user to pre-fill the form in modal
/>
</Container>
);
};

View file

@ -1,6 +1,7 @@
import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";
import http from "../../lib/https";
import { toast } from "sonner";
import { string } from "prop-types";
interface User {
token: string | null;
@ -9,14 +10,26 @@ interface User {
email: string;
userType: string;
phone: string;
bio?: string;
profilePhoto?: string;
}
interface AuthState {
user: User | null;
users: User[];
isAuthenticated: boolean;
isLoading: boolean;
loading: boolean;
error: null | string;
}
const initialState: AuthState = {
users: [],
loading: false,
error: null,
isAuthenticated: false,
user: null,
};
export const fetchAdminProfile = createAsyncThunk<
User,
void,
@ -32,18 +45,45 @@ export const fetchAdminProfile = createAsyncThunk<
return response.data.data;
} catch (error: any) {
toast.error("Error Fetching Profile" + error);
toast.error("Error Fetching Profile: " + error.message);
return rejectWithValue(
error?.response?.data?.message || "An error occurred"
);
}
});
const initialState: AuthState = {
user: null,
isAuthenticated: false,
isLoading: false,
};
export const updateProfile = createAsyncThunk<
User,
{
name: string;
phone?: string;
bio?: string;
profilePhoto?: string | null;
},
{ rejectValue: string }
>(
"updateProfile",
async ({ name, phone, bio, profilePhoto }, { rejectWithValue }) => {
try {
const payload: any = { name };
if (phone) payload.phone = phone;
if (bio) payload.bio = bio;
if (profilePhoto) payload.profilePhoto = profilePhoto;
const response = await http.put("/edit-profile", payload);
console.log("-----------", response);
toast.success("Profile updated successfully");
return response.data.data;
} catch (error: any) {
toast.error("Error updating the profile: " + error.message);
return rejectWithValue(
error?.response?.data?.message || "An error occurred"
);
}
}
);
const profileSlice = createSlice({
name: "profile",
@ -52,15 +92,29 @@ const profileSlice = createSlice({
extraReducers: (builder) => {
builder
.addCase(fetchAdminProfile.pending, (state) => {
state.isLoading = true;
state.loading = true;
})
.addCase(fetchAdminProfile.fulfilled, (state, action) => {
state.isLoading = false;
state.loading = false;
state.user = action.payload;
state.isAuthenticated = true;
})
.addCase(fetchAdminProfile.rejected, (state) => {
state.isLoading = false;
.addCase(fetchAdminProfile.rejected, (state, action) => {
state.loading = false;
state.error = action.payload;
})
.addCase(updateProfile.fulfilled, (state, action) => {
state.loading = false;
state.user = action.payload; // Update current user only
toast.success("Profile Details updated successfully");
})
.addCase(updateProfile.rejected, (state, action) => {
state.loading = false;
state.error = action.payload;
})
.addCase(updateProfile.pending, (state) => {
state.loading = true;
});
},
});