diff --git a/backend/pms/src/main/resources/data.sql b/backend/pms/src/main/resources/data.sql
index b2714e2..e17e333 100644
--- a/backend/pms/src/main/resources/data.sql
+++ b/backend/pms/src/main/resources/data.sql
@@ -87,7 +87,7 @@ VALUES (
'House for Sell in Iowa',
'RENT',
'2024-02-07 00:29:48.576972',
- 3
+ 2
),
(
'Land',
@@ -106,7 +106,7 @@ VALUES (
'Great Building Site Right off Hwy 34',
'RENT',
'2024-02-07 00:44:43.55343',
- 3
+ 2
),
(
'House',
@@ -123,7 +123,7 @@ VALUES (
'1,000',
'RENT',
'2024-02-07 01:04:03.030894',
- 3
+ 2
);
diff --git a/frontend/src/components/Property.js b/frontend/src/components/Property.js
index ede1599..56c1828 100644
--- a/frontend/src/components/Property.js
+++ b/frontend/src/components/Property.js
@@ -4,6 +4,7 @@ import { MdFavoriteBorder, MdOutlineFavorite } from "react-icons/md";
import { Link } from "react-router-dom";
import { formatMoney } from "../utils/money";
import { api } from "../libs/api";
+import { FiEdit2, FiEye } from "react-icons/fi";
const Property = ({
price,
numberOfRoom,
@@ -15,21 +16,23 @@ const Property = ({
favorite,
refetch,
viewOffer,
+ updateProperty,
+ unFav,
}) => {
const addFavorite = async (id) => {
api.post(`favorites/${id}`).then((res) => {
- console.log(res);
+ refetch();
setIsFav(true);
});
};
const removeFavorite = (id) => {
api.delete(`favorites/${id}`).then((res) => {
- console.log(res);
+ refetch();
setIsFav(false);
});
};
- const [isFav, setIsFav] = useState(favorite);
+ const [isFav, setIsFav] = useState(favorite || unFav);
return (
@@ -40,41 +43,48 @@ const Property = ({
Location: {location}
-
-
- Rooms: {numberOfRoom}
- {offerStatus}
+ Rooms: {numberOfRoom}
+
+ {offerStatus}
+
-
-
-
- {
- viewOffer && (
+
- )
- }
+ {updateProperty && (
+
+
+
+
+ )}
+ {viewOffer && (
+
+ )}
+
+
diff --git a/frontend/src/pages/Favorite.js b/frontend/src/pages/Favorite.js
index ba97031..6b7ee49 100644
--- a/frontend/src/pages/Favorite.js
+++ b/frontend/src/pages/Favorite.js
@@ -15,7 +15,7 @@ const Favorite = () => {
{data.map((property) => {
return (
-
+
)
})}
diff --git a/frontend/src/pages/MyProperty.js b/frontend/src/pages/MyProperty.js
index f866661..0cdeecb 100644
--- a/frontend/src/pages/MyProperty.js
+++ b/frontend/src/pages/MyProperty.js
@@ -41,6 +41,7 @@ const MyProperty = () => {
{...property}
refetch={refetch}
viewOffer={handleViewOffer}
+ updateProperty={true}
/>
);
diff --git a/frontend/src/pages/PropertyDetail.js b/frontend/src/pages/PropertyDetail.js
index e321c3c..41c73e1 100644
--- a/frontend/src/pages/PropertyDetail.js
+++ b/frontend/src/pages/PropertyDetail.js
@@ -23,9 +23,7 @@ import { api } from "../libs/api";
const PropertyDetail = () => {
const { id } = useParams();
- const { user } = useSelector((state) => state.auth);
- const isOwner = user?.roles.map((role) => role.role).includes("Owner");
- console.log(isOwner);
+
const { data, isLoading, isError } = useQuery(`properties/${id}`);
const navigate = useNavigate();
const [show, setShow] = React.useState(false);
@@ -86,33 +84,27 @@ const PropertyDetail = () => {
{formatMoney(data.price)}
{data.location}
Rooms: {data.numberOfRoom}
- Status :{data.offerStatus}
-
-
- {
- isOwner ? (
-
-
-
- ): (
-
- )
+ Status :
+
+ {data.offerStatus}
+
+
+
diff --git a/frontend/src/pages/UpdateProperty.js b/frontend/src/pages/UpdateProperty.js
index a3f3043..bef237e 100644
--- a/frontend/src/pages/UpdateProperty.js
+++ b/frontend/src/pages/UpdateProperty.js
@@ -1,416 +1,426 @@
-import { zodResolver } from "@hookform/resolvers/zod";
-import React, { useEffect, useRef } from "react";
+import React, { useCallback, useEffect, useMemo, useState } from "react";
import {
- Button,
- Card,
- Col,
- Form,
- Image,
- InputGroup,
- Row,
+ Button,
+ Form,
+ Row,
+ Col,
+ Image,
+ Nav,
+ Card,
+ InputGroup,
} from "react-bootstrap";
import { useForm } from "react-hook-form";
import { z } from "zod";
-import {
- CATEGORY,
- HOUSE_TYPES,
- Map,
- handleChangePropertyType,
-} from "./AddProperty";
+import { zodResolver } from "@hookform/resolvers/zod";
import { useSelector } from "react-redux";
-import { useMutation } from "react-query";
-import { api } from "../libs/api";
-import { useLocation, useNavigate } from "react-router-dom";
import { apiBaseUrl } from "../libs/constants";
+import { api } from "../libs/api";
+import { useMutation, useQuery } from "react-query";
+import { MapContainer, TileLayer, Marker, Popup } from "react-leaflet";
+import { getCurrLocation, icon, iconURL } from "../utils/map";
+import { FaLocationDot } from "react-icons/fa6";
+import { useNavigate, useParams } from "react-router-dom";
+import Loading from "../components/Loading";
-function UpdateProperty() {
- const [propertyType, setPropertyType] = React.useState(HOUSE_TYPES);
- const { accessToken } = useSelector((state) => state.auth);
- const [images, setImages] = React.useState({});
- const [existingImages, setExistingImages] = React.useState({});
- const [imageKeys, setImageKeys] = React.useState([]);
- const [latLong, setLatLong] = React.useState(0);
- const location = useLocation();
- const id = 1;
- const navigate = useNavigate();
+export const CATEGORY = ["House", "Apartment", "Condo", "Land"];
+export const LAND_TYPES = ["Residential", "Commercial", "Agricultural"];
+export const HOUSE_TYPES = ["Single Family", "Multi Family", "Townhouse"];
+export const APARTMENT_TYPES = ["Studio", "Loft", "Duplex"];
+export const CONDO_TYPES = ["High Rise", "Low Rise", "Mid Rise"];
+export const handleChangePropertyType = (type, setPropertyType) => {
+ switch (type) {
+ case "House":
+ setPropertyType(HOUSE_TYPES);
+ break;
+ case "Apartment":
+ setPropertyType(APARTMENT_TYPES);
+ break;
+ case "Condo":
+ setPropertyType(CONDO_TYPES);
+ break;
+ case "Land":
+ setPropertyType(LAND_TYPES);
+ break;
+ default:
+ setPropertyType(HOUSE_TYPES);
+ break;
+ }
+};
- const PropertySchema = z.object({
- type: z.string(),
- title: z.string().min(3).max(150),
- price: z.string().nullable(),
- description: z.string().min(3).max(255),
- location: z.string().min(3).max(255),
- category: z.string().min(3).max(255),
- subCategory: z.string().min(3).max(200),
- numberOfRoom: z.string().nullable(),
- });
+const UpdateProperty = () => {
+ const [propertyType, setPropertyType] = React.useState(HOUSE_TYPES);
+ const { accessToken } = useSelector((state) => state.auth);
+ const [images, setImages] = React.useState({});
+ const [imageKeys, setImageKeys] = React.useState([]);
+ const [latLong, setLatLong] = React.useState([0, 0]);
+ const navigate = useNavigate();
+ const { id } = useParams();
- const {
- register,
- handleSubmit,
- formState: { errors },
- watch,
- } = useForm({
- resolver: zodResolver(PropertySchema),
- defaultValues: { type: "RENT" },
- });
+ const PropertySchema = z.object({
+ type: z.string(),
+ title: z.string().min(3).max(150),
+ price: z.string().nullable(),
+ description: z.string().min(3).max(255),
+ location: z.string().min(3).max(255),
+ category: z.string().min(3).max(255),
+ subCategory: z.string().min(3).max(200),
+ numberOfRoom: z.string().nullable(),
+ });
- const onSubmit = (data) => {
- data.pictures = imageKeys;
- data.latitude = latLong.lat || 0;
- data.longitude = latLong.lng || 0;
- propertyMutation.mutate(data);
- };
+ const {
+ register,
+ handleSubmit,
+ formState: { errors },
+ watch,
+ setValue,
+ } = useForm({
+ resolver: zodResolver(PropertySchema),
+ defaultValues: { type: "RENT" },
+ });
+ const { data, isLoading } = useQuery(`properties/${id}`);
- const type = watch("type");
- const category = watch("category");
- const handleRemoveImage = (index) => {
- setImages((prev) => {
- const temp = { ...prev };
- delete temp[index];
- return temp;
+ useEffect(() => {
+ if (data) {
+ setValue("type", data.type);
+ setValue("title", data.title);
+ setValue("price", data.price);
+ setValue("description", data.description);
+ setValue("location", data.location);
+ setValue("category", data.category);
+ setValue("subCategory", data.subCategory);
+ setValue("numberOfRoom", data.numberOfRoom);
+ setLatLong([data.latitude, data.longitude]);
+
+ setImageKeys(imageUrlToKey(data.pictures));
+ setImages(data.pictures);
+ }
+ }, [data]);
+
+ const imageUrlToKey = (images = []) => {
+ return images.map((img) => img.split("/")[6]);
+ };
+
+ const propertyMutation = useMutation((data) => {
+ api
+ .put(`properties/${id}`, data)
+ .then((res) => {
+ navigate(`/my-properties`, {
+ state: { message: "Property updated successfully" },
});
- };
+ })
+ .catch((error) => {
+ console.log(error);
+ });
+ });
- const propertyMutation = useMutation((data) => {
- api.put("properties/" + id, data)
- .then((res) => {
- navigate("/my-properties", {
- state: { message: "Property added successfully" },
- });
- })
- .catch((error) => {
- console.log(error);
- });
+ const onSubmit = (data) => {
+ data.pictures = imageKeys;
+ data.latitude = latLong.lat || 0;
+ data.longitude = latLong.lng || 0;
+ propertyMutation.mutate(data);
+ };
+ const type = watch("type");
+ const category = watch("category");
+ const handleRemoveImage = (index) => {
+ setImages((prev) => {
+ const temp = { ...prev };
+ delete temp[index];
+ return temp;
});
+ };
- const [property, setProperty] = React.useState({});
- const propertyFetch = () => {
- api.get("properties/" + id)
- .then((res) => {
- console.log(res.data);
- setProperty(res.data);
- handleChangePropertyType(res.data.type, setPropertyType);
- // alert('ddd', res.data.latitude)
- setLatLong({ lat: res.data.latitude, lng: res.data.longitude });
- // setExistingImages(res.data.pictures)
- setImages(res.data.pictures.map((p) => p));
- })
- .catch((error) => {
- console.log(error);
- });
- };
-
- useEffect(() => {
- propertyFetch();
- }, []);
- const propertyForm = useRef(property);
+ const handleUploadImage = (files) => {
+ setImages((prev) => {
+ const temp = { ...prev };
+ for (let i = 0; i < files.length; i++) {
+ temp[i] = files[i];
+ }
+ return temp;
+ });
- const handleChangeProperty = (e) => {
- const { name, value } = e.target;
- setProperty({ ...property, [name]: value });
- };
+ for (let i = 0; i < files.length; i++) {
+ const formData = new FormData();
+ formData.append("file", files[i]);
- const handleUploadImage = (files) => {
- setImages((prev) => {
+ fetch(apiBaseUrl + "files/upload", {
+ method: "POST",
+ body: formData,
+ headers: {
+ Authorization: `Bearer ${accessToken}`,
+ },
+ })
+ .then((response) => response.json())
+ .then((result) => {
+ setImageKeys((prev) => {
+ return [...prev, result.key];
+ });
+ setImages((prev) => {
const temp = { ...prev };
- for (let i = 0; i < files.length; i++) {
- temp[i + images.length] = files[i];
- }
+ temp[i] = result;
return temp;
+ });
+ })
+ .catch((error) => {
+ console.error("Error:", error);
});
+ }
+ };
- for (let i = 0; i < files.length; i++) {
- const formData = new FormData();
- formData.append("file", files[i]);
+ useEffect(() => {
+ const geo = getCurrLocation();
+ console.log(geo);
+ }, []);
- fetch(apiBaseUrl + "files/upload", {
- method: "POST",
- body: formData,
- headers: {
- Authorization: `Bearer ${accessToken}`,
- },
- })
- .then((response) => response.json())
- .then((result) => {
- setImageKeys((prev) => {
- return [...prev, result.key];
- });
- })
- .catch((error) => {
- console.error("Error:", error);
- });
- }
- };
+ const imageArr = Object.keys(images).map((key) => images[key]);
- const imageArr = Object.keys(images).map((key) => images[key]);
+ if (isLoading) ;
- return (
-
-
-
- Update Property
-
-
-
+
+
+
+ );
+};
export default UpdateProperty;
+
+export const Map = ({ set, center = defaultCenter }) => {
+ const [map, setMap] = useState(null);
+ const [latLong, setLatLong] = useState(null);
+
+ useEffect(() => {
+ set(latLong);
+ }, [latLong]);
+
+ const displayMap = useMemo(
+ () => (
+
+ ),
+ []
+ );
+
+ return (
+
+ {map ? : null}
+ {displayMap}
+
+ );
+};
+
+const defaultCenter = [41.023248, -91.966827];
+const zoom = 15;
+
+function DisplayPosition({ map, setLatLong }) {
+ const [position, setPosition] = useState(() => map.getCenter());
+
+ const onClick = useCallback(() => {
+ map.setView(defaultCenter, zoom);
+ }, [map]);
+
+ const onMove = useCallback(() => {
+ setPosition(map.getCenter());
+ setLatLong(map.getCenter());
+ }, [map]);
+
+ useEffect(() => {
+ map.on("move", onMove);
+ return () => {
+ map.off("move", onMove);
+ };
+ }, [map, onMove]);
+
+ return (
+
+ latitude: {position.lat.toFixed(4)}, longitude: {position.lng.toFixed(4)}{" "}
+
+
+ );
+}
diff --git a/frontend/src/routes/Router.js b/frontend/src/routes/Router.js
index 048b768..50a79e9 100644
--- a/frontend/src/routes/Router.js
+++ b/frontend/src/routes/Router.js
@@ -30,7 +30,7 @@ const Router = () => {
} />
} />
} />
- } />
+ } />
} />
} />
} />