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,6 +94,44 @@ const PropertyView = () => {
<> <>
<Navbar /> <Navbar />
<br /> <br /> <br /> <br /> <br /> <br /> <br /> <br />
<br /> <br />
<div className="container tabs-wrap col-12">
<Navbar />
<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>
<li
role="presentation"
className={activeTab === "Accounting" ? "active tab" : "tab"}
>
<a onClick={() => setActiveTab("Accounting")} role="tab">
Accounting
</a>
</li>
</ul>
<div className="tab-content">
{activeTab === "propertydetails" && (
<div
role="tabpanel"
className="card container tab-pane active col-12"
>
<div className="container col-12"> <div className="container col-12">
{loading ? ( {loading ? (
<div className="loader">Loading...</div> // Loader <div className="loader">Loading...</div> // Loader
@ -79,14 +141,18 @@ const PropertyView = () => {
<div className="row"> <div className="row">
<div className="col-md-5 mt-3"> <div className="col-md-5 mt-3">
<div> <div>
{selectedProperty.images && selectedProperty.images[0] ? ( {selectedProperty.images &&
selectedProperty.images[0] ? (
<img <img
src={selectedProperty.images[0].file || propertydummy} src={
selectedProperty.images[0].file ||
propertydummy
}
alt="Property Thumbnail" alt="Property Thumbnail"
style={{ style={{
marginTop: "0px", marginTop: "0px",
maxWidth: "500px", maxWidth: "400px",
maxHeight: "500px", maxHeight: "400px",
}} }}
/> />
) : ( ) : (
@ -95,11 +161,18 @@ const PropertyView = () => {
alt="Default Property Thumbnail" alt="Default Property Thumbnail"
style={{ style={{
marginTop: "0px", marginTop: "0px",
maxWidth: "500px", maxWidth: "400px",
maxHeight: "500px", maxHeight: "400px",
}} }}
/> />
)} )}
{/* <img
src={selectedProperty.images?.[0]?.file || propertydummy}
alt="Property Thumbnail"
style={{ marginTop: "0px", maxWidth: "400px", maxHeight: "400px" }}
loading="lazy"
/> */}
</div> </div>
<br /> <br />
<div className="label-stock border"> <div className="label-stock border">
@ -111,8 +184,10 @@ const PropertyView = () => {
fontWeight: "normal", fontWeight: "normal",
}} }}
> >
Total Funding Amount:{" "} Funding Required:{" "}
<span style={{ color: "#000000", fontSize: "25px" }}> <span
style={{ color: "#000000", fontSize: "25px" }}
>
<span <span
className="fa fa-dollar" className="fa fa-dollar"
style={{ color: "#F74B02" }} style={{ color: "#F74B02" }}
@ -129,7 +204,9 @@ const PropertyView = () => {
}} }}
> >
Net profit:{" "} Net profit:{" "}
<span style={{ color: "#000000", fontSize: "25px" }}> <span
style={{ color: "#000000", fontSize: "25px" }}
>
<span <span
className="fa fa-dollar" className="fa fa-dollar"
style={{ color: "#F74B02" }} style={{ color: "#F74B02" }}
@ -143,9 +220,14 @@ const PropertyView = () => {
{/* "Willing to Invest/Fund" Button and Conditional Messages */} {/* "Willing to Invest/Fund" Button and Conditional Messages */}
<button <button
className="btn btn-primary back" className="btn btn-primary back"
style={{ backgroundColor: "#fda417", border: "#fda417" }} style={{
backgroundColor: "#fda417",
border: "#fda417",
}}
disabled={isOwner || !isLoggedIn} disabled={isOwner || !isLoggedIn}
onClick={isOwner || !isLoggedIn ? null : handleShowModal} // Show modal only if not owner or logged in onClick={
isOwner || !isLoggedIn ? null : handleShowModal
} // Show modal only if not owner or logged in
> >
<span <span
style={{ style={{
@ -158,12 +240,12 @@ const PropertyView = () => {
</button> </button>
{isOwner && ( {isOwner && (
<span style={{ color: "red", marginTop: "10px" }}> <span style={{ color: "red", marginTop: "10px" }}>
You cannot invest on your property. You cannot invest in your own property.
</span> </span>
)} )}
{!isLoggedIn && ( {!isLoggedIn && (
<span style={{ color: "red", marginTop: "10px" }}> <span style={{ color: "red", marginTop: "10px" }}>
Please login to submit. Please login to invest.
</span> </span>
)} )}
</div> </div>
@ -181,24 +263,32 @@ const PropertyView = () => {
</h4> </h4>
<hr /> <hr />
<p className="product-path"> <p className="product-path">
<span style={{ color: "#fda417", fontSize: "15px" }}> <span
style={{ color: "#fda417", fontSize: "15px" }}
>
City:{" "} City:{" "}
</span>{" "} </span>{" "}
{selectedProperty.city} {selectedProperty.city}
{" "} /{" "} {" "} /{" "}
{" "} {" "}
{" "} {" "}
<span style={{ color: "#fda417", fontSize: "15px" }}> <span
style={{ color: "#fda417", fontSize: "15px" }}
>
County:{" "} County:{" "}
</span>{" "} </span>{" "}
{selectedProperty.county} {" "}/{" "} {selectedProperty.county} {" "}/{" "}
{" "} {" "}
<span style={{ color: "#fda417", fontSize: "15px" }}> <span
style={{ color: "#fda417", fontSize: "15px" }}
>
State:{" "} State:{" "}
</span>{" "} </span>{" "}
{selectedProperty.state} {" "}/ {" "} {selectedProperty.state} {" "}/ {" "}
{" "} {" "}
<span style={{ color: "#fda417", fontSize: "15px" }}> <span
style={{ color: "#fda417", fontSize: "15px" }}
>
Zipcode:{" "} Zipcode:{" "}
</span>{" "} </span>{" "}
{selectedProperty.zip} {selectedProperty.zip}
@ -260,17 +350,19 @@ const PropertyView = () => {
</div> </div>
<div className="card-body"> <div className="card-body">
<p> <p>
Lorem Ipsum is simply dummy text of the printing and Lorem Ipsum is simply dummy text of the printing
typesetting industry. Lorem Ipsum has been the and typesetting industry. Lorem Ipsum has been
industry's standard dummy text ever since the 1500s, the industry's standard dummy text ever since
when an unknown printer took a galley of type and the 1500s, when an unknown printer took a galley
scrambled it to make a type specimen book. It has of type and scrambled it to make a type specimen
survived not only five centuries, but also the leap into book. It has survived not only five centuries,
electronic typesetting, remaining essentially unchanged. but also the leap into electronic typesetting,
It was popularised in the 1960s with the release of remaining essentially unchanged. It was
Letraset sheets containing Lorem Ipsum passages, and popularised in the 1960s with the release of
more recently with desktop publishing software like Letraset sheets containing Lorem Ipsum passages,
Aldus PageMaker including versions of Lorem Ipsum. and more recently with desktop publishing
software like Aldus PageMaker including versions
of Lorem Ipsum.
</p> </p>
</div> </div>
</div> </div>
@ -282,6 +374,31 @@ const PropertyView = () => {
<p>No property found.</p> <p>No property found.</p>
)} )}
</div> </div>
</div>
)}
{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 /> <Footer />
{/* Modal for Investment/Funding */} {/* Modal for Investment/Funding */}
<Modal show={showModal} onHide={handleCloseModal}> <Modal show={showModal} onHide={handleCloseModal}>
@ -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;
}) })
; ;
}, },
}); });