This commit is contained in:
omkieit 2024-10-30 19:40:14 +05:30
parent 9ab07ddfc0
commit e66b5fc26d
10 changed files with 489 additions and 30 deletions

View File

@ -53,7 +53,6 @@ export const getUserProperties = async (req, res) => {
.limit(Number(limit)); .limit(Number(limit));
const total = await PropertyModal.countDocuments({ userId }); const total = await PropertyModal.countDocuments({ userId });
const totalPages = Math.ceil(total / limit); const totalPages = Math.ceil(total / limit);
res.json({ res.json({
properties, properties,
totalPages, totalPages,
@ -65,6 +64,16 @@ export const getUserProperties = async (req, res) => {
}; };
// Fetch property by ID.. which is property view page // Fetch property by ID.. which is property view page
export const getPropertyById = async (req, res) => { export const getPropertyById = async (req, res) => {
const { propertyId } = req.params; const { propertyId } = req.params;

View File

@ -14,6 +14,9 @@ import {
router.post("/", auth, createProperty); router.post("/", auth, createProperty);
router.get("/user/:userId", getUserProperties); router.get("/user/:userId", getUserProperties);
router.get("/:propertyId", getPropertyById); router.get("/:propertyId", getPropertyById);
router.put("/:id", updatePropertyById); router.put("/:id", updatePropertyById);
router.get("/", getProperties); router.get("/", getProperties);

File diff suppressed because one or more lines are too long

View File

@ -45,7 +45,7 @@
<script type="module" crossorigin src="/assets/index-E_rWKug7.js"></script> <script type="module" crossorigin src="/assets/index-CFxhPaJf.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-DUngj0jf.css"> <link rel="stylesheet" crossorigin href="/assets/index-DUngj0jf.css">
</head> </head>

View File

@ -8,6 +8,8 @@ import "../dashboard.css";
import { useSelector } from "react-redux"; import { useSelector } from "react-redux";
import UserProfile from "./UserProfile"; import UserProfile from "./UserProfile";
import { NavLink } from "react-router-dom"; import { NavLink } from "react-router-dom";
import FundingsReceived from "./FundingsReceived";
import OffersSubmitted from "./OffersSubmitted";
const Dashboard = () => { const Dashboard = () => {
const [activeTab, setActiveTab] = useState("dashboard"); const [activeTab, setActiveTab] = useState("dashboard");
@ -26,6 +28,23 @@ const Dashboard = () => {
<UserProperties /> <UserProperties />
</div> </div>
); );
case "Fundings Received":
return (
<div>
<h3>Fundings Received</h3>
<FundingsReceived />
</div>
);
case "Offers Submitted":
return (
<div>
<h3>Offers Submitted</h3>
<OffersSubmitted />
</div>
);
case "closedProperties": case "closedProperties":
return <p>These are your closed properties.</p>; return <p>These are your closed properties.</p>;
default: default:
@ -88,6 +107,29 @@ const Dashboard = () => {
<span className="fa fa-home" style={{ color: "#F74B02" }} /> <span className="fa fa-home" style={{ color: "#F74B02" }} />
<span>Active Properties</span> <span>Active Properties</span>
</button> </button>
<button
className={`btn mt-3 ${
activeTab === "Fundings Received" ? "active" : ""
}`}
onClick={() => setActiveTab("Fundings Received")}
>
<span className="fa fa-home" style={{ color: "#F74B02" }} />
<span>Fundings Received</span>
</button>
<button
className={`btn mt-3 ${
activeTab === "Offers Submitted" ? "active" : ""
}`}
onClick={() => setActiveTab("Offers Submitted")}
>
<span className="fa fa-home" style={{ color: "#F74B02" }} />
<span>Offers Submitted</span>
</button>
<button <button
className={`btn mt-3 ${ className={`btn mt-3 ${
activeTab === "closedProperties" ? "active" : "" activeTab === "closedProperties" ? "active" : ""

View File

@ -0,0 +1,199 @@
import { useEffect, useState } from "react";
import { useSelector, useDispatch } from "react-redux";
import { fetchUserProperties } from "../redux/features/propertySlice";
import { NavLink } from "react-router-dom";
import propertydummy from "../img/propertydummy.jpg";
const UserProperties = () => {
const dispatch = useDispatch();
const { user } = useSelector((state) => ({ ...state.auth }));
const { userProperties, totalPages } = useSelector((state) => state.property);
const [page, setPage] = useState(1);
const limit = 5; // Number of properties per page
// Fetch user properties when "Active Properties" tab is selected
useEffect(() => {
dispatch(fetchUserProperties({ userId: user.result.userId, page, limit }));
}, [dispatch, user?.result?.userId, page]);
// Pagination handler
const handlePageChange = (newPage) => {
setPage(newPage);
};
const fundedProperties = userProperties.filter(
(property) =>
property.fundDetails &&
property.fundDetails.some(
(fund) =>
fund.fundValue !== undefined &&
fund.fundPercentage !== undefined &&
fund.userId
)
);
// console.log("fundedProperties", fundedProperties)
return (
<>
{fundedProperties.length > 0 ? (
<>
<ul>
{fundedProperties.map((property) => (
<li key={property._id}>
<div className="container">
<div className="col-md-12">
<div className="row p-2 bg-white border rounded mt-2">
<div className="col-md-3 mt-1">
<img
src={property.images[0].file || propertydummy}
className="w-70"
alt="Img"
style={{
marginTop: "0px",
maxWidth: "200px",
maxHeight: "200px",
}}
/>
</div>
<div className="col-md-6 mt-1">
<h5>
{" "}
<NavLink
to={`/property/${property.propertyId}`}
>
{property.address}
{"....."}
</NavLink>
</h5>
<div className="d-flex flex-row"></div>
<div className="mt-1 mb-1 spec-1">
<span>100% cotton</span>
<span className="dot" />
<span>Light weight</span>
<span className="dot" />
<span>
Best finish
<br />
</span>
</div>
<div className="mt-1 mb-1 spec-1">
<span>Unique design</span>
<span className="dot" />
<span>For men</span>
<span className="dot" />
<span>
Casual
<br />
</span>
</div>
<p className="text-justify text-truncate para mb-0">
There are many variations of passages of
<br />
<br />
</p>
</div>
<div className="align-items-center align-content-center col-md-3 border-left mt-1">
{/* <div className="d-flex flex-row align-items-center">
<h4 className="mr-1">$14.99</h4>
<span className="strike-text">$20.99</span>
</div>
<h6 className="text-success">Free shipping</h6> */}
<div className="d-flex flex-column mt-4">
<NavLink
to={`/property/${property.propertyId}`}
>
<button
className="btn btn-outline-primary btn-sm mt-2"
type="button"
style={{
backgroundColor: "#fda417",
border: "#fda417",
}}
>
<span
className="fa fa-eye"
style={{ color: "#F74B02" }}
/>{" "}
{" "}
View Details
</button>
</NavLink>
<NavLink
to={`/editproperty/${property.propertyId}`}
>
<button
className="btn btn-outline-primary btn-sm mt-2"
type="button"
style={{
backgroundColor: "#fda417",
border: "#fda417",
}}
>
<span
className="fa fa-edit"
style={{ color: "#F74B02" }}
/>{" "}
{" "}
Edit Details ..
</button>
</NavLink>
</div>
</div>
</div>
</div>
</div>
</li>
))}
</ul>
{/* Pagination Controls */}
<div className="pagination">
<button
onClick={() => handlePageChange(page - 1)}
disabled={page === 1}
>
Previous
</button>
{/* Show page numbers */}
{Array.from({ length: totalPages }, (_, index) => index + 1).map(
(pageNumber) =>
pageNumber === page || // Current page
pageNumber === 1 || // First page
pageNumber === totalPages || // Last page
(pageNumber >= page - 1 && pageNumber <= page + 1) ? ( // Pages near current page
<button
key={pageNumber}
onClick={() => handlePageChange(pageNumber)}
disabled={page === pageNumber}
>
{pageNumber}
</button>
) : pageNumber === 2 || pageNumber === totalPages - 1 ? ( // Add "..." between non-adjacent pages
<span key={pageNumber}>...</span>
) : null
)}
<button
onClick={() => handlePageChange(page + 1)}
disabled={page === totalPages}
>
Next
</button>
</div>
</>
) : (
<p>No active properties found.</p>
)}
</>
);
};
export default UserProperties;

View File

@ -0,0 +1,191 @@
import { useEffect, useState } from "react";
import { useSelector, useDispatch } from "react-redux";
import { getProperties } from "../redux/features/propertySlice"; // Redux action to fetch properties
import { NavLink } from "react-router-dom";
import propertydummy from "../img/propertydummy.jpg";
const OffersSubmitted = () => {
const dispatch = useDispatch();
const { user } = useSelector((state) => ({ ...state.auth }));
// const { userProperties, totalPages } = useSelector((state) => state.property);
const { properties, totalPages } = useSelector((state) => state.property);
const [page, setPage] = useState(1);
const limit = 5; // Number of properties per page
// Fetch user properties when "Active Properties" tab is selected
useEffect(() => {
dispatch(getProperties({ page, limit }));
}, [dispatch, user?.result?.userId, page]);
// Pagination handler
const handlePageChange = (newPage) => {
setPage(newPage);
};
const OffersSubmitted = properties.filter(
(property) =>
property.fundDetails &&
property.fundDetails.some(
(fund) =>
fund.fundValue !== undefined &&
fund.fundPercentage !== undefined &&
fund.userId === user.result._id
)
);
return (
<>
{OffersSubmitted.length > 0 ? (
<>
<ul>
{OffersSubmitted.map((property) => (
<li key={property._id}>
<div className="container">
<div className="col-md-12">
<div className="row p-2 bg-white border rounded mt-2">
<div className="col-md-3 mt-1">
<img
src={property.images[0].file || propertydummy}
className="w-70"
alt="Img"
style={{
marginTop: "0px",
maxWidth: "200px",
maxHeight: "200px",
}}
/>
</div>
<div className="col-md-6 mt-1">
<h5>
{" "}
<NavLink
to={`/property/${property.propertyId}`}
target="_blank"
>
{property.address}
{"....."}
</NavLink>
</h5>
<div className="d-flex flex-row"></div>
<div className="mt-1 mb-1 spec-1">
<span>100% cotton</span>
<span className="dot" />
<span>Light weight</span>
<span className="dot" />
<span>
Best finish
<br />
</span>
</div>
<div className="mt-1 mb-1 spec-1">
<span>Unique design</span>
<span className="dot" />
<span>For men</span>
<span className="dot" />
<span>
Casual
<br />
</span>
</div>
<p className="text-justify text-truncate para mb-0">
There are many variations of passages of
<br />
<br />
</p>
</div>
<div className="align-items-center align-content-center col-md-3 border-left mt-1">
{/* <div className="d-flex flex-row align-items-center">
<h4 className="mr-1">$14.99</h4>
<span className="strike-text">$20.99</span>
</div>
<h6 className="text-success">Free shipping</h6> */}
<div className="d-flex flex-column mt-4">
<NavLink to={`/property/${property.propertyId}`}>
<button
className="btn btn-outline-primary btn-sm mt-2"
type="button"
style={{
backgroundColor: "#fda417",
border: "#fda417",
}}
>
<span
className="fa fa-eye"
style={{ color: "#F74B02" }}
/>{" "}
{" "}
View Details
</button>
</NavLink>
<NavLink to={`/editproperty/${property.propertyId}`}>
<button
className="btn btn-outline-primary btn-sm mt-2"
type="button"
style={{
backgroundColor: "#fda417",
border: "#fda417",
}}
>
<span
className="fa fa-edit"
style={{ color: "#F74B02" }}
/>{" "}
{" "}
Edit Details ..
</button>
</NavLink>
</div>
</div>
</div>
</div>
</div>
</li>
))}
</ul>
{/* Pagination Controls */}
<div className="pagination">
<button
onClick={() => handlePageChange(page - 1)}
disabled={page === 1}
>
Previous
</button>
{/* Show page numbers */}
{Array.from({ length: totalPages }, (_, index) => index + 1).map(
(pageNumber) =>
pageNumber === page || // Current page
pageNumber === 1 || // First page
pageNumber === totalPages || // Last page
(pageNumber >= page - 1 && pageNumber <= page + 1) ? ( // Pages near current page
<button
key={pageNumber}
onClick={() => handlePageChange(pageNumber)}
disabled={page === pageNumber}
>
{pageNumber}
</button>
) : pageNumber === 2 || pageNumber === totalPages - 1 ? ( // Add "..." between non-adjacent pages
<span key={pageNumber}>...</span>
) : null
)}
<button
onClick={() => handlePageChange(page + 1)}
disabled={page === totalPages}
>
Next
</button>
</div>
</>
) : (
<p>No active properties found.</p>
)}
</>
);
};
export default OffersSubmitted;

View File

@ -297,7 +297,8 @@ const PropertyView = () => {
</label> </label>
</h4> </h4>
<hr /> <hr />
<p className="product-path">
<span className="product-path">
<span <span
style={{ color: "#fda417", fontSize: "15px" }} style={{ color: "#fda417", fontSize: "15px" }}
> >
@ -328,7 +329,9 @@ const PropertyView = () => {
</span>{" "} </span>{" "}
{selectedProperty.zip} {selectedProperty.zip}
{" "} {" "}
</p> </span>
<br /> <br />
<div> <div>
<span <span
className="selling-price" className="selling-price"
@ -339,7 +342,7 @@ const PropertyView = () => {
{selectedProperty.totallivingsqft} {selectedProperty.totallivingsqft}
<p></p> <p></p>
<span <span
className="" className="selling-price"
style={{ color: "#fda417", fontSize: "15px" }} style={{ color: "#fda417", fontSize: "15px" }}
> >
Cost per Square Foot:{" "} Cost per Square Foot:{" "}
@ -347,7 +350,7 @@ const PropertyView = () => {
${selectedProperty.costpersqft}/sqft ${selectedProperty.costpersqft}/sqft
<p></p> <p></p>
<span <span
className="" className="selling-price"
style={{ color: "#fda417", fontSize: "15px" }} style={{ color: "#fda417", fontSize: "15px" }}
> >
Year Built:{" "} Year Built:{" "}
@ -425,7 +428,7 @@ const PropertyView = () => {
<li key={index} className="d-flex align-items-center"> <li key={index} className="d-flex align-items-center">
<div className="d-flex align-items-center"> <div className="d-flex align-items-center">
<span> <span>
Total Fund Value: {detail.fundValue}, Interest Percentage: {detail.fundPercentage}% Total Fund Value: $ {detail.fundValue}, Interest Percentage: {detail.fundPercentage}%
</span> </span>
<br /> <br /> <br /> <br />

View File

@ -23,6 +23,8 @@ export const submitProperty = (propertyData) => API.post("/properties", property
// export const fetchUserProperties = (userId) => API.get(`/properties/user/${userId}`, userId); // export const fetchUserProperties = (userId) => API.get(`/properties/user/${userId}`, userId);
export const fetchUserProperties = (userId, page, limit) => API.get( `/properties/user/${userId}?page=${page}&limit=${limit}`, userId); export const fetchUserProperties = (userId, page, limit) => API.get( `/properties/user/${userId}?page=${page}&limit=${limit}`, userId);
export const fetchPropertyById = (id) => API.get(`/properties/${id}`, id); export const fetchPropertyById = (id) => API.get(`/properties/${id}`, id);
export const updateProperty = (id, propertyData) => API.put(`/properties/${id}`, propertyData); export const updateProperty = (id, propertyData) => API.put(`/properties/${id}`, propertyData);

View File

@ -40,6 +40,9 @@ export const fetchUserProperties = createAsyncThunk(
} }
); );
export const fetchPropertyById = createAsyncThunk( export const fetchPropertyById = createAsyncThunk(
"property/fetchPropertyById", "property/fetchPropertyById",
async (id, { rejectWithValue }) => { async (id, { rejectWithValue }) => {
@ -145,6 +148,7 @@ const propertySlice = createSlice({
loading: false, loading: false,
properties: [], properties: [],
fundDetails: [], fundDetails: [],
}, },
reducers: {}, reducers: {},
extraReducers: (builder) => { extraReducers: (builder) => {
@ -236,7 +240,13 @@ const propertySlice = createSlice({
.addCase(deleteFundDetail.rejected, (state, action) => { .addCase(deleteFundDetail.rejected, (state, action) => {
state.loading = false; state.loading = false;
state.error = action.payload; state.error = action.payload;
}); })
;
}, },
}); });