Merge branch 'discounts' into 'dev'
add discount creating See merge request frontend/admin!23
This commit is contained in:
commit
a815229da0
@ -6,16 +6,6 @@
|
|||||||
"src": "favicon.ico",
|
"src": "favicon.ico",
|
||||||
"sizes": "64x64 32x32 24x24 16x16",
|
"sizes": "64x64 32x32 24x24 16x16",
|
||||||
"type": "image/x-icon"
|
"type": "image/x-icon"
|
||||||
},
|
|
||||||
{
|
|
||||||
"src": "logo192.png",
|
|
||||||
"type": "image/png",
|
|
||||||
"sizes": "192x192"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"src": "logo512.png",
|
|
||||||
"type": "image/png",
|
|
||||||
"sizes": "512x512"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"start_url": ".",
|
"start_url": ".",
|
||||||
|
106
src/api/discounts.ts
Normal file
106
src/api/discounts.ts
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
import { CreateDiscountBody, Discount, DiscountType } from "@root/model/discount";
|
||||||
|
import { ServiceType } from "@root/model/tariff";
|
||||||
|
import { authStore } from "@root/stores/auth";
|
||||||
|
|
||||||
|
|
||||||
|
const makeRequest = authStore.getState().makeRequest;
|
||||||
|
|
||||||
|
type CreateDiscount = (props: {
|
||||||
|
purchasesAmount: number;
|
||||||
|
cartPurchasesAmount: number;
|
||||||
|
discountMinValue: number;
|
||||||
|
discountFactor: number;
|
||||||
|
discountDescription: string;
|
||||||
|
discountName: string;
|
||||||
|
/** ISO string */
|
||||||
|
startDate: string;
|
||||||
|
/** ISO string */
|
||||||
|
endDate: string;
|
||||||
|
serviceType: ServiceType;
|
||||||
|
discountType: DiscountType;
|
||||||
|
privilegeId: string;
|
||||||
|
}) => Promise<Discount>;
|
||||||
|
|
||||||
|
export const createDiscountJSON: CreateDiscount = ({
|
||||||
|
endDate,
|
||||||
|
startDate,
|
||||||
|
discountName,
|
||||||
|
cartPurchasesAmount,
|
||||||
|
discountDescription,
|
||||||
|
discountFactor,
|
||||||
|
discountMinValue,
|
||||||
|
purchasesAmount,
|
||||||
|
serviceType,
|
||||||
|
discountType,
|
||||||
|
privilegeId,
|
||||||
|
}) => {
|
||||||
|
const discount: CreateDiscountBody = {
|
||||||
|
Name: discountName,
|
||||||
|
Layer: 1,
|
||||||
|
Description: discountDescription,
|
||||||
|
Condition: {
|
||||||
|
Period: {
|
||||||
|
From: startDate,
|
||||||
|
To: endDate,
|
||||||
|
},
|
||||||
|
User: "",
|
||||||
|
UserType: "",
|
||||||
|
Coupon: "",
|
||||||
|
Usage: 0,
|
||||||
|
PurchasesAmount: 0,
|
||||||
|
CartPurchasesAmount: 0,
|
||||||
|
Product: "",
|
||||||
|
Term: 0,
|
||||||
|
PriceFrom: 0,
|
||||||
|
Group: "",
|
||||||
|
},
|
||||||
|
Target: {
|
||||||
|
Factor: discountFactor,
|
||||||
|
TargetScope: "Sum",
|
||||||
|
Overhelm: false,
|
||||||
|
TargetGroup: "",
|
||||||
|
Products: [{
|
||||||
|
ID: "",
|
||||||
|
Factor: 0,
|
||||||
|
Overhelm: false,
|
||||||
|
}],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
switch (discountType) {
|
||||||
|
case "privilege":
|
||||||
|
discount.Layer = 1;
|
||||||
|
discount.Condition.Product = privilegeId;
|
||||||
|
discount.Condition.Term = discountMinValue;
|
||||||
|
discount.Target.Products = [{
|
||||||
|
Factor: discountFactor,
|
||||||
|
ID: privilegeId,
|
||||||
|
Overhelm: false,
|
||||||
|
}];
|
||||||
|
break;
|
||||||
|
case "service":
|
||||||
|
discount.Layer = 2;
|
||||||
|
discount.Condition.PriceFrom = discountMinValue;
|
||||||
|
discount.Condition.Group = serviceType;
|
||||||
|
discount.Target.TargetGroup = serviceType;
|
||||||
|
break;
|
||||||
|
case "cartPurchasesAmount":
|
||||||
|
discount.Layer = 3;
|
||||||
|
discount.Condition.CartPurchasesAmount = cartPurchasesAmount;
|
||||||
|
break;
|
||||||
|
case "purchasesAmount":
|
||||||
|
discount.Layer = 4;
|
||||||
|
discount.Condition.PurchasesAmount = purchasesAmount;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("Constructed discount", discount);
|
||||||
|
|
||||||
|
return makeRequest<CreateDiscountBody, Discount>({
|
||||||
|
url: "https://admin.pena.digital/price/discount",
|
||||||
|
method: "post",
|
||||||
|
useToken: true,
|
||||||
|
bearer: true,
|
||||||
|
body: discount,
|
||||||
|
});
|
||||||
|
};
|
@ -19,11 +19,12 @@ import { useCartStore } from "@root/stores/cart";
|
|||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { GridSelectionModel } from "@mui/x-data-grid";
|
import { GridSelectionModel } from "@mui/x-data-grid";
|
||||||
import { testUser } from "@root/stores/mocks/user";
|
import { testUser } from "@root/stores/mocks/user";
|
||||||
import { useDiscountStore } from "@root/stores/discounts";
|
import { useMockDiscountStore } from "@root/stores/discounts";
|
||||||
import { calcCartData, createCartItem, findDiscountFactor, formatDiscountFactor } from "./calc";
|
import { calcCartData, createCartItem, findDiscountFactor, formatDiscountFactor } from "./calc";
|
||||||
import { useTariffStore } from "@root/stores/tariffs";
|
import { useTariffStore } from "@root/stores/tariffs";
|
||||||
import { AnyDiscount, CartItemTotal } from "@root/model/cart";
|
import { AnyDiscount, CartItemTotal } from "@root/model/cart";
|
||||||
import { findPrivilegeById } from "@root/stores/privileges";
|
import { findPrivilegeById } from "@root/stores/privileges";
|
||||||
|
import { Privilege } from "@root/model/tariff";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
selectedTariffs: GridSelectionModel;
|
selectedTariffs: GridSelectionModel;
|
||||||
@ -46,7 +47,7 @@ interface MergedTariff {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function Cart({ selectedTariffs }: Props) {
|
export default function Cart({ selectedTariffs }: Props) {
|
||||||
const discounts = useDiscountStore((store) => store.discounts);
|
const discounts = useMockDiscountStore((store) => store.discounts);
|
||||||
const cartTotal = useCartStore((state) => state.cartTotal);
|
const cartTotal = useCartStore((state) => state.cartTotal);
|
||||||
const setCartTotal = useCartStore((store) => store.setCartTotal);
|
const setCartTotal = useCartStore((store) => store.setCartTotal);
|
||||||
const [couponField, setCouponField] = useState<string>("");
|
const [couponField, setCouponField] = useState<string>("");
|
||||||
|
@ -10,9 +10,9 @@ import {
|
|||||||
ServiceDiscount,
|
ServiceDiscount,
|
||||||
UserDiscount,
|
UserDiscount,
|
||||||
} from "@root/model/cart";
|
} from "@root/model/cart";
|
||||||
import { Tariff_BACKEND } from "@root/model/tariff";
|
|
||||||
import { User } from "../../model/user";
|
import { User } from "../../model/user";
|
||||||
import { findPrivilegeById } from "@root/stores/privileges";
|
import { findPrivilegeById } from "@root/stores/privileges";
|
||||||
|
import { SERVICE_LIST, ServiceType, Tariff } from "@root/model/tariff";
|
||||||
|
|
||||||
export function calcCartData({
|
export function calcCartData({
|
||||||
user,
|
user,
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
import { ServiceType } from "./tariff";
|
||||||
|
|
||||||
|
|
||||||
export type Discount = {
|
export type Discount = {
|
||||||
ID: string;
|
ID: string;
|
||||||
Name: string;
|
Name: string;
|
||||||
@ -39,6 +42,50 @@ export type Discount = {
|
|||||||
Deprecated: boolean;
|
Deprecated: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type DiscountData = {
|
export type GetDiscountResponse = {
|
||||||
Discounts: Discount[];
|
Discounts: Discount[];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const discountTypes = {
|
||||||
|
"purchasesAmount": "Лояльность",
|
||||||
|
"cartPurchasesAmount": "Корзина",
|
||||||
|
"service": "Сервис",
|
||||||
|
"privilege": "Товар",
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
export type DiscountType = keyof typeof discountTypes;
|
||||||
|
|
||||||
|
export type CreateDiscountBody = {
|
||||||
|
Name: string;
|
||||||
|
Layer: 1 | 2 | 3 | 4;
|
||||||
|
Description: string;
|
||||||
|
Condition: {
|
||||||
|
Period: {
|
||||||
|
/** ISO string */
|
||||||
|
From: string;
|
||||||
|
/** ISO string */
|
||||||
|
To: string;
|
||||||
|
};
|
||||||
|
User: string;
|
||||||
|
UserType: string;
|
||||||
|
Coupon: string;
|
||||||
|
PurchasesAmount: number;
|
||||||
|
CartPurchasesAmount: number;
|
||||||
|
Product: string;
|
||||||
|
Term: number;
|
||||||
|
Usage: number;
|
||||||
|
PriceFrom: number;
|
||||||
|
Group: ServiceType | "";
|
||||||
|
};
|
||||||
|
Target: {
|
||||||
|
Factor: number;
|
||||||
|
TargetScope: "Sum" | "Group" | "Each";
|
||||||
|
Overhelm: boolean;
|
||||||
|
TargetGroup: ServiceType | "";
|
||||||
|
Products: [{
|
||||||
|
ID: string;
|
||||||
|
Factor: number;
|
||||||
|
Overhelm: false;
|
||||||
|
}];
|
||||||
|
};
|
||||||
|
};
|
21
src/model/privilege.ts
Normal file
21
src/model/privilege.ts
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
export interface RealPrivilege {
|
||||||
|
_id: string;
|
||||||
|
name: string;
|
||||||
|
privilegeId: string;
|
||||||
|
serviceKey: string;
|
||||||
|
description: string;
|
||||||
|
type: "day" | "count";
|
||||||
|
value: PrivilegeValueType;
|
||||||
|
price: number;
|
||||||
|
updatedAt?: string;
|
||||||
|
isDeleted?: boolean;
|
||||||
|
createdAt?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type PrivilegeMap = Record<string, RealPrivilege[]>;
|
||||||
|
|
||||||
|
export type PrivilegeValueType = "шаблон" | "день" | "МБ";
|
||||||
|
|
||||||
|
export type PrivilegeWithAmount = Omit<RealPrivilege, "_id"> & { amount: number; };
|
||||||
|
|
||||||
|
export type PrivilegeWithoutPrice = Omit<PrivilegeWithAmount, "price">;
|
@ -38,13 +38,36 @@ export type Tariff_BACKEND = {
|
|||||||
privilegies: Privilege_BACKEND[],
|
privilegies: Privilege_BACKEND[],
|
||||||
isDeleted: boolean,
|
isDeleted: boolean,
|
||||||
createdAt: string,
|
createdAt: string,
|
||||||
updatedAt: string
|
updatedAt: string;
|
||||||
}
|
};
|
||||||
export type Tariff_FRONTEND = {
|
export type Tariff_FRONTEND = {
|
||||||
id: string,
|
id: string,
|
||||||
name: string,
|
name: string,
|
||||||
amount: number,
|
amount: number,
|
||||||
isFront: boolean,
|
|
||||||
privilegeId: string,
|
privilegeId: string,
|
||||||
customPricePerUnit: number
|
customPricePerUnit?: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** @deprecated */
|
||||||
|
export interface Privilege {
|
||||||
|
serviceKey: ServiceType;
|
||||||
|
name: PrivilegeType;
|
||||||
|
privilegeId: string;
|
||||||
|
description: string;
|
||||||
|
/** Единица измерения привелегии: время в днях/кол-во */
|
||||||
|
type: "day" | "count";
|
||||||
|
/** Стоимость одной единицы привелегии */
|
||||||
|
price: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @deprecated */
|
||||||
|
export interface Tariff {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
privilegeId: string;
|
||||||
|
/** Количество единиц привелегии */
|
||||||
|
amount: number;
|
||||||
|
/** Кастомная цена, если есть, то используется вместо privilege.price */
|
||||||
|
customPricePerUnit?: number;
|
||||||
|
isFront?: boolean;
|
||||||
}
|
}
|
@ -4,34 +4,29 @@ import Select, { SelectChangeEvent } from "@mui/material/Select";
|
|||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { SERVICE_LIST, ServiceType } from "@root/model/tariff";
|
import { SERVICE_LIST, ServiceType } from "@root/model/tariff";
|
||||||
import { CustomTextField } from "@root/kitUI/CustomTextField";
|
import { CustomTextField } from "@root/kitUI/CustomTextField";
|
||||||
import { usePrivilegeStore } from "@root/stores/privileges";
|
import { addRealPrivileges, useRealPrivilegeStore } from "@root/stores/privileges";
|
||||||
import { AnyDiscount } from "@root/model/cart";
|
|
||||||
import { nanoid } from "nanoid";
|
|
||||||
import { addDiscounts } from "@root/stores/discounts";
|
import { addDiscounts } from "@root/stores/discounts";
|
||||||
import { enqueueSnackbar } from "notistack";
|
import { enqueueSnackbar } from "notistack";
|
||||||
|
import { DiscountType, discountTypes } from "@root/model/discount";
|
||||||
|
import { createDiscountJSON } from "@root/api/discounts";
|
||||||
|
import usePrivileges from "@root/utils/hooks/usePrivileges";
|
||||||
|
|
||||||
|
|
||||||
const discountTypes = {
|
|
||||||
"Лояльность": "purchasesAmount",
|
|
||||||
"Корзина": "cartPurchasesAmount",
|
|
||||||
"Сервис": "service",
|
|
||||||
"Товар": "privilege",
|
|
||||||
} as const;
|
|
||||||
type DiscountType = keyof typeof discountTypes;
|
|
||||||
|
|
||||||
export default function CreateDiscount() {
|
export default function CreateDiscount() {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const privileges = usePrivilegeStore(state => state.privileges);
|
const privileges = useRealPrivilegeStore(state => state.privileges);
|
||||||
const [serviceType, setServiceType] = useState<ServiceType>("templategen");
|
const [serviceType, setServiceType] = useState<ServiceType>("templategen");
|
||||||
const [discountType, setDiscountType] = useState<DiscountType>("Лояльность");
|
const [discountType, setDiscountType] = useState<DiscountType>("purchasesAmount");
|
||||||
const [discountNameField, setDiscountNameField] = useState<string>("");
|
const [discountNameField, setDiscountNameField] = useState<string>("");
|
||||||
const [discountDescription, setDiscountDescription] = useState<string>("");
|
const [discountDescriptionField, setDiscountDescriptionField] = useState<string>("");
|
||||||
const [privilegeIdField, setPrivilegeIdField] = useState<string | "">("");
|
const [privilegeIdField, setPrivilegeIdField] = useState<string | "">("");
|
||||||
const [discountFactorField, setDiscountFactorField] = useState<string>("0");
|
const [discountFactorField, setDiscountFactorField] = useState<string>("0");
|
||||||
const [purchasesAmountField, setPurchasesAmountField] = useState<string>("0");
|
const [purchasesAmountField, setPurchasesAmountField] = useState<string>("0");
|
||||||
const [cartPurchasesAmountField, setCartPurchasesAmountField] = useState<string>("0");
|
const [cartPurchasesAmountField, setCartPurchasesAmountField] = useState<string>("0");
|
||||||
const [discountMinValueField, setDiscountMinValueField] = useState<string>("0");
|
const [discountMinValueField, setDiscountMinValueField] = useState<string>("0");
|
||||||
|
|
||||||
|
usePrivileges({ onNewPrivileges: addRealPrivileges });
|
||||||
|
|
||||||
const handleDiscountTypeChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
const handleDiscountTypeChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
setDiscountType(event.target.value as DiscountType);
|
setDiscountType(event.target.value as DiscountType);
|
||||||
};
|
};
|
||||||
@ -40,9 +35,9 @@ export default function CreateDiscount() {
|
|||||||
setServiceType(event.target.value as ServiceType);
|
setServiceType(event.target.value as ServiceType);
|
||||||
};
|
};
|
||||||
|
|
||||||
function handleCreateDiscount() {
|
async function handleCreateDiscount() {
|
||||||
const purchasesAmount = parseFloat(purchasesAmountField.replace(",", "."));
|
const purchasesAmount = parseFloat(purchasesAmountField.replace(",", "."));
|
||||||
const discountFactor = 1 - parseFloat(discountFactorField.replace(",", ".")) / 100;
|
const discountFactor = (100 - parseFloat(discountFactorField.replace(",", "."))) / 100;
|
||||||
const cartPurchasesAmount = parseFloat(cartPurchasesAmountField.replace(",", "."));
|
const cartPurchasesAmount = parseFloat(cartPurchasesAmountField.replace(",", "."));
|
||||||
const discountMinValue = parseFloat(discountMinValueField.replace(",", "."));
|
const discountMinValue = parseFloat(discountMinValueField.replace(",", "."));
|
||||||
|
|
||||||
@ -50,82 +45,28 @@ export default function CreateDiscount() {
|
|||||||
if (!isFinite(discountFactor)) return enqueueSnackbar("Поле discountFactor не число");
|
if (!isFinite(discountFactor)) return enqueueSnackbar("Поле discountFactor не число");
|
||||||
if (!isFinite(cartPurchasesAmount)) return enqueueSnackbar("Поле cartPurchasesAmount не число");
|
if (!isFinite(cartPurchasesAmount)) return enqueueSnackbar("Поле cartPurchasesAmount не число");
|
||||||
if (!isFinite(discountMinValue)) return enqueueSnackbar("Поле discountMinValue не число");
|
if (!isFinite(discountMinValue)) return enqueueSnackbar("Поле discountMinValue не число");
|
||||||
|
if (discountType === "privilege" && !privilegeIdField) return enqueueSnackbar("Привилегия не выбрана");
|
||||||
|
|
||||||
let discount: AnyDiscount;
|
try {
|
||||||
switch (discountType) {
|
const createdDiscount = await createDiscountJSON({
|
||||||
case "Лояльность": {
|
cartPurchasesAmount,
|
||||||
discount = {
|
discountFactor,
|
||||||
_id: nanoid(6),
|
discountMinValue,
|
||||||
name: discountNameField,
|
purchasesAmount,
|
||||||
description: discountDescription,
|
discountDescription: discountDescriptionField,
|
||||||
disabled: false,
|
discountName: discountNameField,
|
||||||
conditionType: "purchasesAmount",
|
startDate: new Date().toISOString(),
|
||||||
condition: {
|
endDate: new Date(Date.now() + 1000 * 3600 * 24 * 30).toISOString(),
|
||||||
purchasesAmount: purchasesAmount,
|
serviceType,
|
||||||
},
|
discountType,
|
||||||
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,
|
privilegeId: privilegeIdField,
|
||||||
factor: discountFactor,
|
});
|
||||||
}],
|
|
||||||
},
|
|
||||||
};
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
addDiscounts([discount]);
|
addDiscounts([createdDiscount]);
|
||||||
|
} catch (error) {
|
||||||
|
console.log("Error creating discount", error);
|
||||||
|
enqueueSnackbar("Ошибка при создании скидки");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -149,8 +90,8 @@ export default function CreateDiscount() {
|
|||||||
<CustomTextField
|
<CustomTextField
|
||||||
id="discount-desc"
|
id="discount-desc"
|
||||||
label="Описание"
|
label="Описание"
|
||||||
value={discountDescription}
|
value={discountDescriptionField}
|
||||||
onChange={e => setDiscountDescription(e.target.value)}
|
onChange={e => setDiscountDescriptionField(e.target.value)}
|
||||||
/>
|
/>
|
||||||
<Typography
|
<Typography
|
||||||
variant="h4"
|
variant="h4"
|
||||||
@ -187,11 +128,16 @@ export default function CreateDiscount() {
|
|||||||
onChange={handleDiscountTypeChange}
|
onChange={handleDiscountTypeChange}
|
||||||
>
|
>
|
||||||
{Object.keys(discountTypes).map(type =>
|
{Object.keys(discountTypes).map(type =>
|
||||||
<FormControlLabel key={type} value={type} control={<Radio color="secondary" />} label={type} />
|
<FormControlLabel
|
||||||
|
key={type}
|
||||||
|
value={type}
|
||||||
|
control={<Radio color="secondary" />}
|
||||||
|
label={discountTypes[type as DiscountType]}
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
</RadioGroup>
|
</RadioGroup>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
{discountType === "Лояльность" &&
|
{discountType === "purchasesAmount" &&
|
||||||
<CustomTextField
|
<CustomTextField
|
||||||
id="discount-purchases"
|
id="discount-purchases"
|
||||||
label="Внесено больше"
|
label="Внесено больше"
|
||||||
@ -203,7 +149,7 @@ export default function CreateDiscount() {
|
|||||||
onChange={e => setPurchasesAmountField(e.target.value)}
|
onChange={e => setPurchasesAmountField(e.target.value)}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
{discountType === "Корзина" &&
|
{discountType === "cartPurchasesAmount" &&
|
||||||
<CustomTextField
|
<CustomTextField
|
||||||
id="discount-cart-purchases"
|
id="discount-cart-purchases"
|
||||||
label="Объем в корзине"
|
label="Объем в корзине"
|
||||||
@ -215,7 +161,7 @@ export default function CreateDiscount() {
|
|||||||
onChange={e => setCartPurchasesAmountField(e.target.value)}
|
onChange={e => setCartPurchasesAmountField(e.target.value)}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
{discountType === "Сервис" &&
|
{discountType === "service" &&
|
||||||
<>
|
<>
|
||||||
<Select
|
<Select
|
||||||
labelId="discount-service-label"
|
labelId="discount-service-label"
|
||||||
@ -249,7 +195,7 @@ export default function CreateDiscount() {
|
|||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
{discountType === "Товар" &&
|
{discountType === "privilege" &&
|
||||||
<>
|
<>
|
||||||
<FormControl
|
<FormControl
|
||||||
fullWidth
|
fullWidth
|
||||||
|
@ -1,17 +1,9 @@
|
|||||||
import { useEffect, useState } from "react";
|
|
||||||
import { enqueueSnackbar } from "notistack";
|
|
||||||
import { Box, Button, styled, useTheme } from "@mui/material";
|
import { Box, Button, styled, useTheme } from "@mui/material";
|
||||||
import { DataGrid, GridColDef, GridRowsProp, GridToolbar } from "@mui/x-data-grid";
|
import { DataGrid, GridColDef, GridRowsProp, GridToolbar } from "@mui/x-data-grid";
|
||||||
import { findDiscountFactor, formatDiscountFactor } from "@root/kitUI/Cart/calc";
|
import { findDiscountFactor, formatDiscountFactor } from "@root/kitUI/Cart/calc";
|
||||||
import {
|
import { activateMockDiscounts, addDiscounts, deactivateMockDiscounts, setMockSelectedDiscountIds, useDiscountStore, useMockDiscountStore, } from "@root/stores/discounts";
|
||||||
activateDiscounts,
|
import useDiscounts from "@root/utils/hooks/useDiscounts";
|
||||||
deactivateDiscounts,
|
|
||||||
setSelectedDiscountIds,
|
|
||||||
useDiscountStore,
|
|
||||||
} from "@root/stores/discounts";
|
|
||||||
import axios from "axios";
|
|
||||||
|
|
||||||
import type { DiscountData } from "@root/model/discount";
|
|
||||||
|
|
||||||
const BoxButton = styled("div")(({ theme }) => ({
|
const BoxButton = styled("div")(({ theme }) => ({
|
||||||
[theme.breakpoints.down(400)]: {
|
[theme.breakpoints.down(400)]: {
|
||||||
@ -66,31 +58,11 @@ const columns: GridColDef[] = [
|
|||||||
|
|
||||||
export default function DiscountDataGrid() {
|
export default function DiscountDataGrid() {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const exampleDiscounts = useDiscountStore((state) => state.discounts);
|
const exampleDiscounts = useMockDiscountStore((state) => state.discounts);
|
||||||
const selectedDiscountIds = useDiscountStore((state) => state.selectedDiscountIds);
|
const selectedDiscountIds = useMockDiscountStore((state) => state.selectedDiscountIds);
|
||||||
|
const realDiscounts = useDiscountStore(state => state.discounts);
|
||||||
|
|
||||||
const [discount, setDiscount] = useState<DiscountData>();
|
useDiscounts({ onNewDiscounts: addDiscounts });
|
||||||
|
|
||||||
const mergeDiscount = [...(discount?.Discounts ?? []), ...exampleDiscounts];
|
|
||||||
|
|
||||||
console.log(mergeDiscount);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const axiosDiscount = async () => {
|
|
||||||
try {
|
|
||||||
const { data } = await axios({
|
|
||||||
method: "get",
|
|
||||||
url: "https://admin.pena.digital/price/discounts",
|
|
||||||
});
|
|
||||||
setDiscount(data);
|
|
||||||
console.log(data);
|
|
||||||
} catch (error) {
|
|
||||||
enqueueSnackbar("Ошибка получения скидок");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
axiosDiscount();
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const discountsGridData: GridRowsProp = exampleDiscounts.map((discount) => {
|
const discountsGridData: GridRowsProp = exampleDiscounts.map((discount) => {
|
||||||
const value =
|
const value =
|
||||||
@ -119,7 +91,7 @@ export default function DiscountDataGrid() {
|
|||||||
rows={discountsGridData}
|
rows={discountsGridData}
|
||||||
columns={columns}
|
columns={columns}
|
||||||
selectionModel={selectedDiscountIds}
|
selectionModel={selectedDiscountIds}
|
||||||
onSelectionModelChange={setSelectedDiscountIds}
|
onSelectionModelChange={setMockSelectedDiscountIds}
|
||||||
sx={{
|
sx={{
|
||||||
color: theme.palette.secondary.main,
|
color: theme.palette.secondary.main,
|
||||||
"& .MuiDataGrid-iconSeparator": {
|
"& .MuiDataGrid-iconSeparator": {
|
||||||
@ -165,7 +137,7 @@ export default function DiscountDataGrid() {
|
|||||||
>
|
>
|
||||||
<Button
|
<Button
|
||||||
variant="contained"
|
variant="contained"
|
||||||
onClick={deactivateDiscounts}
|
onClick={deactivateMockDiscounts}
|
||||||
sx={{
|
sx={{
|
||||||
backgroundColor: theme.palette.menu.main,
|
backgroundColor: theme.palette.menu.main,
|
||||||
width: "200px",
|
width: "200px",
|
||||||
@ -182,7 +154,7 @@ export default function DiscountDataGrid() {
|
|||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
variant="contained"
|
variant="contained"
|
||||||
onClick={activateDiscounts}
|
onClick={activateMockDiscounts}
|
||||||
sx={{
|
sx={{
|
||||||
backgroundColor: theme.palette.menu.main,
|
backgroundColor: theme.palette.menu.main,
|
||||||
width: "200px",
|
width: "200px",
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
// @ts-nocheck
|
||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import Box from "@mui/material/Box";
|
import Box from "@mui/material/Box";
|
||||||
import Button from "@mui/material/Button";
|
import Button from "@mui/material/Button";
|
||||||
@ -48,6 +49,7 @@ interface Props {
|
|||||||
getTariffs: () => void
|
getTariffs: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @deprecated */
|
||||||
export default function EditModal({tariff, getTariffs}:Props) {
|
export default function EditModal({tariff, getTariffs}:Props) {
|
||||||
|
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
// @ts-nocheck
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { GridColDef, GridSelectionModel, GridToolbar } from "@mui/x-data-grid";
|
import { GridColDef, GridSelectionModel, GridToolbar } from "@mui/x-data-grid";
|
||||||
@ -24,6 +25,7 @@ interface Props {
|
|||||||
getTariffs: () => void;
|
getTariffs: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @deprecated */
|
||||||
export default function TariffsDG({ selectedTariffs, handleSelectionChange, getTariffs }: Props) {
|
export default function TariffsDG({ selectedTariffs, handleSelectionChange, getTariffs }: Props) {
|
||||||
const { token } = authStore();
|
const { token } = authStore();
|
||||||
|
|
||||||
|
1
src/react-app-env.d.ts
vendored
Normal file
1
src/react-app-env.d.ts
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/// <reference types="react-scripts" />
|
@ -3,14 +3,40 @@ import { AnyDiscount } from "@root/model/cart";
|
|||||||
import { create } from "zustand";
|
import { create } from "zustand";
|
||||||
import { devtools } from "zustand/middleware";
|
import { devtools } from "zustand/middleware";
|
||||||
import { exampleCartValues } from "./mocks/exampleCartValues";
|
import { exampleCartValues } from "./mocks/exampleCartValues";
|
||||||
|
import { Discount } from "@root/model/discount";
|
||||||
|
|
||||||
|
|
||||||
interface DiscountStore {
|
interface DiscountStore {
|
||||||
discounts: AnyDiscount[];
|
discounts: Discount[];
|
||||||
selectedDiscountIds: GridSelectionModel,
|
selectedDiscountIds: GridSelectionModel,
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useDiscountStore = create<DiscountStore>()(
|
export const useDiscountStore = create<DiscountStore>()(
|
||||||
|
devtools(
|
||||||
|
(set, get) => ({
|
||||||
|
discounts: [],
|
||||||
|
selectedDiscountIds: [],
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
name: "Real discount store",
|
||||||
|
enabled: process.env.NODE_ENV === "development"
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
export const addDiscounts = (newDiscounts: DiscountStore["discounts"]) => useDiscountStore.setState(state => ({ discounts: [...state.discounts, ...newDiscounts] }));
|
||||||
|
|
||||||
|
export const setSelectedDiscountIds = (selectedDiscountIds: DiscountStore["selectedDiscountIds"]) => useDiscountStore.setState({ selectedDiscountIds });
|
||||||
|
|
||||||
|
|
||||||
|
/** @deprecated */
|
||||||
|
interface MockDiscountStore {
|
||||||
|
discounts: AnyDiscount[];
|
||||||
|
selectedDiscountIds: GridSelectionModel,
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @deprecated */
|
||||||
|
export const useMockDiscountStore = create<MockDiscountStore>()(
|
||||||
devtools(
|
devtools(
|
||||||
(set, get) => ({
|
(set, get) => ({
|
||||||
discounts: exampleCartValues.discounts,
|
discounts: exampleCartValues.discounts,
|
||||||
@ -22,11 +48,14 @@ export const useDiscountStore = create<DiscountStore>()(
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
export const addDiscounts = (newDiscounts: AnyDiscount[]) => useDiscountStore.setState(state => ({ discounts: [...state.discounts, ...newDiscounts] }));
|
/** @deprecated */
|
||||||
|
export const addMockDiscounts = (newDiscounts: AnyDiscount[]) => useMockDiscountStore.setState(state => ({ discounts: [...state.discounts, ...newDiscounts] }));
|
||||||
|
|
||||||
export const setSelectedDiscountIds = (selectedDiscountIds: DiscountStore["selectedDiscountIds"]) => useDiscountStore.setState({ selectedDiscountIds });
|
/** @deprecated */
|
||||||
|
export const setMockSelectedDiscountIds = (selectedDiscountIds: MockDiscountStore["selectedDiscountIds"]) => useMockDiscountStore.setState({ selectedDiscountIds });
|
||||||
|
|
||||||
export const activateDiscounts = () => useDiscountStore.setState(state => {
|
/** @deprecated */
|
||||||
|
export const activateMockDiscounts = () => useMockDiscountStore.setState(state => {
|
||||||
const discounts: AnyDiscount[] = [];
|
const discounts: AnyDiscount[] = [];
|
||||||
state.discounts.forEach(discount => {
|
state.discounts.forEach(discount => {
|
||||||
if (!state.selectedDiscountIds.includes(discount._id)) return discounts.push(discount);
|
if (!state.selectedDiscountIds.includes(discount._id)) return discounts.push(discount);
|
||||||
@ -40,7 +69,8 @@ export const activateDiscounts = () => useDiscountStore.setState(state => {
|
|||||||
return { discounts };
|
return { discounts };
|
||||||
});
|
});
|
||||||
|
|
||||||
export const deactivateDiscounts = () => useDiscountStore.setState(state => {
|
/** @deprecated */
|
||||||
|
export const deactivateMockDiscounts = () => useMockDiscountStore.setState(state => {
|
||||||
const discounts: AnyDiscount[] = [];
|
const discounts: AnyDiscount[] = [];
|
||||||
state.discounts.forEach(discount => {
|
state.discounts.forEach(discount => {
|
||||||
if (!state.selectedDiscountIds.includes(discount._id)) return discounts.push(discount);
|
if (!state.selectedDiscountIds.includes(discount._id)) return discounts.push(discount);
|
||||||
|
@ -2,7 +2,27 @@ import { Privilege } from "@root/model/tariff";
|
|||||||
import { create } from "zustand";
|
import { create } from "zustand";
|
||||||
import { devtools } from "zustand/middleware";
|
import { devtools } from "zustand/middleware";
|
||||||
import { exampleCartValues } from "./mocks/exampleCartValues";
|
import { exampleCartValues } from "./mocks/exampleCartValues";
|
||||||
|
import { RealPrivilege } from "@root/model/privilege";
|
||||||
|
|
||||||
|
interface RealPrivilegeStore {
|
||||||
|
privileges: RealPrivilege[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useRealPrivilegeStore = create<RealPrivilegeStore>()(
|
||||||
|
devtools(
|
||||||
|
(set, get) => ({
|
||||||
|
privileges: [],
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
name: "Privilege store",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
export const addRealPrivileges = (privileges: RealPrivilegeStore["privileges"]) => useRealPrivilegeStore.setState({ privileges });
|
||||||
|
|
||||||
|
|
||||||
|
/** @deprecated */
|
||||||
interface PrivilegeStore {
|
interface PrivilegeStore {
|
||||||
privileges: Privilege[];
|
privileges: Privilege[];
|
||||||
isModalOpen: boolean;
|
isModalOpen: boolean;
|
||||||
@ -11,6 +31,7 @@ interface PrivilegeStore {
|
|||||||
addPrivileges: (newPrivileges: Privilege[]) => void;
|
addPrivileges: (newPrivileges: Privilege[]) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @deprecated */
|
||||||
export const usePrivilegeStore = create<PrivilegeStore>()(
|
export const usePrivilegeStore = create<PrivilegeStore>()(
|
||||||
devtools(
|
devtools(
|
||||||
(set, get) => ({
|
(set, get) => ({
|
||||||
@ -21,12 +42,15 @@ export const usePrivilegeStore = create<PrivilegeStore>()(
|
|||||||
addPrivileges: (newPrivileges) => set((state) => ({ privileges: [...state.privileges, ...newPrivileges] })),
|
addPrivileges: (newPrivileges) => set((state) => ({ privileges: [...state.privileges, ...newPrivileges] })),
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
name: "Privilege store",
|
name: "Mock Privilege store",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/** @deprecated */
|
||||||
export const closePrivilegePriceModal = () => usePrivilegeStore.setState({ isModalOpen: false });
|
export const closePrivilegePriceModal = () => usePrivilegeStore.setState({ isModalOpen: false });
|
||||||
|
|
||||||
|
/** @deprecated */
|
||||||
export const openPrivilegePriceModal = (modalPrivilegeId: string | null, defaultPrice: number) =>
|
export const openPrivilegePriceModal = (modalPrivilegeId: string | null, defaultPrice: number) =>
|
||||||
usePrivilegeStore.setState({
|
usePrivilegeStore.setState({
|
||||||
isModalOpen: true,
|
isModalOpen: true,
|
||||||
@ -34,8 +58,10 @@ export const openPrivilegePriceModal = (modalPrivilegeId: string | null, default
|
|||||||
modalPrivilegeId,
|
modalPrivilegeId,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/** @deprecated */
|
||||||
export const changeModalPriceField = (modalPriceField: string) => usePrivilegeStore.setState({ modalPriceField });
|
export const changeModalPriceField = (modalPriceField: string) => usePrivilegeStore.setState({ modalPriceField });
|
||||||
|
|
||||||
|
/** @deprecated */
|
||||||
export const changePrivilegePrice = () => {
|
export const changePrivilegePrice = () => {
|
||||||
const { privileges, modalPrivilegeId, modalPriceField } = usePrivilegeStore.getState();
|
const { privileges, modalPrivilegeId, modalPriceField } = usePrivilegeStore.getState();
|
||||||
|
|
||||||
@ -59,6 +85,7 @@ export const changePrivilegePrice = () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** @deprecated */
|
||||||
export const findPrivilegeById = (privilegeId: string) => {
|
export const findPrivilegeById = (privilegeId: string) => {
|
||||||
return usePrivilegeStore.getState().privileges.find((privilege) => privilege.privilegeId === privilegeId) ?? null;
|
return usePrivilegeStore.getState().privileges.find((privilege) => privilege.privilegeId === privilegeId) ?? null;
|
||||||
};
|
};
|
||||||
|
31
src/utils/hooks/useDiscounts.ts
Normal file
31
src/utils/hooks/useDiscounts.ts
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
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<never, GetDiscountResponse>({
|
||||||
|
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]);
|
||||||
|
}
|
31
src/utils/hooks/usePrivileges.ts
Normal file
31
src/utils/hooks/usePrivileges.ts
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
import { RealPrivilege } from "@root/model/privilege";
|
||||||
|
import { authStore } from "@root/stores/auth";
|
||||||
|
import { useEffect } from "react";
|
||||||
|
|
||||||
|
|
||||||
|
const makeRequest = authStore.getState().makeRequest;
|
||||||
|
|
||||||
|
export default function usePrivileges({ onError, onNewPrivileges }: {
|
||||||
|
onNewPrivileges: (response: RealPrivilege[]) => void;
|
||||||
|
onError?: (error: any) => void;
|
||||||
|
}) {
|
||||||
|
useEffect(() => {
|
||||||
|
const controller = new AbortController();
|
||||||
|
|
||||||
|
makeRequest<never, RealPrivilege[]>({
|
||||||
|
url: "https://admin.pena.digital/strator/privilege",
|
||||||
|
method: "get",
|
||||||
|
useToken: true,
|
||||||
|
bearer: true,
|
||||||
|
signal: controller.signal,
|
||||||
|
}).then(result => {
|
||||||
|
console.log("New privileges", result);
|
||||||
|
onNewPrivileges(result);
|
||||||
|
}).catch(error => {
|
||||||
|
console.log("Error fetching privileges", error);
|
||||||
|
onError?.(error);
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => controller.abort();
|
||||||
|
}, [onError, onNewPrivileges]);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user