done
This commit is contained in:
parent
3b05f20ffe
commit
51f1b4afbd
|
@ -0,0 +1,37 @@
|
|||
|
||||
import FundDetailsModal from "../models/fundDetails.js"
|
||||
|
||||
|
||||
export const submitFundDetails = async (req, res) => {
|
||||
|
||||
const { propertyOwnerId, investorId, investmentAmount, ownershipPercentage, propertyId } = req.body;
|
||||
|
||||
const newFundDetail = new FundDetailsModal({
|
||||
propertyOwnerId,
|
||||
investorId,
|
||||
investmentAmount,
|
||||
ownershipPercentage,
|
||||
propertyId
|
||||
});
|
||||
console.log("newFundDetail", newFundDetail)
|
||||
|
||||
try {
|
||||
const savedFundDetail = await newFundDetail.save();
|
||||
res.status(201).json(savedFundDetail);
|
||||
} catch (error) {
|
||||
res.status(500).json({ message: error.message });
|
||||
}
|
||||
};
|
||||
|
||||
export const getFundDetailsById = async (req, res) => {
|
||||
const { id } = req.params;
|
||||
try {
|
||||
const fundDetails = await FundDetailsModal.findOne({ propertyId: id });
|
||||
if (!fundDetails) {
|
||||
return res.status(404).json({ message: "Fund details not found" });
|
||||
}
|
||||
res.status(200).json(fundDetails);
|
||||
} catch (error) {
|
||||
res.status(500).json({ message: error.message });
|
||||
}
|
||||
};
|
|
@ -7,6 +7,7 @@ import session from "express-session";
|
|||
import userRouter from "./routes/user.js";
|
||||
import propertyRouter from "./routes/property.js";
|
||||
import mysqlRouter from "./routes/mysqlproperty.js";
|
||||
import fundDetailsRouter from "./routes/fundDetails.js";
|
||||
import dotenv from "dotenv";
|
||||
|
||||
const app = express();
|
||||
|
@ -34,6 +35,7 @@ app.use(
|
|||
app.use("/users", userRouter);
|
||||
app.use("/properties", propertyRouter);
|
||||
app.use("/mysql", mysqlRouter); // Use MySQL routes
|
||||
app.use("/fundDetails", fundDetailsRouter);
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
|
||||
import mongoose from "mongoose";
|
||||
|
||||
const fundDetailsSchema = new mongoose.Schema({
|
||||
propertyOwnerId: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
investorId: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
investmentAmount: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
ownershipPercentage: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
propertyId:{
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
}, { timestamps: true });
|
||||
|
||||
const FundDetailsModal = mongoose.model("FundDetails", fundDetailsSchema);
|
||||
export default FundDetailsModal;
|
||||
|
|
@ -1,74 +0,0 @@
|
|||
import mongoose from "mongoose";
|
||||
|
||||
// Schema for property tax information
|
||||
const propertyTaxInfoSchema = mongoose.Schema({
|
||||
propertytaxowned: { type: String },
|
||||
ownedyear: { type: String },
|
||||
taxassessed: { type: String },
|
||||
taxyear: { type: String },
|
||||
});
|
||||
|
||||
// Schema for images
|
||||
const imageSchema = mongoose.Schema({
|
||||
title: { type: String }, // Title of the image
|
||||
file: { type: String }, // Uploaded image URL
|
||||
});
|
||||
|
||||
const propertySchema = mongoose.Schema({
|
||||
address: { type: String, required: true },
|
||||
city: { type: String, required: true },
|
||||
state: { type: String, required: true },
|
||||
county: { type: String, required: true },
|
||||
zip: { type: String, required: true },
|
||||
parcel: { type: String, required: true },
|
||||
subdivision: { type: String, required: true },
|
||||
legal: { type: String, required: true },
|
||||
costpersqft: { type: String, required: true },
|
||||
propertyType: { type: String, required: true },
|
||||
lotacres: { type: String, required: true },
|
||||
yearBuild: { type: String, required: true },
|
||||
totallivingsqft: { type: String, required: true },
|
||||
beds: { type: String, required: true },
|
||||
baths: { type: String, required: true },
|
||||
stories: { type: String, required: true },
|
||||
garage: { type: String, required: true },
|
||||
garagesqft: { type: String, required: true },
|
||||
poolspa: { type: String, required: true },
|
||||
fireplaces: { type: String, required: true },
|
||||
ac: { type: String, required: true },
|
||||
heating: { type: String, required: true },
|
||||
buildingstyle: { type: String, required: true },
|
||||
sitevacant: { type: String, required: true },
|
||||
extwall: { type: String, required: true },
|
||||
roofing: { type: String, required: true },
|
||||
totalSqft: { type: String, required: true },
|
||||
|
||||
// Remove individual property tax fields and replace with array
|
||||
propertyTaxInfo: [propertyTaxInfoSchema], // Array of tax info objects
|
||||
images: [imageSchema],
|
||||
googleMapLink: { type: String },
|
||||
userfirstname: String,
|
||||
usermiddlename: String,
|
||||
userlastname: String,
|
||||
usertitle: String,
|
||||
creator: String,
|
||||
useremail: String,
|
||||
propertyId: String,
|
||||
userId: String,
|
||||
createdAt: {
|
||||
type: Date,
|
||||
default: new Date(),
|
||||
},
|
||||
publishedAt: {
|
||||
type: Date,
|
||||
default: new Date(),
|
||||
},
|
||||
currentYear: {
|
||||
type: Number,
|
||||
default: new Date().getFullYear(),
|
||||
},
|
||||
});
|
||||
|
||||
const PropertyModal = mongoose.model("property", propertySchema);
|
||||
|
||||
export default PropertyModal;
|
|
@ -0,0 +1,10 @@
|
|||
import express from 'express';
|
||||
const router = express.Router();
|
||||
import { submitFundDetails, getFundDetailsById } from '../controllers/fundDetails.js';
|
||||
|
||||
|
||||
|
||||
router.post('/', submitFundDetails);
|
||||
router.get("/:id", getFundDetailsById);
|
||||
|
||||
export default router;
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -45,7 +45,7 @@
|
|||
|
||||
|
||||
|
||||
<script type="module" crossorigin src="/assets/index-7mv97drX.js"></script>
|
||||
<script type="module" crossorigin src="/assets/index-B2o9sH6t.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-iEl-il0E.css">
|
||||
</head>
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
"primeicons": "^7.0.0",
|
||||
"prop-types": "^15.8.1",
|
||||
"react": "^18.3.1",
|
||||
"react-bootstrap": "^2.10.5",
|
||||
"react-dom": "^18.3.1",
|
||||
"react-file-base64": "^1.0.3",
|
||||
"react-icons": "^5.3.0",
|
||||
|
@ -336,6 +337,18 @@
|
|||
"@babel/core": "^7.0.0-0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/runtime": {
|
||||
"version": "7.25.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.7.tgz",
|
||||
"integrity": "sha512-FjoyLe754PMiYsFaN5C94ttGiOmBNYTf6pLr4xXHAT5uctHb092PBszndLDR5XA/jghQvn4n7JMHl7dmTgbm9w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"regenerator-runtime": "^0.14.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/template": {
|
||||
"version": "7.25.0",
|
||||
"dev": true,
|
||||
|
@ -654,12 +667,26 @@
|
|||
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
|
||||
"integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/popperjs"
|
||||
}
|
||||
},
|
||||
"node_modules/@react-aria/ssr": {
|
||||
"version": "3.9.6",
|
||||
"resolved": "https://registry.npmjs.org/@react-aria/ssr/-/ssr-3.9.6.tgz",
|
||||
"integrity": "sha512-iLo82l82ilMiVGy342SELjshuWottlb5+VefO3jOQqQRNYnJBFpUSadswDPbRimSgJUZuFwIEYs6AabkP038fA==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@swc/helpers": "^0.5.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 12"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@reduxjs/toolkit": {
|
||||
"version": "2.2.7",
|
||||
"resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.2.7.tgz",
|
||||
|
@ -693,6 +720,48 @@
|
|||
"node": ">=14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@restart/hooks": {
|
||||
"version": "0.4.16",
|
||||
"resolved": "https://registry.npmjs.org/@restart/hooks/-/hooks-0.4.16.tgz",
|
||||
"integrity": "sha512-f7aCv7c+nU/3mF7NWLtVVr0Ra80RqsO89hO72r+Y/nvQr5+q0UFGkocElTH6MJApvReVh6JHUFYn2cw1WdHF3w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"dequal": "^2.0.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=16.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@restart/ui": {
|
||||
"version": "1.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@restart/ui/-/ui-1.8.0.tgz",
|
||||
"integrity": "sha512-xJEOXUOTmT4FngTmhdjKFRrVVF0hwCLNPdatLCHkyS4dkiSK12cEu1Y0fjxktjJrdst9jJIc5J6ihMJCoWEN/g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.21.0",
|
||||
"@popperjs/core": "^2.11.6",
|
||||
"@react-aria/ssr": "^3.5.0",
|
||||
"@restart/hooks": "^0.4.9",
|
||||
"@types/warning": "^3.0.0",
|
||||
"dequal": "^2.0.3",
|
||||
"dom-helpers": "^5.2.0",
|
||||
"uncontrollable": "^8.0.1",
|
||||
"warning": "^4.0.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=16.14.0",
|
||||
"react-dom": ">=16.14.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@restart/ui/node_modules/uncontrollable": {
|
||||
"version": "8.0.4",
|
||||
"resolved": "https://registry.npmjs.org/uncontrollable/-/uncontrollable-8.0.4.tgz",
|
||||
"integrity": "sha512-ulRWYWHvscPFc0QQXvyJjY6LIXU56f0h8pQFvhxiKk5V1fcI8gp9Ht9leVAhrVjzqMw0BgjspBINx9r6oyJUvQ==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"react": ">=16.14.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-x64-msvc": {
|
||||
"version": "4.21.0",
|
||||
"cpu": [
|
||||
|
@ -705,6 +774,15 @@
|
|||
"win32"
|
||||
]
|
||||
},
|
||||
"node_modules/@swc/helpers": {
|
||||
"version": "0.5.13",
|
||||
"resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.13.tgz",
|
||||
"integrity": "sha512-UoKGxQ3r5kYI9dALKJapMmuK+1zWM/H17Z1+iwnNmzcJRnfFuevZs375TA5rW31pu4BS4NoSy1fRsexDXfWn5w==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"tslib": "^2.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/babel__core": {
|
||||
"version": "7.20.5",
|
||||
"dev": true,
|
||||
|
@ -766,12 +844,27 @@
|
|||
"@types/react": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/react-transition-group": {
|
||||
"version": "4.4.11",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.11.tgz",
|
||||
"integrity": "sha512-RM05tAniPZ5DZPzzNFP+DmrcOdD0efDUxMy3145oljWSl3x9ZV5vhme98gTxFrj2lhXvmGNnUiuDyJgY9IKkNA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/react": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/use-sync-external-store": {
|
||||
"version": "0.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz",
|
||||
"integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/warning": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/warning/-/warning-3.0.3.tgz",
|
||||
"integrity": "sha512-D1XC7WK8K+zZEveUPY+cf4+kgauk8N4eHr/XIHXGlGYkHLud6hK9lYfZk1ry1TNh798cZUCgb6MqGEG8DkJt6Q==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@vitejs/plugin-react": {
|
||||
"version": "4.3.1",
|
||||
"dev": true,
|
||||
|
@ -1135,6 +1228,12 @@
|
|||
"url": "https://github.com/chalk/chalk?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/classnames": {
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz",
|
||||
"integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/clsx": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
|
||||
|
@ -1326,6 +1425,15 @@
|
|||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/dequal": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz",
|
||||
"integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/doctrine": {
|
||||
"version": "2.1.0",
|
||||
"dev": true,
|
||||
|
@ -1337,6 +1445,16 @@
|
|||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/dom-helpers": {
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz",
|
||||
"integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.8.7",
|
||||
"csstype": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/dotenv": {
|
||||
"version": "16.4.5",
|
||||
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz",
|
||||
|
@ -2171,6 +2289,15 @@
|
|||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/invariant": {
|
||||
"version": "2.2.4",
|
||||
"resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
|
||||
"integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/is-array-buffer": {
|
||||
"version": "3.0.4",
|
||||
"dev": true,
|
||||
|
@ -3018,6 +3145,19 @@
|
|||
"react-is": "^16.13.1"
|
||||
}
|
||||
},
|
||||
"node_modules/prop-types-extra": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/prop-types-extra/-/prop-types-extra-1.1.1.tgz",
|
||||
"integrity": "sha512-59+AHNnHYCdiC+vMwY52WmvP5dM3QLeoumYuEyceQDi9aEhtwN9zIQ2ZNo25sMyXnbh32h+P1ezDsUpUH3JAew==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"react-is": "^16.3.2",
|
||||
"warning": "^4.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=0.14.0"
|
||||
}
|
||||
},
|
||||
"node_modules/proxy-from-env": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
|
||||
|
@ -3063,6 +3203,36 @@
|
|||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-bootstrap": {
|
||||
"version": "2.10.5",
|
||||
"resolved": "https://registry.npmjs.org/react-bootstrap/-/react-bootstrap-2.10.5.tgz",
|
||||
"integrity": "sha512-XueAOEn64RRkZ0s6yzUTdpFtdUXs5L5491QU//8ZcODKJNDLt/r01tNyriZccjgRImH1REynUc9pqjiRMpDLWQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.24.7",
|
||||
"@restart/hooks": "^0.4.9",
|
||||
"@restart/ui": "^1.6.9",
|
||||
"@types/react-transition-group": "^4.4.6",
|
||||
"classnames": "^2.3.2",
|
||||
"dom-helpers": "^5.2.1",
|
||||
"invariant": "^2.2.4",
|
||||
"prop-types": "^15.8.1",
|
||||
"prop-types-extra": "^1.1.0",
|
||||
"react-transition-group": "^4.4.5",
|
||||
"uncontrollable": "^7.2.1",
|
||||
"warning": "^4.0.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": ">=16.14.8",
|
||||
"react": ">=16.14.0",
|
||||
"react-dom": ">=16.14.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/react-dom": {
|
||||
"version": "18.3.1",
|
||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
|
||||
|
@ -3123,6 +3293,12 @@
|
|||
"version": "16.13.1",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/react-lifecycles-compat": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz",
|
||||
"integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/react-loading-icons": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/react-loading-icons/-/react-loading-icons-1.1.0.tgz",
|
||||
|
@ -3223,6 +3399,22 @@
|
|||
"react-dom": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/react-transition-group": {
|
||||
"version": "4.4.5",
|
||||
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz",
|
||||
"integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==",
|
||||
"license": "BSD-3-Clause",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.5.5",
|
||||
"dom-helpers": "^5.0.1",
|
||||
"loose-envify": "^1.4.0",
|
||||
"prop-types": "^15.6.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=16.6.0",
|
||||
"react-dom": ">=16.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/redux": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz",
|
||||
|
@ -3258,6 +3450,12 @@
|
|||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/regenerator-runtime": {
|
||||
"version": "0.14.1",
|
||||
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
|
||||
"integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/regexp.prototype.flags": {
|
||||
"version": "1.5.2",
|
||||
"dev": true,
|
||||
|
@ -3769,6 +3967,21 @@
|
|||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/uncontrollable": {
|
||||
"version": "7.2.1",
|
||||
"resolved": "https://registry.npmjs.org/uncontrollable/-/uncontrollable-7.2.1.tgz",
|
||||
"integrity": "sha512-svtcfoTADIB0nT9nltgjujTi7BzVmwjZClOmskKu/E8FW9BXzg9os8OLr4f8Dlnk0rYWJIWr4wv9eKUXiQvQwQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.6.3",
|
||||
"@types/react": ">=16.9.11",
|
||||
"invariant": "^2.2.4",
|
||||
"react-lifecycles-compat": "^3.0.4"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=15.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/update-browserslist-db": {
|
||||
"version": "1.1.0",
|
||||
"dev": true,
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
"primeicons": "^7.0.0",
|
||||
"prop-types": "^15.8.1",
|
||||
"react": "^18.3.1",
|
||||
"react-bootstrap": "^2.10.5",
|
||||
"react-dom": "^18.3.1",
|
||||
"react-file-base64": "^1.0.3",
|
||||
"react-icons": "^5.3.0",
|
||||
|
|
|
@ -2,17 +2,25 @@ import { useEffect, useState } from "react";
|
|||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { fetchPropertyById } from "../redux/features/propertySlice";
|
||||
import propertydummy from "../img/propertydummy.jpg"
|
||||
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 { useNavigate } from "react-router-dom";
|
||||
|
||||
const PropertyView = () => {
|
||||
const { id } = useParams(); // Extract the property ID from the route
|
||||
const dispatch = useDispatch();
|
||||
const { selectedProperty, status, error } = useSelector((state) => state.property);
|
||||
const navigate = useNavigate();
|
||||
const { selectedProperty, status, error } = useSelector(
|
||||
(state) => state.property
|
||||
);
|
||||
const { user } = useSelector((state) => ({ ...state.auth }));
|
||||
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
|
||||
|
@ -30,57 +38,136 @@ const PropertyView = () => {
|
|||
return <p>Error loading property: {error}</p>;
|
||||
}
|
||||
|
||||
// console.log("selectedProperty", selectedProperty);
|
||||
// Handle conditions for the "Willing to Invest/Fund" button and messages
|
||||
const isOwner = user?.result?.userId === selectedProperty?.userId;
|
||||
const isLoggedIn = !!user;
|
||||
|
||||
const handleShowModal = () => {
|
||||
setShowModal(true); // Show the modal
|
||||
};
|
||||
|
||||
const handleCloseModal = () => {
|
||||
setShowModal(false); // Close the modal
|
||||
};
|
||||
|
||||
// Inside your PropertyView component
|
||||
const handleSubmit = (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
const fundDetails = {
|
||||
propertyOwnerId: selectedProperty?.userId,
|
||||
investorId: user?.result?.userId,
|
||||
investmentAmount: fundValue,
|
||||
ownershipPercentage: fundPercentage,
|
||||
propertyId: selectedProperty?.propertyId || "defaultId", // Add a fallback
|
||||
};
|
||||
|
||||
dispatch(submitFundDetails({ fundDetails, id, navigate }));
|
||||
handleCloseModal(); // Close modal after submission
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
<Navbar />
|
||||
<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="container"> */}
|
||||
<div className="card-header bg-white">
|
||||
<div className="row">
|
||||
<div className="col-md-5 mt-3">
|
||||
<div className="bg-white border">
|
||||
{/* {selectedProperty.images && selectedProperty.images[0] && (
|
||||
<img
|
||||
src={selectedProperty.images[0].file || propertydummy}
|
||||
alt="Property Thumbnail"
|
||||
style={{ width: "100px", height: "auto" }}
|
||||
/>
|
||||
)} */}
|
||||
|
||||
<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",
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
|
||||
<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 />
|
||||
{/* "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>
|
||||
|
||||
<div className="col-md-7 mt-3">
|
||||
<div className="product-view">
|
||||
<h4
|
||||
|
@ -95,21 +182,27 @@ const PropertyView = () => {
|
|||
<hr />
|
||||
<p className="product-path">
|
||||
<span style={{ color: "#fda417", fontSize: "15px" }}>
|
||||
city:{" "}
|
||||
City:{" "}
|
||||
</span>{" "}
|
||||
{selectedProperty.city} /
|
||||
{selectedProperty.city}
|
||||
{" "} /{" "}
|
||||
{" "}
|
||||
{" "}
|
||||
<span style={{ color: "#fda417", fontSize: "15px" }}>
|
||||
County:{" "}
|
||||
</span>{" "}
|
||||
{selectedProperty.county} /
|
||||
{selectedProperty.county} {" "}/{" "}
|
||||
{" "}
|
||||
<span style={{ color: "#fda417", fontSize: "15px" }}>
|
||||
State:{" "}
|
||||
</span>{" "}
|
||||
{selectedProperty.state} /
|
||||
{selectedProperty.state} {" "}/ {" "}
|
||||
{" "}
|
||||
<span style={{ color: "#fda417", fontSize: "15px" }}>
|
||||
Zipcode:
|
||||
Zipcode:{" "}
|
||||
</span>{" "}
|
||||
{selectedProperty.zip}
|
||||
{" "}
|
||||
</p>
|
||||
<div>
|
||||
<span
|
||||
|
@ -137,20 +230,23 @@ const PropertyView = () => {
|
|||
{selectedProperty.yearBuild}
|
||||
</div>
|
||||
|
||||
<div className="mt-3 card bg-white">
|
||||
<h5 className="mb-0" style={{ color: "#fda417", fontSize: "15px" }}>
|
||||
Legal Description
|
||||
</h5>
|
||||
<span>
|
||||
{selectedProperty.legal
|
||||
? selectedProperty.legal
|
||||
: "No data available"}
|
||||
</span>
|
||||
</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">
|
||||
|
@ -183,13 +279,58 @@ const PropertyView = () => {
|
|||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<p>No property details found.</p>
|
||||
<p>No property found.</p>
|
||||
)}
|
||||
</div>
|
||||
<Footer />
|
||||
{/* Modal for Investment/Funding */}
|
||||
<Modal show={showModal} onHide={handleCloseModal}>
|
||||
<Modal.Header closeButton>
|
||||
<Modal.Title>Investment/Funding Details</Modal.Title>
|
||||
</Modal.Header>
|
||||
<Modal.Body>
|
||||
<Form onSubmit={handleSubmit}>
|
||||
<Form.Group controlId="fundValue">
|
||||
<Form.Label>Investment Amount ($)</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.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" }}
|
||||
>
|
||||
Submit
|
||||
</Button>
|
||||
{" "}
|
||||
|
||||
<Button
|
||||
variant="primary"
|
||||
onClick={handleCloseModal}
|
||||
style={{ backgroundColor: "#d80b0b", border: "#d80b0b" }}
|
||||
>
|
||||
close
|
||||
</Button>
|
||||
</Form>
|
||||
</Modal.Body>
|
||||
</Modal>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default PropertyView;
|
||||
export default PropertyView;
|
|
@ -140,7 +140,6 @@ useEffect(() => {
|
|||
<NavLink
|
||||
to={`/property/${property.propertyId}`}
|
||||
className="link-primary text-decoration-none"
|
||||
target="_blank"
|
||||
>
|
||||
{property.address}
|
||||
</NavLink>
|
||||
|
|
|
@ -91,7 +91,6 @@ const UserProperties = () => {
|
|||
<div className="d-flex flex-column mt-4">
|
||||
<NavLink
|
||||
to={`/property/${property.propertyId}`}
|
||||
target="_blank"
|
||||
>
|
||||
<button
|
||||
className="btn btn-outline-primary btn-sm mt-2"
|
||||
|
|
|
@ -26,6 +26,7 @@ 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);
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";
|
||||
import * as api from "../api";
|
||||
import { toast } from "react-toastify"; // Import toast here
|
||||
import axios from "axios";
|
||||
|
||||
export const submitFundDetails = createAsyncThunk(
|
||||
"fundDetails/submit",
|
||||
async ({ fundDetails,id,navigate }, { rejectWithValue }) => {
|
||||
try {
|
||||
const response = await api.submitFundDetails(fundDetails, id);
|
||||
toast.success("Details submitted successfully"); // Show toast on success
|
||||
navigate(`/property/${id}`); // Navigate after successful submission
|
||||
return response.data; // Assuming you return JSON data
|
||||
} catch (error) {
|
||||
toast.error("Failed to submit details"); // Show error toast
|
||||
return rejectWithValue(error.response.data);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
export const getFundDetailsById = createAsyncThunk(
|
||||
"fundDetails/getFundDetailsById",
|
||||
async (id, { rejectWithValue }) => {
|
||||
try {
|
||||
const response = await axios.get(`http://localhost:3002/fundDetails/${id}`);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
return rejectWithValue(error.response.data);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
const fundDetailsSlice = createSlice({
|
||||
name: "fundDetails",
|
||||
initialState: {
|
||||
fundDetails: null,
|
||||
status: null,
|
||||
error: null,
|
||||
},
|
||||
reducers: {},
|
||||
extraReducers: (builder) => {
|
||||
builder
|
||||
.addCase(getFundDetailsById.pending, (state) => {
|
||||
state.status = "loading";
|
||||
})
|
||||
.addCase(getFundDetailsById.fulfilled, (state, action) => {
|
||||
state.status = "succeeded";
|
||||
state.fundDetails = action.payload;
|
||||
})
|
||||
.addCase(getFundDetailsById.rejected, (state, action) => {
|
||||
state.status = "failed";
|
||||
state.error = action.payload;
|
||||
})
|
||||
.addCase(submitFundDetails.fulfilled, (state, action) => {
|
||||
state.fundDetails = action.payload;
|
||||
})
|
||||
.addCase(submitFundDetails.rejected, (state, action) => {
|
||||
state.error = action.payload;
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
export default fundDetailsSlice.reducer;
|
|
@ -2,12 +2,13 @@ import { configureStore } from "@reduxjs/toolkit";
|
|||
import AuthReducer from "./features/authSlice";
|
||||
import userReducer from "./features/userSlice";
|
||||
import propertyReducer from "./features/propertySlice";
|
||||
import fundReducer from "./features/fundDetailsSlice"
|
||||
|
||||
export default configureStore({
|
||||
reducer: {
|
||||
auth: AuthReducer,
|
||||
user: userReducer,
|
||||
property: propertyReducer,
|
||||
|
||||
fundDetails:fundReducer,
|
||||
},
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue