Fixed save picture functionality
This commit is contained in:
1 parent
3fd819293c
commit
28c3616004
3 files changed
+73
-61
No files matched your search
@@ -23,24 +23,25 @@ const Avatar = ({ src, small, sx }) => {
|
||||
const border = small ? 1 : 3;
|
||||
|
||||
const [image, setImage] = useState();
|
||||
useEffect(() => {
|
||||
const fetchData = async () => {
|
||||
try {
|
||||
if (user.profileImage.data && user.profileImage.contentType) {
|
||||
const url = await bufferToUrl(user.profileImage);
|
||||
setImage(url);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error converting buffer to URL: ", error);
|
||||
}
|
||||
};
|
||||
// useEffect(() => {
|
||||
// const fetchData = async () => {
|
||||
// try {
|
||||
// if (user.profileImage.data && user.profileImage.contentType) {
|
||||
// const url = await bufferToUrl(user.profileImage);
|
||||
// setImage(url);
|
||||
// }
|
||||
// } catch (error) {
|
||||
// console.error("Error converting buffer to URL: ", error);
|
||||
// }
|
||||
// };
|
||||
|
||||
fetchData();
|
||||
}, [user]);
|
||||
// fetchData();
|
||||
// }, [user]);
|
||||
|
||||
return (
|
||||
<MuiAvatar
|
||||
alt={`${user?.firstname} ${user?.lastname}`}
|
||||
children={`${user.firstname?.charAt(0)}${user.lastname?.charAt(0)}`}
|
||||
src={
|
||||
src === "placeholder"
|
||||
? "/static/images/avatar/2.jpg"
|
||||
@@ -66,11 +67,7 @@ const Avatar = ({ src, small, sx }) => {
|
||||
...style,
|
||||
...sx,
|
||||
}}
|
||||
>
|
||||
{src === undefined
|
||||
? `${user.firstname?.charAt(0)}${user.lastname?.charAt(0)}`
|
||||
: null}
|
||||
</MuiAvatar>
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -30,30 +30,28 @@ const ProfilePanel = () => {
|
||||
const theme = useTheme();
|
||||
const dispatch = useDispatch();
|
||||
|
||||
//redux state
|
||||
const { user, authToken, isLoading } = useSelector((state) => state.auth);
|
||||
|
||||
const idToName = {
|
||||
"edit-first-name": "firstname",
|
||||
"edit-last-name": "lastname",
|
||||
// Disabled for now, will revisit in the future
|
||||
// "edit-email": "email",
|
||||
};
|
||||
|
||||
// Local state for form data, errors, and file handling
|
||||
const [localData, setLocalData] = useState({
|
||||
firstname: user.firstname,
|
||||
lastname: user.lastname,
|
||||
// Disabled for now, will revisit in the future
|
||||
// email: user.email,
|
||||
profileImage: user.profileImage,
|
||||
// email: user.email, // Disabled for now
|
||||
});
|
||||
|
||||
const [errors, setErrors] = useState({});
|
||||
const clearError = (err) => {
|
||||
setErrors((prev) => {
|
||||
const updatedErrors = { ...prev };
|
||||
if (updatedErrors[err]) delete updatedErrors[err];
|
||||
return updatedErrors;
|
||||
});
|
||||
};
|
||||
const [file, setFile] = useState();
|
||||
const intervalRef = useRef(null);
|
||||
const [progress, setProgress] = useState({ value: 0, isLoading: false });
|
||||
|
||||
// Handles input field changes and performs validation
|
||||
const handleChange = (event) => {
|
||||
const { value, id } = event.target;
|
||||
const name = idToName[id];
|
||||
@@ -65,9 +63,7 @@ const ProfilePanel = () => {
|
||||
validateField({ [name]: value }, editProfileValidation, name);
|
||||
};
|
||||
|
||||
const [file, setFile] = useState();
|
||||
const intervalRef = useRef(null);
|
||||
const [progress, setProgress] = useState({ value: 0, isLoading: false });
|
||||
// Handles image file
|
||||
const handlePicture = (event) => {
|
||||
const pic = event.target.files[0];
|
||||
let error = validateField(
|
||||
@@ -83,7 +79,7 @@ const ProfilePanel = () => {
|
||||
size: formatBytes(pic.size),
|
||||
});
|
||||
|
||||
//TODO - potentitally remove once image compression functions are implemented above
|
||||
//TODO - potentitally remove once image compression functions are implemented
|
||||
intervalRef.current = setInterval(() => {
|
||||
const buffer = 12;
|
||||
setProgress((prev) => {
|
||||
@@ -96,6 +92,7 @@ const ProfilePanel = () => {
|
||||
}, 120);
|
||||
};
|
||||
|
||||
// Validates input against provided schema and updates error state
|
||||
const validateField = (toValidate, schema, name = "picture") => {
|
||||
const { error } = schema.validate(toValidate, { abortEarly: false });
|
||||
setErrors((prev) => {
|
||||
@@ -107,57 +104,69 @@ const ProfilePanel = () => {
|
||||
if (error) return true;
|
||||
};
|
||||
|
||||
// Clears specific error from errors state
|
||||
const clearError = (err) => {
|
||||
setErrors((prev) => {
|
||||
const updatedErrors = { ...prev };
|
||||
if (updatedErrors[err]) delete updatedErrors[err];
|
||||
return updatedErrors;
|
||||
});
|
||||
};
|
||||
|
||||
// Resets picture-related states and clears interval
|
||||
const removePicture = () => {
|
||||
clearError("picture");
|
||||
errors["picture"] && clearError("picture");
|
||||
setFile({ src: "placeholder" });
|
||||
//interrupt interval if image upload is canceled prior to completing the process
|
||||
clearInterval(intervalRef.current);
|
||||
clearInterval(intervalRef.current); // interrupt interval if image upload is canceled prior to completing the process
|
||||
setProgress({ value: 0, isLoading: false });
|
||||
};
|
||||
|
||||
// Closes the picture update modal and resets related states
|
||||
const closePictureModal = () => {
|
||||
removePicture();
|
||||
setIsOpen("");
|
||||
};
|
||||
|
||||
// Updates profile image displayed on UI
|
||||
const handleUpdatePicture = () => {
|
||||
setProgress({ value: 0, isLoading: false });
|
||||
setLocalData((prev) => ({
|
||||
...prev,
|
||||
profileImage: null,
|
||||
file: file.src,
|
||||
}));
|
||||
setIsOpen("");
|
||||
};
|
||||
const handleDeletePicture = () => {
|
||||
setFile({ src: "placeholder" });
|
||||
setLocalData((prev) => ({
|
||||
...prev,
|
||||
profileImage: null,
|
||||
}));
|
||||
};
|
||||
|
||||
//TODO - implement delete account function
|
||||
const handleDeleteAccount = () => {};
|
||||
// Handles form submission to update user profile
|
||||
const handleSaveProfile = (event) => {
|
||||
event.preventDefault();
|
||||
if (
|
||||
localData.firstname === user.firstname &&
|
||||
localData.lastname === user.lastname &&
|
||||
localData.profileImage === user.profileImage
|
||||
) {
|
||||
//TODO - add toast(profile data is unchanged) and maybe disable button
|
||||
return;
|
||||
}
|
||||
// if (
|
||||
// localData.firstname === user.firstname &&
|
||||
// localData.lastname === user.lastname
|
||||
// ) {
|
||||
// // TODO: Add toast/notification for unchanged profile data
|
||||
// return;
|
||||
// }
|
||||
|
||||
dispatch(update({ authToken, localData }));
|
||||
//TODO - add toast confirmation
|
||||
// TODO: Add toast/notification for profile update success
|
||||
};
|
||||
|
||||
//modal controllers
|
||||
// Removes current profile image from UI
|
||||
const handleDeletePicture = () => {
|
||||
setFile({ src: "placeholder" });
|
||||
// TODO - implement delete picture function
|
||||
};
|
||||
|
||||
// Initiates the account deletion process
|
||||
const handleDeleteAccount = () => {
|
||||
//TODO - implement delete account function
|
||||
};
|
||||
|
||||
// Modal state and control functions
|
||||
const [isOpen, setIsOpen] = useState("");
|
||||
const isModalOpen = (name) => isOpen === name;
|
||||
|
||||
// console.log(document.querySelector('input[type="file"]')?.files[0]);
|
||||
|
||||
return (
|
||||
<TabPanel value="profile">
|
||||
<form className="edit-profile-form" noValidate spellCheck="false">
|
||||
@@ -385,8 +394,8 @@ const ProfilePanel = () => {
|
||||
{progress.isLoading || progress.value !== 0 || errors["picture"] ? (
|
||||
<ProgressUpload
|
||||
icon={<ImageIcon />}
|
||||
label={file.name}
|
||||
size={file.size}
|
||||
label={file?.name}
|
||||
size={file?.size}
|
||||
progress={progress.value}
|
||||
onClick={removePicture}
|
||||
error={errors["picture"]}
|
||||
|
||||
@@ -47,7 +47,13 @@ export const update = createAsyncThunk(
|
||||
//1.5s delay to show loading spinner
|
||||
await new Promise((resolve) => setTimeout(resolve, 1500));
|
||||
|
||||
const res = await axios.post(`${BASE_URL}/auth/user/${user._id}`, form, {
|
||||
const fd = new FormData();
|
||||
const imageResult = await axios.get(form.file);
|
||||
fd.append("firstname", form.firstname);
|
||||
fd.append("lastname", form.lastname);
|
||||
fd.append("profileImage", imageResult.data);
|
||||
|
||||
const res = await axios.post(`${BASE_URL}/auth/user/${user._id}`, fd, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
"Content-Type": "multipart/form-data",
|
||||
|
||||
Reference in new issue
Block a user