done
This commit is contained in:
parent
ccb1dcbb9e
commit
0593f510af
|
@ -5,7 +5,7 @@ import mongoose from "mongoose";
|
||||||
|
|
||||||
export const createProperty = async (req, res) => {
|
export const createProperty = async (req, res) => {
|
||||||
const propertyData = req.body;
|
const propertyData = req.body;
|
||||||
console.log('Property received:', propertyData);
|
console.log("Property received:", propertyData);
|
||||||
function generateRandomNumber() {
|
function generateRandomNumber() {
|
||||||
return Math.floor(Math.random() * 90000) + 10000;
|
return Math.floor(Math.random() * 90000) + 10000;
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@ export const createProperty = async (req, res) => {
|
||||||
propertyId: propertyId,
|
propertyId: propertyId,
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log('newProperty received:', newProperty);
|
console.log("newProperty received:", newProperty);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await newProperty.save();
|
await newProperty.save();
|
||||||
|
@ -63,17 +63,6 @@ export const getUserProperties = async (req, res) => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Fetch property by ID.. which is property view page
|
// Fetch property by ID.. which is property view page
|
||||||
export const getPropertyById = async (req, res) => {
|
export const getPropertyById = async (req, res) => {
|
||||||
const { propertyId } = req.params;
|
const { propertyId } = req.params;
|
||||||
|
@ -118,13 +107,12 @@ export const updatePropertyById = async (req, res) => {
|
||||||
res.status(200).json(updatedProperty);
|
res.status(200).json(updatedProperty);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error updating property:", error.message);
|
console.error("Error updating property:", error.message);
|
||||||
res.status(500).json({ message: "Failed to update property", error: error.message });
|
res
|
||||||
|
.status(500)
|
||||||
|
.json({ message: "Failed to update property", error: error.message });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Function to update fundDetails
|
// Function to update fundDetails
|
||||||
export const addFundDetails = async (req, res) => {
|
export const addFundDetails = async (req, res) => {
|
||||||
const { id } = req.params; // This should be the propertyId
|
const { id } = req.params; // This should be the propertyId
|
||||||
|
@ -137,14 +125,14 @@ export const addFundDetails = async (req, res) => {
|
||||||
const property = await PropertyModal.findOne({ propertyId: id });
|
const property = await PropertyModal.findOne({ propertyId: id });
|
||||||
|
|
||||||
if (!property) {
|
if (!property) {
|
||||||
return res.status(404).json({ message: 'Property not found' });
|
return res.status(404).json({ message: "Property not found" });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create new fund detail
|
// Create new fund detail
|
||||||
const newFundDetail = {
|
const newFundDetail = {
|
||||||
fundValue,
|
fundValue,
|
||||||
fundPercentage,
|
fundPercentage,
|
||||||
userId
|
userId,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Add new fund detail to fundDetails array
|
// Add new fund detail to fundDetails array
|
||||||
|
@ -154,15 +142,13 @@ export const addFundDetails = async (req, res) => {
|
||||||
await property.save();
|
await property.save();
|
||||||
|
|
||||||
// Return success response with updated property
|
// Return success response with updated property
|
||||||
res.status(200).json({ message: 'Fund details added', property });
|
res.status(200).json({ message: "Fund details added", property });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error adding fund details:", error); // Log error for debugging
|
console.error("Error adding fund details:", error); // Log error for debugging
|
||||||
res.status(500).json({ message: error.message });
|
res.status(500).json({ message: error.message });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export const deleteFundDetail = async (req, res) => {
|
export const deleteFundDetail = async (req, res) => {
|
||||||
const { id, fundDetailId } = req.params;
|
const { id, fundDetailId } = req.params;
|
||||||
const userId = req.userId;
|
const userId = req.userId;
|
||||||
|
@ -175,44 +161,46 @@ export const deleteFundDetail = async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const property = await PropertyModal.findOne({ propertyId: id });
|
const property = await PropertyModal.findOne({ propertyId: id });
|
||||||
if (!property) {
|
if (!property) {
|
||||||
return res.status(404).json({ message: 'Property not found' });
|
return res.status(404).json({ message: "Property not found" });
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log("Fund Details:", property.fundDetails);
|
console.log("Fund Details:", property.fundDetails);
|
||||||
|
|
||||||
const fundDetailIndex = property.fundDetails.findIndex(
|
const fundDetailIndex = property.fundDetails.findIndex(
|
||||||
(detail) => detail._id.toString() === fundDetailId && detail.userId.toString() === userId
|
(detail) =>
|
||||||
|
detail._id.toString() === fundDetailId &&
|
||||||
|
detail.userId.toString() === userId
|
||||||
);
|
);
|
||||||
|
|
||||||
console.log("Fund Detail Index:", fundDetailIndex);
|
console.log("Fund Detail Index:", fundDetailIndex);
|
||||||
if (fundDetailIndex === -1) {
|
if (fundDetailIndex === -1) {
|
||||||
return res.status(403).json({ message: 'Not authorized to delete this fund detail' });
|
return res
|
||||||
|
.status(403)
|
||||||
|
.json({ message: "Not authorized to delete this fund detail" });
|
||||||
}
|
}
|
||||||
|
|
||||||
property.fundDetails.splice(fundDetailIndex, 1);
|
property.fundDetails.splice(fundDetailIndex, 1);
|
||||||
await property.save();
|
await property.save();
|
||||||
|
|
||||||
res.status(200).json({ message: 'Fund detail deleted', property });
|
res.status(200).json({ message: "Fund detail deleted", property });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error deleting fund detail:", error);
|
console.error("Error deleting fund detail:", error);
|
||||||
res.status(500).json({ message: error.message });
|
res.status(500).json({ message: error.message });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Getting funds from the DB
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Getting funds from the DB
|
|
||||||
export const getFundDetails = async (req, res) => {
|
export const getFundDetails = async (req, res) => {
|
||||||
const { id } = req.params; // Property ID
|
const { id } = req.params; // Property ID
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const property = await PropertyModal.findOne({ propertyId: id }, 'fundDetails');
|
const property = await PropertyModal.findOne(
|
||||||
|
{ propertyId: id },
|
||||||
|
"fundDetails"
|
||||||
|
);
|
||||||
|
|
||||||
if (!property) {
|
if (!property) {
|
||||||
return res.status(404).json({ message: 'Property not found' });
|
return res.status(404).json({ message: "Property not found" });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return fund details
|
// Return fund details
|
||||||
|
@ -223,8 +211,6 @@ export const getFundDetails = async (req, res) => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// export const getProperties = async (req, res) => {
|
// export const getProperties = async (req, res) => {
|
||||||
// try {
|
// try {
|
||||||
// const properties = await PropertyModal.find(); // Fetch all properties from MongoDB
|
// const properties = await PropertyModal.find(); // Fetch all properties from MongoDB
|
||||||
|
@ -234,7 +220,6 @@ export const getFundDetails = async (req, res) => {
|
||||||
// }
|
// }
|
||||||
// };
|
// };
|
||||||
|
|
||||||
|
|
||||||
// export const getProperties = async (req, res) => {
|
// export const getProperties = async (req, res) => {
|
||||||
// try {
|
// try {
|
||||||
// const { page = 1, limit = 10 } = req.query;
|
// const { page = 1, limit = 10 } = req.query;
|
||||||
|
@ -256,7 +241,6 @@ export const getFundDetails = async (req, res) => {
|
||||||
// }
|
// }
|
||||||
// };
|
// };
|
||||||
|
|
||||||
|
|
||||||
export const getProperties = async (req, res) => {
|
export const getProperties = async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const { page = 1, limit = 10, keyword = "" } = req.query;
|
const { page = 1, limit = 10, keyword = "" } = req.query;
|
||||||
|
@ -280,10 +264,6 @@ export const getProperties = async (req, res) => {
|
||||||
currentPage: parseInt(page),
|
currentPage: parseInt(page),
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
res.status(500).json({ success: false, message: 'Server error' });
|
res.status(500).json({ success: false, message: "Server error" });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -318,7 +318,18 @@ const propertySchema = mongoose.Schema({
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
TradesinRenovations:[
|
||||||
|
{
|
||||||
|
title: {
|
||||||
|
type: String,
|
||||||
|
required: true, // Set to true if this field is mandatory
|
||||||
|
},
|
||||||
|
price: {
|
||||||
|
type: Number,
|
||||||
|
required: true, // Set to true if this field is mandatory
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
IAB:[
|
IAB:[
|
||||||
{
|
{
|
||||||
title: {
|
title: {
|
||||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -54,7 +54,7 @@
|
||||||
<!-- Custom styles for this template-->
|
<!-- Custom styles for this template-->
|
||||||
<link href="css/sb-admin-2.min.css" rel="stylesheet">
|
<link href="css/sb-admin-2.min.css" rel="stylesheet">
|
||||||
|
|
||||||
<script type="module" crossorigin src="/assets/index-Ta_ndD8p.js"></script>
|
<script type="module" crossorigin src="/assets/index-w0FWAEFq.js"></script>
|
||||||
<link rel="stylesheet" crossorigin href="/assets/index-CN6EriED.css">
|
<link rel="stylesheet" crossorigin href="/assets/index-CN6EriED.css">
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
|
|
|
@ -127,10 +127,28 @@ const Addproperty = () => {
|
||||||
InsuranceClaim: "0",
|
InsuranceClaim: "0",
|
||||||
LongTermRental: "0",
|
LongTermRental: "0",
|
||||||
FinancingCostClosingCost: "0",
|
FinancingCostClosingCost: "0",
|
||||||
|
TradesinRenovations: [
|
||||||
|
{ title: "Planning & Design", price: "0" },
|
||||||
|
{ title: "Demolition & Cleanup", price: "0" },
|
||||||
|
{ title: "Framing", price: "0" },
|
||||||
|
{ title: "Rough-in Services", price: "0" },
|
||||||
|
{ title: "Structural Repairs", price: "0" },
|
||||||
|
{ title: "Insulation & Drywall", price: "0" },
|
||||||
|
{ title: "Cabinetry & Countertops", price: "0" },
|
||||||
|
{ title: "Fixtures & Appliances", price: "0" },
|
||||||
|
{ title: "Flooring and Tiling", price: "0" },
|
||||||
|
{ title: "Plumbing", price: "0" },
|
||||||
|
{ title: "Electrical", price: "0" },
|
||||||
|
{ title: "HVAC", price: "0" },
|
||||||
|
{ title: "Painting", price: "0" },
|
||||||
|
{ title: "Interior Finishes", price: "0" },
|
||||||
|
{ title: "Exterior Work", price: "0" },
|
||||||
|
{ title: "Final Inspections", price: "0" },
|
||||||
|
{ title: "Punch List", price: "0" },
|
||||||
|
{ title: "Staging", price: "0" },
|
||||||
|
],
|
||||||
IAB: [{ title: "IAB Title", URL: "Please enter URL" }],
|
IAB: [{ title: "IAB Title", URL: "Please enter URL" }],
|
||||||
files: [{ title: "", file: "" }],
|
files: [{ title: "", file: "" }],
|
||||||
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const [submitted, setSubmitted] = useState(false);
|
const [submitted, setSubmitted] = useState(false);
|
||||||
|
@ -894,7 +912,8 @@ const Addproperty = () => {
|
||||||
formData.OtherIncome &&
|
formData.OtherIncome &&
|
||||||
formData.InsuranceClaim &&
|
formData.InsuranceClaim &&
|
||||||
formData.LongTermRental &&
|
formData.LongTermRental &&
|
||||||
formData.FinancingCostClosingCost
|
formData.FinancingCostClosingCost &&
|
||||||
|
formData.TradesinRenovations
|
||||||
) {
|
) {
|
||||||
const rateofreturn = calculaterateofreturn();
|
const rateofreturn = calculaterateofreturn();
|
||||||
const totalPurchaseCosts = calculateTotalPurchaseCosts();
|
const totalPurchaseCosts = calculateTotalPurchaseCosts();
|
||||||
|
@ -1014,6 +1033,59 @@ const Addproperty = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const addTrade = () => {
|
||||||
|
setFormData((prevData) => ({
|
||||||
|
...prevData,
|
||||||
|
TradesinRenovations: [...prevData.TradesinRenovations, { title: "", price: "" }],
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
const deleteTrade = (index) => {
|
||||||
|
const updatedCosts = formData.TradesinRenovations.filter((_, i) => i !== index);
|
||||||
|
setFormData((prevData) => ({
|
||||||
|
...prevData,
|
||||||
|
TradesinRenovations: updatedCosts,
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
// Function to handle changes to title and price
|
||||||
|
const handleTrade = (index, field, value) => {
|
||||||
|
const updatedCosts = [...formData.TradesinRenovations];
|
||||||
|
updatedCosts[index][field] = value;
|
||||||
|
setFormData((prevData) => ({
|
||||||
|
...prevData,
|
||||||
|
TradesinRenovations: updatedCosts,
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleTradePrice = (e, index) => {
|
||||||
|
let value = e.target.value;
|
||||||
|
|
||||||
|
// Remove the dollar sign before validating
|
||||||
|
value = value.replace(/^\$/, "").trim(); // Remove '$' if it exists
|
||||||
|
|
||||||
|
// Use a regular expression to allow only numbers and decimals
|
||||||
|
const isNumber = /^\d*\.?\d*$/.test(value);
|
||||||
|
|
||||||
|
// If valid number, update state, otherwise show the alert
|
||||||
|
if (isNumber || value === "") {
|
||||||
|
const updatedCosts = formData.TradesinRenovations.map((cost, i) =>
|
||||||
|
i === index
|
||||||
|
? { ...cost, price: value, isInvalid: false } // Reset isInvalid if valid number
|
||||||
|
: cost
|
||||||
|
);
|
||||||
|
setFormData({ ...formData, TradesinRenovations: updatedCosts });
|
||||||
|
} else {
|
||||||
|
const updatedCosts = formData.TradesinRenovations.map((cost, i) =>
|
||||||
|
i === index
|
||||||
|
? { ...cost, isInvalid: true } // Keep isInvalid true for invalid input
|
||||||
|
: cost
|
||||||
|
);
|
||||||
|
setFormData({ ...formData, TradesinRenovations: updatedCosts });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -4098,6 +4170,94 @@ const Addproperty = () => {
|
||||||
<div role="tabpanel" className="card tab-pane active">
|
<div role="tabpanel" className="card tab-pane active">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<span
|
||||||
|
style={{
|
||||||
|
color: "#fda417",
|
||||||
|
fontSize: "14px",
|
||||||
|
fontWeight: "bold",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Trades in Renovations
|
||||||
|
</span>
|
||||||
|
|
||||||
|
{formData.TradesinRenovations.map((title, index) => (
|
||||||
|
<div key={index} className="row gy-3 align-items-center">
|
||||||
|
<div className="col-md-4">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
className="form-control"
|
||||||
|
value={title.title}
|
||||||
|
onChange={(e) =>
|
||||||
|
handleTrade(index, "title", e.target.value)
|
||||||
|
}
|
||||||
|
placeholder="Title"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="col-md-4">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
className={`form-control ${
|
||||||
|
title.isInvalid ? "is-invalid" : ""
|
||||||
|
}`}
|
||||||
|
value={`$ ${title.price}`}
|
||||||
|
onChange={(e) => handleTradePrice(e, index)}
|
||||||
|
placeholder="Price"
|
||||||
|
style={{ textAlign: "right" }}
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
{title.isInvalid && (
|
||||||
|
<div className="invalid-feedback">
|
||||||
|
Please enter a valid number.
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className="col-md-2 d-flex justify-content-start">
|
||||||
|
<button
|
||||||
|
className="btn btn-danger"
|
||||||
|
onClick={() => deleteTrade(index)}
|
||||||
|
style={{ marginLeft: "5px" }}
|
||||||
|
>
|
||||||
|
x
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div className="col-md-4">
|
||||||
|
<button
|
||||||
|
onClick={addTrade}
|
||||||
|
className="btn btn-primary back"
|
||||||
|
style={{ backgroundColor: "#fda417", border: "#fda417" }}
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
style={{
|
||||||
|
fontSize: "20px",
|
||||||
|
fontWeight: "normal",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
+
|
||||||
|
</span>{" "}
|
||||||
|
Add Trades in Renovations
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<hr
|
||||||
|
style={{
|
||||||
|
borderColor: "#fda417", // Set the color of the line
|
||||||
|
borderWidth: "1px", // Optional: Adjust the thickness of the line
|
||||||
|
backgroundColor: "#fda417", // Optional: Apply color if using for background
|
||||||
|
height: "1px", // Optional: Set height to match the border width
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<span
|
<span
|
||||||
style={{
|
style={{
|
||||||
color: "#fda417",
|
color: "#fda417",
|
||||||
|
|
|
@ -132,6 +132,26 @@ const EditProperty = () => {
|
||||||
InsuranceClaim: "0",
|
InsuranceClaim: "0",
|
||||||
LongTermRental: "0",
|
LongTermRental: "0",
|
||||||
FinancingCostClosingCost: "0",
|
FinancingCostClosingCost: "0",
|
||||||
|
TradesinRenovations: [
|
||||||
|
{ title: "Planning & Design", price: "0" },
|
||||||
|
{ title: "Demolition & Cleanup", price: "0" },
|
||||||
|
{ title: "Framing", price: "0" },
|
||||||
|
{ title: "Rough-in Services", price: "0" },
|
||||||
|
{ title: "Structural Repairs", price: "0" },
|
||||||
|
{ title: "Insulation & Drywall", price: "0" },
|
||||||
|
{ title: "Cabinetry & Countertops", price: "0" },
|
||||||
|
{ title: "Fixtures & Appliances", price: "0" },
|
||||||
|
{ title: "Flooring and Tiling", price: "0" },
|
||||||
|
{ title: "Plumbing", price: "0" },
|
||||||
|
{ title: "Electrical", price: "0" },
|
||||||
|
{ title: "HVAC", price: "0" },
|
||||||
|
{ title: "Painting", price: "0" },
|
||||||
|
{ title: "Interior Finishes", price: "0" },
|
||||||
|
{ title: "Exterior Work", price: "0" },
|
||||||
|
{ title: "Final Inspections", price: "0" },
|
||||||
|
{ title: "Punch List", price: "0" },
|
||||||
|
{ title: "Staging", price: "0" },
|
||||||
|
],
|
||||||
IAB: [{ title: "IAB Title", URL: "Please enter URL" }],
|
IAB: [{ title: "IAB Title", URL: "Please enter URL" }],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -213,6 +233,7 @@ const EditProperty = () => {
|
||||||
images: selectedProperty.images || [{ title: "", file: "" }],
|
images: selectedProperty.images || [{ title: "", file: "" }],
|
||||||
googleMapLink: selectedProperty.googleMapLink,
|
googleMapLink: selectedProperty.googleMapLink,
|
||||||
rateofreturn: selectedProperty.rateofreturn,
|
rateofreturn: selectedProperty.rateofreturn,
|
||||||
|
TradesinRenovations:selectedProperty.TradesinRenovations,
|
||||||
IAB:selectedProperty.IAB,
|
IAB:selectedProperty.IAB,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1046,6 +1067,59 @@ const EditProperty = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const addTrade = () => {
|
||||||
|
setFormData((prevData) => ({
|
||||||
|
...prevData,
|
||||||
|
TradesinRenovations: [...prevData.TradesinRenovations, { title: "", price: "" }],
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
const deleteTrade = (index) => {
|
||||||
|
const updatedCosts = formData.TradesinRenovations.filter((_, i) => i !== index);
|
||||||
|
setFormData((prevData) => ({
|
||||||
|
...prevData,
|
||||||
|
TradesinRenovations: updatedCosts,
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
// Function to handle changes to title and price
|
||||||
|
const handleTrade = (index, field, value) => {
|
||||||
|
const updatedCosts = [...formData.TradesinRenovations];
|
||||||
|
updatedCosts[index][field] = value;
|
||||||
|
setFormData((prevData) => ({
|
||||||
|
...prevData,
|
||||||
|
TradesinRenovations: updatedCosts,
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleTradePrice = (e, index) => {
|
||||||
|
let value = e.target.value;
|
||||||
|
|
||||||
|
// Remove the dollar sign before validating
|
||||||
|
value = value.replace(/^\$/, "").trim(); // Remove '$' if it exists
|
||||||
|
|
||||||
|
// Use a regular expression to allow only numbers and decimals
|
||||||
|
const isNumber = /^\d*\.?\d*$/.test(value);
|
||||||
|
|
||||||
|
// If valid number, update state, otherwise show the alert
|
||||||
|
if (isNumber || value === "") {
|
||||||
|
const updatedCosts = formData.TradesinRenovations.map((cost, i) =>
|
||||||
|
i === index
|
||||||
|
? { ...cost, price: value, isInvalid: false } // Reset isInvalid if valid number
|
||||||
|
: cost
|
||||||
|
);
|
||||||
|
setFormData({ ...formData, TradesinRenovations: updatedCosts });
|
||||||
|
} else {
|
||||||
|
const updatedCosts = formData.TradesinRenovations.map((cost, i) =>
|
||||||
|
i === index
|
||||||
|
? { ...cost, isInvalid: true } // Keep isInvalid true for invalid input
|
||||||
|
: cost
|
||||||
|
);
|
||||||
|
setFormData({ ...formData, TradesinRenovations: updatedCosts });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const addIAB = () => {
|
const addIAB = () => {
|
||||||
setFormData((prevData) => ({
|
setFormData((prevData) => ({
|
||||||
|
@ -4179,6 +4253,91 @@ const EditProperty = () => {
|
||||||
<div role="tabpanel" className="card tab-pane active">
|
<div role="tabpanel" className="card tab-pane active">
|
||||||
|
|
||||||
|
|
||||||
|
<span
|
||||||
|
style={{
|
||||||
|
color: "#fda417",
|
||||||
|
fontSize: "14px",
|
||||||
|
fontWeight: "bold",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Trades in Renovations
|
||||||
|
</span>
|
||||||
|
|
||||||
|
{formData.TradesinRenovations.map((title, index) => (
|
||||||
|
<div key={index} className="row gy-3 align-items-center">
|
||||||
|
<div className="col-md-4">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
className="form-control"
|
||||||
|
value={title.title}
|
||||||
|
onChange={(e) =>
|
||||||
|
handleTrade(index, "title", e.target.value)
|
||||||
|
}
|
||||||
|
placeholder="Title"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="col-md-4">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
className={`form-control ${
|
||||||
|
title.isInvalid ? "is-invalid" : ""
|
||||||
|
}`}
|
||||||
|
value={`$ ${title.price}`}
|
||||||
|
onChange={(e) => handleTradePrice(e, index)}
|
||||||
|
placeholder="Price"
|
||||||
|
style={{ textAlign: "right" }}
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
{title.isInvalid && (
|
||||||
|
<div className="invalid-feedback">
|
||||||
|
Please enter a valid number.
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className="col-md-2 d-flex justify-content-start">
|
||||||
|
<button
|
||||||
|
className="btn btn-danger"
|
||||||
|
onClick={() => deleteTrade(index)}
|
||||||
|
style={{ marginLeft: "5px" }}
|
||||||
|
>
|
||||||
|
x
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div className="col-md-4">
|
||||||
|
<button
|
||||||
|
onClick={addTrade}
|
||||||
|
className="btn btn-primary back"
|
||||||
|
style={{ backgroundColor: "#fda417", border: "#fda417" }}
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
style={{
|
||||||
|
fontSize: "20px",
|
||||||
|
fontWeight: "normal",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
+
|
||||||
|
</span>{" "}
|
||||||
|
Add Trades in Renovations
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<hr
|
||||||
|
style={{
|
||||||
|
borderColor: "#fda417", // Set the color of the line
|
||||||
|
borderWidth: "1px", // Optional: Adjust the thickness of the line
|
||||||
|
backgroundColor: "#fda417", // Optional: Apply color if using for background
|
||||||
|
height: "1px", // Optional: Set height to match the border width
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
|
||||||
<span
|
<span
|
||||||
style={{
|
style={{
|
||||||
color: "#fda417",
|
color: "#fda417",
|
||||||
|
|
|
@ -8,6 +8,7 @@ export const submitProperty = createAsyncThunk(
|
||||||
try {
|
try {
|
||||||
const response = await api.submitProperty(propertyData);
|
const response = await api.submitProperty(propertyData);
|
||||||
return response.data;
|
return response.data;
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return rejectWithValue(error.response.data);
|
return rejectWithValue(error.response.data);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue