This commit is contained in:
omkieit 2024-10-23 23:16:58 +05:30
parent d02de3dafa
commit 5a1f3d8e7a
17 changed files with 294 additions and 243 deletions

View File

@ -1,47 +0,0 @@
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 });
}
};
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,10 +80,8 @@ 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("fundDetails", fundDetails);
const { fundValue, fundPercentage } = req.body;
try {
// Find the property by propertyId instead of _id
@ -93,6 +91,17 @@ export const updatePropertyById = async (req, res) => {
{ new: true }
);
// Push the new fund details into the existing fundDetails array
updatedProperty.fundDetails.push({
fundValue,
fundPercentage,
});
// Save the updated document
await updatedProperty.save();
console.log("Received propertyId:", updatedProperty); // Log the received propertyId
if (!updatedProperty) {
return res.status(404).json({ message: "Property not found" });
}
@ -104,6 +113,72 @@ export const updatePropertyById = async (req, res) => {
}
};
// Function to update fundDetails
export const addFundDetails = async (req, res) => {
const { id } = req.params; // This should be the propertyId
const { fundValue, fundPercentage } = req.body;
console.log("d", id, { fundValue, fundPercentage });
try {
// Change findById to findOne with the correct field name
const property = await PropertyModal.findOne({ propertyId: id });
if (!property) {
return res.status(404).json({ message: 'Property not found' });
}
// Create new fund detail
const newFundDetail = {
fundValue,
fundPercentage,
};
// Add new fund detail to fundDetails array
property.fundDetails.push(newFundDetail);
// Save updated property
await property.save();
// Return success response with updated property
res.status(200).json({ message: 'Fund details added', property });
} catch (error) {
console.error("Error adding fund details:", error); // Log error for debugging
res.status(500).json({ message: error.message });
}
};
// Getting funds from the DB
export const getFundDetails = async (req, res) => {
const { id } = req.params; // Property ID
try {
const property = await PropertyModal.findOne({ propertyId: id }, 'fundDetails');
if (!property) {
return res.status(404).json({ message: 'Property not found' });
}
// Return fund details
res.status(200).json({ fundDetails: property.fundDetails });
} catch (error) {
console.error("Error fetching fund details:", error);
res.status(500).json({ message: error.message });
}
};
// export const getProperties = async (req, res) => {
// try {
// const properties = await PropertyModal.find(); // Fetch all properties from MongoDB

View File

@ -7,7 +7,6 @@ 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();
@ -35,7 +34,6 @@ app.use(
app.use("/users", userRouter);
app.use("/properties", propertyRouter);
app.use("/mysql", mysqlRouter); // Use MySQL routes
app.use("/fundDetails", fundDetailsRouter);

View File

@ -1,30 +0,0 @@
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,
},
status: { type: Boolean, default: false },
}, { timestamps: true });
const FundDetailsModal = mongoose.model("FundDetails", fundDetailsSchema);
export default FundDetailsModal;

View File

@ -8,6 +8,7 @@ const propertyTaxInfoSchema = mongoose.Schema({
taxyear: { type: String },
});
// Schema for images
const imageSchema = mongoose.Schema({
title: { type: String }, // Title of the image
@ -302,7 +303,18 @@ const propertySchema = mongoose.Schema({
type: Number,
required: true, // Set to true if this field is mandatory
},
fundDetails:[],
fundDetails: [
{
fundValue: {
type: Number, // Adjust type if needed (String or Number)
required: true,
},
fundPercentage: {
type: Number, // Adjust type if needed
required: true,
},
},
],
});
const PropertyModal = mongoose.model("property", propertySchema);

View File

@ -1,12 +0,0 @@
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;

View File

@ -1,12 +1,22 @@
import express from 'express';
import express from "express";
const router = express.Router();
import auth from '../middleware/auth.js';
import { createProperty, getUserProperties, getPropertyById, updatePropertyById, getProperties} from '../controllers/property.js';
import auth from "../middleware/auth.js";
import {
createProperty,
getUserProperties,
getPropertyById,
updatePropertyById,
getProperties,
addFundDetails,
getFundDetails,
} from "../controllers/property.js";
router.post('/', auth, createProperty);
router.get('/user/:userId', getUserProperties);
router.get('/:propertyId', getPropertyById);
router.post("/", auth, createProperty);
router.get("/user/:userId", getUserProperties);
router.get("/:propertyId", getPropertyById);
router.put("/:id", updatePropertyById);
router.get('/', getProperties);
router.get("/", getProperties);
router.put("/:id/fund-details", addFundDetails);
router.get("/:id/fund-details", getFundDetails);
export default router;

View File

@ -3,8 +3,8 @@ const router = express.Router();
import { signup, signin, verifyUser, showUser, forgotPassword, resetPassword, updateUser } from "../controllers/user.js";
router.post("/signin", signin);
router.post("/signup", signup);
router.post("/signin", signin);
router.get('/:id/verify/:token/', verifyUser);
router.get('/:userId', showUser);
router.post("/forgotpassword", forgotPassword);

File diff suppressed because one or more lines are too long

View File

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

View File

@ -6,50 +6,58 @@ 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,
getFundDetailsById,
} from "../redux/features/fundDetailsSlice";
import { useNavigate } from "react-router-dom";
import { addFundDetails } from "../redux/features/propertySlice";
import { toast } from "react-toastify";
import { fetchFundDetails} from "../redux/features/fundSlice";
const PropertyView = () => {
const { id } = useParams(); // Extract the property ID from the route
const dispatch = useDispatch();
const navigate = useNavigate();
const { selectedProperty, status, error } = useSelector(
(state) => state.property
);
const { user } = useSelector((state) => ({ ...state.auth }));
const { fundDetails } = useSelector((state) => state.fundDetails);
console.log("funddetails", fundDetails);
// This also works !!
// const fundDetails = useSelector(selectFundDetails);
// console.log("fundDetailsa", fundDetails)
const {fundDetails} = useSelector((state) => state.fundDetails);
useEffect(() => {
dispatch(fetchFundDetails(id));
}, [dispatch, id]);
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
const [formData, setFormData] = useState({
fundValue: "0",
fundPercentage: "0",
});
useEffect(() => {
if (id) {
dispatch(fetchPropertyById(id));
dispatch(getFundDetailsById(id));
}
}, [id, dispatch]);
useEffect(() => {
dispatch(fetchFundDetails(id));
}, [dispatch, id]);
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>;
// }
@ -70,24 +78,24 @@ const PropertyView = () => {
setShowModal(false); // Close the modal
};
// Inside your PropertyView component
const handleChange = (e) => {
const { name, value } = e.target;
setFormData({
...formData,
[name]: value,
});
};
const handleSubmit = (e) => {
e.preventDefault();
if (fundValue <= 0 || fundPercentage <= 0 || fundPercentage > 100) {
alert("Please enter valid values.");
return;
}
const fundDetails = {
propertyOwnerId: selectedProperty?.userId,
investorId: user?.result?.userId,
investmentAmount: fundValue,
ownershipPercentage: fundPercentage,
propertyId: selectedProperty?.propertyId || "defaultId", // Add a fallback
fundValue: Number(formData.fundValue), // Ensure number conversion if needed
fundPercentage: Number(formData.fundPercentage),
};
dispatch(submitFundDetails({ fundDetails, id, navigate }));
handleCloseModal(); // Close modal after submission
dispatch(addFundDetails({ id, fundDetails, toast }));
handleCloseModal();
};
return (
@ -381,18 +389,44 @@ const PropertyView = () => {
<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>
{selectedProperty.fundDetails.length === 0 ? (
<p>No fund details available.</p>
) : (
<ul>
{selectedProperty.fundDetails.map((detail, index) => (
<li key={index}>
Fund Value: {detail.fundValue}, Fund Percentage: {detail.fundPercentage}%
</li>
))}
</ul>
)}
{fundDetails.length === 0 ? (
<p>No fund details available.</p>
) : (
<ul>
{fundDetails.map((detail, index) => (
<li key={index}>
Fund Value: {detail.fundValue}, Fund Percentage: {detail.fundPercentage}%
</li>
))}
</ul>
)}
</div>
</div>
)}
</div>
)}
@ -401,6 +435,7 @@ const PropertyView = () => {
</div>
<Footer />
{/* Modal for Investment/Funding */}
{/* Modal for Investment/Funding */}
<Modal show={showModal} onHide={handleCloseModal}>
<Modal.Header closeButton>
<Modal.Title>Investment/Funding Details</Modal.Title>
@ -411,16 +446,20 @@ const PropertyView = () => {
<Form.Label>Fund Value</Form.Label>
<Form.Control
type="number"
value={fundValue}
onChange={(e) => setFundValue(e.target.value)}
id="fundValue"
name="fundValue" // Added the name attribute
value={formData.fundValue}
onChange={handleChange}
/>
</Form.Group>
<Form.Group>
<Form.Label>Fund Percentage</Form.Label>
<Form.Control
type="number"
value={fundPercentage}
onChange={(e) => setFundPercentage(e.target.value)}
id="fundPercentage"
name="fundPercentage" // Added the name attribute
value={formData.fundPercentage}
onChange={handleChange}
/>
</Form.Group>
<Button variant="primary" type="submit">
@ -433,4 +472,4 @@ const PropertyView = () => {
);
};
export default PropertyView;
export default PropertyView;

View File

@ -25,9 +25,9 @@ export const submitProperty = (propertyData) => API.post("/properties", property
export const fetchUserProperties = (userId, page, limit) => API.get( `/properties/user/${userId}?page=${page}&limit=${limit}`, userId);
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 = (fundDetailsArray) => API.post(`/fundDetails`, fundDetailsArray);
export const getFundDetailsById = (fundDetails) => API.post(`/fundDetails`, fundDetails);

View File

@ -24,6 +24,7 @@ export const register = createAsyncThunk(
async ({ formValue, navigate, toast }, { rejectWithValue }) => {
try {
const response = await api.signUp(formValue);
console.log("response", response)
toast.success("Register Successfully");
navigate("/registrationsuccess");
return response.data;

View File

@ -1,65 +0,0 @@
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;

View File

@ -0,0 +1,45 @@
// fundDetailsSlice.js
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit';
import axios from 'axios';
export const fetchFundDetails = createAsyncThunk(
'fundDetails/fetchFundDetails',
async (id, { rejectWithValue }) => {
try {
const response = await axios.get(`http://localhost:3002/properties/${id}/fund-details`);
return response.data.fundDetails;
} catch (error) {
return rejectWithValue(error.response.data);
}
}
);
const fundDetailsSlice = createSlice({
name: 'fundDetails',
initialState: {
fundDetails: [],
loading: false,
error: null,
},
reducers: {},
extraReducers: (builder) => {
builder
.addCase(fetchFundDetails.pending, (state) => {
state.loading = true;
})
.addCase(fetchFundDetails.fulfilled, (state, action) => {
state.loading = false;
state.fundDetails = action.payload;
})
.addCase(fetchFundDetails.rejected, (state, action) => {
state.loading = false;
state.error = action.payload;
});
},
});
export const selectFundDetails = (state) => state.fundDetails.fundDetails;
export const selectLoading = (state) => state.fundDetails.loading;
export const selectError = (state) => state.fundDetails.error;
export default fundDetailsSlice.reducer;

View File

@ -58,14 +58,27 @@ export const updateProperty = createAsyncThunk(
try {
const response = await api.updateProperty(id, propertyData);
return response.data;
} catch (error) {
return rejectWithValue(error.response.data);
}
}
);
export const addFundDetails = createAsyncThunk(
'property/addFundDetails',
async ({ id, fundDetails, toast }, { rejectWithValue }) => {
try {
const response = await axios.put(
`http://localhost:3002/properties/${id}/fund-details`,
fundDetails);
toast.success("Submitted Successfully");
return response.data;
} catch (error) {
return rejectWithValue(error.response.data);
}
}
);
// export const getProperties = createAsyncThunk("property/getProperties", async () => {
@ -168,9 +181,17 @@ const propertySlice = createSlice({
state.loading = false;
state.error = action.error.message;
})
;
.addCase(addFundDetails.pending, (state) => {
state.loading = true;
})
.addCase(addFundDetails.fulfilled, (state, action) => {
state.loading = false;
state.property = action.payload.property;
})
.addCase(addFundDetails.rejected, (state, action) => {
state.loading = false;
state.error = action.payload;
});
},
});

View File

@ -2,13 +2,17 @@ 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"
import fundDetailsReducer from "./features/fundSlice";
export default configureStore({
reducer: {
auth: AuthReducer,
user: userReducer,
property: propertyReducer,
fundDetails:fundReducer,
fundDetails: fundDetailsReducer,
},
});