Merge branch 'dev' of penahub.gitlab.yandexcloud.net:frontend/admin into dev
This commit is contained in:
commit
0026081093
@ -19,7 +19,7 @@ import Error404 from "@pages/Error404";
|
|||||||
import Users from "@pages/dashboard/Content/Users";
|
import Users from "@pages/dashboard/Content/Users";
|
||||||
import Entities from "@pages/dashboard/Content/Entities";
|
import Entities from "@pages/dashboard/Content/Entities";
|
||||||
import Tariffs from "@pages/dashboard/Content/Tariffs";
|
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 PromocodeManagement from "@pages/dashboard/Content/PromocodeManagement";
|
||||||
import { SettingRoles } from "@pages/Setting/SettingRoles";
|
import { SettingRoles } from "@pages/Setting/SettingRoles";
|
||||||
import Support from "@pages/dashboard/Content/Support/Support";
|
import Support from "@pages/dashboard/Content/Support/Support";
|
||||||
|
@ -328,9 +328,6 @@ function DiscountTooltip({ discount, cartItemTotal }: {
|
|||||||
<>
|
<>
|
||||||
<Typography>Скидка: {discount?.name}</Typography>
|
<Typography>Скидка: {discount?.name}</Typography>
|
||||||
<Typography>{discount?.description}</Typography>
|
<Typography>{discount?.description}</Typography>
|
||||||
<Typography>-------</Typography>
|
|
||||||
<Typography>layer: {discount?.layer}</Typography>
|
|
||||||
<Typography>id: {discount?._id}</Typography>
|
|
||||||
</>
|
</>
|
||||||
}>
|
}>
|
||||||
<span>{discountText}</span>
|
<span>{discountText}</span>
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
import { TextField, useTheme } from "@mui/material";
|
import { SxProps, TextField, Theme, useTheme } from "@mui/material";
|
||||||
import { HTMLInputTypeAttribute, ChangeEvent } from "react";
|
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;
|
id: string;
|
||||||
label: string;
|
label: string;
|
||||||
value: number | string | null;
|
value: number | string | null;
|
||||||
type?: HTMLInputTypeAttribute;
|
type?: HTMLInputTypeAttribute;
|
||||||
setValue: (e: ChangeEvent<HTMLInputElement>) => void;
|
sx?: SxProps<Theme>;
|
||||||
|
onChange: (e: ChangeEvent<HTMLInputElement>) => void;
|
||||||
}) {
|
}) {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
|
||||||
@ -19,6 +20,7 @@ export function CustomTextField({ id, label, value, type, setValue }: {
|
|||||||
variant="filled"
|
variant="filled"
|
||||||
color="secondary"
|
color="secondary"
|
||||||
type={type}
|
type={type}
|
||||||
|
sx={sx}
|
||||||
InputProps={{
|
InputProps={{
|
||||||
style: {
|
style: {
|
||||||
backgroundColor: theme.palette.content.main,
|
backgroundColor: theme.palette.content.main,
|
||||||
|
@ -6,7 +6,7 @@ interface DiscountBase {
|
|||||||
name: string;
|
name: string;
|
||||||
description: string;
|
description: string;
|
||||||
/** Этап применения скидки */
|
/** Этап применения скидки */
|
||||||
layer: number;
|
layer?: number;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ export const SERVICE_LIST = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
serviceKey: "dwarfener",
|
serviceKey: "dwarfener",
|
||||||
displayName: "Сокращатель ссылок",
|
displayName: "Аналитика сокращателя",
|
||||||
},
|
},
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
|
@ -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<boolean>(false);
|
|
||||||
const [serviceType, setServiceType] = useState<ServiceType>("templategen");
|
|
||||||
const [startDate, setStartDate] = useState<Date>(new Date());
|
|
||||||
const [endDate, setEndDate] = useState<Date>(new Date());
|
|
||||||
const [discountTypeField, setDiscountTypeField] = useState<string>("");
|
|
||||||
const [discountNameField, setDiscountNameField] = useState<string>("");
|
|
||||||
const [discountDescriptionField, setDiscountDescriptionField] = useState<string>("");
|
|
||||||
const [discountConditionType, setDiscountConditionType] = useState<DiscountConditionType | null>(null);
|
|
||||||
const [discountFactor, setDiscountFactor] = useState<number>(1);
|
|
||||||
const [purchasesAmountThreshold, setPurchasesAmountThreshold] = useState<number>(0);
|
|
||||||
const [cartPurchasesAmountThreshold, setCartPurchasesAmountThreshold] = useState<number>(0);
|
|
||||||
const [discountMinValue, setDiscountMinValue] = useState<number>(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 (
|
|
||||||
<>
|
|
||||||
<LocalizationProvider dateAdapter={AdapterDayjs}>
|
|
||||||
<Typography
|
|
||||||
variant="subtitle1"
|
|
||||||
sx={{
|
|
||||||
width: "90%",
|
|
||||||
height: "60px",
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "column",
|
|
||||||
justifyContent: "center",
|
|
||||||
alignItems: "center",
|
|
||||||
color: theme.palette.secondary.main
|
|
||||||
}}>
|
|
||||||
СКИДКИ
|
|
||||||
</Typography>
|
|
||||||
|
|
||||||
<Box
|
|
||||||
sx={{
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "column",
|
|
||||||
justifyContent: "left",
|
|
||||||
alignItems: "left",
|
|
||||||
marginTop: "15px",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<TextField
|
|
||||||
id="standard-basic"
|
|
||||||
label={"Название"}
|
|
||||||
variant="filled"
|
|
||||||
color="secondary"
|
|
||||||
sx={{
|
|
||||||
height: "30px",
|
|
||||||
}}
|
|
||||||
InputProps={{
|
|
||||||
style: {
|
|
||||||
backgroundColor: theme.palette.content.main,
|
|
||||||
color: theme.palette.secondary.main,
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
InputLabelProps={{
|
|
||||||
style: {
|
|
||||||
color: theme.palette.secondary.main
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
value={discountNameField}
|
|
||||||
onChange={e => setDiscountNameField(e.target.value)}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Typography
|
|
||||||
variant="h4"
|
|
||||||
sx={{
|
|
||||||
width: "90%",
|
|
||||||
height: "40px",
|
|
||||||
fontWeight: "normal",
|
|
||||||
color: theme.palette.grayDisabled.main,
|
|
||||||
marginTop: "75px",
|
|
||||||
paddingLeft: '10px',
|
|
||||||
}}>
|
|
||||||
Условия:
|
|
||||||
</Typography>
|
|
||||||
|
|
||||||
<Select
|
|
||||||
labelId="demo-simple-select-label"
|
|
||||||
id="demo-simple-select"
|
|
||||||
value={serviceType}
|
|
||||||
label="Age"
|
|
||||||
onChange={handleServiceTypeChange}
|
|
||||||
sx={{
|
|
||||||
color: theme.palette.secondary.main,
|
|
||||||
border: "1px solid",
|
|
||||||
borderColor: theme.palette.secondary.main,
|
|
||||||
"&.Mui-focused .MuiOutlinedInput-notchedOutline": {
|
|
||||||
borderColor: theme.palette.secondary.main
|
|
||||||
},
|
|
||||||
".MuiSvgIcon-root ": {
|
|
||||||
fill: theme.palette.secondary.main,
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<MenuItem value={"templategen"}>Шаблонизатор</MenuItem>
|
|
||||||
<MenuItem value={"squiz"}>Опросник</MenuItem>
|
|
||||||
<MenuItem value={"dwarfener"}>Аналитика сокращателя</MenuItem>
|
|
||||||
</Select>
|
|
||||||
|
|
||||||
<TextField
|
|
||||||
id="standard-basic"
|
|
||||||
label={"Процент скидки"}
|
|
||||||
variant="filled"
|
|
||||||
color="secondary"
|
|
||||||
sx={{
|
|
||||||
marginTop: "15px"
|
|
||||||
}}
|
|
||||||
InputProps={{
|
|
||||||
style: {
|
|
||||||
backgroundColor: theme.palette.content.main,
|
|
||||||
color: theme.palette.secondary.main,
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
InputLabelProps={{
|
|
||||||
style: {
|
|
||||||
color: theme.palette.secondary.main
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
value={discountFactor}
|
|
||||||
onChange={e => setDiscountFactor(Number(e.target.value) || 1)}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<TextField
|
|
||||||
id="standard-basic"
|
|
||||||
label={"Внесено больше"}
|
|
||||||
variant="filled"
|
|
||||||
color="secondary"
|
|
||||||
type="number"
|
|
||||||
sx={{
|
|
||||||
marginTop: "15px"
|
|
||||||
}}
|
|
||||||
InputProps={{
|
|
||||||
style: {
|
|
||||||
backgroundColor: theme.palette.content.main,
|
|
||||||
color: theme.palette.secondary.main,
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
InputLabelProps={{
|
|
||||||
style: {
|
|
||||||
color: theme.palette.secondary.main
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
value={purchasesAmountThreshold}
|
|
||||||
onChange={e => setPurchasesAmountThreshold(Number(e.target.value) || 0)}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<TextField
|
|
||||||
id="standard-basic"
|
|
||||||
label={"Объем в корзине"}
|
|
||||||
variant="filled"
|
|
||||||
color="secondary"
|
|
||||||
type="number"
|
|
||||||
sx={{
|
|
||||||
marginTop: "15px"
|
|
||||||
}}
|
|
||||||
InputProps={{
|
|
||||||
style: {
|
|
||||||
backgroundColor: theme.palette.content.main,
|
|
||||||
color: theme.palette.secondary.main,
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
InputLabelProps={{
|
|
||||||
style: {
|
|
||||||
color: theme.palette.secondary.main
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
value={cartPurchasesAmountThreshold}
|
|
||||||
onChange={e => setCartPurchasesAmountThreshold(Number(e.target.value) || 0)}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<TextField
|
|
||||||
id="standard-basic"
|
|
||||||
label={"Минимальное значение"}
|
|
||||||
variant="filled"
|
|
||||||
color="secondary"
|
|
||||||
type="number"
|
|
||||||
sx={{
|
|
||||||
marginTop: "15px"
|
|
||||||
}}
|
|
||||||
InputProps={{
|
|
||||||
style: {
|
|
||||||
backgroundColor: theme.palette.content.main,
|
|
||||||
color: theme.palette.secondary.main,
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
InputLabelProps={{
|
|
||||||
style: {
|
|
||||||
color: theme.palette.secondary.main
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
value={discountMinValue}
|
|
||||||
onChange={e => setDiscountMinValue(Number(e.target.value) || 0)}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<TableContainer component={Paper} sx={{
|
|
||||||
width: "100%",
|
|
||||||
marginTop: "35px",
|
|
||||||
backgroundColor: theme.palette.content.main
|
|
||||||
}}>
|
|
||||||
<Table aria-label="simple table">
|
|
||||||
<TableBody>
|
|
||||||
<TableRow sx={{ border: "1px solid white" }} >
|
|
||||||
<TableCell component="th" scope="row" sx={{ color: theme.palette.secondary.main }}>
|
|
||||||
Работает, если заплатите 100500 денег
|
|
||||||
</TableCell>
|
|
||||||
</TableRow>
|
|
||||||
<TableRow sx={{ border: "1px solid white" }} >
|
|
||||||
<TableCell component="th" scope="row" sx={{ color: theme.palette.secondary.main }}>
|
|
||||||
Вы должны будете продать душу дьяволу
|
|
||||||
</TableCell>
|
|
||||||
</TableRow>
|
|
||||||
</TableBody>
|
|
||||||
</Table>
|
|
||||||
</TableContainer>
|
|
||||||
|
|
||||||
<Typography
|
|
||||||
variant="h4"
|
|
||||||
sx={{
|
|
||||||
width: "90%",
|
|
||||||
height: "40px",
|
|
||||||
fontWeight: "normal",
|
|
||||||
color: theme.palette.grayDisabled.main,
|
|
||||||
marginTop: "55px"
|
|
||||||
}}>
|
|
||||||
Дата действия:
|
|
||||||
</Typography>
|
|
||||||
|
|
||||||
<Box
|
|
||||||
sx={{
|
|
||||||
width: "100%",
|
|
||||||
display: "flex",
|
|
||||||
flexWrap: 'wrap'
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Typography sx={{
|
|
||||||
width: "35px",
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "column",
|
|
||||||
justifyContent: "center",
|
|
||||||
alignItems: "left",
|
|
||||||
}}>С</Typography>
|
|
||||||
|
|
||||||
<DesktopDatePicker
|
|
||||||
inputFormat="DD/MM/YYYY"
|
|
||||||
value={startDate}
|
|
||||||
onChange={(e) => { if (e) { setStartDate(e); } }}
|
|
||||||
renderInput={(params) => <TextField {...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 }
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Typography sx={{
|
|
||||||
width: "65px",
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "column",
|
|
||||||
justifyContent: "center",
|
|
||||||
alignItems: "center",
|
|
||||||
}}>по</Typography>
|
|
||||||
|
|
||||||
<DesktopDatePicker
|
|
||||||
inputFormat="DD/MM/YYYY"
|
|
||||||
value={endDate}
|
|
||||||
onChange={(e) => { if (e) { setEndDate(e); } }}
|
|
||||||
renderInput={(params) => <TextField {...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 }
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
|
|
||||||
|
|
||||||
<Box sx={{
|
|
||||||
display: "flex",
|
|
||||||
width: "90%",
|
|
||||||
marginTop: theme.spacing(2),
|
|
||||||
}}>
|
|
||||||
<Box sx={{
|
|
||||||
width: "20px",
|
|
||||||
height: "42px",
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "column",
|
|
||||||
justifyContent: "left",
|
|
||||||
alignItems: "left",
|
|
||||||
marginRight: theme.spacing(1)
|
|
||||||
}}>
|
|
||||||
<Checkbox
|
|
||||||
sx={{
|
|
||||||
color: theme.palette.secondary.main,
|
|
||||||
"&.Mui-checked": {
|
|
||||||
color: theme.palette.secondary.main,
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
checked={isInfinite}
|
|
||||||
onClick={() => setIsInfinite(p => !p)}
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
<Box sx={{
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "column",
|
|
||||||
justifyContent: "center",
|
|
||||||
alignItems: "center"
|
|
||||||
}}>
|
|
||||||
Бессрочно
|
|
||||||
</Box>
|
|
||||||
</Box>
|
|
||||||
|
|
||||||
<Box sx={{
|
|
||||||
width: "90%",
|
|
||||||
marginTop: "55px",
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "column",
|
|
||||||
justifyContent: "center",
|
|
||||||
alignItems: "center"
|
|
||||||
}}>
|
|
||||||
<Button
|
|
||||||
variant="contained"
|
|
||||||
sx={{
|
|
||||||
backgroundColor: theme.palette.menu.main,
|
|
||||||
height: "52px",
|
|
||||||
fontWeight: "normal",
|
|
||||||
fontSize: "17px",
|
|
||||||
"&:hover": {
|
|
||||||
backgroundColor: theme.palette.grayMedium.main
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
onClick={createDiscount}
|
|
||||||
>Cоздать</Button>
|
|
||||||
</Box>
|
|
||||||
|
|
||||||
</Box>
|
|
||||||
|
|
||||||
<Box style={{ width: "80%", marginTop: "55px" }}>
|
|
||||||
<Box style={{ height: 600 }}>
|
|
||||||
<DataGrid
|
|
||||||
checkboxSelection={true}
|
|
||||||
rows={discountsGridData}
|
|
||||||
columns={columns}
|
|
||||||
selectionModel={selectedDiscountIds}
|
|
||||||
onSelectionModelChange={setSelectedDiscountIds}
|
|
||||||
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 }}
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
</Box>
|
|
||||||
|
|
||||||
<Box sx={{
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "column",
|
|
||||||
justifyContent: "center",
|
|
||||||
alignItems: "center",
|
|
||||||
width: '100%',
|
|
||||||
marginTop: "45px"
|
|
||||||
}}>
|
|
||||||
<BoxButton sx={{
|
|
||||||
maxWidth: "420px",
|
|
||||||
width: '100%',
|
|
||||||
display: "flex",
|
|
||||||
justifyContent: "space-between",
|
|
||||||
flexWrap: 'wrap',
|
|
||||||
}}>
|
|
||||||
<Button
|
|
||||||
variant="contained"
|
|
||||||
onClick={deactivateDiscounts}
|
|
||||||
sx={{
|
|
||||||
backgroundColor: theme.palette.menu.main,
|
|
||||||
width: "200px",
|
|
||||||
height: "48px",
|
|
||||||
fontWeight: "normal",
|
|
||||||
fontSize: "17px",
|
|
||||||
marginBottom: '10px',
|
|
||||||
"&:hover": {
|
|
||||||
backgroundColor: theme.palette.grayMedium.main
|
|
||||||
}
|
|
||||||
}}>
|
|
||||||
Деактивировать
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
<Button
|
|
||||||
variant="contained"
|
|
||||||
onClick={activateDiscounts}
|
|
||||||
sx={{
|
|
||||||
backgroundColor: theme.palette.menu.main,
|
|
||||||
width: "200px",
|
|
||||||
height: "48px",
|
|
||||||
fontWeight: "normal",
|
|
||||||
fontSize: "17px",
|
|
||||||
"&:hover": {
|
|
||||||
backgroundColor: theme.palette.grayMedium.main
|
|
||||||
}
|
|
||||||
}}>
|
|
||||||
Активировать
|
|
||||||
</Button>
|
|
||||||
</BoxButton>
|
|
||||||
</Box>
|
|
||||||
|
|
||||||
</LocalizationProvider>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
export default DiscountManagement;
|
|
@ -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<ServiceType>("templategen");
|
||||||
|
const [discountType, setDiscountType] = useState<DiscountType>("Лояльность");
|
||||||
|
const [discountNameField, setDiscountNameField] = useState<string>("");
|
||||||
|
const [discountDescription, setDiscountDescription] = useState<string>("");
|
||||||
|
const [privilegeIdField, setPrivilegeIdField] = useState<string | "">("");
|
||||||
|
const [discountFactorField, setDiscountFactorField] = useState<string>("0");
|
||||||
|
const [purchasesAmountField, setPurchasesAmountField] = useState<string>("0");
|
||||||
|
const [cartPurchasesAmountField, setCartPurchasesAmountField] = useState<string>("0");
|
||||||
|
const [discountMinValueField, setDiscountMinValueField] = useState<string>("0");
|
||||||
|
|
||||||
|
const handleDiscountTypeChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
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 (
|
||||||
|
<Box sx={{
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
justifyContent: "left",
|
||||||
|
alignItems: "left",
|
||||||
|
marginTop: "15px",
|
||||||
|
width: "100%",
|
||||||
|
padding: "16px",
|
||||||
|
maxWidth: "600px",
|
||||||
|
gap: "1em",
|
||||||
|
}}>
|
||||||
|
<CustomTextField
|
||||||
|
id="discount-name"
|
||||||
|
label="Название"
|
||||||
|
value={discountNameField}
|
||||||
|
onChange={e => setDiscountNameField(e.target.value)}
|
||||||
|
/>
|
||||||
|
<CustomTextField
|
||||||
|
id="discount-desc"
|
||||||
|
label="Описание"
|
||||||
|
value={discountDescription}
|
||||||
|
onChange={e => setDiscountDescription(e.target.value)}
|
||||||
|
/>
|
||||||
|
<Typography
|
||||||
|
variant="h4"
|
||||||
|
sx={{
|
||||||
|
width: "90%",
|
||||||
|
fontWeight: "normal",
|
||||||
|
color: theme.palette.grayDisabled.main,
|
||||||
|
paddingLeft: "10px",
|
||||||
|
}}>
|
||||||
|
Условия:
|
||||||
|
</Typography>
|
||||||
|
<CustomTextField
|
||||||
|
id="discount-factor"
|
||||||
|
label="Процент скидки"
|
||||||
|
value={discountFactorField}
|
||||||
|
type="number"
|
||||||
|
onChange={e => setDiscountFactorField(e.target.value)}
|
||||||
|
/>
|
||||||
|
<FormControl>
|
||||||
|
<FormLabel
|
||||||
|
id="discount-type"
|
||||||
|
sx={{
|
||||||
|
color: "white",
|
||||||
|
"&.Mui-focused": {
|
||||||
|
color: "white",
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>Тип скидки</FormLabel>
|
||||||
|
<RadioGroup
|
||||||
|
row
|
||||||
|
aria-labelledby="discount-type"
|
||||||
|
name="discount-type"
|
||||||
|
value={discountType}
|
||||||
|
onChange={handleDiscountTypeChange}
|
||||||
|
>
|
||||||
|
{Object.keys(discountTypes).map(type =>
|
||||||
|
<FormControlLabel key={type} value={type} control={<Radio color="secondary" />} label={type} />
|
||||||
|
)}
|
||||||
|
</RadioGroup>
|
||||||
|
</FormControl>
|
||||||
|
{discountType === "Лояльность" &&
|
||||||
|
<CustomTextField
|
||||||
|
id="discount-purchases"
|
||||||
|
label="Внесено больше"
|
||||||
|
type="number"
|
||||||
|
sx={{
|
||||||
|
marginTop: "15px"
|
||||||
|
}}
|
||||||
|
value={purchasesAmountField}
|
||||||
|
onChange={e => setPurchasesAmountField(e.target.value)}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
{discountType === "Корзина" &&
|
||||||
|
<CustomTextField
|
||||||
|
id="discount-cart-purchases"
|
||||||
|
label="Объем в корзине"
|
||||||
|
type="number"
|
||||||
|
sx={{
|
||||||
|
marginTop: "15px"
|
||||||
|
}}
|
||||||
|
value={cartPurchasesAmountField}
|
||||||
|
onChange={e => setCartPurchasesAmountField(e.target.value)}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
{discountType === "Сервис" &&
|
||||||
|
<>
|
||||||
|
<Select
|
||||||
|
labelId="discount-service-label"
|
||||||
|
id="discount-service"
|
||||||
|
value={serviceType}
|
||||||
|
onChange={handleServiceTypeChange}
|
||||||
|
sx={{
|
||||||
|
color: theme.palette.secondary.main,
|
||||||
|
borderColor: theme.palette.secondary.main,
|
||||||
|
"&.Mui-focused .MuiOutlinedInput-notchedOutline": {
|
||||||
|
borderColor: theme.palette.secondary.main
|
||||||
|
},
|
||||||
|
".MuiSvgIcon-root ": {
|
||||||
|
fill: theme.palette.secondary.main,
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{SERVICE_LIST.map(service =>
|
||||||
|
<MenuItem key={service.serviceKey} value={service.serviceKey}>{service.displayName}</MenuItem>
|
||||||
|
)}
|
||||||
|
</Select>
|
||||||
|
<CustomTextField
|
||||||
|
id="discount-min-value"
|
||||||
|
label="Минимальное значение"
|
||||||
|
type="number"
|
||||||
|
sx={{
|
||||||
|
marginTop: "15px"
|
||||||
|
}}
|
||||||
|
value={discountMinValueField}
|
||||||
|
onChange={e => setDiscountMinValueField(e.target.value)}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
{discountType === "Товар" &&
|
||||||
|
<>
|
||||||
|
<FormControl
|
||||||
|
fullWidth
|
||||||
|
sx={{
|
||||||
|
color: theme.palette.secondary.main,
|
||||||
|
"& .MuiInputLabel-outlined": {
|
||||||
|
color: theme.palette.secondary.main,
|
||||||
|
},
|
||||||
|
"& .MuiInputLabel-outlined.MuiInputLabel-shrink": {
|
||||||
|
color: theme.palette.secondary.main,
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<InputLabel
|
||||||
|
id="privilege-select-label"
|
||||||
|
sx={{
|
||||||
|
color: theme.palette.secondary.main,
|
||||||
|
fontSize: "16px",
|
||||||
|
lineHeight: "19px",
|
||||||
|
}}
|
||||||
|
>Привелегия</InputLabel>
|
||||||
|
<Select
|
||||||
|
labelId="privilege-select-label"
|
||||||
|
id="privilege-select"
|
||||||
|
value={privilegeIdField}
|
||||||
|
label="Привелегия"
|
||||||
|
onChange={e => setPrivilegeIdField(e.target.value)}
|
||||||
|
sx={{
|
||||||
|
color: theme.palette.secondary.main,
|
||||||
|
borderColor: theme.palette.secondary.main,
|
||||||
|
"&.Mui-focused .MuiOutlinedInput-notchedOutline": {
|
||||||
|
borderColor: theme.palette.secondary.main,
|
||||||
|
},
|
||||||
|
".MuiSvgIcon-root ": {
|
||||||
|
fill: theme.palette.secondary.main,
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
inputProps={{ sx: { pt: "12px" } }}
|
||||||
|
>
|
||||||
|
{privileges.map((privilege, index) => (
|
||||||
|
<MenuItem key={index} value={privilege.privilegeId}>
|
||||||
|
{privilege.description}
|
||||||
|
</MenuItem>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
</FormControl>
|
||||||
|
<CustomTextField
|
||||||
|
id="discount-min-value"
|
||||||
|
label="Минимальное значение"
|
||||||
|
type="number"
|
||||||
|
sx={{
|
||||||
|
marginTop: "15px"
|
||||||
|
}}
|
||||||
|
value={discountMinValueField}
|
||||||
|
onChange={e => setDiscountMinValueField(e.target.value)}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
<Box sx={{
|
||||||
|
width: "90%",
|
||||||
|
marginTop: "55px",
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
justifyContent: "center",
|
||||||
|
alignItems: "center"
|
||||||
|
}}>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
sx={{
|
||||||
|
backgroundColor: theme.palette.menu.main,
|
||||||
|
height: "52px",
|
||||||
|
fontWeight: "normal",
|
||||||
|
fontSize: "17px",
|
||||||
|
"&:hover": {
|
||||||
|
backgroundColor: theme.palette.grayMedium.main
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
onClick={handleCreateDiscount}
|
||||||
|
>Cоздать</Button>
|
||||||
|
</Box>
|
||||||
|
</Box >
|
||||||
|
);
|
||||||
|
}
|
112
src/pages/dashboard/Content/DiscountManagement/DatePickers.tsx
Normal file
112
src/pages/dashboard/Content/DiscountManagement/DatePickers.tsx
Normal file
@ -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<boolean>(false);
|
||||||
|
const [startDate, setStartDate] = useState<Date>(new Date());
|
||||||
|
const [endDate, setEndDate] = useState<Date>(new Date());
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Typography
|
||||||
|
variant="h4"
|
||||||
|
sx={{
|
||||||
|
width: "90%",
|
||||||
|
height: "40px",
|
||||||
|
fontWeight: "normal",
|
||||||
|
color: theme.palette.grayDisabled.main,
|
||||||
|
marginTop: "55px"
|
||||||
|
}}>
|
||||||
|
Дата действия:
|
||||||
|
</Typography>
|
||||||
|
<Box sx={{
|
||||||
|
width: "100%",
|
||||||
|
display: "flex",
|
||||||
|
flexWrap: 'wrap'
|
||||||
|
}}>
|
||||||
|
<Typography sx={{
|
||||||
|
width: "35px",
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
justifyContent: "center",
|
||||||
|
alignItems: "left",
|
||||||
|
}}>С</Typography>
|
||||||
|
<DesktopDatePicker
|
||||||
|
inputFormat="DD/MM/YYYY"
|
||||||
|
value={startDate}
|
||||||
|
onChange={(e) => { if (e) { setStartDate(e); } }}
|
||||||
|
renderInput={(params) => <TextField {...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 }
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Typography sx={{
|
||||||
|
width: "65px",
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
justifyContent: "center",
|
||||||
|
alignItems: "center",
|
||||||
|
}}>по</Typography>
|
||||||
|
<DesktopDatePicker
|
||||||
|
inputFormat="DD/MM/YYYY"
|
||||||
|
value={endDate}
|
||||||
|
onChange={(e) => { if (e) { setEndDate(e); } }}
|
||||||
|
renderInput={(params) => <TextField {...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 }
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
<Box sx={{
|
||||||
|
display: "flex",
|
||||||
|
width: "90%",
|
||||||
|
marginTop: theme.spacing(2),
|
||||||
|
}}>
|
||||||
|
<Box sx={{
|
||||||
|
width: "20px",
|
||||||
|
height: "42px",
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
justifyContent: "left",
|
||||||
|
alignItems: "left",
|
||||||
|
marginRight: theme.spacing(1)
|
||||||
|
}}>
|
||||||
|
<Checkbox
|
||||||
|
sx={{
|
||||||
|
color: theme.palette.secondary.main,
|
||||||
|
"&.Mui-checked": {
|
||||||
|
color: theme.palette.secondary.main,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
checked={isInfinite}
|
||||||
|
onClick={() => setIsInfinite(p => !p)}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
<Box sx={{
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
justifyContent: "center",
|
||||||
|
alignItems: "center"
|
||||||
|
}}>
|
||||||
|
Бессрочно
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
@ -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 (
|
||||||
|
<Box sx={{ width: "100%", marginTop: "55px", p: "16px", maxWidth: "1000px" }}>
|
||||||
|
<Box sx={{ height: 600 }}>
|
||||||
|
<DataGrid
|
||||||
|
checkboxSelection={true}
|
||||||
|
rows={discountsGridData}
|
||||||
|
columns={columns}
|
||||||
|
selectionModel={selectedDiscountIds}
|
||||||
|
onSelectionModelChange={setSelectedDiscountIds}
|
||||||
|
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 }}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
<Box sx={{
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
justifyContent: "center",
|
||||||
|
alignItems: "center",
|
||||||
|
width: '100%',
|
||||||
|
marginTop: "45px"
|
||||||
|
}}>
|
||||||
|
<BoxButton sx={{
|
||||||
|
maxWidth: "420px",
|
||||||
|
width: '100%',
|
||||||
|
display: "flex",
|
||||||
|
justifyContent: "space-between",
|
||||||
|
flexWrap: 'wrap',
|
||||||
|
}}>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
onClick={deactivateDiscounts}
|
||||||
|
sx={{
|
||||||
|
backgroundColor: theme.palette.menu.main,
|
||||||
|
width: "200px",
|
||||||
|
height: "48px",
|
||||||
|
fontWeight: "normal",
|
||||||
|
fontSize: "17px",
|
||||||
|
marginBottom: '10px',
|
||||||
|
"&:hover": {
|
||||||
|
backgroundColor: theme.palette.grayMedium.main
|
||||||
|
}
|
||||||
|
}}>
|
||||||
|
Деактивировать
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
onClick={activateDiscounts}
|
||||||
|
sx={{
|
||||||
|
backgroundColor: theme.palette.menu.main,
|
||||||
|
width: "200px",
|
||||||
|
height: "48px",
|
||||||
|
fontWeight: "normal",
|
||||||
|
fontSize: "17px",
|
||||||
|
"&:hover": {
|
||||||
|
backgroundColor: theme.palette.grayMedium.main
|
||||||
|
}
|
||||||
|
}}>
|
||||||
|
Активировать
|
||||||
|
</Button>
|
||||||
|
</BoxButton>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
@ -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 (
|
||||||
|
<>
|
||||||
|
<LocalizationProvider dateAdapter={AdapterDayjs}>
|
||||||
|
<Typography
|
||||||
|
variant="subtitle1"
|
||||||
|
sx={{
|
||||||
|
width: "90%",
|
||||||
|
height: "60px",
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
justifyContent: "center",
|
||||||
|
alignItems: "center",
|
||||||
|
color: theme.palette.secondary.main
|
||||||
|
}}>
|
||||||
|
СКИДКИ
|
||||||
|
</Typography>
|
||||||
|
<CreateDiscount />
|
||||||
|
<DiscountDataGrid />
|
||||||
|
</LocalizationProvider>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export default DiscountManagement;
|
@ -106,20 +106,20 @@ export default function CreateTariff() {
|
|||||||
id="tariff-name"
|
id="tariff-name"
|
||||||
label="Название тарифа"
|
label="Название тарифа"
|
||||||
value={nameField}
|
value={nameField}
|
||||||
setValue={e => setNameField(e.target.value)}
|
onChange={e => setNameField(e.target.value)}
|
||||||
/>
|
/>
|
||||||
<CustomTextField
|
<CustomTextField
|
||||||
id="tariff-amount"
|
id="tariff-amount"
|
||||||
label="Кол-во единиц привилегии"
|
label="Кол-во единиц привилегии"
|
||||||
value={amountField}
|
value={amountField}
|
||||||
setValue={e => setAmountField(e.target.value)}
|
onChange={e => setAmountField(e.target.value)}
|
||||||
type="number"
|
type="number"
|
||||||
/>
|
/>
|
||||||
<CustomTextField
|
<CustomTextField
|
||||||
id="tariff-custom-price"
|
id="tariff-custom-price"
|
||||||
label="Кастомная цена (не обязательно)"
|
label="Кастомная цена (не обязательно)"
|
||||||
value={customPriceField}
|
value={customPriceField}
|
||||||
setValue={e => setCustomPriceField(e.target.value)}
|
onChange={e => setCustomPriceField(e.target.value)}
|
||||||
type="number"
|
type="number"
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
|
@ -30,7 +30,7 @@ export default function ChangePriceModal() {
|
|||||||
id="privilege-custom-price"
|
id="privilege-custom-price"
|
||||||
label="Цена"
|
label="Цена"
|
||||||
value={modalPriceField}
|
value={modalPriceField}
|
||||||
setValue={e => changeModalPriceField(e.target.value)}
|
onChange={e => changeModalPriceField(e.target.value)}
|
||||||
type="number"
|
type="number"
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
|
Loading…
Reference in New Issue
Block a user