This commit is contained in:
omkieit 2024-10-23 00:13:17 +05:30
parent 2dd33296d0
commit d02de3dafa
11 changed files with 379 additions and 366 deletions

View File

@ -35,3 +35,13 @@ export const getFundDetailsById = async (req, res) => {
res.status(500).json({ message: error.message }); res.status(500).json({ message: error.message });
} }
}; };
export const getAllFunds = async (req, res) => {
try {
// const allFunds = await FundDetailsModal.find();
const allFunds = await FundDetailsModal.findOne();
res.status(200).json(allFunds);
} catch (error) {
res.status(500).json({ message: "Server error" });
}
};

View File

@ -80,9 +80,10 @@ export const getPropertyById = async (req, res) => {
export const updatePropertyById = async (req, res) => { export const updatePropertyById = async (req, res) => {
const { id } = req.params; // This should be the propertyId const { id } = req.params; // This should be the propertyId
const updateData = req.body; const updateData = req.body;
const fundDetails=req.body
console.log("Received propertyId:", id); // Log the received propertyId console.log("Received propertyId:", id); // Log the received propertyId
console.log("updateData", updateData); console.log("fundDetails", fundDetails);
try { try {
// Find the property by propertyId instead of _id // Find the property by propertyId instead of _id

View File

@ -302,6 +302,7 @@ const propertySchema = mongoose.Schema({
type: Number, type: Number,
required: true, // Set to true if this field is mandatory required: true, // Set to true if this field is mandatory
}, },
fundDetails:[],
}); });
const PropertyModal = mongoose.model("property", propertySchema); const PropertyModal = mongoose.model("property", propertySchema);

View File

@ -1,10 +1,12 @@
import express from 'express'; import express from 'express';
const router = express.Router(); const router = express.Router();
import { submitFundDetails, getFundDetailsById } from '../controllers/fundDetails.js'; import { submitFundDetails, getFundDetailsById } from '../controllers/fundDetails.js';
import { getAllFunds } from '../controllers/fundDetails.js';
router.post('/', submitFundDetails); router.post('/', submitFundDetails);
router.get("/allFunds", getAllFunds);
router.get("/:id", getFundDetailsById); router.get("/:id", getFundDetailsById);
export default router; export default router;

File diff suppressed because one or more lines are too long

View File

@ -45,7 +45,7 @@
<script type="module" crossorigin src="/assets/index-YX7OIV1T.js"></script> <script type="module" crossorigin src="/assets/index-CrKcgQxs.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-iEl-il0E.css"> <link rel="stylesheet" crossorigin href="/assets/index-iEl-il0E.css">
</head> </head>

View File

@ -20,6 +20,7 @@ import EditProperty from "./components/EditProperty";
import SearchProperties from "./components/SearchProperties"; import SearchProperties from "./components/SearchProperties";
import ProfileView from "./components/ProfileView"; import ProfileView from "./components/ProfileView";
const App = () => { const App = () => {
return ( return (
<BrowserRouter> <BrowserRouter>
@ -31,6 +32,7 @@ const App = () => {
<Route path="/contact" element={<Contact />}></Route> <Route path="/contact" element={<Contact />}></Route>
<Route path="/register" element={<Register />}></Route> <Route path="/register" element={<Register />}></Route>
<Route <Route
path="/registrationsuccess" path="/registrationsuccess"
element={ element={

View File

@ -1,110 +0,0 @@
import { useState, useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import { fetchPropertyById } from "../redux/features/propertySlice";
import { updateProperty } from "../redux/features/propertySlice";
import { useParams } from "react-router-dom";
import Navbar from "./Navbar";
import Footer from "./Footer";
const EditProperty = () => {
const { id } = useParams();
const dispatch = useDispatch();
const { selectedProperty } = useSelector((state) => state.property);
const [formData, setFormData] = useState({
propertyType: "",
yearBuild: "",
totalSqft: "",
});
useEffect(() => {
dispatch(fetchPropertyById(id));
}, [dispatch, id]);
useEffect(() => {
if (selectedProperty) {
setFormData({
propertyType: selectedProperty.propertyType,
yearBuild: selectedProperty.yearBuild,
totalSqft: selectedProperty.totalSqft,
});
}
}, [selectedProperty]);
const handleChange = (e) => {
setFormData({ ...formData, [e.target.name]: e.target.value });
};
const handleSubmit = (e) => {
e.preventDefault();
dispatch(updateProperty({ id, propertyData: formData }));
};
return (
<>
<Navbar />
<br /> <br /> <br /> <br /> <br /> <br />
<div className="edit-property-form">
<h2>Edit Property</h2>
<form onSubmit={handleSubmit}>
<div>
<select
className="form-floating mb-3 form-control"
name="propertyType"
value={formData.propertyType}
onChange={handleChange}
required
>
<option value="">Please Select Property Type</option>
<option value="Residential">Residential</option>
<option value="Land">Land</option>
<option value="Commercial">Commercial</option>
<option value="Industrial">Industrial</option>
<option value="Water">Water</option>
</select>
</div>
<div className="col-12">
<div className="form-floating mb-3">
<input
type="text"
className="form-control"
name="yearBuild"
value={formData.yearBuild}
onChange={handleChange}
placeholder="Year build"
required
/>
<label htmlFor="yearBuild" className="form-label">
Year Build
</label>
</div>
</div>
<div className="form-floating mb-3">
<input
type="text"
className="form-control"
name="totalSqft"
value={formData.totalSqft}
onChange={handleChange}
placeholder="Total SQFT"
required
/>
<label htmlFor="totalSqft" className="form-label">
Total SQFT
</label>
</div>
<button type="submit">Update Property</button>
</form>
</div>
<Footer />
</>
);
};
export default EditProperty;

View File

@ -6,7 +6,10 @@ import propertydummy from "../img/propertydummy.jpg";
import Navbar from "./Navbar"; import Navbar from "./Navbar";
import Footer from "./Footer"; import Footer from "./Footer";
import { Modal, Button, Form } from "react-bootstrap"; // Importing Modal components import { Modal, Button, Form } from "react-bootstrap"; // Importing Modal components
import { submitFundDetails } from "../redux/features/fundDetailsSlice"; import {
submitFundDetails,
getFundDetailsById,
} from "../redux/features/fundDetailsSlice";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
const PropertyView = () => { const PropertyView = () => {
@ -17,22 +20,39 @@ const PropertyView = () => {
(state) => state.property (state) => state.property
); );
const { user } = useSelector((state) => ({ ...state.auth })); const { user } = useSelector((state) => ({ ...state.auth }));
const { fundDetails } = useSelector((state) => state.fundDetails);
console.log("funddetails", fundDetails);
const [activeTab, setActiveTab] = useState("propertydetails");
const [loading, setLoading] = useState(true); // Loader state const [loading, setLoading] = useState(true); // Loader state
const [showModal, setShowModal] = useState(false); // Modal state const [showModal, setShowModal] = useState(false); // Modal state
const [fundValue, setFundValue] = useState(""); // Fund value state const [fundValue, setFundValue] = useState(""); // Fund value state
const [fundPercentage, setFundPercentage] = useState(""); // Fund percentage state const [fundPercentage, setFundPercentage] = useState(""); // Fund percentage state
useEffect(() => { useEffect(() => {
// Fetch the property by ID when the component loads
if (id) { if (id) {
dispatch(fetchPropertyById(id)); dispatch(fetchPropertyById(id));
setLoading(false); dispatch(getFundDetailsById(id));
} }
}, [id, dispatch]); }, [id, dispatch]);
if (status === "loading") { useEffect(() => {
return <p>Loading property details...</p>; if (status === "succeeded") {
} setLoading(false);
}
}, [status]);
useEffect(() => {
if (fundDetails) {
setFundValue(fundDetails.investmentAmount);
setFundPercentage(fundDetails.ownershipPercentage);
}
}, [fundDetails]);
// if (status === "loading") {
// return <p>Loading property details...</p>;
// }
if (status === "failed") { if (status === "failed") {
return <p>Error loading property: {error}</p>; return <p>Error loading property: {error}</p>;
@ -53,6 +73,10 @@ const PropertyView = () => {
// Inside your PropertyView component // Inside your PropertyView component
const handleSubmit = (e) => { const handleSubmit = (e) => {
e.preventDefault(); e.preventDefault();
if (fundValue <= 0 || fundPercentage <= 0 || fundPercentage > 100) {
alert("Please enter valid values.");
return;
}
const fundDetails = { const fundDetails = {
propertyOwnerId: selectedProperty?.userId, propertyOwnerId: selectedProperty?.userId,
@ -70,217 +94,310 @@ const PropertyView = () => {
<> <>
<Navbar /> <Navbar />
<br /> <br /> <br /> <br /> <br /> <br /> <br /> <br />
<div className="container col-12"> <br /> <br />
{loading ? ( <div className="container tabs-wrap col-12">
<div className="loader">Loading...</div> // Loader <Navbar />
) : selectedProperty ? (
<div className="py-3 py-md-5 bg-light">
<div className="card-header bg-white">
<div className="row">
<div className="col-md-5 mt-3">
<div>
{selectedProperty.images && selectedProperty.images[0] ? (
<img
src={selectedProperty.images[0].file || propertydummy}
alt="Property Thumbnail"
style={{
marginTop: "0px",
maxWidth: "500px",
maxHeight: "500px",
}}
/>
) : (
<img
src={propertydummy}
alt="Default Property Thumbnail"
style={{
marginTop: "0px",
maxWidth: "500px",
maxHeight: "500px",
}}
/>
)}
</div>
<br />
<div className="label-stock border">
<p
style={{
color: "#fda417",
fontSize: "30px",
padding: "10px",
fontWeight: "normal",
}}
>
Total Funding Amount:{" "}
<span style={{ color: "#000000", fontSize: "25px" }}>
<span
className="fa fa-dollar"
style={{ color: "#F74B02" }}
/>{" "}
{selectedProperty.totalCoststoBuyAtoB}
</span>
</p>
<p
style={{
color: "#fda417",
fontSize: "30px",
padding: "10px",
fontWeight: "normal",
}}
>
Net profit:{" "}
<span style={{ color: "#000000", fontSize: "25px" }}>
<span
className="fa fa-dollar"
style={{ color: "#F74B02" }}
/>{" "}
{selectedProperty.NetProfit}
</span>
</p>
</div>
<br /> <ul className="nav nav-tabs" role="tablist">
{/* "Willing to Invest/Fund" Button and Conditional Messages */} <li
<button role="presentation"
className="btn btn-primary back" className={activeTab === "propertydetails" ? "active tab" : "tab"}
style={{ backgroundColor: "#fda417", border: "#fda417" }} >
disabled={isOwner || !isLoggedIn} <a onClick={() => setActiveTab("propertydetails")} role="tab">
onClick={isOwner || !isLoggedIn ? null : handleShowModal} // Show modal only if not owner or logged in Property Details
> </a>
<span </li>
style={{ <li
fontSize: "25px", role="presentation"
fontWeight: "normal", className={activeTab === "Funding Details" ? "active tab" : "tab"}
}} >
> <a onClick={() => setActiveTab("Funding Details")} role="tab">
Willing to Invest/Fund Funding Details
</span>{" "} </a>
</button> </li>
{isOwner && (
<span style={{ color: "red", marginTop: "10px" }}>
You cannot invest on your property.
</span>
)}
{!isLoggedIn && (
<span style={{ color: "red", marginTop: "10px" }}>
Please login to submit.
</span>
)}
</div>
<div className="col-md-7 mt-3"> <li
<div className="product-view"> role="presentation"
<h4 className={activeTab === "Accounting" ? "active tab" : "tab"}
className="product-name" >
style={{ color: "#fda417", fontSize: "25px" }} <a onClick={() => setActiveTab("Accounting")} role="tab">
> Accounting
{selectedProperty.address} </a>
<label className="label-stock bg-success"> </li>
Verified Property </ul>
</label>
</h4>
<hr />
<p className="product-path">
<span style={{ color: "#fda417", fontSize: "15px" }}>
City:{" "}
</span>{" "}
{selectedProperty.city}
{" "} /{" "}
{" "}
{" "}
<span style={{ color: "#fda417", fontSize: "15px" }}>
County:{" "}
</span>{" "}
{selectedProperty.county} {" "}/{" "}
{" "}
<span style={{ color: "#fda417", fontSize: "15px" }}>
State:{" "}
</span>{" "}
{selectedProperty.state} {" "}/ {" "}
{" "}
<span style={{ color: "#fda417", fontSize: "15px" }}>
Zipcode:{" "}
</span>{" "}
{selectedProperty.zip}
{" "}
</p>
<div>
<span
className="selling-price"
style={{ color: "#fda417", fontSize: "15px" }}
>
Total Living Square Foot:{" "}
</span>
{selectedProperty.totallivingsqft}
<p></p>
<span
className=""
style={{ color: "#fda417", fontSize: "15px" }}
>
Cost per Square Foot:{" "}
</span>
${selectedProperty.costpersqft}/sqft
<p></p>
<span
className=""
style={{ color: "#fda417", fontSize: "15px" }}
>
Year Built:{" "}
</span>
{selectedProperty.yearBuild}
</div>
<div className="mt-3 card bg-white label-stock border"> <div className="tab-content">
<h5 {activeTab === "propertydetails" && (
className="mb-0" <div
style={{ color: "#fda417", fontSize: "15px" }} role="tabpanel"
> className="card container tab-pane active col-12"
Legal Description >
</h5> <div className="container col-12">
<span> {loading ? (
{selectedProperty.legal <div className="loader">Loading...</div> // Loader
? selectedProperty.legal ) : selectedProperty ? (
: "No data available"} <div className="py-3 py-md-5 bg-light">
</span>
</div>
</div>
</div>
</div>
<div className="row">
<div className="col-md-12 mt-3">
<div className="card">
<div className="card-header bg-white"> <div className="card-header bg-white">
<h4 <div className="row">
className="product-name" <div className="col-md-5 mt-3">
style={{ color: "#fda417", fontSize: "25px" }} <div>
> {selectedProperty.images &&
Description selectedProperty.images[0] ? (
</h4> <img
</div> src={
<div className="card-body"> selectedProperty.images[0].file ||
<p> propertydummy
Lorem Ipsum is simply dummy text of the printing and }
typesetting industry. Lorem Ipsum has been the alt="Property Thumbnail"
industry's standard dummy text ever since the 1500s, style={{
when an unknown printer took a galley of type and marginTop: "0px",
scrambled it to make a type specimen book. It has maxWidth: "400px",
survived not only five centuries, but also the leap into maxHeight: "400px",
electronic typesetting, remaining essentially unchanged. }}
It was popularised in the 1960s with the release of />
Letraset sheets containing Lorem Ipsum passages, and ) : (
more recently with desktop publishing software like <img
Aldus PageMaker including versions of Lorem Ipsum. src={propertydummy}
</p> alt="Default Property Thumbnail"
style={{
marginTop: "0px",
maxWidth: "400px",
maxHeight: "400px",
}}
/>
)}
{/* <img
src={selectedProperty.images?.[0]?.file || propertydummy}
alt="Property Thumbnail"
style={{ marginTop: "0px", maxWidth: "400px", maxHeight: "400px" }}
loading="lazy"
/> */}
</div>
<br />
<div className="label-stock border">
<p
style={{
color: "#fda417",
fontSize: "30px",
padding: "10px",
fontWeight: "normal",
}}
>
Funding Required:{" "}
<span
style={{ color: "#000000", fontSize: "25px" }}
>
<span
className="fa fa-dollar"
style={{ color: "#F74B02" }}
/>{" "}
{selectedProperty.totalCoststoBuyAtoB}
</span>
</p>
<p
style={{
color: "#fda417",
fontSize: "30px",
padding: "10px",
fontWeight: "normal",
}}
>
Net profit:{" "}
<span
style={{ color: "#000000", fontSize: "25px" }}
>
<span
className="fa fa-dollar"
style={{ color: "#F74B02" }}
/>{" "}
{selectedProperty.NetProfit}
</span>
</p>
</div>
<br />
{/* "Willing to Invest/Fund" Button and Conditional Messages */}
<button
className="btn btn-primary back"
style={{
backgroundColor: "#fda417",
border: "#fda417",
}}
disabled={isOwner || !isLoggedIn}
onClick={
isOwner || !isLoggedIn ? null : handleShowModal
} // Show modal only if not owner or logged in
>
<span
style={{
fontSize: "25px",
fontWeight: "normal",
}}
>
Willing to Invest/Fund
</span>{" "}
</button>
{isOwner && (
<span style={{ color: "red", marginTop: "10px" }}>
You cannot invest in your own property.
</span>
)}
{!isLoggedIn && (
<span style={{ color: "red", marginTop: "10px" }}>
Please login to invest.
</span>
)}
</div>
<div className="col-md-7 mt-3">
<div className="product-view">
<h4
className="product-name"
style={{ color: "#fda417", fontSize: "25px" }}
>
{selectedProperty.address}
<label className="label-stock bg-success">
Verified Property
</label>
</h4>
<hr />
<p className="product-path">
<span
style={{ color: "#fda417", fontSize: "15px" }}
>
City:{" "}
</span>{" "}
{selectedProperty.city}
{" "} /{" "}
{" "}
{" "}
<span
style={{ color: "#fda417", fontSize: "15px" }}
>
County:{" "}
</span>{" "}
{selectedProperty.county} {" "}/{" "}
{" "}
<span
style={{ color: "#fda417", fontSize: "15px" }}
>
State:{" "}
</span>{" "}
{selectedProperty.state} {" "}/ {" "}
{" "}
<span
style={{ color: "#fda417", fontSize: "15px" }}
>
Zipcode:{" "}
</span>{" "}
{selectedProperty.zip}
{" "}
</p>
<div>
<span
className="selling-price"
style={{ color: "#fda417", fontSize: "15px" }}
>
Total Living Square Foot:{" "}
</span>
{selectedProperty.totallivingsqft}
<p></p>
<span
className=""
style={{ color: "#fda417", fontSize: "15px" }}
>
Cost per Square Foot:{" "}
</span>
${selectedProperty.costpersqft}/sqft
<p></p>
<span
className=""
style={{ color: "#fda417", fontSize: "15px" }}
>
Year Built:{" "}
</span>
{selectedProperty.yearBuild}
</div>
<div className="mt-3 card bg-white label-stock border">
<h5
className="mb-0"
style={{ color: "#fda417", fontSize: "15px" }}
>
Legal Description
</h5>
<span>
{selectedProperty.legal
? selectedProperty.legal
: "No data available"}
</span>
</div>
</div>
</div>
</div>
<div className="row">
<div className="col-md-12 mt-3">
<div className="card">
<div className="card-header bg-white">
<h4
className="product-name"
style={{ color: "#fda417", fontSize: "25px" }}
>
Description
</h4>
</div>
<div className="card-body">
<p>
Lorem Ipsum is simply dummy text of the printing
and typesetting industry. Lorem Ipsum has been
the industry's standard dummy text ever since
the 1500s, when an unknown printer took a galley
of type and scrambled it to make a type specimen
book. It has survived not only five centuries,
but also the leap into electronic typesetting,
remaining essentially unchanged. It was
popularised in the 1960s with the release of
Letraset sheets containing Lorem Ipsum passages,
and more recently with desktop publishing
software like Aldus PageMaker including versions
of Lorem Ipsum.
</p>
</div>
</div>
</div>
</div>
</div> </div>
</div> </div>
</div> ) : (
<p>No property found.</p>
)}
</div> </div>
</div> </div>
</div> )}
) : (
<p>No property found.</p> {activeTab === "Funding Details" && (
)} <div>
{activeTab === "Funding Details" && (
<div className="tab-pane active">
{fundDetails ? (
<div>
<p>Investment Amount: ${fundDetails.investmentAmount}</p>
<p>
Ownership Percentage: {fundDetails.ownershipPercentage}%
</p>
</div>
) : (
<p>No funding details available.</p>
)}
</div>
)}
</div>
)}
{activeTab === "Accounting" && <div></div>}
</div>
</div> </div>
<Footer /> <Footer />
{/* Modal for Investment/Funding */} {/* Modal for Investment/Funding */}
@ -290,42 +407,25 @@ const PropertyView = () => {
</Modal.Header> </Modal.Header>
<Modal.Body> <Modal.Body>
<Form onSubmit={handleSubmit}> <Form onSubmit={handleSubmit}>
<Form.Group controlId="fundValue"> <Form.Group>
<Form.Label>Investment Amount ($)</Form.Label> <Form.Label>Fund Value</Form.Label>
<Form.Control <Form.Control
type="number" type="number"
placeholder="Enter amount"
value={fundValue} value={fundValue}
onChange={(e) => setFundValue(e.target.value)} onChange={(e) => setFundValue(e.target.value)}
required
/> />
</Form.Group> </Form.Group>
<Form.Group controlId="fundPercentage"> <Form.Group>
<Form.Label>Ownership Percentage (%)</Form.Label> <Form.Label>Fund Percentage</Form.Label>
<Form.Control <Form.Control
type="number" type="number"
placeholder="Enter percentage"
value={fundPercentage} value={fundPercentage}
onChange={(e) => setFundPercentage(e.target.value)} onChange={(e) => setFundPercentage(e.target.value)}
required
/> />
</Form.Group> </Form.Group>
<Button <Button variant="primary" type="submit">
variant="primary"
type="submit"
style={{ backgroundColor: "#fda417", border: "#fda417" }}
>
Submit Submit
</Button> </Button>
{" "}
<Button
variant="primary"
onClick={handleCloseModal}
style={{ backgroundColor: "#d80b0b", border: "#d80b0b" }}
>
close
</Button>
</Form> </Form>
</Modal.Body> </Modal.Body>
</Modal> </Modal>

View File

@ -26,7 +26,8 @@ export const fetchUserProperties = (userId, page, limit) => API.get( `/propertie
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);
export const showUser = (userId) => API.get(`/users/${userId}`); export const showUser = (userId) => API.get(`/users/${userId}`);
export const submitFundDetails = (fundDetails) => API.post(`/fundDetails`, fundDetails); export const submitFundDetails = (fundDetailsArray) => API.post(`/fundDetails`, fundDetailsArray);
export const getFundDetailsById = (fundDetails) => API.post(`/fundDetails`, fundDetails);

View File

@ -64,6 +64,10 @@ export const updateProperty = createAsyncThunk(
} }
); );
// export const getProperties = createAsyncThunk("property/getProperties", async () => { // export const getProperties = createAsyncThunk("property/getProperties", async () => {
// const response = await axios.get(`${import.meta.env.VITE_REACT_APP_SECRET}/properties`); // Backend endpoint // const response = await axios.get(`${import.meta.env.VITE_REACT_APP_SECRET}/properties`); // Backend endpoint
// return response.data; // return response.data;
@ -164,6 +168,8 @@ const propertySlice = createSlice({
state.loading = false; state.loading = false;
state.error = action.error.message; state.error = action.error.message;
}) })
; ;
}, },
}); });