diff --git a/src/components/EditVehicleModal/editVehicleModal.tsx b/src/components/EditVehicleModal/editVehicleModal.tsx index 09ddc30..131a7b6 100644 --- a/src/components/EditVehicleModal/editVehicleModal.tsx +++ b/src/components/EditVehicleModal/editVehicleModal.tsx @@ -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 = ({ @@ -44,49 +44,84 @@ const EditVehicleModal: React.FC = ({ company: "", modelName: "", chargeType: "", - imageUrl: null, + image: null, }, }); const [imagePreview, setImagePreview] = useState(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) => { - 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) => { + // 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) => { + 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 = ({ 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 = ({ color="#000000" fontSize={"16px"} > - Preview ( - {imagePreview.startsWith("blob") - ? "New" - : "Existing"} - ): + Preview (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() { }} /> */} - + {/* Notification and Profile Section */} diff --git a/src/components/Modals/EditProfileModal/editProfileModal.tsx b/src/components/Modals/EditProfileModal/editProfileModal.tsx index 09ab9c7..c1d8a77 100644 --- a/src/components/Modals/EditProfileModal/editProfileModal.tsx +++ b/src/components/Modals/EditProfileModal/editProfileModal.tsx @@ -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 = ({ open, handleClose, @@ -42,34 +41,47 @@ const EditProfileModal: React.FC = ({ } = useForm(); const [imagePreview, setImagePreview] = useState(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) => { 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(); }; diff --git a/src/components/Modals/VehicleViewModal/index.tsx b/src/components/Modals/VehicleViewModal/index.tsx index 8204e5a..f47051e 100644 --- a/src/components/Modals/VehicleViewModal/index.tsx +++ b/src/components/Modals/VehicleViewModal/index.tsx @@ -146,14 +146,14 @@ export default function VehicleViewModal({ open, setViewModal, id }: Props) { > Image: - {selectedVehicle.imageUrl ? ( + {selectedVehicle.image ? ( Vehicle { 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) { diff --git a/src/pages/VehicleList/index.tsx b/src/pages/VehicleList/index.tsx index f175d7e..f9a9966 100644 --- a/src/pages/VehicleList/index.tsx +++ b/src/pages/VehicleList/index.tsx @@ -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 ( <> diff --git a/src/redux/slices/VehicleSlice.ts b/src/redux/slices/VehicleSlice.ts index 2b645da..25d1e43 100644 --- a/src/redux/slices/VehicleSlice.ts +++ b/src/redux/slices/VehicleSlice.ts @@ -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( diff --git a/src/redux/slices/profileSlice.ts b/src/redux/slices/profileSlice.ts index a2fe6ca..2e2d479 100644 --- a/src/redux/slices/profileSlice.ts +++ b/src/redux/slices/profileSlice.ts @@ -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,