done
This commit is contained in:
parent
2dd33296d0
commit
d02de3dafa
|
@ -35,3 +35,13 @@ export const getFundDetailsById = async (req, res) => {
|
|||
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" });
|
||||
}
|
||||
};
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
@ -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>
|
||||
|
||||
|
|
|
@ -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={
|
||||
|
|
|
@ -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;
|
|
@ -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,6 +94,44 @@ const PropertyView = () => {
|
|||
<>
|
||||
<Navbar />
|
||||
<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">
|
||||
{loading ? (
|
||||
<div className="loader">Loading...</div> // Loader
|
||||
|
@ -79,14 +141,18 @@ const PropertyView = () => {
|
|||
<div className="row">
|
||||
<div className="col-md-5 mt-3">
|
||||
<div>
|
||||
{selectedProperty.images && selectedProperty.images[0] ? (
|
||||
{selectedProperty.images &&
|
||||
selectedProperty.images[0] ? (
|
||||
<img
|
||||
src={selectedProperty.images[0].file || propertydummy}
|
||||
src={
|
||||
selectedProperty.images[0].file ||
|
||||
propertydummy
|
||||
}
|
||||
alt="Property Thumbnail"
|
||||
style={{
|
||||
marginTop: "0px",
|
||||
maxWidth: "500px",
|
||||
maxHeight: "500px",
|
||||
maxWidth: "400px",
|
||||
maxHeight: "400px",
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
|
@ -95,11 +161,18 @@ const PropertyView = () => {
|
|||
alt="Default Property Thumbnail"
|
||||
style={{
|
||||
marginTop: "0px",
|
||||
maxWidth: "500px",
|
||||
maxHeight: "500px",
|
||||
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">
|
||||
|
@ -111,8 +184,10 @@ const PropertyView = () => {
|
|||
fontWeight: "normal",
|
||||
}}
|
||||
>
|
||||
Total Funding Amount:{" "}
|
||||
<span style={{ color: "#000000", fontSize: "25px" }}>
|
||||
Funding Required:{" "}
|
||||
<span
|
||||
style={{ color: "#000000", fontSize: "25px" }}
|
||||
>
|
||||
<span
|
||||
className="fa fa-dollar"
|
||||
style={{ color: "#F74B02" }}
|
||||
|
@ -129,7 +204,9 @@ const PropertyView = () => {
|
|||
}}
|
||||
>
|
||||
Net profit:{" "}
|
||||
<span style={{ color: "#000000", fontSize: "25px" }}>
|
||||
<span
|
||||
style={{ color: "#000000", fontSize: "25px" }}
|
||||
>
|
||||
<span
|
||||
className="fa fa-dollar"
|
||||
style={{ color: "#F74B02" }}
|
||||
|
@ -143,9 +220,14 @@ const PropertyView = () => {
|
|||
{/* "Willing to Invest/Fund" Button and Conditional Messages */}
|
||||
<button
|
||||
className="btn btn-primary back"
|
||||
style={{ backgroundColor: "#fda417", border: "#fda417" }}
|
||||
style={{
|
||||
backgroundColor: "#fda417",
|
||||
border: "#fda417",
|
||||
}}
|
||||
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
|
||||
style={{
|
||||
|
@ -158,12 +240,12 @@ const PropertyView = () => {
|
|||
</button>
|
||||
{isOwner && (
|
||||
<span style={{ color: "red", marginTop: "10px" }}>
|
||||
You cannot invest on your property.
|
||||
You cannot invest in your own property.
|
||||
</span>
|
||||
)}
|
||||
{!isLoggedIn && (
|
||||
<span style={{ color: "red", marginTop: "10px" }}>
|
||||
Please login to submit.
|
||||
Please login to invest.
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
@ -181,24 +263,32 @@ const PropertyView = () => {
|
|||
</h4>
|
||||
<hr />
|
||||
<p className="product-path">
|
||||
<span style={{ color: "#fda417", fontSize: "15px" }}>
|
||||
<span
|
||||
style={{ color: "#fda417", fontSize: "15px" }}
|
||||
>
|
||||
City:{" "}
|
||||
</span>{" "}
|
||||
{selectedProperty.city}
|
||||
{" "} /{" "}
|
||||
{" "}
|
||||
{" "}
|
||||
<span style={{ color: "#fda417", fontSize: "15px" }}>
|
||||
<span
|
||||
style={{ color: "#fda417", fontSize: "15px" }}
|
||||
>
|
||||
County:{" "}
|
||||
</span>{" "}
|
||||
{selectedProperty.county} {" "}/{" "}
|
||||
{" "}
|
||||
<span style={{ color: "#fda417", fontSize: "15px" }}>
|
||||
<span
|
||||
style={{ color: "#fda417", fontSize: "15px" }}
|
||||
>
|
||||
State:{" "}
|
||||
</span>{" "}
|
||||
{selectedProperty.state} {" "}/ {" "}
|
||||
{" "}
|
||||
<span style={{ color: "#fda417", fontSize: "15px" }}>
|
||||
<span
|
||||
style={{ color: "#fda417", fontSize: "15px" }}
|
||||
>
|
||||
Zipcode:{" "}
|
||||
</span>{" "}
|
||||
{selectedProperty.zip}
|
||||
|
@ -260,17 +350,19 @@ const PropertyView = () => {
|
|||
</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.
|
||||
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>
|
||||
|
@ -282,6 +374,31 @@ const PropertyView = () => {
|
|||
<p>No property found.</p>
|
||||
)}
|
||||
</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 />
|
||||
{/* Modal for Investment/Funding */}
|
||||
<Modal show={showModal} onHide={handleCloseModal}>
|
||||
|
@ -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>
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
})
|
||||
|
||||
|
||||
;
|
||||
},
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue