basically it is a social media app in which I’m trying to edit user profile pic and cover img by an input form and it is giving errors like not returning data after submitting the form, I’m using react.js,react-bootstrap for form, and react redux for state management, action reducers are giving me an error
so here are my files
// InfoCard.jsx (a card where basic information about user profile is displayed and a pen button to edit user profile)
import React, { useEffect, useState } from "react";
import "./InfoCard.css";
import ProfileModal from "../profileModal/ProfileModal";
import { useDispatch, useSelector } from "react-redux";
import { useParams } from "react-router-dom";
import * as UserApi from "../../api/UserRequest.js";
import { logOut } from "../../actions/AuthAction.js";
const InfoCard = () => {
const dispatch = useDispatch();
const params = useParams();
const profileUserId = params.id;
const [profileUser, setProfileUser] = useState({});
const { user } = useSelector((state) => state.AuthReducer.authData);
console.log("Authenticated user:", user);
useEffect(() => {
const fetchProfileUser = async () => {
try {
if (profileUserId === user._id) {
setProfileUser(user);
} else {
const profileUser = await UserApi.getUser(profileUserId);
setProfileUser(profileUser);
console.log("Fetched profile user data:", profileUser);
}
} catch (error) {
console.error("Error fetching profile user:", error);
}
};
console.log(user);
fetchProfileUser();
console.log("profileUser in InfoCard.jsx : " + profileUser)
}, [user]);
const handleLogout = () => {
dispatch(logOut());
console.log("User logged out");
};
//console.log("InfoCard render - profileUser:", profileUser);
return (
<div className="InfoCard">
<div className="infoHead">
<h4>Profile Info</h4>
{user._id === profileUserId ? (
<div>
<ProfileModal
data = {user}
/>
</div>
) : (
""
)}
</div>
<div className="info">
<span>
<b>Status </b>
</span>
<span>{profileUser.relationship}</span>
</div>
<div className="info">
<span>
<b>Lives in </b>
</span>
<span>{profileUser.livesin}</span>
</div>
<div className="info">
<span>
<b>Works at </b>
</span>
<span>{profileUser.worksAt}</span>
</div>
<button className="button logout-button" onClick={handleLogout}>
Logout
</button>
</div>
);
};
export default InfoCard;
after clicking on to the pen button to edit profile modal is opened
// ProfileModal.jsx
import React, { useEffect } from "react";
import Button from "react-bootstrap/Button";
import Modal from "react-bootstrap/Modal";
import { useState } from "react";
import { UilPen } from "@iconscout/react-unicons";
import Form from "react-bootstrap/Form";
import { useDispatch } from "react-redux";
import { useParams } from "react-router-dom";
import { UploadImage } from "../../actions/UploadAction.js";
import { UpdateUser } from "../../actions/UserAction.js";
function ProfileModal( {data} ) {
const [show, setShow] = useState(false);
const handleClose = () => setShow(false);
const handleShow = () => setShow(true);
const { password, ...other } = data
const dispatch = useDispatch()
const params = useParams()
// maybe its because we have made the data a state whhich is stupid as how can we change state
const [formData, setFormData] = useState(other);
const [profileImage, setProfileImage] = useState("")
const [coverImage, setCoverImage] = useState("")
//const { user } = useSelector((state) => state.AuthReducer.authData);
//console.log(data);
const handleChange = (e) => {
setFormData({...formData, [e.target.name]: e.target.value})
}
const onImageChange = (e) => {
if (e.target.files && e.target.files[0]) {
let img = e.target.files[0];
console.log("Selected image:", img);
if (e.target.name === "profileImage") {
setProfileImage(img);
console.log("Profile image set:", img);
} else if (e.target.name === "coverImage") {
setCoverImage(img);
console.log("Cover image set:", img);
}
}
};
// form submission
const handleSubmit = async (e) => {
e.preventDefault();
let UserData = formData;
if (profileImage) {
const data = new FormData();
const fileName = Date.now() + profileImage.name;
data.append("name", fileName);
data.append("file", profileImage);
UserData.profilePicture = fileName;
try {
dispatch(UploadImage(data));
} catch (err) {
console.log("profileimg error" + err);
}
if (coverImage) {
const data = new FormData();
const fileName = Date.now() + coverImage.name;
data.append("name", fileName);
data.append("file", coverImage);
UserData.coverPicture = fileName;
try {
dispatch(UploadImage(data));
} catch (err) {
console.log("coverImg error" +err);
}
}
dispatch(UpdateUser(params.id, UserData));
}
};
return (
<>
<UilPen
width="2rem"
height="1.2rem"
variant="primary"
onClick={handleShow}
/>
<Modal
dialogClassName="modal-dialog modal-xl modal"
size="xxl"
aria-labelledby="contained-modal-title-vcenter "
centered
show={show}
onHide={handleClose}
>
<Modal.Header closeButton>
<Modal.Title>Your Info</Modal.Title>
</Modal.Header>
<Modal.Body
style={{ maxHeight: "70vh", overflowY: "auto" }}
className="modal-body"
>
<Form>
<Form.Group className="mb-3" controlId="exampleForm.ControlInput1">
<Form.Label>First Name</Form.Label>
<Form.Control
type="text"
placeholder="Enter your first name"
className="border-0 bg-input p-3"
name="firstname"
onChange={handleChange}
value={formData.firstname}
style={{
backgroundColor: "var(--inputColor)",
outline: "none",
boxShadow: "none",
padding: "10px 15px", // Adjust the padding as needed
}}
/>
</Form.Group>
<Form.Group className="mb-3" controlId="exampleForm.ControlInput2">
<Form.Label>Last Name</Form.Label>
<Form.Control
type="text"
placeholder="Enter your last name"
className="border-0 bg-input p-3"
name="lastname"
onChange={handleChange}
value={formData.lastname}
style={{
backgroundColor: "var(--inputColor)",
outline: "none",
boxShadow: "none",
padding: "10px 15px", // Adjust the padding as needed
}}
/>
</Form.Group>
<Form.Group className="mb-3" controlId="exampleForm.ControlInput3">
<Form.Label>Works at</Form.Label>
<Form.Control
type="text"
placeholder="Enter your workplace"
className="border-0 bg-input p-3"
name="worksAt"
onChange={handleChange}
value={formData.worksAt}
style={{
backgroundColor: "var(--inputColor)",
outline: "none",
boxShadow: "none",
padding: "10px 15px", // Adjust the padding as needed
}}
/>
</Form.Group>
<Form.Group className="mb-3" controlId="exampleForm.ControlInput4">
<Form.Label>Lives In</Form.Label>
<Form.Control
type="text"
placeholder="Enter your location"
className="border-0 bg-input p-3"
name="livesin"
onChange={handleChange}
value={formData.livesin}
style={{
backgroundColor: "var(--inputColor)",
outline: "none",
boxShadow: "none",
padding: "10px 15px", // Adjust the padding as needed
}}
/>
</Form.Group>
<Form.Group className="mb-3" controlId="exampleForm.ControlInput5">
<Form.Label>Country</Form.Label>
<Form.Control
type="text"
placeholder="Enter your country"
className="border-0 bg-input p-3"
name="country"
onChange={handleChange}
value={formData.country}
style={{
backgroundColor: "var(--inputColor)",
outline: "none",
boxShadow: "none",
padding: "10px 15px", // Adjust the padding as needed
}}
/>
</Form.Group>
<Form.Group className="mb-3" controlId="exampleForm.ControlInput6">
<Form.Label>Relationship Status</Form.Label>
<Form.Control
type="text"
placeholder="Enter your relationship status"
className="border-0 bg-input p-3"
name="relationship"
onChange={handleChange}
value={formData.relationship}
style={{
backgroundColor: "var(--inputColor)",
outline: "none",
boxShadow: "none",
padding: "10px 15px", // Adjust the padding as needed
}}
/>
</Form.Group>
<Form.Group
className="mb-3"
controlId="exampleForm.ControlTextarea1"
>
<Form.Label>About</Form.Label>
<Form.Control
className="border-0 bg-input p-3"
as="textarea"
placeholder="Tell us about yourself"
rows={3}
name="about"
onChange={handleChange}
value={formData.about}
style={{
backgroundColor: "var(--inputColor)",
outline: "none",
boxShadow: "none",
padding: "10px 15px", // Adjust the padding as needed
}}
/>
</Form.Group>
<Form.Group className="mb-3" controlId="exampleForm.ControlInput7">
<Form.Label>Profile Image</Form.Label>
<Form.Control
type="file"
name="profileImage"
onChange={onImageChange}
style={{
outline: "none",
boxShadow: "none",
padding: "10px 15px", // Adjust the padding as needed
}}
/>
</Form.Group>
<Form.Group className="mb-3" controlId="exampleForm.ControlInput8">
<Form.Label>Cover Image</Form.Label>
<Form.Control
type="file"
name="coverImage"
onChange={onImageChange}
style={{
outline: "none",
boxShadow: "none",
padding: "10px 15px", // Adjust the padding as needed
}}
/>
</Form.Group>
</Form>
</Modal.Body>
<Modal.Footer>
<button className="button info-btn " onClick={handleSubmit}>Update</button>
</Modal.Footer>
</Modal>
</>
);
}
export default ProfileModal;
now in the modal all fields are updated correctly except images field, images changes are being held correctly as the data is being console logged displaying the changes, bu i think that on submitting there is an error while dealing with profile Img and cover img, and append is being underlined in red by vs code itself, UploadImage is returning null data, although upload image is successfully uploading posts in the app so it is clear maybe that the backend is fine
// possible error
if (profileImage) {
const data = new FormData();
const fileName = Date.now() + profileImage.name;
data.append("name", fileName);
data.append("file", profileImage);
UserData.profilePicture = fileName;
try {
dispatch(UploadImage(data));
} catch (err) {
console.log("profileimg error" + err);
}
if (coverImage) {
const data = new FormData();
const fileName = Date.now() + coverImage.name;
data.append("name", fileName);
data.append("file", coverImage);
UserData.coverPicture = fileName;
try {
dispatch(UploadImage(data));
} catch (err) {
console.log("coverImg error" +err);
}
}
since Im using React redux so heres my redux structure
//UploadRequest.js
import axios from "axios";
const API = axios.create({ baseURL: "http://localhost:5000" });
API.interceptors.request.use((req) => {
if (localStorage.getItem('profile')) {
req.headers.Authorization = `Bearer ${JSON.parse(localStorage.getItem('profile')).accessToken}`;
}
return req;
});
export const UploadImage = (data) => API.post("/upload/", data);
export const UploadPost = (data) => API.post("/posts", data);
images are being stored and being posted correctly in the app so the backend seems fine
// UploadAction.js
import * as UploadApi from "../api/UploadRequest";
export const UploadImage = (data) => async (dispatch) => {
try {
console.log("Image upload Action start ho gya hy")
console.log("UploadImage data:" + data) // here it is returning UploadImage data:[object FormData]
await UploadApi.UploadImage(data);
} catch (error) {
console.log(error);
dispatch({ type: "UPLOAD_FAIL" });
}
};
export const UploadPost = (data) => async (dispatch) => {
dispatch({ type: 'UPLOAD_START' });
try {
const newPost = await UploadApi.UploadPost(data);
dispatch({ type: 'UPLOAD_SUCCESS', data: newPost });
} catch (error) {
console.log(error);
dispatch({ type: 'UPLOAD_FAIL' });
}
};
so on the frontend it seems like everything is updated correctly but when i close and reopen the modal the image fields are emptied again and the profile and over img are being shown as error
// PostReducer.js
this is where uploading state are being managed
const PostReducer = (
state = { posts: [], loading: false, error: false, uploading: false },
action
) => {
switch (action.type) {
// belongs to PostShare.jsx
case "UPLOAD_START":
return { ...state, error: false, uploading: true };
case "UPLOAD_SUCCESS":
return {
...state,
posts: [action.data, ...state.posts],
uploading: false,
error: false,
};
case "UPLOAD_FAIL":
return { ...state, uploading: false, error: true };
}
}
export default PostReducer;