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

@ -34,4 +34,14 @@ export const getFundDetailsById = async (req, res) => {
} catch (error) {
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) => {
const { id } = req.params; // This should be the propertyId
const updateData = req.body;
const fundDetails=req.body
console.log("Received propertyId:", id); // Log the received propertyId
console.log("updateData", updateData);
console.log("fundDetails", fundDetails);
try {
// Find the property by propertyId instead of _id

View File

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

View File

@ -1,10 +1,12 @@
import express from 'express';
const router = express.Router();
import { submitFundDetails, getFundDetailsById } from '../controllers/fundDetails.js';
import { getAllFunds } from '../controllers/fundDetails.js';
router.post('/', submitFundDetails);
router.get("/allFunds", getAllFunds);
router.get("/:id", getFundDetailsById);
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">
</head>

View File

@ -20,6 +20,7 @@ import EditProperty from "./components/EditProperty";
import SearchProperties from "./components/SearchProperties";
import ProfileView from "./components/ProfileView";
const App = () => {
return (
<BrowserRouter>
@ -31,6 +32,7 @@ const App = () => {
<Route path="/contact" element={<Contact />}></Route>
<Route path="/register" element={<Register />}></Route>
<Route
path="/registrationsuccess"
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 Footer from "./Footer";
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";
const PropertyView = () => {
@ -17,22 +20,39 @@ const PropertyView = () => {
(state) => state.property
);
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 [showModal, setShowModal] = useState(false); // Modal state
const [fundValue, setFundValue] = useState(""); // Fund value state
const [fundPercentage, setFundPercentage] = useState(""); // Fund percentage state
useEffect(() => {
// Fetch the property by ID when the component loads
if (id) {
dispatch(fetchPropertyById(id));
setLoading(false);
dispatch(getFundDetailsById(id));
}
}, [id, dispatch]);
if (status === "loading") {
return <p>Loading property details...</p>;
}
useEffect(() => {
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") {
return <p>Error loading property: {error}</p>;
@ -53,6 +73,10 @@ const PropertyView = () => {
// Inside your PropertyView component
const handleSubmit = (e) => {
e.preventDefault();
if (fundValue <= 0 || fundPercentage <= 0 || fundPercentage > 100) {
alert("Please enter valid values.");
return;
}
const fundDetails = {
propertyOwnerId: selectedProperty?.userId,
@ -70,217 +94,310 @@ const PropertyView = () => {
<>
<Navbar />
<br /> <br /> <br /> <br />
<div className="container col-12">
{loading ? (
<div className="loader">Loading...</div> // Loader
) : 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 /> <br />
<div className="container tabs-wrap col-12">
<Navbar />
<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 on your property.
</span>
)}
{!isLoggedIn && (
<span style={{ color: "red", marginTop: "10px" }}>
Please login to submit.
</span>
)}
</div>
<ul className="nav nav-tabs" role="tablist">
<li
role="presentation"
className={activeTab === "propertydetails" ? "active tab" : "tab"}
>
<a onClick={() => setActiveTab("propertydetails")} role="tab">
Property Details
</a>
</li>
<li
role="presentation"
className={activeTab === "Funding Details" ? "active tab" : "tab"}
>
<a onClick={() => setActiveTab("Funding Details")} role="tab">
Funding Details
</a>
</li>
<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>
<li
role="presentation"
className={activeTab === "Accounting" ? "active tab" : "tab"}
>
<a onClick={() => setActiveTab("Accounting")} role="tab">
Accounting
</a>
</li>
</ul>
<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="tab-content">
{activeTab === "propertydetails" && (
<div
role="tabpanel"
className="card container tab-pane active col-12"
>
<div className="container col-12">
{loading ? (
<div className="loader">Loading...</div> // Loader
) : selectedProperty ? (
<div className="py-3 py-md-5 bg-light">
<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 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: "400px",
maxHeight: "400px",
}}
/>
) : (
<img
src={propertydummy}
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>
) : (
<p>No property found.</p>
)}
</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>
<Footer />
{/* Modal for Investment/Funding */}
@ -290,42 +407,25 @@ const PropertyView = () => {
</Modal.Header>
<Modal.Body>
<Form onSubmit={handleSubmit}>
<Form.Group controlId="fundValue">
<Form.Label>Investment Amount ($)</Form.Label>
<Form.Group>
<Form.Label>Fund Value</Form.Label>
<Form.Control
type="number"
placeholder="Enter amount"
value={fundValue}
onChange={(e) => setFundValue(e.target.value)}
required
/>
</Form.Group>
<Form.Group controlId="fundPercentage">
<Form.Label>Ownership Percentage (%)</Form.Label>
<Form.Group>
<Form.Label>Fund Percentage</Form.Label>
<Form.Control
type="number"
placeholder="Enter percentage"
value={fundPercentage}
onChange={(e) => setFundPercentage(e.target.value)}
required
/>
</Form.Group>
<Button
variant="primary"
type="submit"
style={{ backgroundColor: "#fda417", border: "#fda417" }}
>
<Button variant="primary" type="submit">
Submit
</Button>
{" "}
<Button
variant="primary"
onClick={handleCloseModal}
style={{ backgroundColor: "#d80b0b", border: "#d80b0b" }}
>
close
</Button>
</Form>
</Modal.Body>
</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 updateProperty = (id, propertyData) => API.put(`/properties/${id}`, propertyData);
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 () => {
// const response = await axios.get(`${import.meta.env.VITE_REACT_APP_SECRET}/properties`); // Backend endpoint
// return response.data;
@ -164,6 +168,8 @@ const propertySlice = createSlice({
state.loading = false;
state.error = action.error.message;
})
;
},
});