diff --git a/src/hooks/tariff.hook.ts b/src/hooks/tariff.hook.ts deleted file mode 100644 index 5374082..0000000 --- a/src/hooks/tariff.hook.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { useEffect, useState } from "react"; -import axios from "axios"; - -export type Privilege = { - createdAt: string; - description: string; - isDeleted: boolean; - name: string; - price: number; - privilegeId: string; - serviceKey: string; - type: "count" | "day" | "mb"; - updatedAt: string; - value: string; - _id: string; -}; - -type UseTariffs = { - tariffs: Record | undefined; - isError: boolean; - isLoading: boolean; - errorMessage: string; -}; - -export const useTariffs = (): UseTariffs => { - const [tariffs, setTariffs] = useState>(); - const [isLoading, setIsLoading] = useState(false); - const [isError, setIsError] = useState(false); - const [errorMessage, setErrorMessage] = useState(""); - - useEffect(() => { - const getPrivilegies = async () => { - const { data } = await axios>({ - method: "get", - url: "https://admin.pena.digital/strator/tariff/", - }); - - return data; - }; - - setIsLoading(true); - getPrivilegies() - .then(setTariffs) - .catch(() => { - setIsError(true); - setErrorMessage("Ошибка при получении тарифов"); - }) - .finally(() => setIsLoading(false)); - }, []); - - return { tariffs, isError, isLoading, errorMessage }; -}; diff --git a/src/hooks/useCombinedPrivileges.hook.ts b/src/hooks/useCombinedPrivileges.hook.ts deleted file mode 100644 index c1a4c7a..0000000 --- a/src/hooks/useCombinedPrivileges.hook.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { useEffect, useState } from "react"; - -import { usePrivilegeStore } from "@root/stores/privilegesStore"; -import { useRefreshPrivilegesStore } from "./useRefreshPrivilegesStore.hook"; -import { exampleCartValues } from "@stores/mocks/exampleCartValues" -import { mergedBackFrontPrivilege } from "@root/model/privilege"; - -interface UseCombinedPrivileges { - mergedPrivileges: mergedBackFrontPrivilege[] -} -const translatorServiceKey = { - Шаблонизатор: "templategen" -} -export const useCombinedPrivileges = ():UseCombinedPrivileges => { - -const [mergedPrivileges, setMergedPrivileges] = useState([]) - - const backendPrivileges = usePrivilegeStore((state) => state.privileges); - const frontendPrivileges = exampleCartValues.privileges; - - useEffect(() => { - setMergedPrivileges([...backendPrivileges.map((privilege) => ({ - serviceKey: privilege.serviceKey, - privilegeId: privilege.privilegeId, - name: privilege.name, - description: privilege.description, - type: privilege.type, - price: privilege.price, - })), ...frontendPrivileges]) - }, [backendPrivileges]) - - return { mergedPrivileges }; -}; diff --git a/src/hooks/useDiscounts.hook.ts b/src/hooks/useDiscounts.hook.ts new file mode 100644 index 0000000..6c30d09 --- /dev/null +++ b/src/hooks/useDiscounts.hook.ts @@ -0,0 +1,30 @@ +import { authStore } from "@root/stores/auth"; +import { setDiscounts } from "@root/stores/discounts"; + +import type { GetDiscountResponse } from "@root/model/discount"; + +const makeRequest = authStore.getState().makeRequest; + +export const useDiscounts = () => { + const requestDiscounts = async () => { + const controller = new AbortController(); + + makeRequest({ + url: "https://admin.pena.digital/price/discounts", + method: "get", + useToken: true, + bearer: true, + signal: controller.signal, + }) + .then((result) => { + setDiscounts(result.Discounts); + }) + .catch((error) => { + console.log("Error fetching discounts", error); + }); + + return () => controller.abort(); + }; + + return { requestDiscounts }; +}; diff --git a/src/hooks/useGetPrivileges.hook.ts b/src/hooks/useGetPrivileges.hook.ts deleted file mode 100644 index fc4fd84..0000000 --- a/src/hooks/useGetPrivileges.hook.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { useEffect, useState } from "react"; -import axios from "axios"; -import { RealPrivilege } from "@root/model/privilege"; - -export type Privilege = { - createdAt: string; - description: string; - isDeleted: boolean; - name: string; - price: number; - privilegeId: string; - serviceKey: string; - type: "count" | "day" | "mb"; - updatedAt: string; - value: string; - _id: string; -}; - -type UsePrivilegies = { - privilegies: RealPrivilege[] - isError: boolean; - isLoading: boolean; - errorMessage: string; -}; - -export const useGetPrivilegies = (): UsePrivilegies => { - const [privilegies, setPrivilegies] = useState([]); - const [isLoading, setIsLoading] = useState(false); - const [isError, setIsError] = useState(false); - const [errorMessage, setErrorMessage] = useState(""); - - useEffect(() => { - const getPrivilegies = async () => { - const { data } = await axios({ - method: "get", - url: "https://admin.pena.digital/strator/privilege/service", - }); - - return data; - }; - - setIsLoading(true); - getPrivilegies() - .then(setPrivilegies) - .catch(() => { - setIsError(true); - setErrorMessage("Ошибка при получении привилегий"); - }) - .finally(() => setIsLoading(false)); - }, []); - - return { privilegies, isError, isLoading, errorMessage }; -}; diff --git a/src/hooks/usePrivilegies.hook.ts b/src/hooks/usePrivilegies.hook.ts new file mode 100644 index 0000000..183240c --- /dev/null +++ b/src/hooks/usePrivilegies.hook.ts @@ -0,0 +1,82 @@ +import { useState, useEffect } from "react"; +import axios from "axios"; + +import { resetPrivilegeArray } from "@root/stores/privilegesStore"; +import { exampleCartValues } from "@stores/mocks/exampleCartValues"; + +import type { RealPrivilege } from "@root/model/privilege"; + +export type Privilege = { + createdAt: string; + description: string; + isDeleted: boolean; + name: string; + price: number; + privilegeId: string; + serviceKey: string; + type: "count" | "day" | "mb"; + updatedAt: string; + value: string; + _id: string; +}; + +type SeverPrivilegiesResponse = { + templategen: RealPrivilege[]; +}; + +type UsePrivilegies = { + requestPrivilegies: () => Promise; + isError: boolean; + isLoading: boolean; + errorMessage: string; +}; + +export const usePrivilegies = (): UsePrivilegies => { + const [privilegies, setPrivilegies] = useState([]); + const [isLoading, setIsLoading] = useState(false); + const [isError, setIsError] = useState(false); + const [errorMessage, setErrorMessage] = useState(""); + + useEffect(() => { + let extracted: RealPrivilege[] = []; + for (let serviceKey in privilegies) { + //Приходит объект. В его значениях массивы привилегий для разных сервисов. Высыпаем в общую кучу и обновляем стор + extracted = extracted.concat(privilegies[serviceKey]); + } + + let readyArray = extracted.map((privilege) => ({ + serviceKey: privilege.serviceKey, + privilegeId: privilege.privilegeId, + name: privilege.name, + description: privilege.description, + type: privilege.type, + price: privilege.price, + value: privilege.value, + id: privilege._id, + })); + + resetPrivilegeArray([...readyArray, ...exampleCartValues.privileges]); + }, [privilegies]); + + const requestPrivilegies = async () => { + setIsLoading(true); + + await axios + .get( + "https://admin.pena.digital/strator/privilege/service" + ) + .then(({ data }) => setPrivilegies(data.templategen)) + .catch(() => { + setIsError(true); + setErrorMessage("Ошибка при получении привилегий"); + }) + .finally(() => setIsLoading(false)); + }; + + return { + requestPrivilegies, + isError, + isLoading, + errorMessage, + }; +}; diff --git a/src/hooks/useRefreshPrivilegesStore.hook.ts b/src/hooks/useRefreshPrivilegesStore.hook.ts deleted file mode 100644 index 739302b..0000000 --- a/src/hooks/useRefreshPrivilegesStore.hook.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { useEffect, useState } from "react"; -import axios from "axios"; -import { RealPrivilege } from "@root/model/privilege"; -import { resetPrivilegeArray } from "@root/stores/privilegesStore"; -import { useGetPrivilegies } from "./useGetPrivileges.hook"; - -type RefreshPrivilegesStore = { - isError: boolean; - isLoading: boolean; - errorMessage: string; -}; - -export const useRefreshPrivilegesStore = (): RefreshPrivilegesStore => { - const gotten = useGetPrivilegies() - const [isLoading, setIsLoading] = useState(gotten.isLoading); - const [isError, setIsError] = useState(gotten.isError); - const [errorMessage, setErrorMessage] = useState(gotten.errorMessage); - - useEffect(() => { - let extracted:RealPrivilege[] = [] - for (let serviceKey in gotten.privilegies) { //Приходит объект. В его значениях массивы привилегий для разных сервисов. Высыпаем в общую кучу и обновляем стор - extracted = extracted.concat(gotten.privilegies[serviceKey]) - } - let readyArray = extracted.map((privilege) => ({ - serviceKey: privilege.serviceKey, - privilegeId: privilege.privilegeId, - name: privilege.name, - description: privilege.description, - type: privilege.type, - price: privilege.price, - value: privilege.value, - id: privilege._id, - })) - resetPrivilegeArray(readyArray) - }, [gotten.privilegies]); - - - - return {isError:gotten.isError, isLoading:gotten.isLoading, errorMessage:gotten.errorMessage}; -}; diff --git a/src/hooks/useGetTariffs.hook.ts b/src/hooks/useTariffs.hook.ts similarity index 58% rename from src/hooks/useGetTariffs.hook.ts rename to src/hooks/useTariffs.hook.ts index f1df644..daa8a41 100644 --- a/src/hooks/useGetTariffs.hook.ts +++ b/src/hooks/useTariffs.hook.ts @@ -4,9 +4,8 @@ import { authStore } from "@root/stores/auth"; import { Tariff, Tariff_BACKEND } from "@root/model/tariff"; import { resetTariffsStore } from "@root/stores/tariffsStore"; - type UseGetTariffs = { - requestTariffs: (page?: number, limit?: number) => Promise; + requestTariffs: (page?: number, tariffs?: Tariff_BACKEND[]) => Promise; isLoading: boolean; }; @@ -15,15 +14,37 @@ type GetTariffsResponse = { tariffs: Tariff_BACKEND[]; }; -export const useGetTariffs = (): UseGetTariffs => { +export const useTariffs = (): UseGetTariffs => { const token = authStore((state) => state.token); - const [allTariffs, setAllTariffs] = useState>({}); const [isLoading, setIsLoading] = useState(false); + const [tariffs, setTariffs] = useState([]); - let newSt:Record + useEffect(() => { + const convertedTariffs: Record = {}; + tariffs + .filter(({ isDeleted }) => !isDeleted) + .forEach((tariff) => { + convertedTariffs[tariff._id] = { + id: tariff._id, + name: tariff.name, + isCustom: tariff.price ? true : false, + amount: tariff.privilegies[0].amount, + isFront: false, + privilegeId: tariff.privilegies[0].privilegeId, + price: tariff.privilegies[0].price, + isDeleted: tariff.isDeleted, + customPricePerUnit: tariff.price, + }; + }); - const requestTariffs = async (page: number = 1): Promise => { + resetTariffsStore(convertedTariffs); + }, [tariffs]); + + const requestTariffs = async ( + page: number = 1, + existingTariffs: Tariff_BACKEND[] = [] + ): Promise => { setIsLoading(true); try { @@ -35,48 +56,17 @@ export const useGetTariffs = (): UseGetTariffs => { } ); - // data.tariffs.forEach(async (t:any) => { - // await axios({ - // method: "delete", - // url: "https://admin.pena.digital/strator/tariff/delete", - // headers: { - // Authorization: `Bearer ${token}`, - // }, - // data: { id: t._id }, - // }); - // }) - - - const tariffsObj:Record = {} - data.tariffs.filter((tariff) => {return !tariff.isDeleted}).forEach((tariff) => { - tariffsObj[tariff._id] = { - id: tariff._id, - name: tariff.name, - isCustom: tariff.price ? true : false, - amount: tariff.privilegies[0].amount, - isFront: false, - privilegeId: tariff.privilegies[0].privilegeId, - price: tariff.privilegies[0].price, - isDeleted: tariff.isDeleted, - customPricePerUnit: tariff.price, - - } - }) - - newSt = {...newSt, ...tariffsObj} - - if (page < data.totalPages) { - return requestTariffs(page + 1); + return requestTariffs(page + 1, [...existingTariffs, ...data.tariffs]); } - resetTariffsStore(newSt) - setIsLoading(false); - } catch { - setIsLoading(false); + setTariffs([...existingTariffs, ...data.tariffs]); + } catch { throw new Error("Ошибка при получении тарифов"); + } finally { + setIsLoading(false); } - } + }; return { requestTariffs, isLoading }; }; diff --git a/src/kitUI/Cart/Cart.tsx b/src/kitUI/Cart/Cart.tsx index 2dd1f7b..15c488b 100644 --- a/src/kitUI/Cart/Cart.tsx +++ b/src/kitUI/Cart/Cart.tsx @@ -15,10 +15,15 @@ import { FormControlLabel, } from "@mui/material"; import Input from "@kitUI/input"; -import { useEffect, useState } from "react"; +import { useState } from "react"; import { GridSelectionModel } from "@mui/x-data-grid"; -import { calcCartData, createCartItem, findDiscountFactor, formatDiscountFactor } from "./calc"; +import { + calcCartData, + createCartItem, + findDiscountFactor, + formatDiscountFactor, +} from "./calc"; import { AnyDiscount, CartItemTotal } from "@root/model/cart"; import { Privilege } from "@root/model/tariff"; @@ -29,10 +34,11 @@ import { findPrivilegeById } from "@root/stores/privilegesStore"; import { testUser } from "@root/stores/mocks/user"; import { useTariffStore } from "@root/stores/tariffsStore"; import { Discount } from "@root/model/discount"; -import useDiscounts from "@root/utils/hooks/useDiscounts"; import { authStore } from "@root/stores/auth"; interface Props { + requestPrivilegies: () => Promise; + requestDiscounts: () => Promise<() => void>; selectedTariffs: GridSelectionModel; } @@ -52,49 +58,63 @@ interface MergedTariff { isFront: boolean; } -export default function Cart({ selectedTariffs }: Props) { - let cartTariffs = Object.values(useTariffStore().tariffs) - // useDiscounts({ onNewDiscounts: setDiscounts }); +export default function Cart({ + requestPrivilegies, + requestDiscounts, + selectedTariffs, +}: Props) { + let cartTariffs = Object.values(useTariffStore().tariffs); // const discounts = useDiscountStore((store) => store.discounts); const [discounts, setDiscounts] = useState([]); const cartTotal = useCartStore((state) => state.cartTotal); const setCartTotal = useCartStore((store) => store.setCartTotal); const [couponField, setCouponField] = useState(""); const [loyaltyField, setLoyaltyField] = useState(""); - const makeRequest = authStore.getState().makeRequest; + const makeRequest = authStore.getState().makeRequest; const [errorMessage, setErrorMessage] = useState(null); const [isNonCommercial, setIsNonCommercial] = useState(false); -console.log(cartTotal) + const cartRows = cartTotal?.items.map((cartItemTotal) => { const privilege = findPrivilegeById(cartItemTotal.tariff.privilegeId); const service = privilege?.serviceKey; - const serviceDiscount = service ? cartTotal.discountsByService[privilege?.serviceKey] : null; + const serviceDiscount = service + ? cartTotal.discountsByService[privilege?.serviceKey] + : null; - console.log(cartTotal.discountsByService) - console.log(serviceDiscount) - console.log(cartItemTotal) + console.log(cartTotal.discountsByService); + console.log(serviceDiscount); + console.log(cartItemTotal); const envolvedDiscountsElement = ( {cartItemTotal.envolvedDiscounts.map((discount, index, arr) => ( - - {index < arr.length - (serviceDiscount ? 0 : 1) && } + + {index < arr.length - (serviceDiscount ? 0 : 1) && ( + + )} ))} {serviceDiscount && ( - + )} ); - const totalIncludingServiceDiscount = cartItemTotal.totalPrice * (serviceDiscount?.Target.Factor || 1); - console.log(cartItemTotal.totalPrice) - console.log(serviceDiscount?.Target.Factor) - console.log(serviceDiscount) + const totalIncludingServiceDiscount = + cartItemTotal.totalPrice * (serviceDiscount?.Target.Factor || 1); + console.log(cartItemTotal.totalPrice); + console.log(serviceDiscount?.Target.Factor); + console.log(serviceDiscount); return { id: cartItemTotal.tariff.id, @@ -109,7 +129,10 @@ console.log(cartTotal) const cartDiscountsResultFactor = cartDiscounts && cartDiscounts?.length > 1 && - cartDiscounts.reduce((acc, discount) => acc * findDiscountFactor(discount), 1); + cartDiscounts.reduce( + (acc, discount) => acc * findDiscountFactor(discount), + 1 + ); const envolvedCartDiscountsElement = cartDiscounts && ( ))}   - {cartDiscountsResultFactor && `= ${formatDiscountFactor(cartDiscountsResultFactor)}`} + {cartDiscountsResultFactor && + `= ${formatDiscountFactor(cartDiscountsResultFactor)}`} ); async function handleCalcCartClick() { + await requestPrivilegies(); + await requestDiscounts(); + //рассчитать - const dis = await makeRequest({ - url: "https://admin.pena.digital/price/discounts", - method: "get", - useToken: true, - bearer: true, - }) - console.log(dis) - // @ts-ignore - setDiscounts(dis.Discounts) + const dis = await makeRequest({ + url: "https://admin.pena.digital/price/discounts", + method: "get", + useToken: true, + bearer: true, + }); + console.log(dis); + // @ts-ignore + setDiscounts(dis.Discounts); - const cartItems = cartTariffs.filter((tariff) => selectedTariffs.includes(tariff.id)).map((tariff) => createCartItem(tariff)); + const cartItems = cartTariffs + .filter((tariff) => selectedTariffs.includes(tariff.id)) + .map((tariff) => createCartItem(tariff)); - console.log(cartItems) + console.log(cartItems); let loyaltyValue = parseInt(loyaltyField); if (!isFinite(loyaltyValue)) loyaltyValue = 0; - const activeDiscounts = discounts.filter((discount) => !discount.Deprecated); + const activeDiscounts = discounts.filter( + (discount) => !discount.Deprecated + ); const cartData = calcCartData({ user: testUser, @@ -293,22 +324,34 @@ console.log(cartTotal) }} > - + Имя - + Описание - + Скидки - + стоимость @@ -349,7 +392,7 @@ console.log(cartTotal) color: theme.palette.secondary.main, }} > - {(row.price/100).toFixed(2)} ₽ + {(row.price / 100).toFixed(2)} ₽ ))} @@ -378,7 +421,7 @@ console.log(cartTotal) marginTop: "10px", }} > - ИТОГО: {(cartTotal?.totalPrice/100).toFixed(2)} ₽ + ИТОГО: {(cartTotal?.totalPrice / 100).toFixed(2)} ₽ )} @@ -392,10 +435,16 @@ console.log(cartTotal) ); } -function DiscountTooltip({ discount, cartItemTotal }: { discount: Discount; cartItemTotal?: CartItemTotal }) { +function DiscountTooltip({ + discount, + cartItemTotal, +}: { + discount: Discount; + cartItemTotal?: CartItemTotal; +}) { const discountText = formatDiscountFactor(findDiscountFactor(discount)); - return discountText ? + return discountText ? ( @@ -406,6 +455,7 @@ function DiscountTooltip({ discount, cartItemTotal }: { discount: Discount; cart > {discountText} - : - Ошибка поиска значения скидки + ) : ( + Ошибка поиска значения скидки + ); } diff --git a/src/pages/dashboard/Content/DiscountManagement/DiscountDataGrid.tsx b/src/pages/dashboard/Content/DiscountManagement/DiscountDataGrid.tsx index d9c91ff..4442b89 100644 --- a/src/pages/dashboard/Content/DiscountManagement/DiscountDataGrid.tsx +++ b/src/pages/dashboard/Content/DiscountManagement/DiscountDataGrid.tsx @@ -1,169 +1,200 @@ -import { Box, IconButton, useTheme } from "@mui/material"; -import { DataGrid, GridColDef, GridRowsProp, GridToolbar } from "@mui/x-data-grid"; +import { useEffect } from "react"; +import { Box, IconButton, useTheme, Tooltip } from "@mui/material"; +import { + DataGrid, + GridColDef, + GridRowsProp, + GridToolbar, +} from "@mui/x-data-grid"; import { formatDiscountFactor } from "@root/kitUI/Cart/calc"; -import { openEditDiscountDialog, setDiscounts, setSelectedDiscountIds, updateDiscount, useDiscountStore } from "@root/stores/discounts"; -import useDiscounts from "@root/utils/hooks/useDiscounts"; -import DeleteIcon from '@mui/icons-material/Delete'; -import EditIcon from '@mui/icons-material/Edit'; +import { + openEditDiscountDialog, + setSelectedDiscountIds, + updateDiscount, + useDiscountStore, +} from "@root/stores/discounts"; +import DeleteIcon from "@mui/icons-material/Delete"; +import EditIcon from "@mui/icons-material/Edit"; import { deleteDiscount } from "@root/api/discounts"; import { GridSelectionModel } from "@mui/x-data-grid"; +import { useDiscounts } from "@root/hooks/useDiscounts.hook"; +import AutorenewIcon from "@mui/icons-material/Autorenew"; const columns: GridColDef[] = [ - // { - // field: "id", - // headerName: "ID", - // width: 70, - // sortable: false, - // }, - { - field: "name", - headerName: "Название скидки", - width: 150, - sortable: false, - renderCell: ({ row, value }) => ( - {value} - ), - }, - { - field: "description", - headerName: "Описание", - width: 120, - sortable: false, - }, - { - field: "conditionType", - headerName: "Тип условия", - width: 120, - sortable: false, - }, - { - field: "factor", - headerName: "Процент скидки", - width: 120, - sortable: false, - }, - { - field: "value", - headerName: "Значение", - width: 120, - sortable: false, - }, - { - field: "active", - headerName: "Активна", - width: 80, - sortable: false, - }, - { - field: "edit", - headerName: "Изменить", - width: 80, - sortable: false, - renderCell: ({ row }) => { - return ( - { - openEditDiscountDialog(row.id); - }} - > - - - ); - }, - }, - { - field: "delete", - headerName: "Удалить", - width: 80, - sortable: false, - renderCell: ({ row }) => ( - { - deleteDiscount(row.id).then(updateDiscount); - }} - > - - - ), + // { + // field: "id", + // headerName: "ID", + // width: 70, + // sortable: false, + // }, + { + field: "name", + headerName: "Название скидки", + width: 150, + sortable: false, + renderCell: ({ row, value }) => ( + {value} + ), + }, + { + field: "description", + headerName: "Описание", + width: 120, + sortable: false, + }, + { + field: "conditionType", + headerName: "Тип условия", + width: 120, + sortable: false, + }, + { + field: "factor", + headerName: "Процент скидки", + width: 120, + sortable: false, + }, + { + field: "value", + headerName: "Значение", + width: 120, + sortable: false, + }, + { + field: "active", + headerName: "Активна", + width: 80, + sortable: false, + }, + { + field: "edit", + headerName: "Изменить", + width: 80, + sortable: false, + renderCell: ({ row }) => { + return ( + { + openEditDiscountDialog(row.id); + }} + > + + + ); }, + }, + { + field: "delete", + headerName: "Удалить", + width: 80, + sortable: false, + renderCell: ({ row }) => ( + { + deleteDiscount(row.id).then(updateDiscount); + }} + > + + + ), + }, ]; -const layerTranslate = [ - "", - "Товар", - "Сервис", - "корзина", - "лояльность", -]; +const layerTranslate = ["", "Товар", "Сервис", "корзина", "лояльность"]; const layerValue = [ - "", - "Term", - "PriceFrom", - "CartPurchasesAmount", - "PurchasesAmount", + "", + "Term", + "PriceFrom", + "CartPurchasesAmount", + "PurchasesAmount", ]; interface Props { - selectedRowsHC: (array:GridSelectionModel) => void + selectedRowsHC: (array: GridSelectionModel) => void; } -export default function DiscountDataGrid({selectedRowsHC}:Props) { - const theme = useTheme(); - const selectedDiscountIds = useDiscountStore((state) => state.selectedDiscountIds); - const realDiscounts = useDiscountStore(state => state.discounts); - const editDiscountId = useDiscountStore(state => state.editDiscountId); +export default function DiscountDataGrid({ selectedRowsHC }: Props) { + const theme = useTheme(); + const selectedDiscountIds = useDiscountStore( + (state) => state.selectedDiscountIds + ); + const realDiscounts = useDiscountStore((state) => state.discounts); + const editDiscountId = useDiscountStore((state) => state.editDiscountId); + const { requestDiscounts } = useDiscounts(); - useDiscounts({ onNewDiscounts: setDiscounts }); + useEffect(() => { + requestDiscounts(); + }, []); - const rowBackDicounts: GridRowsProp = realDiscounts.filter(e => e.Layer > 0).map(discount => { - console.log(discount.Condition[layerValue[discount.Layer] as keyof typeof discount.Condition]) - return({ + const rowBackDicounts: GridRowsProp = realDiscounts + .filter((e) => e.Layer > 0) + .map((discount) => { + console.log( + discount.Condition[ + layerValue[discount.Layer] as keyof typeof discount.Condition + ] + ); + return { id: discount.ID, name: discount.Name, description: discount.Description, conditionType: layerTranslate[discount.Layer], factor: formatDiscountFactor(discount.Target.Factor), - value: discount.Condition[layerValue[discount.Layer] as keyof typeof discount.Condition], + value: + discount.Condition[ + layerValue[discount.Layer] as keyof typeof discount.Condition + ], active: discount.Deprecated ? "🚫" : "✅", deleted: discount.Audit.Deleted, - })}); + }; + }); - return ( - - - { - selectedRowsHC(array) - setSelectedDiscountIds(array) - }} - disableSelectionOnClick - sx={{ - color: theme.palette.secondary.main, - "& .MuiDataGrid-iconSeparator": { - display: "none", - }, - "& .css-levciy-MuiTablePagination-displayedRows": { - color: theme.palette.secondary.main, - }, - "& .MuiSvgIcon-root": { - color: theme.palette.secondary.main, - }, - "& .MuiTablePagination-selectLabel": { - color: theme.palette.secondary.main, - }, - "& .MuiInputBase-root": { - color: theme.palette.secondary.main, - }, - "& .MuiButton-text": { - color: theme.palette.secondary.main, - }, - }} - components={{ Toolbar: GridToolbar }} - /> - - - ); + return ( + + + + + + + + { + selectedRowsHC(array); + setSelectedDiscountIds(array); + }} + disableSelectionOnClick + sx={{ + color: theme.palette.secondary.main, + "& .MuiDataGrid-iconSeparator": { + display: "none", + }, + "& .css-levciy-MuiTablePagination-displayedRows": { + color: theme.palette.secondary.main, + }, + "& .MuiSvgIcon-root": { + color: theme.palette.secondary.main, + }, + "& .MuiTablePagination-selectLabel": { + color: theme.palette.secondary.main, + }, + "& .MuiInputBase-root": { + color: theme.palette.secondary.main, + }, + "& .MuiButton-text": { + color: theme.palette.secondary.main, + }, + }} + components={{ Toolbar: GridToolbar }} + /> + + + ); } diff --git a/src/pages/dashboard/Content/Tariffs/CreateTariff.tsx b/src/pages/dashboard/Content/Tariffs/CreateTariff.tsx index ebe2e32..9c1f97f 100644 --- a/src/pages/dashboard/Content/Tariffs/CreateTariff.tsx +++ b/src/pages/dashboard/Content/Tariffs/CreateTariff.tsx @@ -1,56 +1,63 @@ import { useState } from "react"; -import { Typography, Container, Button, Select, MenuItem, FormControl, InputLabel, useTheme, Box } from "@mui/material"; +import { + Typography, + Container, + Button, + Select, + MenuItem, + FormControl, + InputLabel, + useTheme, + Box, +} from "@mui/material"; import { nanoid } from "nanoid"; import { enqueueSnackbar } from "notistack"; import axios from "axios"; import { CustomTextField } from "@root/kitUI/CustomTextField"; -import { Tariff } from "@root/model/tariff"; - import { authStore } from "@root/stores/auth"; -import { findPrivilegeById, usePrivilegeStore } from "@root/stores/privilegesStore"; -import { useGetTariffs } from "@root/hooks/useGetTariffs.hook"; +import { + findPrivilegeById, + usePrivilegeStore, +} from "@root/stores/privilegesStore"; -interface Props { - getTariffs: () => void -} - -export default function CreateTariff() { +type CreateTariffProps = { + requestTariffs: () => Promise; +}; +export default function CreateTariff({ requestTariffs }: CreateTariffProps) { const { token } = authStore(); const theme = useTheme(); - const privileges = usePrivilegeStore( store => store.privileges); + const privileges = usePrivilegeStore((store) => store.privileges); const [nameField, setNameField] = useState(""); const [amountField, setAmountField] = useState(""); const [customPriceField, setCustomPriceField] = useState(""); const [privilegeIdField, setPrivilegeIdField] = useState(""); - const privilege = findPrivilegeById(privilegeIdField) - - const { requestTariffs } = useGetTariffs() + const privilege = findPrivilegeById(privilegeIdField); const checkFulledFields = () => { if (nameField.length === 0) { enqueueSnackbar("Пустое название тарифа"); - return false + return false; } if (amountField.length === 0) { enqueueSnackbar("Пустое кол-во едениц привилегии"); - return false + return false; } if (privilegeIdField.length === 0) { enqueueSnackbar("Не выбрана привилегия"); - return false + return false; } if (!privilege) { enqueueSnackbar("Привилегия с таким id не найдена"); - return false + return false; } - return true - } + return true; + }; const createTariffBackend = () => { if (checkFulledFields() && privilege !== null) { @@ -78,14 +85,14 @@ export default function CreateTariff() { ], }, }) - .then(() => { - requestTariffs() - }) - .catch(() => { - enqueueSnackbar("что-то пошло не так") - }) + .then(() => { + requestTariffs(); + }) + .catch(() => { + enqueueSnackbar("что-то пошло не так"); + }); } - } + }; // const createTariffFrontend = () => { // if (checkFulledFields() && privilege !== null) { // updateTariffStore({ @@ -137,30 +144,30 @@ export default function CreateTariff() { Привилегия + border: "1px solid", + }, + ".MuiSvgIcon-root ": { + fill: theme.palette.secondary.main, + }, + }} + inputProps={{ sx: { pt: "12px" } }} + > + {privileges.map((privilege) => ( + + {privilege.description} + + ))} + {privilege && ( {/* Тариф: diff --git a/src/pages/dashboard/Content/Tariffs/EditModal.tsx b/src/pages/dashboard/Content/Tariffs/EditModal.tsx index 50c2a92..f57a7f8 100644 --- a/src/pages/dashboard/Content/Tariffs/EditModal.tsx +++ b/src/pages/dashboard/Content/Tariffs/EditModal.tsx @@ -9,28 +9,24 @@ import axios from "axios"; import { authStore } from "@root/stores/auth"; import { Privilege, Tariff } from "@root/model/tariff"; import { useTariffStore, updateTariff } from "@root/stores/tariffsStore"; -import { arrayBuffer } from "stream/consumers"; -import { useGetTariffs } from "@root/hooks/useGetTariffs.hook"; import { findPrivilegeById } from "@root/stores/privilegesStore"; import { enqueueSnackbar } from "notistack"; - interface EditProps { - tarifIid: string, - tariffName: string, - tariffPrice: number, - privilege: Privilege, - token: string + tarifIid: string; + tariffName: string; + tariffPrice: number; + privilege: Privilege; + token: string; } - const editTariff = ({ tarifIid, tariffName, tariffPrice, privilege, - token -}:EditProps): Promise => { + token, +}: EditProps): Promise => { return axios({ method: "put", url: `https://admin.pena.digital/strator/tariff/${tarifIid}`, @@ -41,120 +37,142 @@ const editTariff = ({ name: tariffName, price: tariffPrice, isCustom: false, - privilegies: [privilege] + privilegies: [privilege], }, }); -} +}; interface Props { - tariff: Tariff + tariff: Tariff; + requestTariffs: () => Promise; } -export default function EditModal({tariff = undefined}:Props) { +export default function EditModal({ + tariff = undefined, + requestTariffs, +}: Props) { const [open, setOpen] = useState(false); const [name, setName] = useState(""); const [price, setPrice] = useState(""); const { token } = authStore(); const tariffs = useTariffStore((state) => state.tariffs); - const currentTariff = tariff ? tariffs[tariff.id] : undefined - const { requestTariffs } = useGetTariffs() - + const currentTariff = tariff ? tariffs[tariff.id] : undefined; + useEffect(() => { - setOpen(tariff !== undefined) - }, [tariff]) + setOpen(tariff !== undefined); + }, [tariff]); - return setOpen(false)} - aria-labelledby="modal-modal-title" - aria-describedby="modal-modal-description" + return ( + setOpen(false)} + aria-labelledby="modal-modal-title" + aria-describedby="modal-modal-description" + > + - - - Редактирование тариффа - + Редактирование тариффа + - {currentTariff !== undefined && ( - - Название Тарифа: {currentTariff.name} - setName(event.target.value)} - label="Имя" - name="name" - value={name} - sx={{ marginBottom: "10px" }} - /> - Цена за единицу: {currentTariff.pricePerUnit} - setPrice(event.target.value)} - label="Цена за единицу" - name="price" - value={price} - sx={{ marginBottom: "10px" }} - /> - - - )} - - + } else { + //front/store + let array = tariffs; + let index; + tariffs.forEach((p: any, i: number) => { + if (currentTariff.id == p.id) index = i; + }); + if (index !== undefined) { + array[index].name = name; + array[index].amount = Number(price); + updateTariffs(array); + setOpen(false); + } else { + console.log("не нашел такой тариф в сторе"); + } + } + }} + > + Редактировать + + + )} + + + ); } diff --git a/src/pages/dashboard/Content/Tariffs/Privileges/Privileges.tsx b/src/pages/dashboard/Content/Tariffs/Privileges/Privileges.tsx index 9566a9f..85c963a 100644 --- a/src/pages/dashboard/Content/Tariffs/Privileges/Privileges.tsx +++ b/src/pages/dashboard/Content/Tariffs/Privileges/Privileges.tsx @@ -1,8 +1,8 @@ import { GridColDef } from "@mui/x-data-grid"; import DataGrid from "@kitUI/datagrid"; -import { Typography } from "@mui/material"; -import { useCombinedPrivileges } from "@root/hooks/useCombinedPrivileges.hook"; +import { Tooltip, IconButton } from "@mui/material"; import { usePrivilegeStore } from "@root/stores/privilegesStore"; +import AutorenewIcon from "@mui/icons-material/Autorenew"; const columns: GridColDef[] = [ { field: "id", headerName: "id", width: 150 }, @@ -12,25 +12,31 @@ const columns: GridColDef[] = [ { field: "price", headerName: "Стоимость", width: 100 }, ]; -export default function Privileges() { +type Props = { + requestPrivilegies: () => Promise; +}; + +export default function Privileges({ requestPrivilegies }: Props) { const privileges = usePrivilegeStore((state) => state.privileges); // const { mergedPrivileges } = useCombinedPrivileges(); const privilegesGridData = privileges - .filter(privilege => ( - !privilege.isDeleted - )) - .map((privilege) => ({ - id: privilege.privilegeId, - name: privilege.name, - description: privilege.description, - type: privilege.type, - price: privilege.price, - })); + .filter((privilege) => !privilege.isDeleted) + .map((privilege) => ({ + id: privilege.privilegeId, + name: privilege.name, + description: privilege.description, + type: privilege.type, + price: privilege.price, + })); return ( - + <> + + + + + + + ); } diff --git a/src/pages/dashboard/Content/Tariffs/index.tsx b/src/pages/dashboard/Content/Tariffs/index.tsx index daeb7f1..75023b8 100644 --- a/src/pages/dashboard/Content/Tariffs/index.tsx +++ b/src/pages/dashboard/Content/Tariffs/index.tsx @@ -1,53 +1,30 @@ import { useState, useEffect } from "react"; -import { Container, IconButton, Tooltip, Typography } from "@mui/material"; +import { Container, Typography } from "@mui/material"; import { GridSelectionModel } from "@mui/x-data-grid"; import Cart from "@root/kitUI/Cart/Cart"; -import axios from "axios"; -import { enqueueSnackbar } from "notistack"; -import { authStore } from "@root/stores/auth"; -import { useTariffStore } from "@root/stores/tariffsStore"; -import { usePrivilegeStore, resetPrivilegeArray } from "@root/stores/privilegesStore"; -import { useGetTariffs } from "@root/hooks/useGetTariffs.hook"; +import { useTariffs } from "@root/hooks/useTariffs.hook"; +import { usePrivilegies } from "@root/hooks/usePrivilegies.hook"; +import { useDiscounts } from "@root/hooks/useDiscounts.hook"; import TariffsDG from "./tariffsDG"; import CreateTariff from "./CreateTariff"; import Privileges from "./Privileges/Privileges"; import ChangePriceModal from "./Privileges/ChangePriceModal"; -import {useRefreshPrivilegesStore} from "@root/hooks/useRefreshPrivilegesStore.hook" -import { Tariff } from "@root/model/tariff"; -import AutorenewIcon from '@mui/icons-material/Autorenew'; -import { RealPrivilege } from "@root/model/privilege"; -import { Discount, GetDiscountResponse } from "@root/model/discount"; export default function Tariffs() { - const token = authStore((state) => state.token); - const privileges = usePrivilegeStore((state) => state.privileges); - const tariffs = useTariffStore((state) => state.tariffs); - const [selectedTariffs, setSelectedTariffs] = useState([]); - const refreshStores = async () => { - const priv = await axios({ - method: "get", - url: "https://admin.pena.digital/strator/privilege/service", - }); - let extracted:RealPrivilege[] = [] - for (let serviceKey in priv.data) { //Приходит объект. В его значениях массивы привилегий для разных сервисов. Высыпаем в общую кучу и обновляем стор - extracted = extracted.concat(priv.data[serviceKey]) - } - let readyArray = extracted.map((privilege) => ({ - serviceKey: privilege.serviceKey, - privilegeId: privilege.privilegeId, - name: privilege.name, - description: privilege.description, - type: privilege.type, - price: privilege.price, - value: privilege.value, - id: privilege._id, - })) - resetPrivilegeArray(readyArray) - enqueueSnackbar("привилегии обновлены") - } + const [selectedTariffs, setSelectedTariffs] = useState( + [] + ); + const { requestTariffs } = useTariffs(); + const { requestPrivilegies } = usePrivilegies(); + const { requestDiscounts } = useDiscounts(); + + useEffect(() => { + requestTariffs(); + requestPrivilegies(); + }, []); return ( - - - - - Список привилегий - - + - + Список тарифов setSelectedTariffs(selectionModel)} + handleSelectionChange={(selectionModel) => + setSelectedTariffs(selectionModel) + } + requestTariffs={requestTariffs} /> - + ); -} \ No newline at end of file +} diff --git a/src/pages/dashboard/Content/Tariffs/tariffsDG.tsx b/src/pages/dashboard/Content/Tariffs/tariffsDG.tsx index d4f23e8..0bbf603 100644 --- a/src/pages/dashboard/Content/Tariffs/tariffsDG.tsx +++ b/src/pages/dashboard/Content/Tariffs/tariffsDG.tsx @@ -2,7 +2,7 @@ import React from "react"; import { useEffect, useState } from "react"; import { GridColDef, GridSelectionModel, GridToolbar } from "@mui/x-data-grid"; -import { Box, Button, IconButton } from "@mui/material"; +import { Box, Button, IconButton,Tooltip } from "@mui/material"; import BackspaceIcon from "@mui/icons-material/Backspace"; import { enqueueSnackbar } from "notistack"; import ModeEditOutlineOutlinedIcon from "@mui/icons-material/ModeEditOutlineOutlined"; @@ -15,28 +15,33 @@ import { findPrivilegeById } from "@root/stores/privilegesStore"; import axios from "axios"; import { authStore } from "@root/stores/auth"; -import DeleteModal from "@root/kitUI/DeleteModal"; +import DeleteModal from "@root/pages/dashboard/Content/Tariffs/DeleteModal"; import EditModal from "./EditModal"; import { Tariff } from "@root/model/tariff"; +import AutorenewIcon from "@mui/icons-material/Autorenew"; interface Props { selectedTariffs: GridSelectionModel; handleSelectionChange: (selectionModel: GridSelectionModel) => void; + requestTariffs: () => Promise; } -export default function TariffsDG({ selectedTariffs, handleSelectionChange }: Props) { - const tariffs = Object.values(useTariffStore().tariffs) +export default function TariffsDG({ + selectedTariffs, + handleSelectionChange, + requestTariffs, +}: Props) { + const tariffs = Object.values(useTariffStore().tariffs); const [deletedRows, setDeletedRows] = useState([]); const [openDeleteModal, setOpenDeleteModal] = useState(false); const [changingTariff, setChangingTariff] = useState(); const [tariffDelete, setTariffDelete] = useState(false); - -console.log(selectedTariffs) + console.log(selectedTariffs); const closeDeleteModal = () => { - setOpenDeleteModal(false) - } + setOpenDeleteModal(false); + }; const columns: GridColDef[] = [ { field: "id", headerName: "ID", width: 100 }, @@ -78,23 +83,27 @@ console.log(selectedTariffs) }, ]; - const gridData = tariffs ?.map((tariff) => { - console.log(tariff) + console.log(tariff); const privilege = findPrivilegeById(tariff.privilegeId); return { id: tariff.id, name: tariff.name, - serviceName: privilege?.serviceKey == "templategen" ? "Шаблонизатор" : privilege?.serviceKey, + serviceName: + privilege?.serviceKey == "templategen" + ? "Шаблонизатор" + : privilege?.serviceKey, privilegeName: privilege?.name, amount: tariff.amount, pricePerUnit: tariff.isCustom ? (tariff.customPricePerUnit || 0) / 100 : (tariff?.price || 0) / 100, type: - findPrivilegeById(tariff.privilegeId)?.value === "шаблон" ? "штука" : findPrivilegeById(tariff.privilegeId)?.value, - customPricePerUnit: tariff.customPricePerUnit === 0 ? "Нет" : "Да", + findPrivilegeById(tariff.privilegeId)?.value === "шаблон" + ? "штука" + : findPrivilegeById(tariff.privilegeId)?.value, + customPricePerUnit: tariff.customPricePerUnit === 0 ? "Нет" : "Да", total: tariff.amount ? (tariff.amount * (tariff.isCustom @@ -106,10 +115,15 @@ console.log(selectedTariffs) }) .sort((item, previous) => (!item?.isFront && previous?.isFront ? 1 : -1)); - // console.log(gridData) + // console.log(gridData) return ( <> + + requestTariffs()}> + + + {selectedTariffs.length ? ( - - @@ -134,8 +159,9 @@ console.log(selectedTariffs) closeDeleteModal(); }} selectedTariffs={selectedTariffs} - /> - + requestTariffs={requestTariffs} + /> + ); } diff --git a/src/pages/dashboard/index.tsx b/src/pages/dashboard/index.tsx index 9023167..bcfc4a3 100644 --- a/src/pages/dashboard/index.tsx +++ b/src/pages/dashboard/index.tsx @@ -1,67 +1,66 @@ import * as React from "react"; -import {Outlet} from 'react-router-dom' -import {useTheme} from '@mui/material/styles'; -import {Box} from "@mui/material"; -import {ThemeProvider} from "@mui/material"; -import CssBaseline from '@mui/material/CssBaseline'; +import { Outlet } from "react-router-dom"; +import { useTheme } from "@mui/material/styles"; +import { Box } from "@mui/material"; +import { ThemeProvider } from "@mui/material"; +import CssBaseline from "@mui/material/CssBaseline"; import Menu from "./Menu"; import Header from "./Header"; import ModalAdmin from "./ModalAdmin"; import ModalUser from "./ModalUser"; import ModalEntities from "./ModalEntities"; -import {useMatch} from "react-router-dom"; -import {useRefreshPrivilegesStore} from "@root/hooks/useRefreshPrivilegesStore.hook" -import { useGetTariffs } from "@root/hooks/useGetTariffs.hook"; +import { useMatch } from "react-router-dom"; export default () => { - useRefreshPrivilegesStore() - const {requestTariffs} = useGetTariffs() - React.useEffect(() => { - requestTariffs() - },[]) - const theme = useTheme() - return ( - - + + + + + - - - - - - - - - + + + + - - - - - ) -} + + + + + ); +}; diff --git a/src/utils/hooks/useDiscounts.ts b/src/utils/hooks/useDiscounts.ts deleted file mode 100644 index 03892a1..0000000 --- a/src/utils/hooks/useDiscounts.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { Discount, GetDiscountResponse } from "@root/model/discount"; -import { authStore } from "@root/stores/auth"; -import { useEffect } from "react"; - - -const makeRequest = authStore.getState().makeRequest; - -export default function useDiscounts({ onError, onNewDiscounts }: { - onNewDiscounts: (response: Discount[]) => void; - onError?: (error: any) => void; -}) { - useEffect(() => { - const controller = new AbortController(); - - makeRequest({ - url: "https://admin.pena.digital/price/discounts", - method: "get", - useToken: true, - bearer: true, - signal: controller.signal, - }).then(result => { - console.log("New discounts", result); - onNewDiscounts(result.Discounts); - }).catch(error => { - console.log("Error fetching discounts", error); - onError?.(error); - }); - - return () => controller.abort(); - }, [onError, onNewDiscounts]); -} \ No newline at end of file