address of pd add edit and delete also change ui of product table

This commit is contained in:
Sibunnayak 2024-10-15 11:46:12 +05:30
parent 54b64f5b64
commit 7f6ee992b2
4 changed files with 656 additions and 208 deletions

View File

@ -52,21 +52,21 @@ const AddMultiplePd = () => {
}, },
} }
); );
// console.log(data); console.log(data);
if (data.errors && data.errors.length > 0) { if (data?.errors && data?.errors?.length > 0) {
setErrors(data.errors); setErrors(data.errors);
} }
if (data.newlyCreated && data.newlyCreated.length > 0) { if (data?.newlyCreated && data?.newlyCreated?.length > 0) {
setNewlyCreated(data.newlyCreated); setNewlyCreated(data?.newlyCreated);
} }
if (data.updatedDistributors && data.updatedDistributors.length > 0) { if (data?.updatedDistributors && data?.updatedDistributors?.length > 0) {
setUpdatedDistributors(data.updatedDistributors); setUpdatedDistributors(data?.updatedDistributors);
// console.log(data.updatedDistributors); // console.log(data.updatedDistributors);
} }
// Redirect or display success message // Redirect or display success message
if (data.errors && data.errors.length > 0) { if (data?.errors && data?.errors.length > 0) {
setErrors(data.errors); setErrors(data?.errors);
swal({ swal({
title: "SpreadSheet Upload Successful", title: "SpreadSheet Upload Successful",
text: "A few Principal Distributor have errors. Please fix them and upload again.", text: "A few Principal Distributor have errors. Please fix them and upload again.",
@ -74,8 +74,8 @@ const AddMultiplePd = () => {
button: "OK", button: "OK",
}); });
} else if ( } else if (
data.processedUsers.newlyCreated > 0 || data?.newlyCreated > 0 ||
data.processedUsers.updatedDistributors > 0 data?.updatedDistributors > 0
) { ) {
swal({ swal({
title: "SpreadSheet Upload Successful", title: "SpreadSheet Upload Successful",
@ -85,7 +85,7 @@ const AddMultiplePd = () => {
}); });
} else { } else {
toast.success("File processed successfully with no new entries."); toast.success("File processed successfully with no new entries.");
navigate("/principal-distributors"); navigate("/principal-distributor");
} }
setFile(null); // Clear the file input setFile(null); // Clear the file input
document.querySelector('input[type="file"]').value = ""; document.querySelector('input[type="file"]').value = "";

View File

@ -121,6 +121,9 @@ const AddPrincipalDistributor = () => {
`/api/shipping/address/admin/new/${userId}`, `/api/shipping/address/admin/new/${userId}`,
{ {
...data, ...data,
Name: user.name,
phoneNumber: user.phone,
isDefault: true,
state: selectedState.label, // Send selected state label state: selectedState.label, // Send selected state label
city: selectedCity.label, // Send selected city label city: selectedCity.label, // Send selected city label
}, },

View File

@ -1,11 +1,16 @@
import { Typography, Button } from "@mui/material";
import axios from "axios"; import axios from "axios";
import React, { useCallback, useEffect, useState, useRef } from "react"; import React, { useCallback, useEffect, useState, useRef } from "react";
import { Link, useParams, useNavigate } from "react-router-dom"; import { Link, useParams, useNavigate } from "react-router-dom";
import swal from "sweetalert"; import swal from "sweetalert";
import { isAutheticated } from "src/auth"; import { isAutheticated } from "src/auth";
import { City, State } from "country-state-city";
import { Modal, Button } from "react-bootstrap";
import { Autocomplete, TextField, Typography, Box } from "@mui/material";
const SinglePrincipalDistributorAllDetails = () => { const SinglePrincipalDistributorAllDetails = () => {
const token = isAutheticated();
const { _id } = useParams();
const [user, setUser] = useState(null); const [user, setUser] = useState(null);
const [userOrder, setUserOrder] = useState({ const [userOrder, setUserOrder] = useState({
totalOrders: 0, totalOrders: 0,
@ -13,9 +18,185 @@ const SinglePrincipalDistributorAllDetails = () => {
lastPurchaseOrderDate: null, lastPurchaseOrderDate: null,
}); });
const [userAllAddress, setUserAllAddress] = useState([]); const [userAllAddress, setUserAllAddress] = useState([]);
const [gstNumber, setGstNumber] = useState(null);
const [panNumber, setPanNumber] = useState(null);
const [tradeName, setTradeName] = useState(null);
const [showModal, setShowModal] = useState(false);
const [isEditMode, setIsEditMode] = useState(false);
const [stateOptions, setStateOptions] = useState([]);
const [cityOptions, setCityOptions] = useState([]);
const [selectedState, setSelectedState] = useState(null);
const [selectedCity, setSelectedCity] = useState(null);
const [currentAddress, setCurrentAddress] = useState({
Name: "",
tradeName: "",
gstNumber: "",
panNumber: "",
phoneNumber: "",
street: "",
city: "",
state: "",
postalCode: "",
country: "India",
isDefault: false,
});
const token = isAutheticated(); // Fetch states when the component mounts
const { _id } = useParams(); useEffect(() => {
const fetchStates = () => {
const states = State.getStatesOfCountry("IN").map((state) => ({
label: state.name,
value: state.isoCode,
}));
setStateOptions(states);
};
fetchStates();
}, []);
// Fetch cities when a state is selected
useEffect(() => {
const fetchCities = () => {
if (selectedState) {
const cities = City.getCitiesOfState("IN", selectedState.value).map(
(city) => ({
label: city.name,
value: city.name,
})
);
setCityOptions(cities);
} else {
setCityOptions([]); // Clear cities if no state is selected
}
};
fetchCities();
}, [selectedState]);
// Open modal for add or edit mode
const handleOpenModal = (address = null) => {
setIsEditMode(!!address); // Set edit mode if address is provided
const initialAddress = address || {
Name: "",
tradeName: tradeName,
gstNumber: gstNumber,
panNumber: panNumber,
phoneNumber: "",
street: "",
city: "",
state: "",
postalCode: "",
country: "India",
isDefault: false,
};
setCurrentAddress(initialAddress);
// Fetch city options based on the state from the backend
if (address) {
const state =
stateOptions.find((option) => option.label === address.state) || null;
// Set selected state from backend address
setSelectedState(state);
// Fetch cities if state is found
if (state) {
const cities = City.getCitiesOfState("IN", state.value).map((city) => ({
label: city.name,
value: city.name,
}));
setCityOptions(cities);
// Set selected city if it exists in the fetched city options
const city =
cities.find((option) => option.label === address.city) || null;
setSelectedCity(city); // Set the selected city
}
} else {
setSelectedState(null);
setSelectedCity(null);
setCityOptions([]); // Clear city options if no address is provided
}
setShowModal(true);
};
// Close modal without saving changes
const handleCloseModal = () => {
setShowModal(false);
// Reset selections to previous state when modal is closed
setSelectedState(null); // Reset state selection
setSelectedCity(null); // Reset city selection
setCurrentAddress({
Name: "",
tradeName: "",
gstNumber: "",
panNumber: "",
phoneNumber: "",
street: "",
city: "",
state: "",
postalCode: "",
country: "India",
isDefault: false,
});
};
// Save address logic for adding or updating
const handleSaveAddress = async () => {
try {
const updatedAddress = {
...currentAddress,
gstNumber: gstNumber,
panNumber: panNumber,
tradeName: tradeName,
};
const apiUrl = isEditMode
? `/api/shipping/address/update/${currentAddress._id}`
: `/api/shipping/address/admin/new/${_id}`;
// console.log(currentAddress);
const method = isEditMode ? "patch" : "post";
// Prepare the headers with the token
const headers = {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json",
};
// Make the API call with the headers
await axios[method](apiUrl, updatedAddress, { headers });
swal(
"Success!",
`Address ${isEditMode ? "updated" : "added"} successfully!`,
"success"
);
handleCloseModal();
getUserAddress();
} catch (error) {
console.error("Error saving address:", error);
swal("Error!", "There was an error saving the address.", "error");
}
};
const handleStateChange = (event, newValue) => {
setSelectedState(newValue);
setCurrentAddress((prev) => ({
...prev,
state: newValue ? newValue.label : "",
city: "", // Clear city when state changes
}));
setSelectedCity(null); // Reset city selection
setCityOptions([]); // Clear city options on state change
};
const handleCityChange = (event, newValue) => {
setSelectedCity(newValue);
setCurrentAddress((prev) => ({
...prev,
city: newValue ? newValue.label : "",
}));
};
// Fetch Shipping address of the individual user // Fetch Shipping address of the individual user
const getUserAddress = useCallback(async () => { const getUserAddress = useCallback(async () => {
@ -28,7 +209,11 @@ const SinglePrincipalDistributorAllDetails = () => {
}, },
} }
); );
// console.log(response.data);
setUserAllAddress(response.data?.UserShippingAddress || []); setUserAllAddress(response.data?.UserShippingAddress || []);
setGstNumber(response.data?.UserShippingAddress[0]?.gstNumber || "");
setPanNumber(response.data?.UserShippingAddress[0]?.panNumber || "");
setTradeName(response.data?.UserShippingAddress[0]?.tradeName || "");
} catch (error) { } catch (error) {
swal({ swal({
title: "Warning", title: "Warning",
@ -68,6 +253,7 @@ const SinglePrincipalDistributorAllDetails = () => {
Authorization: `Bearer ${token}`, Authorization: `Bearer ${token}`,
}, },
}); });
// console.log(response.data);
setUser(response.data.user); setUser(response.data.user);
} catch (error) { } catch (error) {
swal({ swal({
@ -85,6 +271,37 @@ const SinglePrincipalDistributorAllDetails = () => {
getUserAddress(); getUserAddress();
getUserDetails(); getUserDetails();
}, [_id, getOrdersCount, getUserAddress, getUserDetails]); }, [_id, getOrdersCount, getUserAddress, getUserDetails]);
const handledeleteAddress = async (id) => {
try {
const response = await axios.delete(
`/api/shipping/address/delete/${id}`, // Address ID in the URL
{
headers: {
Authorization: `Bearer ${token}`, // Authorization header
},
data: { userId: _id }, // User ID in the request body
}
);
swal({
title: "Success",
text: response.data.message,
icon: "success",
button: "Close",
});
getUserAddress();
} catch (error) {
// Handle errors here, ensuring that you access the error message correctly
swal({
title: "Warning",
text: error.response?.data?.message || error.message, // Improved error handling
icon: "error",
button: "Close",
dangerMode: true,
});
}
};
return ( return (
<div> <div>
@ -96,17 +313,7 @@ const SinglePrincipalDistributorAllDetails = () => {
</div> </div>
<div className="page-title-right"> <div className="page-title-right">
<Link to="/principal-distributor"> <Link to="/principal-distributor">
<Button <Button className="btn btn-danger btn-sm">Back</Button>
variant="contained"
color="secondary"
style={{
fontWeight: "bold",
marginBottom: "1rem",
textTransform: "capitalize",
}}
>
Back
</Button>
</Link> </Link>
</div> </div>
</div> </div>
@ -210,10 +417,18 @@ const SinglePrincipalDistributorAllDetails = () => {
<div style={{ marginTop: "2rem" }}> <div style={{ marginTop: "2rem" }}>
<h5 style={{ fontWeight: "bold", marginBottom: "1rem" }}> <h5 style={{ fontWeight: "bold", marginBottom: "1rem" }}>
&bull; Addresses{" "} &bull; Addresses{" "}
</h5>{" "}
<h5 style={{ fontWeight: "bold", marginLeft: "1rem" }}>
&bull; Total Addresses : {userAllAddress?.length}{" "}
</h5> </h5>
<div className="d-flex justify-content-between align-items-center mb-3">
<h5 style={{ fontWeight: "bold" }}>
&bull; Total Addresses: {userAllAddress?.length || 0}{" "}
</h5>
<Button
className="btn btn-primary"
onClick={() => handleOpenModal()} // Open modal for adding
>
Add Address
</Button>
</div>
{userAllAddress?.length > 0 && ( {userAllAddress?.length > 0 && (
<div className="table-responsive table-shoot mt-3"> <div className="table-responsive table-shoot mt-3">
<table <table
@ -225,41 +440,264 @@ const SinglePrincipalDistributorAllDetails = () => {
style={{ background: "rgb(140, 213, 213)" }} style={{ background: "rgb(140, 213, 213)" }}
> >
<tr> <tr>
<th>SL No.</th> <th style={{ width: "5%" }}>SL No.</th>
<th>Address </th> <th style={{ width: "20%" }}>Trade Name</th>
{/* <th>Profile Image</th> */} <th style={{ width: "10%" }}>GST</th>
<th style={{ width: "10%" }}>PAN</th>
<th style={{ width: "37%" }}>Address</th>
<th style={{ width: "7%" }}>Default</th>
<th style={{ width: "11%" }}>Action</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{userAllAddress?.length === 0 && ( {userAllAddress?.map((address, i) => (
<tr className="text-center"> <tr key={address._id || i}>
<td colSpan="6"> <td className="text-start">
<h5>No Data Available</h5> <strong>{i + 1}</strong>
</td> </td>
</tr> <td className="text-start">
)}
{userAllAddress?.map((address, i) => {
return (
<tr key={i}>
<td className="text-start">{i + 1}</td>
<td style={{ maxWidth: "400px" }}>
<strong> <strong>
{address?.first_Name} {address?.last_name} {address?.tradeName
{address.tradeName ? `${address.tradeName}`
? `${address.tradeName},` : "No Trade Name"}
: "No tradeName "}
{address.gstNumber ? `${address.gstNumber},` : ""}
{address?.street},{address?.city},{address?.state},
{address?.country},{address?.postalCode}
</strong> </strong>
</td> </td>
<td className="text-start">
<strong>{address.gstNumber}</strong>
</td>
<td className="text-start">
<strong>{address.panNumber}</strong>
</td>
<td className="text-start">
<strong>
{address?.Name}-{address?.street}, {address?.city},{" "}
{address?.state}, {address?.country},{" "}
{address?.postalCode}
</strong>
</td>
<td className="text-center">
<strong>
{address.isDefault ? "Yes" : "No"}
</strong>
</td>
<td className="text-start">
<Button
className="btn btn-warning btn-sm me-2"
onClick={() => handleOpenModal(address)} // Open modal for editing
>
Edit
</Button>
<Button
className="btn btn-danger btn-sm"
onClick={() => handledeleteAddress(address._id)}
>
Delete
</Button>
</td>
</tr> </tr>
); ))}
})}
</tbody> </tbody>
</table> </table>
</div> </div>
)} )}
{/* Modal for Adding/Editing Address */}
<Modal
show={showModal}
onHide={handleCloseModal}
dialogClassName="modal-lg"
>
<Modal.Header closeButton>
<Modal.Title>
{isEditMode ? "Edit Shipping Address" : "Add Shipping Address"}
</Modal.Title>
</Modal.Header>
<Modal.Body>
<div className="container">
<div className="row">
{/* Name and Trade Name */}
<div className="col-md-6">
<label>Name</label>
<input
type="text"
value={currentAddress?.Name || ""}
onChange={(e) =>
setCurrentAddress({
...currentAddress,
Name: e.target.value,
})
}
className="form-control mb-3"
placeholder="Enter name"
/>
</div>
<div className="col-md-6">
<label>Trade Name</label>
<input
type="text"
value={currentAddress?.tradeName || ""}
onChange={(e) =>
setCurrentAddress({
...currentAddress,
tradeName: e.target.value,
})
}
className="form-control mb-3"
placeholder="Enter trade name"
/>
</div>
</div>
<div className="row">
{/* GST Number and PAN Number */}
<div className="col-md-6">
<label>GST Number</label>
<input
type="text"
value={currentAddress?.gstNumber || ""}
onChange={(e) =>
setCurrentAddress({
...currentAddress,
gstNumber: e.target.value,
})
}
className="form-control mb-3"
placeholder="Enter GST number"
/>
</div>
<div className="col-md-6">
<label>PAN Number</label>
<input
type="text"
value={currentAddress?.panNumber || ""}
onChange={(e) =>
setCurrentAddress({
...currentAddress,
panNumber: e.target.value,
})
}
className="form-control mb-3"
placeholder="Enter PAN number"
/>
</div>
</div>
<div className="row">
{/* Phone Number and Street */}
<div className="col-md-6">
<label>Phone Number</label>
<input
type="text"
value={currentAddress?.phoneNumber || ""}
onChange={(e) =>
setCurrentAddress({
...currentAddress,
phoneNumber: e.target.value,
})
}
className="form-control mb-3"
placeholder="Enter phone number"
/>
</div>
<div className="col-md-6">
<label>Street</label>
<input
type="text"
value={currentAddress?.street || ""}
onChange={(e) =>
setCurrentAddress({
...currentAddress,
street: e.target.value,
})
}
className="form-control mb-3"
placeholder="Enter street"
/>
</div>
</div>
<div className="row">
{/* State and City */}
<div className="col-md-6">
<Autocomplete
options={stateOptions}
value={selectedState}
onChange={handleStateChange}
renderInput={(params) => (
<TextField {...params} label="Select State" />
)}
/>
</div>
<div className="col-md-6">
<Autocomplete
options={cityOptions}
value={selectedCity}
onChange={handleCityChange}
isOptionEqualToValue={(option, value) =>
option.value === value.value
}
renderInput={(params) => (
<TextField {...params} label="Select City" />
)}
/>
</div>
</div>
<div className="row">
{/* Postal Code and Country */}
<div className="col-md-6">
<label>Postal Code</label>
<input
type="text"
value={currentAddress?.postalCode || ""}
onChange={(e) =>
setCurrentAddress({
...currentAddress,
postalCode: e.target.value,
})
}
className="form-control mb-3"
placeholder="Enter postal code"
/>
</div>
<div className="col-md-6">
<label>Country</label>
<input
type="text"
disabled
value={currentAddress?.country || ""}
className="form-control mb-3"
/>
</div>
</div>
<div className="row">
<div className="col-md-6">
<label>Is Default Address</label>
<select
className="form-control mb-3"
value={currentAddress.isDefault ? "Yes" : "No"}
onChange={(e) =>
setCurrentAddress({
...currentAddress,
isDefault: e.target.value === "Yes", // Convert Yes/No to true/false
})
}
>
<option value="Yes">Yes</option>
<option value="No">No</option>
</select>
</div>
</div>
</div>
</Modal.Body>
<Modal.Footer>
{/* <Button variant="secondary" onClick={handleCloseModal}>
Cancel
</Button> */}
<Button variant="primary" onClick={handleSaveAddress}>
Save
</Button>
</Modal.Footer>
</Modal>
</div> </div>
</div> </div>
</div> </div>

View File

@ -322,69 +322,110 @@ const Products = () => {
style={{ background: "#ecdddd" }} style={{ background: "#ecdddd" }}
> >
<tr> <tr>
<th className="text-start">Image</th> <th className="text-start" style={{ width: "8%" }}>
<th className="text-start">SKU</th> Image
<th className="text-start">Product</th> </th>
<th className="text-start">Category Name</th> <th className="text-start" style={{ width: "10%" }}>
<th className="text-start">Brand Name</th> SKU
<th className="text-start">Price</th> </th>
<th className="text-start">Status</th> <th className="text-start" style={{ width: "20%" }}>
Product
<th className="text-start">Added On</th> </th>
<th className="text-start">Actions</th> <th className="text-start" style={{ width: "15%" }}>
Category Name
</th>
<th className="text-start" style={{ width: "15%" }}>
Brand Name
</th>
<th className="text-start" style={{ width: "10%" }}>
Price
</th>
<th className="text-start" style={{ width: "10%" }}>
Status
</th>
<th className="text-start" style={{ width: "12%" }}>
Added On
</th>
<th className="text-start" style={{ width: "12%" }}>
Actions
</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{loading ? ( {loading ? (
<tr> <tr>
<td className="text-center" colSpan="6"> <td className="text-center" colSpan="9">
Loading... Loading...
</td> </td>
</tr> </tr>
) : productsData?.length > 0 ? ( ) : productsData?.length > 0 ? (
productsData?.map((product, i) => { productsData?.map((product, i) => (
return (
<tr key={i}> <tr key={i}>
<th> <td>
{product?.image && {product?.image &&
product?.image?.length !== 0 ? ( product?.image?.length !== 0 ? (
<>
<img <img
src={product?.image[0]?.url} src={product?.image[0]?.url}
width="50" width="50"
alt="preview" alt="preview"
style={{ borderRadius: "5px" }}
/> />
</>
) : ( ) : (
<div <div style={{ fontSize: "13px" }}>
className=""
style={{ fontSize: "13px" }}
>
<p className="m-0">No</p> <p className="m-0">No</p>
<p className="m-0">image</p> <p className="m-0">image</p>
<p className="m-0">uploaded!</p> <p className="m-0">uploaded!</p>
</div> </div>
)} )}
</th> </td>
<td className="text-start">{product.SKU}</td> <td
<td className="text-start">{product.name}</td> className="text-start"
<td className="text-start"> style={{
{product.category?.categoryName !== "" whiteSpace: "nowrap",
? product.category?.categoryName overflow: "hidden",
: "Category Not selected "} textOverflow: "ellipsis",
}}
>
{product.SKU}
</td>
<td
className="text-start"
style={{
whiteSpace: "nowrap",
overflow: "hidden",
textOverflow: "ellipsis",
}}
>
{product.name}
</td>
<td
className="text-start"
style={{
whiteSpace: "nowrap",
overflow: "hidden",
textOverflow: "ellipsis",
}}
>
{product.category?.categoryName ||
"Category Not selected"}
</td>
<td
className="text-start"
style={{
whiteSpace: "nowrap",
overflow: "hidden",
textOverflow: "ellipsis",
}}
>
{product.brand?.brandName ||
"Brand Not selected"}
</td> </td>
<td className="text-start"> <td className="text-start">
{product.brand?.brandName !== ""
? product.brand?.brandName
: "Brand Not selected "}
</td>
<th className="text-start">
{currencyDetails?.CurrencySymbol} {currencyDetails?.CurrencySymbol}
{product?.price} {product?.price}
</th> </td>
<td className="text-start"> <td className="text-start">
<span className=""></span>
<button <button
type="button" type="button"
className={`badge text-white ${ className={`badge text-white ${
@ -392,9 +433,7 @@ const Products = () => {
? "text-bg-success" ? "text-bg-success"
: "text-bg-danger" : "text-bg-danger"
}`} }`}
onClick={() => { onClick={() => handleStatus(product._id)}
handleStatus(product._id);
}}
> >
{product?.product_Status} {product?.product_Status}
</button> </button>
@ -421,16 +460,10 @@ const Products = () => {
<button <button
style={{ style={{
color: "white", color: "white",
marginRight: "1rem", marginRight: "0.5rem",
}} }}
type="button" type="button"
className=" className="btn btn-primary btn-sm waves-effect waves-light btn-table mx-1 mt-1"
btn btn-primary btn-sm
waves-effect waves-light
btn-table
mx-1
mt-1
"
> >
View View
</button> </button>
@ -440,58 +473,32 @@ const Products = () => {
<button <button
style={{ style={{
color: "white", color: "white",
marginRight: "1rem", marginRight: "0.5rem",
}} }}
type="button" type="button"
className=" className="btn btn-info btn-sm waves-effect waves-light btn-table mt-1 mx-1"
btn btn-info btn-sm
waves-effect waves-light
btn-table
mt-1
mx-1
"
> >
Edit Edit
</button> </button>
</Link> </Link>
<Link
to={"#"}
style={{
marginRight: "1rem",
}}
>
<button <button
style={{ color: "white" }} style={{ color: "white" }}
type="button" type="button"
className=" className="btn btn-danger btn-sm waves-effect waves-light btn-table mt-1 mx-1"
btn btn-danger btn-sm onClick={() => handleDelete(product._id)}
waves-effect waves-light
btn-table
mt-1
mx-1
"
onClick={() => {
handleDelete(product._id);
}}
> >
Delete Delete
</button> </button>
</Link>
</td> </td>
</tr> </tr>
); ))
})
) : ( ) : (
!loading &&
productsData?.length === 0 && (
<tr className="text-center"> <tr className="text-center">
<td colSpan="6"> <td colSpan="9">
<h5>No Product Available...</h5> <h5>No Product Available...</h5>
</td> </td>
</tr> </tr>
)
)} )}
</tbody> </tbody>
</table> </table>