Profile Image Added and Edit Api integration in profiePage , Vehicle Image bug fixed
This commit is contained in:
parent
570faa40d4
commit
bf8799c396
|
@ -13,7 +13,7 @@ interface EditVehicleModalProps {
|
|||
company: string,
|
||||
modelName: string,
|
||||
chargeType: string,
|
||||
imageUrl: File | null
|
||||
image: File | null
|
||||
) => void;
|
||||
editRow: any;
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ interface FormData {
|
|||
company: string;
|
||||
modelName: string;
|
||||
chargeType: string;
|
||||
imageUrl: File | null;
|
||||
image: File | null;
|
||||
}
|
||||
|
||||
const EditVehicleModal: React.FC<EditVehicleModalProps> = ({
|
||||
|
@ -44,49 +44,84 @@ const EditVehicleModal: React.FC<EditVehicleModalProps> = ({
|
|||
company: "",
|
||||
modelName: "",
|
||||
chargeType: "",
|
||||
imageUrl: null,
|
||||
image: null,
|
||||
},
|
||||
});
|
||||
|
||||
const [imagePreview, setImagePreview] = useState<string | null>(null);
|
||||
|
||||
// Set form values and image preview when editRow changes
|
||||
useEffect(() => {
|
||||
if (editRow) {
|
||||
// Set form fields
|
||||
setValue("name", editRow.name || "");
|
||||
setValue("company", editRow.company || "");
|
||||
setValue("modelName", editRow.modelName || "");
|
||||
setValue("chargeType", editRow.chargeType || "");
|
||||
const IMAGE_BASE_URL = `${process.env.REACT_APP_BACKEND_URL}`;
|
||||
useEffect(() => {
|
||||
if (open && editRow) {
|
||||
// Reset form with editRow values
|
||||
reset({
|
||||
name: editRow.name || "",
|
||||
company: editRow.company || "",
|
||||
modelName: editRow.modelName || "",
|
||||
chargeType: editRow.chargeType || "",
|
||||
image: editRow.image, // Always start with null for the form's image field
|
||||
});
|
||||
|
||||
// Set image preview for existing image
|
||||
if (editRow?.imageUrl) {
|
||||
const imageUrl =
|
||||
editRow.imageUrl.startsWith("http") ||
|
||||
editRow.imageUrl.startsWith("blob")
|
||||
? editRow.imageUrl
|
||||
: `${process.env.REACT_APP_BACKEND_URL}/image/${editRow.imageUrl}`;
|
||||
|
||||
setImagePreview(imageUrl);
|
||||
} else {
|
||||
setImagePreview(null);
|
||||
}
|
||||
// Set image preview for existing image
|
||||
if (editRow.image) {
|
||||
const image = editRow.image.startsWith("http")
|
||||
? editRow.image
|
||||
: `${process.env.REACT_APP_BACKEND_URL}/image/${editRow.image}`;
|
||||
setImagePreview(image);
|
||||
} else {
|
||||
// Reset form and preview when no editRow
|
||||
reset();
|
||||
setImagePreview(null);
|
||||
}
|
||||
}, [editRow, setValue, reset]);
|
||||
} else {
|
||||
reset();
|
||||
setImagePreview(null);
|
||||
}
|
||||
}, [open, editRow, reset]);
|
||||
// useEffect(() => {
|
||||
// if (editRow) {
|
||||
// // Set form fields
|
||||
// setValue("name", editRow.name || "");
|
||||
// setValue("company", editRow.company || "");
|
||||
// setValue("modelName", editRow.modelName || "");
|
||||
// setValue("chargeType", editRow.chargeType || "");
|
||||
|
||||
// // Set image preview for existing image
|
||||
// if (editRow?.image) {
|
||||
// const image =
|
||||
// editRow.image.startsWith("http") ||
|
||||
// editRow.image.startsWith("blob")
|
||||
// ? editRow.image
|
||||
// : `${process.env.REACT_APP_BACKEND_URL}/image/${editRow.image}`;
|
||||
|
||||
// setImagePreview(image);
|
||||
// } else {
|
||||
// setImagePreview(null);
|
||||
// }
|
||||
// } else {
|
||||
// // Reset form and preview when no editRow
|
||||
// reset();
|
||||
// setImagePreview(null);
|
||||
// }
|
||||
// }, [editRow, setValue, reset]);
|
||||
|
||||
// Handle image upload
|
||||
const handleImageChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const file = e.target.files?.[0];
|
||||
if (file) {
|
||||
setImagePreview(URL.createObjectURL(file)); // Show preview of new image
|
||||
setValue("imageUrl", file); // Update form with new file
|
||||
// const handleImageChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
// const file = e.target.files?.[0];
|
||||
// if (file) {
|
||||
// setImagePreview(URL.createObjectURL(file)); // Show preview of new image
|
||||
// setValue("image", file); // Update form with new file
|
||||
// }
|
||||
// };
|
||||
const handleImageChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const file = e.target.files?.[0];
|
||||
if (file) {
|
||||
if (imagePreview?.startsWith("blob:")) {
|
||||
URL.revokeObjectURL(imagePreview);
|
||||
}
|
||||
};
|
||||
|
||||
const image = URL.createObjectURL(file);
|
||||
setImagePreview(image);
|
||||
setValue("image", file);
|
||||
}
|
||||
};
|
||||
// Handle form submission
|
||||
const onSubmit = (data: FormData) => {
|
||||
handleUpdate(
|
||||
|
@ -95,7 +130,7 @@ const EditVehicleModal: React.FC<EditVehicleModalProps> = ({
|
|||
data.company,
|
||||
data.modelName,
|
||||
data.chargeType,
|
||||
data.imageUrl // Pass File | null to handleUpdate
|
||||
data.image // Pass File | null to handleUpdate
|
||||
);
|
||||
|
||||
handleClose();
|
||||
|
@ -382,11 +417,7 @@ const EditVehicleModal: React.FC<EditVehicleModalProps> = ({
|
|||
color="#000000"
|
||||
fontSize={"16px"}
|
||||
>
|
||||
Preview (
|
||||
{imagePreview.startsWith("blob")
|
||||
? "New"
|
||||
: "Existing"}
|
||||
):
|
||||
Preview
|
||||
</Typography>
|
||||
<img
|
||||
src={imagePreview}
|
||||
|
|
|
@ -27,7 +27,16 @@ export default function Header() {
|
|||
// Use a ref to make the full click area act as anchor
|
||||
const menuAnchorRef = useRef<HTMLDivElement | null>(null);
|
||||
const [menuOpen, setMenuOpen] = useState(false);
|
||||
|
||||
const IMAGE_BASE_URL = `${process.env.REACT_APP_BACKEND_URL}`;
|
||||
|
||||
const displayUser = React.useMemo(
|
||||
() => ({
|
||||
profilePhoto: user?.profilePhoto
|
||||
? `${IMAGE_BASE_URL}/image/${user.profilePhoto}`
|
||||
: "/avatar.png",
|
||||
}),
|
||||
[user]
|
||||
);
|
||||
const handleClick = () => {
|
||||
setMenuOpen((prev) => !prev);
|
||||
};
|
||||
|
@ -102,7 +111,7 @@ export default function Header() {
|
|||
}}
|
||||
/>
|
||||
</Box> */}
|
||||
|
||||
|
||||
{/* Notification and Profile Section */}
|
||||
<Stack
|
||||
direction="row"
|
||||
|
@ -130,7 +139,7 @@ export default function Header() {
|
|||
{/* Avatar */}
|
||||
<Avatar
|
||||
alt="User Avatar"
|
||||
src="/avatar.png"
|
||||
src={displayUser?.profilePhoto}
|
||||
sx={{ width: 36, height: 36 }}
|
||||
/>
|
||||
|
||||
|
|
|
@ -13,8 +13,8 @@ interface EditProfileModalProps {
|
|||
handleUpdate: (
|
||||
name: string,
|
||||
phone: string,
|
||||
bio?: string,
|
||||
profilePhoto?: string | null
|
||||
bio: string,
|
||||
profilePhoto?: File | string | null
|
||||
) => void;
|
||||
editUser: any;
|
||||
}
|
||||
|
@ -22,11 +22,10 @@ interface EditProfileModalProps {
|
|||
interface FormData {
|
||||
name: string;
|
||||
phone: string;
|
||||
bio?: string;
|
||||
profilePhoto?: string | null;
|
||||
bio: string;
|
||||
profilePhoto?: File | string | null;
|
||||
}
|
||||
|
||||
|
||||
const EditProfileModal: React.FC<EditProfileModalProps> = ({
|
||||
open,
|
||||
handleClose,
|
||||
|
@ -42,34 +41,47 @@ const EditProfileModal: React.FC<EditProfileModalProps> = ({
|
|||
} = useForm<FormData>();
|
||||
|
||||
const [imagePreview, setImagePreview] = useState<string | null>(null);
|
||||
|
||||
const IMAGE_BASE_URL = `${process.env.REACT_APP_BACKEND_URL}`;
|
||||
useEffect(() => {
|
||||
if (editUser) {
|
||||
setValue("name", editUser.name || "");
|
||||
setValue("phone", editUser.phone || "");
|
||||
setValue("bio", editUser.bio || "");
|
||||
setImagePreview(editUser.profilePhoto || null);
|
||||
if (open && editUser) {
|
||||
reset({
|
||||
name: editUser.name || "",
|
||||
phone: editUser.phone || "",
|
||||
bio: editUser.bio || "",
|
||||
profilePhoto: editUser.profilePhoto || null,
|
||||
});
|
||||
|
||||
if (editUser.profilePhoto) {
|
||||
setImagePreview(
|
||||
`${IMAGE_BASE_URL}/image/${editUser.profilePhoto}`
|
||||
);
|
||||
} else {
|
||||
setImagePreview(null);
|
||||
}
|
||||
}
|
||||
}, [editUser, setValue]);
|
||||
}, [open, editUser, reset, IMAGE_BASE_URL]);
|
||||
|
||||
const handleImageChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const file = e.target.files?.[0];
|
||||
if (file) {
|
||||
if (imagePreview?.startsWith("blob:")) {
|
||||
URL.revokeObjectURL(imagePreview);
|
||||
}
|
||||
const imageUrl = URL.createObjectURL(file);
|
||||
setImagePreview(imageUrl);
|
||||
setValue("profilePhoto", imageUrl);
|
||||
setValue("profilePhoto", file);
|
||||
}
|
||||
};
|
||||
|
||||
const handleModalClose = () => {
|
||||
handleClose();
|
||||
|
||||
setImagePreview(null);
|
||||
reset(); // Reset form
|
||||
};
|
||||
|
||||
const onSubmit = (data: FormData) => {
|
||||
console.log("Form Data:-----", data);
|
||||
handleUpdate(data.name, data.phone, data.bio, data.profilePhoto);
|
||||
reset();
|
||||
handleUpdate(data.name, data.phone, data.bio, data.profilePhoto);
|
||||
handleModalClose();
|
||||
};
|
||||
|
||||
|
|
|
@ -146,14 +146,14 @@ export default function VehicleViewModal({ open, setViewModal, id }: Props) {
|
|||
>
|
||||
<strong>Image:</strong>
|
||||
</Typography>
|
||||
{selectedVehicle.imageUrl ? (
|
||||
{selectedVehicle.image ? (
|
||||
<img
|
||||
src={
|
||||
selectedVehicle.imageUrl.startsWith(
|
||||
selectedVehicle.image.startsWith(
|
||||
"http"
|
||||
)
|
||||
? selectedVehicle.imageUrl
|
||||
: `${process.env.REACT_APP_BACKEND_URL}/image/${selectedVehicle.imageUrl}`
|
||||
? selectedVehicle.image
|
||||
: `${process.env.REACT_APP_BACKEND_URL}/image/${selectedVehicle.image}`
|
||||
}
|
||||
alt="Vehicle"
|
||||
style={{
|
||||
|
|
|
@ -45,26 +45,29 @@ const ProfilePage = () => {
|
|||
const handleUpdate = (
|
||||
name: string,
|
||||
phone: string,
|
||||
bio?: string,
|
||||
profilePhoto?: string | null
|
||||
bio: string,
|
||||
profilePhoto: File|string | null
|
||||
) => {
|
||||
console.log("Dispatching updateProfile...");
|
||||
console.log("Dispatching updateProfile...",profilePhoto);
|
||||
dispatch(updateProfile({ name, phone, bio, profilePhoto }));
|
||||
};
|
||||
|
||||
const IMAGE_BASE_URL = `${process.env.REACT_APP_BACKEND_URL}`;
|
||||
|
||||
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
|
||||
? `${IMAGE_BASE_URL}/image/${user.profilePhoto}`
|
||||
: "/avatar.png",
|
||||
}),
|
||||
[user]
|
||||
);
|
||||
|
||||
// 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) {
|
||||
|
|
|
@ -29,7 +29,6 @@ export default function VehicleList() {
|
|||
dispatch(vehicleList());
|
||||
}, [dispatch]);
|
||||
|
||||
console.log("Backend URL:", process.env.REACT_APP_BACKEND_URL);
|
||||
|
||||
const handleClickOpen = () => {
|
||||
setRowData(null);
|
||||
|
@ -48,7 +47,7 @@ export default function VehicleList() {
|
|||
company: string;
|
||||
modelName: string;
|
||||
chargeType: string;
|
||||
imageFile: File;
|
||||
imageFile: File ;
|
||||
}) => {
|
||||
try {
|
||||
setIsAdding(true);
|
||||
|
@ -70,7 +69,7 @@ const handleUpdate = (
|
|||
company: string,
|
||||
modelName: string,
|
||||
chargeType: string,
|
||||
imageUrl: File | null
|
||||
image: File | null
|
||||
) => {
|
||||
dispatch(
|
||||
updateVehicle({
|
||||
|
@ -79,7 +78,7 @@ const handleUpdate = (
|
|||
company,
|
||||
modelName,
|
||||
chargeType,
|
||||
imageUrl, // File or null
|
||||
image, // File or null
|
||||
})
|
||||
);
|
||||
};
|
||||
|
@ -87,7 +86,7 @@ const handleUpdate = (
|
|||
|
||||
const categoryColumns: Column[] = [
|
||||
{ id: "srno", label: "Sr No" },
|
||||
{ id: "imageUrl", label: "Image" },
|
||||
{ id: "image", label: "Image" },
|
||||
{ id: "name", label: "Vehicle Name" },
|
||||
{ id: "company", label: "Company" },
|
||||
{ id: "modelName", label: "Model Name" },
|
||||
|
@ -96,40 +95,37 @@ const handleUpdate = (
|
|||
{ id: "action", label: "Action", align: "center" },
|
||||
];
|
||||
|
||||
const categoryRows = vehicles?.length
|
||||
? vehicles?.map(
|
||||
(
|
||||
vehicle: {
|
||||
id: number;
|
||||
name: string;
|
||||
company: string;
|
||||
modelName: string;
|
||||
chargeType: string;
|
||||
imageUrl: string;
|
||||
},
|
||||
index: number
|
||||
) => {
|
||||
const imageUrl = vehicle?.imageUrl
|
||||
? `${process.env.REACT_APP_BACKEND_URL}/image/${vehicle?.imageUrl}`
|
||||
: "/images/fallback.jpg";
|
||||
console.log(
|
||||
"Vehicle:",
|
||||
vehicle.name,
|
||||
"Image URL:",
|
||||
imageUrl
|
||||
);
|
||||
return {
|
||||
id: vehicle?.id,
|
||||
srno: index + 1,
|
||||
name: vehicle?.name,
|
||||
company: vehicle?.company,
|
||||
modelName: vehicle?.modelName,
|
||||
chargeType: vehicle?.chargeType,
|
||||
imageUrl,
|
||||
};
|
||||
}
|
||||
)
|
||||
: [];
|
||||
const categoryRows = vehicles?.length
|
||||
? vehicles.map(
|
||||
(
|
||||
vehicle: {
|
||||
id: number;
|
||||
name: string;
|
||||
company: string;
|
||||
modelName: string;
|
||||
chargeType: string;
|
||||
image: string ;
|
||||
},
|
||||
index: number
|
||||
) => {
|
||||
const image = vehicle?.image
|
||||
? typeof vehicle.image === "string" &&
|
||||
vehicle.image.startsWith("http")
|
||||
? vehicle.image
|
||||
: `${process.env.REACT_APP_BACKEND_URL}/image/${vehicle.image}`
|
||||
: "/images/fallback.jpg"; // Fallback image
|
||||
return {
|
||||
id: vehicle.id,
|
||||
srno: index + 1,
|
||||
name: vehicle.name,
|
||||
company: vehicle.company,
|
||||
modelName: vehicle.modelName,
|
||||
chargeType: vehicle.chargeType,
|
||||
image,
|
||||
};
|
||||
}
|
||||
)
|
||||
: [];
|
||||
|
||||
return (
|
||||
<>
|
||||
|
|
|
@ -15,7 +15,7 @@ interface Vehicle {
|
|||
company: string;
|
||||
modelName: string;
|
||||
chargeType: string;
|
||||
imageUrl: string;
|
||||
image: string;
|
||||
}
|
||||
|
||||
interface VehicleState {
|
||||
|
@ -120,13 +120,13 @@ export const updateVehicle = createAsyncThunk<
|
|||
company: string;
|
||||
modelName: string;
|
||||
chargeType: string;
|
||||
imageUrl: File | string | null;
|
||||
image: File | string | null;
|
||||
},
|
||||
{ rejectValue: string }
|
||||
>(
|
||||
"updateVehicle",
|
||||
async (
|
||||
{ id, name, company, modelName, chargeType, imageUrl },
|
||||
{ id, name, company, modelName, chargeType, image },
|
||||
{ rejectWithValue }
|
||||
) => {
|
||||
try {
|
||||
|
@ -136,8 +136,8 @@ export const updateVehicle = createAsyncThunk<
|
|||
formData.append("modelName", modelName);
|
||||
formData.append("chargeType", chargeType);
|
||||
|
||||
if (imageUrl instanceof File) {
|
||||
formData.append("image", imageUrl); // Append new file
|
||||
if (image instanceof File) {
|
||||
formData.append("image", image); // Append new file
|
||||
}
|
||||
|
||||
const response = await http.patch(
|
||||
|
|
|
@ -10,7 +10,7 @@ interface User {
|
|||
email: string;
|
||||
userType: string;
|
||||
phone: string;
|
||||
bio?: string;
|
||||
bio: string;
|
||||
profilePhoto?: string;
|
||||
}
|
||||
|
||||
|
@ -53,29 +53,40 @@ export const fetchAdminProfile = createAsyncThunk<
|
|||
});
|
||||
|
||||
export const updateProfile = createAsyncThunk<
|
||||
User,
|
||||
User,
|
||||
{
|
||||
name: string;
|
||||
phone?: string;
|
||||
bio?: string;
|
||||
profilePhoto?: string | null;
|
||||
phone: string;
|
||||
bio: string;
|
||||
profilePhoto?: File | 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);
|
||||
// Create form data
|
||||
const formData = new FormData();
|
||||
formData.append("name", name);
|
||||
formData.append("phone", phone);
|
||||
formData.append("bio", bio);
|
||||
|
||||
if (profilePhoto instanceof File) {
|
||||
formData.append("profilePhoto", profilePhoto); // ✅ File
|
||||
}
|
||||
|
||||
// Make the request with the form data
|
||||
const response = await http.put("/edit-profile", formData, {
|
||||
headers: {
|
||||
"Content-Type": "multipart/form-data",
|
||||
},
|
||||
});
|
||||
|
||||
// Handle success
|
||||
toast.success("Profile updated successfully");
|
||||
return response.data.data;
|
||||
} catch (error: any) {
|
||||
// Handle error
|
||||
toast.error("Error updating the profile: " + error.message);
|
||||
return rejectWithValue(
|
||||
error?.response?.data?.message || "An error occurred"
|
||||
|
@ -84,7 +95,6 @@ export const updateProfile = createAsyncThunk<
|
|||
}
|
||||
);
|
||||
|
||||
|
||||
const profileSlice = createSlice({
|
||||
name: "profile",
|
||||
initialState,
|
||||
|
|
Loading…
Reference in a new issue