diff --git a/src/routes.js b/src/routes.js index 8d719c4..f972a8d 100644 --- a/src/routes.js +++ b/src/routes.js @@ -175,6 +175,8 @@ import TaskSalesCoordinator from "./views/Tasks/TaskSalesCoordinator"; import TaskTerritoryManager from "./views/Tasks/TaskTerritoryManager"; import SingleUserTask from "./views/Tasks/SingleUserTask"; import Tasks from "./views/Tasks/Task"; +import DistributorLiqudations from "./views/PrincipalDistributors/DistributorLiqudation"; +import UpdatePrincipalDistributor from "./views/PrincipalDistributors/updateprincipaldistributor"; const routes = [ //dashboard @@ -457,6 +459,12 @@ const routes = [ element: DistributorStocks, navName: "Distributor", }, + { + path: "/:distributortype/Liqudation/:id", + name: " Distributor Liqudation", + element: DistributorLiqudations, + navName: "Distributor", + }, { path: "/:distributortype/opening-inventory/:id", name: " Distributor Opening Inventory", @@ -526,6 +534,12 @@ const routes = [ element: addPrincipalDistributor, navName: "PrincipalDistributor", }, + { + path: "/update-principal-distributor/:id", + name: "PrincipalDistributor", + element: UpdatePrincipalDistributor, + navName: "PrincipalDistributor", + }, { path: "/add-principal-distributor/multiple", name: "PrincipalDistributor", diff --git a/src/views/PrincipalDistributors/DistributorLiqudation.js b/src/views/PrincipalDistributors/DistributorLiqudation.js new file mode 100644 index 0000000..fd510ed --- /dev/null +++ b/src/views/PrincipalDistributors/DistributorLiqudation.js @@ -0,0 +1,479 @@ +import React, { useState, useEffect, useRef, useCallback } from "react"; +import { Link, useParams } from "react-router-dom"; +import axios from "axios"; +import Button from "@material-ui/core/Button"; +import { useNavigate } from "react-router-dom"; +import { isAutheticated } from "src/auth"; +import swal from "sweetalert"; +import debounce from "lodash.debounce"; +import { Typography, Paper } from "@mui/material"; +const DistributorLiqudations = () => { + const token = isAutheticated(); + const navigate = useNavigate(); + const { id } = useParams(); + const { distributortype } = useParams(); + const { stocks } = useParams(); + const [loading, setLoading] = useState(false); + const [productsData, setProductsData] = useState([]); + const [categories, setCategories] = useState([]); + const [brands, setBrands] = useState([]); + const [user, setUser] = useState(null); + + const nameRef = useRef(); + const categoryRef = useRef(); + const brandRef = useRef(); + + const [currentPage, setCurrentPage] = useState(1); + const [itemPerPage, setItemPerPage] = useState(10); + const [totalData, setTotalData] = useState(0); + // Fetch User Details + const getUserDetails = useCallback(async () => { + try { + const response = await axios.get( + distributortype === "principaldistributor" + ? `/api/v1/admin/user/${id}` + : `/api/getRD/${id}`, + { + headers: { + Authorization: `Bearer ${token}`, + }, + } + ); + distributortype === "principaldistributor" + ? setUser(response.data.user) + : setUser(response.data); + } catch (error) { + swal({ + title: "Warning", + text: error.message, + icon: "error", + button: "Close", + dangerMode: true, + }); + } + }, [id, token]); + + // Call getUserDetails on component mount + useEffect(() => { + getUserDetails(); + }, [getUserDetails]); + + const getProductsData = async () => { + setLoading(true); + try { + const response = await axios.get( + distributortype === "principaldistributor" + ? `/api/pd/stock/${id}` + : `/api/rd/stock/${id}`, + { + headers: { + Authorization: `Bearer ${token}`, + }, + params: { + page: currentPage, + show: itemPerPage, + name: nameRef.current?.value || "", + category: categoryRef.current?.value || "", + brand: brandRef.current?.value || "", + }, + } + ); + // console.log(response.data); + setProductsData(response.data?.products || []); + setTotalData(response.data?.totalProducts || 0); + } catch (err) { + const msg = err?.response?.data?.msg || "Something went wrong!"; + swal({ + title: "Error", + text: msg, + icon: "error", + button: "Retry", + dangerMode: true, + }); + } finally { + setLoading(false); + } + }; + + const getCatagories = () => { + axios + .get(`/api/category/getCategories`, { + headers: { + "Access-Control-Allow-Origin": "*", + Authorization: `Bearer ${token}`, + }, + }) + .then((res) => { + // console.log(res?.data?.categories); + setCategories(res?.data?.categories); + }); + }; + const getBrands = () => { + axios + .get(`/api/brand/getBrands`, { + headers: { + "Access-Control-Allow-Origin": "*", + Authorization: `Bearer ${token}`, + }, + }) + .then((res) => { + // console.log(res?.data?.brands); + setBrands(res?.data?.brands); + }); + }; + + const [currencyDetails, setCurrencyDetails] = useState(null); + + const getCurrency = async () => { + try { + const response = await axios.get("/api/currency/getall", { + // headers: { + // Authorization: `Bearer ${token}`, + // }, + }); + + if (response.status === 200) { + setCurrencyDetails(response?.data?.currency[0]); + } + } catch (error) { + console.log(error); + } + }; + useEffect(() => { + getCatagories(); + getCurrency(); + getBrands(); + }, []); + + useEffect(() => { + getProductsData(); + }, [itemPerPage, currentPage]); + + const debouncedSearch = useCallback( + debounce(() => { + setCurrentPage(1); + getProductsData(); + }, 500), + [] + ); + + const handleSearchChange = () => { + debouncedSearch(); + }; + const handleCancel = () => { + navigate( + distributortype === "principaldistributor" + ? // ? stocks==="stocks"?"/principal-distributor":"/opening-inventory" + "/principal-distributor" + : "/retail-distributor" + ); + }; + return ( +
+
+
+
+
+ +
+
+ + Name: {user?.name} + + + Mobile Number:{" "} + {distributortype === "principaldistributor" + ? user?.phone + : user?.mobile_number} + + + Email: {user?.email} + +
+ + {/* Back Button on the right */} +
+ +
+
+
+ {/* Section Heading: Product Stocks */} +
+
+
+ Monthly Product Details Report +
+
+
+
+
+ +
+
+
+
+
+
+
+ +
+
+
+ + +
+
+ + +
+
+ + +
+
+ +
+ + + + + + + + + + + + + + + + {loading ? ( + + + + ) : productsData?.length > 0 ? ( + productsData?.map((product, i) => { + return ( + + + + + + + + + + + ); + }) + ) : ( + !loading && + productsData?.length === 0 && ( + + + + ) + )} + +
SKU CodeSKU DescriptionCategory NameBrand NameOpn. StocksLiqudationOrder QuantityClosing stocks
+ Loading... +
{product.SKU}{product.name} + {product.category !== "" + ? product.category + : "Category Not selected "} + + {product.brand !== "" + ? product.brand + : "Brand Not selected "} + + {product.monthstartstock} + + {product.liquidation} + + {product.monthlyorderquantity} + {product.stock}
+
No Product Available...
+
+
+ +
+
+
+ Showing {currentPage * itemPerPage - itemPerPage + 1} to{" "} + {Math.min(currentPage * itemPerPage, totalData)} of{" "} + {totalData} entries +
+
+ +
+
+
    +
  • + setCurrentPage((prev) => prev - 1)} + disabled={loading} + > + Previous + +
  • + + {!(currentPage - 1 < 1) && ( +
  • + + setCurrentPage((prev) => prev - 1) + } + disabled={loading} + > + {currentPage - 1} + +
  • + )} + +
  • + + {currentPage} + +
  • + + {!( + (currentPage + 1) * itemPerPage - itemPerPage > + totalData - 1 + ) && ( +
  • + { + setCurrentPage((prev) => prev + 1); + }} + disabled={loading} + > + {currentPage + 1} + +
  • + )} + +
  • + totalData - 1 + ) + ? "paginate_button page-item next" + : "paginate_button page-item next disabled" + } + > + setCurrentPage((prev) => prev + 1)} + disabled={loading} + > + Next + +
  • +
+
+
+
+
+
+
+
+
+
+
+ ); +}; + +export default DistributorLiqudations; diff --git a/src/views/PrincipalDistributors/principalDistributor.js b/src/views/PrincipalDistributors/principalDistributor.js index 07096a1..662f9b1 100644 --- a/src/views/PrincipalDistributors/principalDistributor.js +++ b/src/views/PrincipalDistributors/principalDistributor.js @@ -172,7 +172,7 @@ const principalDistributor = () => { if (response.data.success) { toast.success( - "Password reset successfully! Email sent to Territory Manager." + "Password reset successfully! Email sent to Principal Distributor." ); } } catch (error) { @@ -526,6 +526,18 @@ const principalDistributor = () => { +
+ + + + + +
+ {/* + + */} )) diff --git a/src/views/PrincipalDistributors/updateprincipaldistributor.js b/src/views/PrincipalDistributors/updateprincipaldistributor.js new file mode 100644 index 0000000..344e01a --- /dev/null +++ b/src/views/PrincipalDistributors/updateprincipaldistributor.js @@ -0,0 +1,712 @@ +import React, { useState, useEffect, useCallback } from "react"; +import { + TextField, + Button, + Card, + Grid, + Typography, + FormHelperText, + Autocomplete, + CircularProgress, + FormControl, + InputLabel, +} from "@mui/material"; +import { useNavigate, useParams } from "react-router-dom"; +import { toast } from "react-hot-toast"; +import axios from "axios"; +import { isAutheticated } from "src/auth"; +import { City, State } from "country-state-city"; + +const UpdatePrincipalDistributor = () => { + const navigate = useNavigate(); + const token = isAutheticated(); + const { id } = useParams(); + + const [user, setUser] = useState({ + PD_ID: "", + SBU: "", + name: "", + email: "", + phone: "", + }); + + const [data, setData] = useState({ + street: "", + city: "", + state: "", + postalCode: "", + country: "India", + tradeName: "", + gstNumber: "", + panNumber: "", + }); + + const [loading, setLoading] = useState(false); + const [stateOptions, setStateOptions] = useState([]); + const [cityOptions, setCityOptions] = useState([]); + const [selectedState, setSelectedState] = useState(null); + const [selectedCity, setSelectedCity] = useState(null); + const [currentAddressid, setCurrentAddressid] = useState(null); + + // Fetch User Details + const getUserDetails = useCallback(async () => { + try { + const response = await axios.get(`/api/v1/admin/user/${id}`, { + headers: { + Authorization: `Bearer ${token}`, + }, + }); + // console.log(response.data); + // setUser(response.data.user); + setUser((prev) => ({ + ...prev, + PD_ID: response.data.user.uniqueId, + SBU: response.data.user.SBU, + name: response.data.user.name, + email: response.data.user.email, + phone: response.data.user.phone, + })); + } catch (error) { + swal({ + title: "Warning", + text: error.message, + icon: "error", + button: "Close", + dangerMode: true, + }); + } + }, [id, token]); + // Fetch Shipping address of the individual user + const getUserAddress = useCallback(async () => { + try { + const response = await axios.get( + `/api/shipping/address/user/address/${id}`, + { + headers: { + Authorization: `Bearer ${token}`, + }, + } + ); + // console.log(response.data); + const defaultAddress = + response.data?.UserShippingAddress.find( + (address) => address.isDefault + ) || + response.data?.UserShippingAddress[0] || + {}; + // console.log(defaultAddress); + setCurrentAddressid(defaultAddress._id); + setData((prev) => ({ + ...prev, + street: defaultAddress.street || "", + city: defaultAddress.city || "", + state: defaultAddress.state || "", + postalCode: defaultAddress.postalCode || "", + country: defaultAddress.country || "India", + tradeName: defaultAddress.tradeName || "", + gstNumber: defaultAddress.gstNumber || "", + panNumber: defaultAddress.panNumber || "", + })); + // Fetch city options based on the state from the backend + if (defaultAddress.state) { + const state = + stateOptions.find( + (option) => option.label === defaultAddress.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 === defaultAddress.city) || + null; + setSelectedCity(city); // Set the selected city + } + } else { + setSelectedState(null); + setSelectedCity(null); + setCityOptions([]); // Clear city options if no address is provided + } + } catch (error) { + swal({ + title: "Warning", + text: error.message, + icon: "error", + button: "Close", + dangerMode: true, + }); + } + }, [id, token, stateOptions]); + useEffect(() => { + getUserAddress(); + getUserDetails(); + }, [id, getUserAddress, getUserDetails]); + + // Fetch states when the component mounts + useEffect(() => { + const fetchStates = () => { + const states = State.getStatesOfCountry("IN").map((state) => ({ + label: state.name, + value: state.isoCode, + })); + setStateOptions(states); + }; + fetchStates(); + }, []); + useEffect(() => { + if (stateOptions.length > 0) { + getUserAddress(); + } + }, [stateOptions, getUserAddress]); + + // 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]); + + const handleInputChange = (e) => { + setUser({ ...user, [e.target.name]: e.target.value }); + }; + + const handleDataChange = (e) => { + setData({ ...data, [e.target.name]: e.target.value }); + }; + + const handleStateChange = (event, newValue) => { + setSelectedState(newValue); + setData((prev) => ({ + ...prev, + state: newValue ? newValue.label : "", + city: "", + })); + setSelectedCity(null); // Clear city when state changes + setCityOptions([]); // Reset city options + }; + + const handleCityChange = (event, newValue) => { + setSelectedCity(newValue); + setData((prev) => ({ + ...prev, + city: newValue ? newValue.label : "", + })); + }; + + const handleFormSubmit = async (e) => { + e.preventDefault(); + try { + // Validate input fields + if ( + !user.PD_ID || + !user.name || + !user.email || + !user.phone || + !data.panNumber || + !data.tradeName || + !data.gstNumber || + !data.country || + !data.state || + !data.city || + !data.street || + !data.postalCode + ) { + throw new Error("Fill all fields!"); + } + + setLoading(true); + + // Attempt to register user + const userResponse = await axios.put(`/api/v1/user/update/${id}`, { + ...user, + role: "principal-Distributor", + }); + + if (userResponse.status === 201 || userResponse.status === 200) { + // const userId = userResponse.data.userId; + // console.log(userId); + // Add address details for the user + const addressResponse = await axios.patch( + `/api/shipping/address/update/${currentAddressid}`, + { + ...data, + Name: user.name, + phoneNumber: user.phone, + isDefault: true, + state: data.state, + city: data.city, + // state: selectedState.label, // Send selected state label + // city: selectedCity.label, // Send selected city label + }, + { + headers: { + Authorization: `Bearer ${token}`, + }, + } + ); + + setLoading(false); + if (addressResponse.status === 201) { + toast.success("Principal Distributor and Address updated Successfully"); + navigate("/principal-distributor"); + } + } + } catch (error) { + setLoading(false); + if (error.response && error.response?.data) { + toast.error(error.response?.data.message || "Something went wrong!"); + } else { + toast.error("Something went wrong!"); + } + } + }; + + const handleCancel = () => { + navigate("/principal-distributor"); + }; + + return ( +
+ + + + Update Principal Distributor + +
+ + Basic Information + + + {/* Principal Distributor ID */} + + + + Principal Distributor ID* + + + + + + + + {/* Principal Distributor SBU */} + + + + SBU* + + + + + + + + {/* Name */} + + + + Name* + + + + + + + + {/* Email */} + + + + Email* + + + + + + + + {/* Phone Number */} + + + + Phone Number* + + + + + + + + + + Business Details + + + {/* PAN Number */} + + + + PAN Number* + + + + + + + + {/* Trade Name */} + + + + Trade Name* + + + + + + + + {/* GST Number */} + + + + GST Number* + + + + + + + + + + Address + + + {/* Country */} + + + + Country* + + + + + + + + {/* State */} + + + + State* + + + + option.label} + value={selectedState} + onChange={handleStateChange} + renderInput={(params) => ( + + )} + /> + + + + + + + {/* City */} + + + + City* + + + + option.label} + value={selectedCity} + onChange={handleCityChange} + isOptionEqualToValue={(option, value) => + option.value === value.value + } + renderInput={(params) => ( + + )} + /> + + + + + + + {/* Street */} + + + + Street* + + + + + + + + {/* Postal Code */} + + + + Postal Code* + + + + + + + + + +
+
+
+ ); +}; + +export default UpdatePrincipalDistributor; diff --git a/src/views/RetailDistributors/RetailDistributor.js b/src/views/RetailDistributors/RetailDistributor.js index a3c6b60..650f950 100644 --- a/src/views/RetailDistributors/RetailDistributor.js +++ b/src/views/RetailDistributors/RetailDistributor.js @@ -133,7 +133,7 @@ const RetailDistributor = () => { if (response.data.success) { toast.success( - "Password reset successfully! Email sent to Territory Manager." + "Password reset successfully! Email sent to Retailer." ); } } catch (error) { diff --git a/src/views/SalesCoOrdinators/SalesCoOrdinator.js b/src/views/SalesCoOrdinators/SalesCoOrdinator.js index a2ccef2..ad71ad7 100644 --- a/src/views/SalesCoOrdinators/SalesCoOrdinator.js +++ b/src/views/SalesCoOrdinators/SalesCoOrdinator.js @@ -125,7 +125,7 @@ const SalesCoOrdinator = () => { if (response.data.success) { toast.success( - "Password reset successfully! Email sent to Territory Manager." + "Password reset successfully! Email sent to Sales Coordinator." ); } } catch (error) {