feat: CreatePromocodeForm

This commit is contained in:
IlyaDoronin 2024-02-22 17:12:50 +03:00
parent 77c2d834c9
commit bd6dfc182e
5 changed files with 392 additions and 438 deletions

@ -20,7 +20,7 @@ import Users from "@pages/dashboard/Content/Users";
import Entities from "@pages/dashboard/Content/Entities";
import Tariffs from "@pages/dashboard/Content/Tariffs";
import DiscountManagement from "@root/pages/dashboard/Content/DiscountManagement/DiscountManagement";
import PromocodeManagement from "@pages/dashboard/Content/PromocodeManagement";
import { PromocodeManagement } from "@root/pages/dashboard/Content/PromocodeManagement";
import { SettingRoles } from "@pages/Setting/SettingRoles";
import Support from "@pages/dashboard/Content/Support/Support";
@ -104,7 +104,11 @@ root.render(
}
/>
{componentsArray.map((element) => (
<Route key={element[0]} path={element[0]} element={element[1]} />
<Route
key={element[0]}
path={element[0]}
element={element[1]}
/>
))}
</Route>

@ -1,436 +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, GridToolbar } from "@mui/x-data-grid";
import MenuItem from "@mui/material/MenuItem";
import Select, { SelectChangeEvent } from "@mui/material/Select";
import theme from "../../../theme";
import { usePromocodeStore } from "../../../stores/promocodes";
import { useRef, useState } from "react";
import { ServiceType } from "@root/model/tariff";
const columns: GridColDef[] = [
{
field: "id",
headerName: "ID",
width: 30,
sortable: false,
},
{
field: "name",
headerName: "Название промокода",
width: 200,
sortable: false,
},
{
field: "endless",
headerName: "Бесконечный",
width: 120,
sortable: false,
},
{
field: "from",
headerName: "От",
width: 120,
sortable: false,
},
{
field: "dueTo",
headerName: "До",
width: 120,
sortable: false,
},
{
field: "privileges",
headerName: "Привилегии",
width: 210,
sortable: false,
}
];
const PromocodeManagement: React.FC = () => {
const [checkboxState, setCheckboxState] = useState<boolean>(false);
const toggleCheckbox = () => { setCheckboxState(!checkboxState); };
const [value1, setValue1] = useState<Date>(new Date());
const [value2, setValue2] = useState<Date>(new Date());
const [service, setService] = useState<ServiceType>("templategen");
const handleChange = (event: SelectChangeEvent) => {
setService(event.target.value as ServiceType);
};
const promocodes = usePromocodeStore(state => state.promocodes);
const addPromocodes = usePromocodeStore(state => state.addPromocodes);
function createPromocode() {
// TODO
}
// const promocodeArrayConverted = promocodes.map((item) => {
// 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.serviceKey} - ${privilege.discount}%`
// : `${privilege.serviceKey} - ${privilege.discount * 100}%`;
// return acc;
// }, "");
// return { ...item, privileges: result, from: strFrom, dueTo: strDueTo };
// } else {
// return { ...item, from: strFrom, dueTo: strDueTo };
// }
// });
// const createPromocode = (name: string, discount: number) => {
// const newPromocode = {
// id: new Date().getTime(),
// name,
// endless: checkboxState,
// from: checkboxState ? "" : new Date(value1).getTime() + "",
// dueTo: checkboxState ? "" : new Date(value2).getTime() + "",
// privileges: [{
// good: service,
// discount: discount / 100
// }]
// };
// const promocodeArrayUpdated = [...promocodes, newPromocode];
// addPromocodes(promocodeArrayUpdated);
// };
const promocodeGridData = promocodes.map(procomode => {
// TODO
})
const fieldName = useRef<HTMLInputElement | null>(null);
const fieldDiscount = useRef<HTMLInputElement | null>(null);
// const checkFields = () => {
// if (fieldName.current != null && fieldDiscount.current != null) {
// createPromocode(fieldName.current.value, Number(fieldDiscount.current.value));
// }
// };
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",
}}>
{/*<Typography */}
{/* variant="h4" */}
{/* sx={{*/}
{/* width: "90%",*/}
{/* height: "40px",*/}
{/* fontWeight: "normal",*/}
{/* color: theme.palette.grayDisabled.main,*/}
{/* marginTop: "35px"*/}
{/*}}>*/}
{/* Название:*/}
{/*</Typography>*/}
<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
}
}}
inputRef={fieldName}
/>
<Typography
variant="h4"
sx={{
width: "90%",
height: "40px",
fontWeight: "normal",
color: theme.palette.grayDisabled.main,
marginTop: "75px"
}}>
Условия:
</Typography>
<Select
labelId="demo-simple-select-label"
id="demo-simple-select"
value={service}
label="Age"
onChange={handleChange}
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={"Шаблонизатор документов"}>Шаблонизатор</MenuItem>
<MenuItem value={"Опросник"}>Опросник</MenuItem>
<MenuItem value={"Аналитика сокращателя"}>Аналитика сокращателя</MenuItem>
<MenuItem value={"АБ тесты"}>АБ тесты</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
}
}}
inputRef={fieldDiscount}
/>
<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={value1}
onChange={(e) => { if (e) { setValue1(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={value2}
onChange={(e) => { if (e) { setValue2(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,
},
}} onClick={() => toggleCheckbox()} />
</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={createPromocode} >
Cоздать
</Button>
</Box>
</Box>
<Box style={{ width: "80%", marginTop: "55px" }}>
<Box style={{ height: 400 }}>
<DataGrid
checkboxSelection={true}
rows={promocodeGridData}
columns={columns}
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 }}
onSelectionModelChange={(ids) => console.log("datagrid select")}
/>
</Box>
</Box>
</LocalizationProvider>
</>
);
};
export default PromocodeManagement;

@ -0,0 +1,300 @@
import { useEffect, useState } from "react";
import {
Typography,
TextField,
Button,
RadioGroup,
Radio,
FormControlLabel,
Select,
} from "@mui/material";
import { Formik, Field, Form } from "formik";
import { DesktopDatePicker } from "@mui/x-date-pickers/DesktopDatePicker";
import MenuItem from "@mui/material/MenuItem";
import theme from "../../../../theme";
import { requestPrivileges } from "@root/services/privilegies.service";
import { usePrivilegeStore } from "@root/stores/privilegesStore";
import { useCartStore } from "@root/stores/cart";
import type { TextFieldProps } from "@mui/material";
type BonusType = "discount" | "privilege";
type LayerType = "privilege" | "service";
type FormValues = {
codeword: string;
description: string;
greetings: string;
dueTo: string;
activationCount: string;
privilegeId: string;
amount: string;
layer: string;
factor: string;
target: string;
threshold: string;
};
type CustomTextFieldProps = {
name: string;
label: string;
required?: boolean;
};
const CustomTextField = ({
name,
label,
required = false,
}: CustomTextFieldProps) => (
<Field
name={name}
label={label}
required={required}
variant="filled"
color="secondary"
as={TextField}
sx={{ width: "100%", marginTop: "15px" }}
InputProps={{
style: {
backgroundColor: theme.palette.content.main,
color: theme.palette.secondary.main,
},
}}
InputLabelProps={{
style: { color: theme.palette.secondary.main },
}}
/>
);
export const CreatePromocodeForm = () => {
const [dueTo, setDueTo] = useState<Date | null>(new Date());
const [bonusType, setBonusType] = useState<BonusType>("discount");
const [layerType, setLayerType] = useState<LayerType>("privilege");
const { privileges } = usePrivilegeStore();
const { cartData } = useCartStore();
const initialValues: FormValues = {
codeword: "",
description: "",
greetings: "",
dueTo: "",
activationCount: "",
privilegeId: "",
amount: "",
layer: "",
factor: "",
target: "",
threshold: "",
};
useEffect(() => {
requestPrivileges();
}, []);
const createPromocode = (values: FormValues) => {
console.log(values);
};
return (
<Formik initialValues={initialValues} onSubmit={createPromocode}>
{(props) => (
<Form
style={{
width: "100%",
maxWidth: "600px",
}}
>
<CustomTextField name="codeword" label="Кодовое слово" required />
<CustomTextField name="description" label="Описание" required />
<CustomTextField
name="greetings"
label="Приветственное сообщение"
required
/>
<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={dueTo}
onChange={(date: Date | null) => {
if (date) {
setDueTo(date);
}
}}
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="Количество активаций промокода"
/>
<RadioGroup
row
name="bonusType"
value={bonusType}
sx={{ marginTop: "15px" }}
onChange={({ target }: React.ChangeEvent<HTMLInputElement>) => {
setBonusType(target.value as BonusType);
}}
onBlur={props.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={layerType}
sx={{ marginTop: "15px" }}
onChange={({ target }: React.ChangeEvent<HTMLInputElement>) => {
setLayerType(target.value as LayerType);
}}
onBlur={props.handleBlur}
>
<FormControlLabel
value="privilege"
control={<Radio color="secondary" />}
label="Привилегия"
/>
<FormControlLabel
value="service"
control={<Radio color="secondary" />}
label="Сервис"
/>
</RadioGroup>
<CustomTextField name="factor" label="Процент скидки" required />
<Typography
variant="h4"
sx={{
height: "40px",
fontWeight: "normal",
marginTop: "15px",
padding: "0 12px",
color: theme.palette.secondary.main,
}}
>
{layerType === "privilege"
? "Выбор привилегии"
: "Выбор сервиса"}
</Typography>
<Field
name="target"
as={Select}
label={layerType === "privilege" ? "Привилегия" : "Сервис"}
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={
layerType === "privilege"
? privileges.map(({ name, privilegeId }) => (
<MenuItem key={privilegeId} value={privilegeId}>
{name}
</MenuItem>
))
: cartData?.services.map(({ serviceKey }) => (
<MenuItem key={serviceKey} value={serviceKey}>
{serviceKey}
</MenuItem>
))
}
/>
<CustomTextField
name="threshold"
label="При каком значении применяется скидка"
required
/>
</>
)}
{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 />
</>
)}
<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>
);
};

@ -0,0 +1,56 @@
import { Box } from "@mui/material";
import { DataGrid, GridColDef, GridToolbar } from "@mui/x-data-grid";
import { usePromocodeStore } from "@root/stores/promocodes";
import theme from "@root/theme";
const columns: GridColDef[] = [
{ field: "id", headerName: "ID", width: 30, sortable: false },
{
field: "name",
headerName: "Название промокода",
width: 200,
sortable: false,
},
{ field: "endless", headerName: "Бесконечный", width: 120, sortable: false },
{ field: "from", headerName: "От", width: 120, sortable: false },
{ field: "dueTo", headerName: "До", width: 120, sortable: false },
{
field: "privileges",
headerName: "Привилегии",
width: 210,
sortable: false,
},
];
export const PromocodesList = () => {
const { promocodes } = usePromocodeStore();
return (
<Box style={{ width: "80%", marginTop: "55px" }}>
<Box style={{ height: 400 }}>
<DataGrid
checkboxSelection={true}
rows={promocodes}
columns={columns}
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 }}
onSelectionModelChange={(ids) => console.log("datagrid select")}
/>
</Box>
</Box>
);
};

@ -0,0 +1,30 @@
import { Typography } from "@mui/material";
import { LocalizationProvider } from "@mui/x-date-pickers/LocalizationProvider";
import { AdapterDayjs } from "@mui/x-date-pickers/AdapterDayjs";
import { PromocodesList } from "./PromocodesList";
import { CreatePromocodeForm } from "./CreatePromocodeForm";
import theme from "@root/theme";
export const PromocodeManagement = () => (
<LocalizationProvider dateAdapter={AdapterDayjs}>
<Typography
variant="subtitle1"
sx={{
width: "90%",
height: "60px",
display: "flex",
flexDirection: "column",
justifyContent: "center",
alignItems: "center",
textTransform: "uppercase",
color: theme.palette.secondary.main,
}}
>
Создание промокода
</Typography>
<CreatePromocodeForm />
<PromocodesList />
</LocalizationProvider>
);