370 lines
15 KiB
TypeScript
370 lines
15 KiB
TypeScript
import {
|
||
Button,
|
||
FormControlLabel,
|
||
MenuItem,
|
||
Radio,
|
||
RadioGroup,
|
||
Select,
|
||
TextField,
|
||
Typography,
|
||
} from "@mui/material";
|
||
import { DesktopDatePicker } from "@mui/x-date-pickers/DesktopDatePicker";
|
||
import { Field, Form, Formik } from "formik";
|
||
import { useEffect, useState } from "react";
|
||
|
||
import { requestPrivileges } from "@root/services/privilegies.service";
|
||
import { usePrivilegeStore } from "@root/stores/privilegesStore";
|
||
|
||
import { SERVICE_LIST } from "@root/model/privilege";
|
||
import theme from "@root/theme";
|
||
|
||
import type { TextFieldProps } from "@mui/material";
|
||
import { CreatePromocodeBody } from "@root/model/promocodes";
|
||
import type { ChangeEvent } from "react";
|
||
|
||
type BonusType = "discount" | "privilege";
|
||
|
||
type FormValues = {
|
||
codeword: string;
|
||
description: string;
|
||
greetings: string;
|
||
dueTo: number;
|
||
activationCount: number;
|
||
privilegeId: string;
|
||
amount: number;
|
||
layer: 1 | 2;
|
||
factor: number;
|
||
target: string;
|
||
threshold: number;
|
||
};
|
||
|
||
const initialValues: FormValues = {
|
||
codeword: "",
|
||
description: "",
|
||
greetings: "",
|
||
dueTo: 0,
|
||
activationCount: 0,
|
||
privilegeId: "",
|
||
amount: 0,
|
||
layer: 1,
|
||
factor: 0,
|
||
target: "",
|
||
threshold: 0,
|
||
};
|
||
|
||
type Props = {
|
||
createPromocode: (body: CreatePromocodeBody) => Promise<void>;
|
||
};
|
||
|
||
export const CreatePromocodeForm = ({ createPromocode }: Props) => {
|
||
const [bonusType, setBonusType] = useState<BonusType>("discount");
|
||
const { privileges } = usePrivilegeStore();
|
||
|
||
useEffect(() => {
|
||
requestPrivileges();
|
||
}, []);
|
||
|
||
const submitForm = (values: FormValues) => {
|
||
const body = {
|
||
...values,
|
||
threshold: values.layer === 1 ? values.threshold : values.threshold * 100,
|
||
};
|
||
|
||
const factorFromDiscountValue = 1 - body.factor / 100;
|
||
|
||
return createPromocode({
|
||
codeword: body.codeword,
|
||
description: body.description,
|
||
greetings: body.greetings,
|
||
dueTo: body.dueTo,
|
||
activationCount: body.activationCount,
|
||
bonus: {
|
||
privilege: { privilegeID: body.privilegeId, amount: body.amount },
|
||
discount: {
|
||
layer: body.layer,
|
||
factor: factorFromDiscountValue,
|
||
target: body.target,
|
||
threshold: body.threshold,
|
||
},
|
||
},
|
||
});
|
||
};
|
||
|
||
return (
|
||
<Formik initialValues={initialValues} onSubmit={submitForm}>
|
||
{({ values, handleChange, handleBlur, setFieldValue }) => (
|
||
<Form
|
||
style={{
|
||
width: "100%",
|
||
maxWidth: "600px",
|
||
padding: "0 10px",
|
||
}}
|
||
>
|
||
<CustomTextField
|
||
name="codeword"
|
||
label="Кодовое слово"
|
||
required
|
||
onChange={handleChange}
|
||
/>
|
||
<CustomTextField
|
||
name="description"
|
||
label="Описание"
|
||
required
|
||
onChange={handleChange}
|
||
/>
|
||
<CustomTextField
|
||
name="greetings"
|
||
label="Приветственное сообщение"
|
||
required
|
||
onChange={handleChange}
|
||
/>
|
||
<Typography
|
||
variant="h4"
|
||
sx={{
|
||
height: "40px",
|
||
fontWeight: "normal",
|
||
marginTop: "15px",
|
||
color: theme.palette.secondary.main,
|
||
}}
|
||
>
|
||
Время существования промокода
|
||
</Typography>
|
||
<Field
|
||
name="dueTo"
|
||
as={DesktopDatePicker}
|
||
inputFormat="DD/MM/YYYY"
|
||
value={values.dueTo ? new Date(Number(values.dueTo) * 1000) : null}
|
||
onChange={(event: any) => {
|
||
setFieldValue("dueTo", event.$d.getTime() / 1000 || null);
|
||
}}
|
||
renderInput={(params: TextFieldProps) => <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 },
|
||
},
|
||
}}
|
||
/>
|
||
<CustomTextField
|
||
name="activationCount"
|
||
label="Количество активаций промокода"
|
||
onChange={({ target }) =>
|
||
setFieldValue(
|
||
"activationCount",
|
||
Number(target.value.replace(/\D/g, ""))
|
||
)
|
||
}
|
||
/>
|
||
<RadioGroup
|
||
row
|
||
name="bonusType"
|
||
value={bonusType}
|
||
sx={{ marginTop: "15px" }}
|
||
onChange={({ target }: React.ChangeEvent<HTMLInputElement>) => {
|
||
setBonusType(target.value as BonusType);
|
||
}}
|
||
onBlur={handleBlur}
|
||
>
|
||
<FormControlLabel
|
||
value="discount"
|
||
control={<Radio color="secondary" />}
|
||
label="Скидка"
|
||
/>
|
||
<FormControlLabel
|
||
value="privilege"
|
||
control={<Radio color="secondary" />}
|
||
label="Привилегия"
|
||
/>
|
||
</RadioGroup>
|
||
{bonusType === "discount" && (
|
||
<>
|
||
<RadioGroup
|
||
row
|
||
name="layer"
|
||
value={values.layer}
|
||
sx={{ marginTop: "15px" }}
|
||
onChange={({ target }: React.ChangeEvent<HTMLInputElement>) => {
|
||
setFieldValue("target", "");
|
||
setFieldValue("layer", Number(target.value));
|
||
}}
|
||
onBlur={handleBlur}
|
||
>
|
||
<FormControlLabel
|
||
value="1"
|
||
control={<Radio color="secondary" />}
|
||
label="Привилегия"
|
||
/>
|
||
<FormControlLabel
|
||
value="2"
|
||
control={<Radio color="secondary" />}
|
||
label="Сервис"
|
||
/>
|
||
</RadioGroup>
|
||
<CustomTextField
|
||
name="factor"
|
||
label="Процент скидки"
|
||
required
|
||
onChange={({ target }) => {
|
||
setFieldValue(
|
||
"factor",
|
||
Number(target.value.replace(/\D/g, ""))
|
||
);
|
||
}}
|
||
/>
|
||
<Typography
|
||
variant="h4"
|
||
sx={{
|
||
height: "40px",
|
||
fontWeight: "normal",
|
||
marginTop: "15px",
|
||
padding: "0 12px",
|
||
color: theme.palette.secondary.main,
|
||
}}
|
||
>
|
||
{values.layer === 1 ? "Выбор привилегии" : "Выбор сервиса"}
|
||
</Typography>
|
||
<Field
|
||
name="target"
|
||
as={Select}
|
||
label={values.layer === 1 ? "Привилегия" : "Сервис"}
|
||
sx={{
|
||
width: "100%",
|
||
border: "2px solid",
|
||
color: theme.palette.secondary.main,
|
||
borderColor: theme.palette.secondary.main,
|
||
"&.Mui-focused .MuiOutlinedInput-notchedOutline": {
|
||
border: "none",
|
||
},
|
||
".MuiSvgIcon-root ": { fill: theme.palette.secondary.main },
|
||
}}
|
||
children={
|
||
values.layer === 1
|
||
? privileges.map(({ name, privilegeId }) => (
|
||
<MenuItem key={privilegeId} value={privilegeId}>
|
||
{name}
|
||
</MenuItem>
|
||
))
|
||
: SERVICE_LIST.map(({ displayName, serviceKey }) => (
|
||
<MenuItem key={serviceKey} value={serviceKey}>
|
||
{displayName}
|
||
</MenuItem>
|
||
))
|
||
}
|
||
/>
|
||
<CustomTextField
|
||
name="threshold"
|
||
label="При каком значении применяется скидка"
|
||
onChange={({ target }) =>
|
||
setFieldValue(
|
||
"threshold",
|
||
Number(target.value.replace(/\D/g, ""))
|
||
)
|
||
}
|
||
/>
|
||
</>
|
||
)}
|
||
{bonusType === "privilege" && (
|
||
<>
|
||
<Typography
|
||
variant="h4"
|
||
sx={{
|
||
height: "40px",
|
||
fontWeight: "normal",
|
||
marginTop: "15px",
|
||
padding: "0 12px",
|
||
color: theme.palette.secondary.main,
|
||
}}
|
||
>
|
||
Выбор привилегии
|
||
</Typography>
|
||
<Field
|
||
name="privilegeId"
|
||
as={Select}
|
||
label="Привилегия"
|
||
sx={{
|
||
width: "100%",
|
||
border: "2px solid",
|
||
color: theme.palette.secondary.main,
|
||
borderColor: theme.palette.secondary.main,
|
||
"&.Mui-focused .MuiOutlinedInput-notchedOutline": {
|
||
border: "none",
|
||
},
|
||
".MuiSvgIcon-root ": { fill: theme.palette.secondary.main },
|
||
}}
|
||
children={privileges.map(({ name, privilegeId }) => (
|
||
<MenuItem key={privilegeId} value={privilegeId}>
|
||
{name}
|
||
</MenuItem>
|
||
))}
|
||
/>
|
||
<CustomTextField
|
||
name="amount"
|
||
label="Количество"
|
||
required
|
||
onChange={({ target }) =>
|
||
setFieldValue(
|
||
"amount",
|
||
Number(target.value.replace(/\D/g, ""))
|
||
)
|
||
}
|
||
/>
|
||
</>
|
||
)}
|
||
<Button
|
||
variant="contained"
|
||
sx={{
|
||
display: "block",
|
||
padding: "10px",
|
||
margin: "15px auto 0",
|
||
fontWeight: "normal",
|
||
fontSize: "18px",
|
||
backgroundColor: theme.palette.menu.main,
|
||
"&:hover": { backgroundColor: theme.palette.grayMedium.main },
|
||
}}
|
||
type="submit"
|
||
>
|
||
Cоздать
|
||
</Button>
|
||
</Form>
|
||
)}
|
||
</Formik>
|
||
);
|
||
};
|
||
|
||
type CustomTextFieldProps = {
|
||
name: string;
|
||
label: string;
|
||
required?: boolean;
|
||
onChange: (event: ChangeEvent<HTMLInputElement>) => void;
|
||
};
|
||
|
||
const CustomTextField = ({
|
||
name,
|
||
label,
|
||
required = false,
|
||
onChange,
|
||
}: CustomTextFieldProps) => (
|
||
<Field
|
||
name={name}
|
||
label={label}
|
||
required={required}
|
||
variant="filled"
|
||
color="secondary"
|
||
as={TextField}
|
||
onChange={onChange}
|
||
sx={{ width: "100%", marginTop: "15px" }}
|
||
InputProps={{
|
||
style: {
|
||
backgroundColor: theme.palette.content.main,
|
||
color: theme.palette.secondary.main,
|
||
},
|
||
}}
|
||
InputLabelProps={{
|
||
style: { color: theme.palette.secondary.main },
|
||
}}
|
||
/>
|
||
);
|