diff --git a/src/index.tsx b/src/index.tsx
index cfeaa9e..e1348c6 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -19,7 +19,7 @@ import Error404 from "@pages/Error404";
import Users from "@pages/dashboard/Content/Users";
import Entities from "@pages/dashboard/Content/Entities";
import Tariffs from "@pages/dashboard/Content/Tariffs";
-import DiscountManagement from "@pages/dashboard/Content/DiscountManagement";
+import DiscountManagement from "@root/pages/dashboard/Content/DiscountManagement/DiscountManagement";
import PromocodeManagement from "@pages/dashboard/Content/PromocodeManagement";
import { SettingRoles } from "@pages/Setting/SettingRoles";
import Support from "@pages/dashboard/Content/Support/Support";
diff --git a/src/kitUI/Cart/Cart.tsx b/src/kitUI/Cart/Cart.tsx
index f35f33b..3cbd5fa 100644
--- a/src/kitUI/Cart/Cart.tsx
+++ b/src/kitUI/Cart/Cart.tsx
@@ -328,9 +328,6 @@ function DiscountTooltip({ discount, cartItemTotal }: {
<>
Скидка: {discount?.name}
{discount?.description}
- -------
- layer: {discount?.layer}
- id: {discount?._id}
>
}>
{discountText}
diff --git a/src/kitUI/CustomTextField.tsx b/src/kitUI/CustomTextField.tsx
index d06729a..1d632fc 100644
--- a/src/kitUI/CustomTextField.tsx
+++ b/src/kitUI/CustomTextField.tsx
@@ -1,13 +1,14 @@
-import { TextField, useTheme } from "@mui/material";
+import { SxProps, TextField, Theme, useTheme } from "@mui/material";
import { HTMLInputTypeAttribute, ChangeEvent } from "react";
-export function CustomTextField({ id, label, value, type, setValue }: {
+export function CustomTextField({ id, label, value, type, sx, onChange: setValue }: {
id: string;
label: string;
value: number | string | null;
type?: HTMLInputTypeAttribute;
- setValue: (e: ChangeEvent) => void;
+ sx?: SxProps;
+ onChange: (e: ChangeEvent) => void;
}) {
const theme = useTheme();
@@ -19,6 +20,7 @@ export function CustomTextField({ id, label, value, type, setValue }: {
variant="filled"
color="secondary"
type={type}
+ sx={sx}
InputProps={{
style: {
backgroundColor: theme.palette.content.main,
diff --git a/src/model/cart.ts b/src/model/cart.ts
index c809037..a751a1f 100644
--- a/src/model/cart.ts
+++ b/src/model/cart.ts
@@ -6,7 +6,7 @@ interface DiscountBase {
name: string;
description: string;
/** Этап применения скидки */
- layer: number;
+ layer?: number;
disabled?: boolean;
}
diff --git a/src/model/tariff.ts b/src/model/tariff.ts
index 8ed9c58..25c18ec 100644
--- a/src/model/tariff.ts
+++ b/src/model/tariff.ts
@@ -9,7 +9,7 @@ export const SERVICE_LIST = [
},
{
serviceKey: "dwarfener",
- displayName: "Сокращатель ссылок",
+ displayName: "Аналитика сокращателя",
},
] as const;
diff --git a/src/pages/dashboard/Content/DiscountManagement.tsx b/src/pages/dashboard/Content/DiscountManagement.tsx
deleted file mode 100644
index 4a5d7be..0000000
--- a/src/pages/dashboard/Content/DiscountManagement.tsx
+++ /dev/null
@@ -1,562 +0,0 @@
-import { Box, Typography, TextField, Checkbox, Button } from "@mui/material";
-import { LocalizationProvider } from "@mui/x-date-pickers/LocalizationProvider";
-import { AdapterDayjs } from "@mui/x-date-pickers/AdapterDayjs";
-import { DesktopDatePicker } from "@mui/x-date-pickers/DesktopDatePicker";
-import Table from "@mui/material/Table";
-import TableBody from "@mui/material/TableBody";
-import TableCell from "@mui/material/TableCell";
-import TableRow from "@mui/material/TableRow";
-import TableContainer from "@mui/material/TableContainer";
-import Paper from "@mui/material/Paper";
-import { DataGrid, GridColDef, GridRowsProp, GridToolbar } from "@mui/x-data-grid";
-import MenuItem from "@mui/material/MenuItem";
-import Select, { SelectChangeEvent } from "@mui/material/Select";
-import theme from "../../../theme";
-import { styled } from "@mui/material/styles";
-import { activateDiscounts, deactivateDiscounts, setSelectedDiscountIds, useDiscountStore } from "../../../stores/discounts";
-import { useState } from "react";
-import { DiscountConditionType } from "@root/model/cart";
-import { ServiceType } from "@root/model/tariff";
-import { findDiscountFactor, formatDiscountFactor } from "@root/kitUI/Cart/calc";
-
-
-const BoxButton = styled('div')(({ theme }) => ({
- [theme.breakpoints.down(400)]: {
- justifyContent: 'center'
- },
-}));
-
-
-const columns: GridColDef[] = [
- {
- field: "id",
- headerName: "ID",
- width: 30,
- sortable: false,
- },
- {
- field: "name",
- headerName: "Название скидки",
- width: 200,
- sortable: false,
- },
- {
- field: "description",
- headerName: "Описание",
- width: 120,
- sortable: false,
- },
- {
- field: "conditionType",
- headerName: "Тип условия",
- width: 120,
- sortable: false,
- },
- {
- field: "factor",
- headerName: "Процент скидки",
- width: 120,
- sortable: false,
- },
- {
- field: "active",
- headerName: "Активна",
- width: 120,
- sortable: false,
- },
-];
-
-
-const DiscountManagement: React.FC = () => {
- const discounts = useDiscountStore(state => state.discounts);
- const selectedDiscountIds = useDiscountStore(state => state.selectedDiscountIds);
- const [isInfinite, setIsInfinite] = useState(false);
- const [serviceType, setServiceType] = useState("templategen");
- const [startDate, setStartDate] = useState(new Date());
- const [endDate, setEndDate] = useState(new Date());
- const [discountTypeField, setDiscountTypeField] = useState("");
- const [discountNameField, setDiscountNameField] = useState("");
- const [discountDescriptionField, setDiscountDescriptionField] = useState("");
- const [discountConditionType, setDiscountConditionType] = useState(null);
- const [discountFactor, setDiscountFactor] = useState(1);
- const [purchasesAmountThreshold, setPurchasesAmountThreshold] = useState(0);
- const [cartPurchasesAmountThreshold, setCartPurchasesAmountThreshold] = useState(0);
- const [discountMinValue, setDiscountMinValue] = useState(0);
-
- const handleServiceTypeChange = (event: SelectChangeEvent) => {
- setServiceType(event.target.value as ServiceType);
- };
-
- function createDiscount() {
- // TODO
- }
-
- // const discountsArrayConverted = discounts.map((item) => {
- // const basketMorePerc = Math.round(Number(item.basketMore) * 100) + "%";
- // const toTimePerc = Math.round(Number(item.toTime) * 100) + "%";
- // const toCapacityPerc = Math.round(Number(item.toCapacity) * 100) + "%";
-
- // const dateFrom = item.from ? new Date(Number(item.from)) : "";
- // const dateDueTo = item.from ? new Date(Number(item.dueTo)) : "";
-
- // const strFrom = dateFrom
- // ? `${dateFrom.getDate()}.${dateFrom.getMonth()}.${dateFrom.getFullYear()}`
- // : "-";
-
- // const strDueTo = dateDueTo
- // ? `${dateDueTo.getDate()}.${dateDueTo.getMonth()}.${dateDueTo.getFullYear()}`
- // : "-";
-
- // if (item.privileges.length) {
- // const result = item.privileges.reduce((acc, privilege) => {
- // acc = acc
- // ? `${acc}, ${privilege.good} - ${privilege.discount}%`
- // : `${privilege.good} - ${Math.round(privilege.discount * 100)}%`;
-
- // return acc;
- // }, "");
-
- // return {
- // ...item, privileges: result, from: strFrom, dueTo: strDueTo,
- // basketMore: basketMorePerc, toTime: toTimePerc, toCapacity: toCapacityPerc
- // };
- // } else {
- // return {
- // ...item, from: strFrom, dueTo: strDueTo,
- // basketMore: basketMorePerc, toTime: toTimePerc, toCapacity: toCapacityPerc
- // };
- // }
- // });
-
- const discountsGridData: GridRowsProp = discounts.map(discount => {
- return {
- id: discount._id,
- name: discount.name,
- description: discount.description,
- conditionType: discount.conditionType,
- factor: formatDiscountFactor(findDiscountFactor(discount)),
- active: discount.disabled ? "🚫" : "✅",
- };
- });
-
- return (
- <>
-
-
- СКИДКИ
-
-
-
- setDiscountNameField(e.target.value)}
- />
-
-
- Условия:
-
-
-
-
- setDiscountFactor(Number(e.target.value) || 1)}
- />
-
- setPurchasesAmountThreshold(Number(e.target.value) || 0)}
- />
-
- setCartPurchasesAmountThreshold(Number(e.target.value) || 0)}
- />
-
- setDiscountMinValue(Number(e.target.value) || 0)}
- />
-
-
-
-
-
-
- Работает, если заплатите 100500 денег
-
-
-
-
- Вы должны будете продать душу дьяволу
-
-
-
-
-
-
-
- Дата действия:
-
-
-
- С
-
- { if (e) { setStartDate(e); } }}
- renderInput={(params) => }
- InputProps={{
- sx: {
- height: "40px",
- color: theme.palette.secondary.main,
- border: "1px solid",
- borderColor: theme.palette.secondary.main,
- "& .MuiSvgIcon-root": { color: theme.palette.secondary.main }
- }
- }}
- />
-
- по
-
- { if (e) { setEndDate(e); } }}
- renderInput={(params) => }
- InputProps={{
- sx: {
- height: "40px",
- color: theme.palette.secondary.main,
- border: "1px solid",
- borderColor: theme.palette.secondary.main,
- "& .MuiSvgIcon-root": { color: theme.palette.secondary.main }
- }
- }}
- />
-
-
-
-
-
- setIsInfinite(p => !p)}
- />
-
-
- Бессрочно
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- >
- );
-};
-
-
-export default DiscountManagement;
diff --git a/src/pages/dashboard/Content/DiscountManagement/CreateDiscount.tsx b/src/pages/dashboard/Content/DiscountManagement/CreateDiscount.tsx
new file mode 100644
index 0000000..4b5dc56
--- /dev/null
+++ b/src/pages/dashboard/Content/DiscountManagement/CreateDiscount.tsx
@@ -0,0 +1,335 @@
+import { Box, Typography, Button, useTheme, FormControl, FormLabel, RadioGroup, FormControlLabel, Radio, InputLabel } from "@mui/material";
+import MenuItem from "@mui/material/MenuItem";
+import Select, { SelectChangeEvent } from "@mui/material/Select";
+import { useState } from "react";
+import { SERVICE_LIST, ServiceType } from "@root/model/tariff";
+import { CustomTextField } from "@root/kitUI/CustomTextField";
+import { usePrivilegeStore } from "@root/stores/privileges";
+import { AnyDiscount } from "@root/model/cart";
+import { nanoid } from "nanoid";
+import { addDiscounts } from "@root/stores/discounts";
+import { enqueueSnackbar } from "notistack";
+
+
+const discountTypes = {
+ "Лояльность": "purchasesAmount",
+ "Корзина": "cartPurchasesAmount",
+ "Сервис": "service",
+ "Товар": "privilege",
+} as const;
+type DiscountType = keyof typeof discountTypes;
+
+export default function CreateDiscount() {
+ const theme = useTheme();
+ const privileges = usePrivilegeStore(state => state.privileges);
+ const [serviceType, setServiceType] = useState("templategen");
+ const [discountType, setDiscountType] = useState("Лояльность");
+ const [discountNameField, setDiscountNameField] = useState("");
+ const [discountDescription, setDiscountDescription] = useState("");
+ const [privilegeIdField, setPrivilegeIdField] = useState("");
+ const [discountFactorField, setDiscountFactorField] = useState("0");
+ const [purchasesAmountField, setPurchasesAmountField] = useState("0");
+ const [cartPurchasesAmountField, setCartPurchasesAmountField] = useState("0");
+ const [discountMinValueField, setDiscountMinValueField] = useState("0");
+
+ const handleDiscountTypeChange = (event: React.ChangeEvent) => {
+ setDiscountType(event.target.value as DiscountType);
+ };
+
+ const handleServiceTypeChange = (event: SelectChangeEvent) => {
+ setServiceType(event.target.value as ServiceType);
+ };
+
+ function handleCreateDiscount() {
+ const purchasesAmount = parseFloat(purchasesAmountField.replace(",", "."));
+ const discountFactor = 1 - parseFloat(discountFactorField.replace(",", ".")) / 100;
+ const cartPurchasesAmount = parseFloat(cartPurchasesAmountField.replace(",", "."));
+ const discountMinValue = parseFloat(discountMinValueField.replace(",", "."));
+
+ if (!isFinite(purchasesAmount)) return enqueueSnackbar("Поле purchasesAmount не число");
+ if (!isFinite(discountFactor)) return enqueueSnackbar("Поле discountFactor не число");
+ if (!isFinite(cartPurchasesAmount)) return enqueueSnackbar("Поле cartPurchasesAmount не число");
+ if (!isFinite(discountMinValue)) return enqueueSnackbar("Поле discountMinValue не число");
+
+ let discount: AnyDiscount;
+ switch (discountType) {
+ case "Лояльность": {
+ discount = {
+ _id: nanoid(6),
+ name: discountNameField,
+ description: discountDescription,
+ disabled: false,
+ conditionType: "purchasesAmount",
+ condition: {
+ purchasesAmount: purchasesAmount,
+ },
+ factor: discountFactor,
+ };
+ break;
+ }
+ case "Корзина": {
+ discount = {
+ _id: nanoid(6),
+ name: discountNameField,
+ description: discountDescription,
+ disabled: false,
+ conditionType: "cartPurchasesAmount",
+ condition: {
+ cartPurchasesAmount: cartPurchasesAmount,
+ },
+ factor: discountFactor,
+ };
+ break;
+ }
+ case "Сервис": {
+ discount = {
+ _id: nanoid(6),
+ name: discountNameField,
+ description: discountDescription,
+ disabled: false,
+ conditionType: "service",
+ condition: {
+ service: {
+ id: serviceType,
+ value: discountMinValue,
+ },
+ },
+ target: {
+ service: serviceType,
+ factor: discountFactor,
+ },
+ };
+ break;
+ }
+ case "Товар": {
+ discount = {
+ _id: nanoid(6),
+ name: discountNameField,
+ description: discountDescription,
+ disabled: false,
+ conditionType: "privilege",
+ condition: {
+ privilege: {
+ id: privilegeIdField,
+ value: discountMinValue,
+ },
+ },
+ target: {
+ products: [{
+ privilegeId: privilegeIdField,
+ factor: discountFactor,
+ }],
+ },
+ };
+ break;
+ }
+ }
+
+ addDiscounts([discount]);
+ }
+
+ return (
+
+ setDiscountNameField(e.target.value)}
+ />
+ setDiscountDescription(e.target.value)}
+ />
+
+ Условия:
+
+ setDiscountFactorField(e.target.value)}
+ />
+
+ Тип скидки
+
+ {Object.keys(discountTypes).map(type =>
+ } label={type} />
+ )}
+
+
+ {discountType === "Лояльность" &&
+ setPurchasesAmountField(e.target.value)}
+ />
+ }
+ {discountType === "Корзина" &&
+ setCartPurchasesAmountField(e.target.value)}
+ />
+ }
+ {discountType === "Сервис" &&
+ <>
+
+ setDiscountMinValueField(e.target.value)}
+ />
+ >
+ }
+ {discountType === "Товар" &&
+ <>
+
+ Привелегия
+
+
+ setDiscountMinValueField(e.target.value)}
+ />
+ >
+ }
+
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/src/pages/dashboard/Content/DiscountManagement/DatePickers.tsx b/src/pages/dashboard/Content/DiscountManagement/DatePickers.tsx
new file mode 100644
index 0000000..2749c1f
--- /dev/null
+++ b/src/pages/dashboard/Content/DiscountManagement/DatePickers.tsx
@@ -0,0 +1,112 @@
+import { Box, Checkbox, TextField, Typography, useTheme } from "@mui/material";
+import { DesktopDatePicker } from "@mui/x-date-pickers/DesktopDatePicker";
+import { useState } from "react";
+
+
+export default function DatePickers() {
+ const theme = useTheme();
+ const [isInfinite, setIsInfinite] = useState(false);
+ const [startDate, setStartDate] = useState(new Date());
+ const [endDate, setEndDate] = useState(new Date());
+
+
+ return (
+ <>
+
+ Дата действия:
+
+
+ С
+ { if (e) { setStartDate(e); } }}
+ renderInput={(params) => }
+ InputProps={{
+ sx: {
+ height: "40px",
+ color: theme.palette.secondary.main,
+ border: "1px solid",
+ borderColor: theme.palette.secondary.main,
+ "& .MuiSvgIcon-root": { color: theme.palette.secondary.main }
+ }
+ }}
+ />
+ по
+ { if (e) { setEndDate(e); } }}
+ renderInput={(params) => }
+ InputProps={{
+ sx: {
+ height: "40px",
+ color: theme.palette.secondary.main,
+ border: "1px solid",
+ borderColor: theme.palette.secondary.main,
+ "& .MuiSvgIcon-root": { color: theme.palette.secondary.main }
+ }
+ }}
+ />
+
+
+
+ setIsInfinite(p => !p)}
+ />
+
+
+ Бессрочно
+
+
+ >
+ );
+};
\ No newline at end of file
diff --git a/src/pages/dashboard/Content/DiscountManagement/DiscountDataGrid.tsx b/src/pages/dashboard/Content/DiscountManagement/DiscountDataGrid.tsx
new file mode 100644
index 0000000..a5f7394
--- /dev/null
+++ b/src/pages/dashboard/Content/DiscountManagement/DiscountDataGrid.tsx
@@ -0,0 +1,165 @@
+import { Box, Button, styled, useTheme } from "@mui/material";
+import { DataGrid, GridColDef, GridRowsProp, GridToolbar } from "@mui/x-data-grid";
+import { findDiscountFactor, formatDiscountFactor } from "@root/kitUI/Cart/calc";
+import { activateDiscounts, deactivateDiscounts, setSelectedDiscountIds, useDiscountStore } from "@root/stores/discounts";
+
+
+const BoxButton = styled('div')(({ theme }) => ({
+ [theme.breakpoints.down(400)]: {
+ justifyContent: 'center'
+ },
+}));
+
+const columns: GridColDef[] = [
+ {
+ field: "id",
+ headerName: "ID",
+ width: 70,
+ sortable: false,
+ },
+ {
+ field: "name",
+ headerName: "Название скидки",
+ width: 150,
+ sortable: false,
+ },
+ {
+ 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: 120,
+ sortable: false,
+ },
+];
+
+export default function DiscountDataGrid() {
+ const theme = useTheme();
+ const discounts = useDiscountStore(state => state.discounts);
+ const selectedDiscountIds = useDiscountStore(state => state.selectedDiscountIds);
+
+ const discountsGridData: GridRowsProp = discounts.map(discount => {
+ const value =
+ (discount.condition as any).purchasesAmount ??
+ (discount.condition as any).cartPurchasesAmount ??
+ (discount.condition as any).service?.value ??
+ (discount.condition as any).privilege?.value ??
+ "-";
+
+ return {
+ id: discount._id,
+ name: discount.name,
+ description: discount.description,
+ conditionType: discount.conditionType,
+ factor: formatDiscountFactor(findDiscountFactor(discount)),
+ active: discount.disabled ? "🚫" : "✅",
+ value,
+ };
+ });
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/src/pages/dashboard/Content/DiscountManagement/DiscountManagement.tsx b/src/pages/dashboard/Content/DiscountManagement/DiscountManagement.tsx
new file mode 100644
index 0000000..00ec49d
--- /dev/null
+++ b/src/pages/dashboard/Content/DiscountManagement/DiscountManagement.tsx
@@ -0,0 +1,35 @@
+import { Typography, useTheme } from "@mui/material";
+import { LocalizationProvider } from "@mui/x-date-pickers/LocalizationProvider";
+import { AdapterDayjs } from "@mui/x-date-pickers/AdapterDayjs";
+import DiscountDataGrid from "./DiscountDataGrid";
+import CreateDiscount from "./CreateDiscount";
+
+
+const DiscountManagement: React.FC = () => {
+ const theme = useTheme();
+
+ return (
+ <>
+
+
+ СКИДКИ
+
+
+
+
+ >
+ );
+};
+
+
+export default DiscountManagement;
diff --git a/src/pages/dashboard/Content/Tariffs/CreateTariff.tsx b/src/pages/dashboard/Content/Tariffs/CreateTariff.tsx
index 3f3e7b1..2b450fd 100644
--- a/src/pages/dashboard/Content/Tariffs/CreateTariff.tsx
+++ b/src/pages/dashboard/Content/Tariffs/CreateTariff.tsx
@@ -106,20 +106,20 @@ export default function CreateTariff() {
id="tariff-name"
label="Название тарифа"
value={nameField}
- setValue={e => setNameField(e.target.value)}
+ onChange={e => setNameField(e.target.value)}
/>
setAmountField(e.target.value)}
+ onChange={e => setAmountField(e.target.value)}
type="number"
/>
setCustomPriceField(e.target.value)}
+ onChange={e => setCustomPriceField(e.target.value)}
type="number"
/>