fix: conflicts resolved

This commit is contained in:
IlyaDoronin 2024-05-21 11:53:09 +03:00
commit 5ccffb8196
10 changed files with 734 additions and 279 deletions

@ -1,7 +1,7 @@
import eslint from "@eslint/js";
import tseslint from "typescript-eslint";
const eslint = require("@eslint/js");
const tseslint = require("typescript-eslint");
export default tseslint.config(eslint.configs.recommended, ...tseslint.configs.recommended, {
module.exports = tseslint.config(eslint.configs.recommended, ...tseslint.configs.recommended, {
rules: {
semi: "error",
"prefer-const": "error",

@ -2,7 +2,6 @@
"name": "adminka",
"version": "0.1.0",
"private": true,
"type": "module",
"dependencies": {
"@date-io/dayjs": "^2.15.0",
"@emotion/react": "^11.10.4",

@ -1,11 +1,12 @@
import makeRequest from "@root/api/makeRequest";
import type {
CreatePromocodeBody,
GetPromocodeListBody,
Promocode,
PromocodeList,
PromocodeStatistics,
CreatePromocodeBody,
EditPromocodeBody,
GetPromocodeListBody,
Promocode,
PromocodeList,
PromocodeStatistics,
} from "@root/model/promocodes";
import { parseAxiosError } from "@root/utils/parse-error";
@ -68,6 +69,33 @@ export const getAllPromocodes = async () => {
}
};
export const getNotActivePromocodes = async () => {
try {
const promocodes: Promocode[] = [];
let page = 0;
while (true) {
const promocodeList = await getPromocodeList({
limit: 100,
filter: {
active: false,
},
page,
});
if (promocodeList.items.length === 0) break;
promocodes.push(...promocodeList.items);
page++;
}
return promocodes;
} catch (nativeError) {
const [error] = parseAxiosError(nativeError);
throw new Error(`Ошибка при получении списка промокодов. ${error}`);
}
};
const createPromocode = async (body: CreatePromocodeBody) => {
try {
const createPromocodeResponse = await makeRequest<CreatePromocodeBody, Promocode>({
@ -88,6 +116,20 @@ const createPromocode = async (body: CreatePromocodeBody) => {
}
};
const editPromocode = async (body: EditPromocodeBody) => {
try {
const editPromocodeResponse = await makeRequest<unknown, Promocode>({
url: process.env.REACT_APP_DOMAIN + "/codeword/promocode" + "/edit",
method: "PUT",
body,
});
return [editPromocodeResponse];
} catch (nativeError) {
const [error] = parseAxiosError(nativeError);
return [null, `Ошибка редактирования промокода. ${error}`];
}
};
const deletePromocode = async (id: string): Promise<void> => {
try {
await makeRequest<never, never>({
@ -121,10 +163,12 @@ const getPromocodeStatistics = async (id: string, from: number, to: number) => {
};
export const promocodeApi = {
getPromocodeList,
createPromocode,
deletePromocode,
getAllPromocodes,
getPromocodeStatistics,
createFastlink,
getPromocodeList,
createPromocode,
editPromocode,
deletePromocode,
getAllPromocodes,
getNotActivePromocodes,
getPromocodeStatistics,
createFastlink,
};

@ -3,20 +3,30 @@ import useSwr, { mutate } from "swr";
import { enqueueSnackbar } from "notistack";
import { promocodeApi } from "./requests";
import type { CreatePromocodeBody, PromocodeList } from "@root/model/promocodes";
import type {
CreatePromocodeBody, EditPromocodeBody,
PromocodeList,
} from "@root/model/promocodes";
export function usePromocodes(page: number, pageSize: number, promocodeId: string, to: number, from: number) {
const promocodesCountRef = useRef<number>(0);
const swrResponse = useSwr(
["promocodes", page, pageSize],
async (key) => {
const result = await promocodeApi.getPromocodeList({
limit: key[2],
filter: {
active: true,
},
page: key[1],
});
export function usePromocodes(
page: number,
pageSize: number,
promocodeId: string,
to: number,
from: number,
active: boolean
) {
const promocodesCountRef = useRef<number>(0);
const swrResponse = useSwr(
["promocodes", page, pageSize, active],
async (key) => {
const result = await promocodeApi.getPromocodeList({
limit: key[2],
filter: {
active: key[3],
},
page: key[1],
});
promocodesCountRef.current = result.count;
return result;
@ -44,15 +54,38 @@ export function usePromocodes(page: number, pageSize: number, promocodeId: strin
[page, pageSize]
);
const deletePromocode = useCallback(
async function (id: string) {
try {
await mutate<PromocodeList | undefined, void>(
["promocodes", page, pageSize],
promocodeApi.deletePromocode(id),
{
optimisticData(currentData, displayedData) {
if (!displayedData) return;
const editPromocode = useCallback(
async function (body: EditPromocodeBody) {
try {
await promocodeApi.editPromocode(body);
mutate<PromocodeList | undefined, void>(
["promocodes", page, pageSize, active],
);
await promocodeApi.getPromocodeList({
limit: pageSize,
filter: {
active: active,
},
page: page,
});
} catch (error) {
console.error("Error editing promocode", error);
if (error instanceof Error)
enqueueSnackbar(error.message, { variant: "error" });
}
},
[page, pageSize,]
);
const deletePromocode = useCallback(
async function (id: string) {
try {
await mutate<PromocodeList | undefined, void>(
["promocodes", page, pageSize],
promocodeApi.deletePromocode(id),
{
optimisticData(currentData, displayedData) {
if (!displayedData) return;
return {
count: displayedData.count - 1,
@ -112,14 +145,15 @@ export function usePromocodes(page: number, pageSize: number, promocodeId: strin
[page, pageSize]
);
return {
...swrResponse,
createPromocode,
deletePromocode,
createFastLink,
promocodeStatistics: promocodeStatistics.data,
promocodesCount: promocodesCountRef.current,
};
return {
...swrResponse,
createPromocode,
deletePromocode,
editPromocode,
createFastLink,
promocodeStatistics: promocodeStatistics.data,
promocodesCount: promocodesCountRef.current,
};
}
export function useAllPromocodes() {
@ -134,3 +168,16 @@ export function useAllPromocodes() {
return data;
}
export function useNotActivePromocodes() {
const { data } = useSwr("notActivePromocodes", promocodeApi.getNotActivePromocodes, {
keepPreviousData: true,
suspense: true,
onError(err) {
console.error("Error fetching all promocodes", err);
enqueueSnackbar(err.message, { variant: "error" });
},
});
return data;
}

@ -49,3 +49,13 @@ export type PromocodeStatistics = {
usageCount: number;
usageMap: Record<string, number>;
};
export type EditPromocodeBody = {
id: string,
description: string,
greetings: string,
dueTo: number,
activationCount: number,
delete: boolean
}

@ -0,0 +1,202 @@
import {
Box,
Button,
Typography,
Modal,
TextField,
useTheme,
useMediaQuery,
TextFieldProps,
} from "@mui/material";
import {CustomTextField} from "@kitUI/CustomTextField";
import {DesktopDatePicker} from "@mui/x-date-pickers/DesktopDatePicker";
import {useEffect, useState} from "react";
import {EditPromocodeBody, Promocode} from "@root/model/promocodes";
import {enqueueSnackbar} from "notistack";
const host = window.location.hostname;
const isTest = host.includes("s");
type EditModalProps = {
id: string;
setId: (id: string) => void;
promocodes: Promocode[];
editPromocode: (body: EditPromocodeBody) => Promise<void>
};
export const EditModal = ({id, setId, promocodes, editPromocode}: EditModalProps) => {
const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down(550));
const promocode = promocodes.find((item) => item.id === id);
const [descriptionField, setDescriptionField] = useState<string>("");
const [greetingsField, setGreetingsField] = useState<string>("");
const [dueToField, setDueToField] = useState<number>(0);
const [activationField, setActivationField] = useState<number>(0);
useEffect(
function setCurrentPromocodeFields() {
if (!promocode) return;
setDescriptionField(promocode.description);
setGreetingsField(promocode.greetings);
setDueToField(promocode.dueTo);
setActivationField(promocode.activationCount);
},
[promocode]
);
async function handleEditClick() {
if (!promocode) return enqueueSnackbar(`Тариф ${id} не найден`);
if (!descriptionField) return enqueueSnackbar('Поле "Описание" пустое');
if (!greetingsField) return enqueueSnackbar('Поле "Приветственное сообщение" пустое');
const editPromocodeBody: EditPromocodeBody = {
id: id,
description: descriptionField,
greetings: greetingsField,
dueTo: dueToField,
activationCount: activationField,
delete: promocode.delete
};
await editPromocode(editPromocodeBody);
setId("");
}
return (
<Modal
open={Boolean(id)}
onClose={() => {
setId("");
}}
sx={{
"& > .MuiBox-root": { outline: "none", padding: "32px 32px 16px" },
}}
>
<Box
sx={{
position: "absolute",
top: "50%",
left: "50%",
transform: "translate(-50%, -50%)",
width: "95%",
maxWidth: "600px",
background: "#1F2126",
border: "2px solid gray",
borderRadius: "6px",
boxShadow: 24,
p: 4,
}}
>
<Box
sx={{
display: "flex",
gap: "30px",
justifyContent: "center",
alignItems: "center",
flexDirection: "column",
}}
>
<Box
sx={{display: "flex",
flexDirection: "column",
gap: "15px"
}}
>
<Typography
variant="h4"
sx={{
height: "40px",
fontWeight: "normal",
color: theme.palette.secondary.main,
}}
>Редактировать промокод: {promocode?.codeword}</Typography>
{promocode && (
<>
<CustomTextField
id={""}
name="description"
label="Описание"
value={descriptionField}
onChange={(event) => setDescriptionField(event.target.value)}
/>
<CustomTextField
id={""}
name="greetings"
label="Приветственое сообщение"
value={greetingsField}
onChange={(event) => setGreetingsField(event.target.value)}
/>
<Typography
variant="h4"
sx={{
height: "40px",
fontWeight: "normal",
marginTop: "15px",
color: theme.palette.secondary.main,
}}
>
Время существования промокода
</Typography>
<DesktopDatePicker
inputFormat="DD/MM/YYYY"
value={dueToField === 0 ? null : new Date(Number(dueToField) * 1000)}
onChange={(event: any) => {
setDueToField(event.$d.getTime() / 1000 || 0);
}}
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
id={""}
name="activationCount"
label="Количество активаций промокода"
value={activationField}
onChange={({ target }) =>
setActivationField(Number(target.value.replace(/\D/g, "")))
}
/>
</>
)}
</Box>
<Box
sx={{
display: "flex",
gap: "30px",
justifyContent: "center",
alignItems: "center",
}}
>
<Button sx={{ maxWidth: "100px" }}
onClick={handleEditClick}
>
Сохранить изменения
</Button>
<Button sx={{ maxWidth: "100px" }} onClick={() => {
setId("");
}}>
Отмена
</Button>
</Box>
</Box>
</Box>
</Modal>
);
};

@ -1,5 +1,5 @@
import { useState } from "react";
import { Box, Typography, useTheme } from "@mui/material";
import {Box, Button, FormControl, InputLabel, MenuItem, Select, Typography, useTheme} from "@mui/material";
import { DataGrid, GridLoadingOverlay, GridToolbar } from "@mui/x-data-grid";
import { AdapterDayjs } from "@mui/x-date-pickers/AdapterDayjs";
import { LocalizationProvider } from "@mui/x-date-pickers/LocalizationProvider";
@ -9,6 +9,9 @@ import { CreatePromocodeForm } from "./CreatePromocodeForm";
import { usePromocodeGridColDef } from "./usePromocodeGridColDef";
import { StatisticsModal } from "./StatisticsModal";
import DeleteModal from "./DeleteModal";
import {promocodeApi} from "@root/api/promocode/requests";
import {SelectChangeEvent} from "@mui/material/Select";
import {EditModal} from "@pages/dashboard/Content/PromocodeManagement/EditModal";
export const PromocodeManagement = () => {
const theme = useTheme();
@ -16,91 +19,135 @@ export const PromocodeManagement = () => {
const [deleteModal, setDeleteModal] = useState<string>("");
const deleteModalHC = (id: string) => setDeleteModal(id);
const [showStatisticsModalId, setShowStatisticsModalId] = useState<string>("");
const [page, setPage] = useState<number>(0);
const [to, setTo] = useState(0);
const [from, setFrom] = useState(0);
const [pageSize, setPageSize] = useState<number>(10);
const {
data,
error,
isValidating,
promocodesCount,
promocodeStatistics,
deletePromocode,
createPromocode,
createFastLink,
} = usePromocodes(page, pageSize, showStatisticsModalId, to, from);
const columns = usePromocodeGridColDef(setShowStatisticsModalId, deleteModalHC);
if (error) return <Typography>Ошибка загрузки промокодов</Typography>;
const [showStatisticsModalId, setShowStatisticsModalId] =
useState<string>("");
const [showEditModalId, setShowEditModalId] =
useState<string>("");
const [page, setPage] = useState<number>(0);
const [to, setTo] = useState(0);
const [from, setFrom] = useState(0);
const [pageSize, setPageSize] = useState<number>(10);
const [active, setActive] = useState(true);
const {
data,
error,
isValidating,
promocodesCount,
promocodeStatistics,
deletePromocode,
createPromocode,
editPromocode,
createFastLink,
} = usePromocodes(page, pageSize, showStatisticsModalId, to, from, active);
const columns = usePromocodeGridColDef(
setShowEditModalId,
setShowStatisticsModalId,
deleteModalHC
);
if (error) return <Typography>Ошибка загрузки промокодов</Typography>;
return (
<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 createPromocode={createPromocode} />
<Box style={{ width: "80%", marginTop: "55px" }}>
<DataGrid
disableSelectionOnClick={true}
rows={data?.items ?? []}
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 },
"& .MuiDataGrid-overlay": {
backgroundColor: "rgba(255, 255, 255, 0.1)",
animation: `${fadeIn} 0.5s ease-out`,
},
}}
components={{
Toolbar: GridToolbar,
LoadingOverlay: GridLoadingOverlay,
}}
loading={isValidating}
paginationMode="server"
page={page}
onPageChange={setPage}
rowCount={promocodesCount}
pageSize={pageSize}
onPageSizeChange={setPageSize}
rowsPerPageOptions={[10, 25, 50, 100]}
autoHeight
/>
</Box>
<StatisticsModal
id={showStatisticsModalId}
setId={setShowStatisticsModalId}
promocodeStatistics={promocodeStatistics}
to={to}
setTo={setTo}
from={from}
setFrom={setFrom}
promocodes={data?.items ?? []}
createFastLink={createFastLink}
/>
<DeleteModal id={deleteModal} setModal={setDeleteModal} deletePromocode={deletePromocode} />
</LocalizationProvider>
);
return (
<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 createPromocode={createPromocode} />
<Box sx={{marginTop: "55px", width: "80%", display: "flex"}}>
<FormControl variant="standard" sx={{ m: 1, minWidth: 120 }}>
<Select
labelId="demo-simple-select-standard-label"
id="demo-simple-select-standard"
sx={{color: "white",
backgroundColor: "transparent",
padding: "5px",
border: "1px solid white",
borderRadius: "4px",
".MuiSelect-icon": {
color: "white"
}
}}
value={active? "true" : "false"}
onChange={(event: SelectChangeEvent) => {
setActive((event.target.value) === "true" ? true : false);
}}
label="Age"
>
<MenuItem value={"true"}>Активные</MenuItem>
<MenuItem value={"false"}>Неактивные</MenuItem>
</Select>
</FormControl>
</Box>
<Box style={{ width: "80%", marginTop: "25px" }}>
<DataGrid
disableSelectionOnClick={true}
rows={data?.items ?? []}
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 },
"& .MuiDataGrid-overlay": {
backgroundColor: "rgba(255, 255, 255, 0.1)",
animation: `${fadeIn} 0.5s ease-out`,
},
}}
components={{
Toolbar: GridToolbar,
LoadingOverlay: GridLoadingOverlay,
}}
loading={isValidating}
paginationMode="server"
page={page}
onPageChange={setPage}
rowCount={promocodesCount}
pageSize={pageSize}
onPageSizeChange={setPageSize}
rowsPerPageOptions={[10, 25, 50, 100]}
autoHeight
/>
</Box>
<EditModal
id={showEditModalId}
setId={setShowEditModalId}
promocodes={data?.items ?? []}
editPromocode={editPromocode}
/>
<StatisticsModal
id={showStatisticsModalId}
setId={setShowStatisticsModalId}
promocodeStatistics={promocodeStatistics}
to={to}
setTo={setTo}
from={from}
setFrom={setFrom}
promocodes={data?.items ?? []}
createFastLink={createFastLink}
/>
<DeleteModal
id={deleteModal}
setModal={setDeleteModal}
deletePromocode={deletePromocode}
/>
</LocalizationProvider>
);
};

@ -3,95 +3,117 @@ import { GridColDef } from "@mui/x-data-grid";
import { Promocode } from "@root/model/promocodes";
import { useMemo, useState } from "react";
import { BarChart, Delete } from "@mui/icons-material";
import { BarChart, Delete, Edit } from "@mui/icons-material";
import { promocodeApi } from "@root/api/promocode/requests";
export function usePromocodeGridColDef(setStatistics: (id: string) => void, deletePromocode: (id: string) => void) {
const validity = (value: string | number) => {
if (value === 0) {
return "неоганичен";
} else {
return new Date(value).toLocaleString();
}
};
return useMemo<GridColDef<Promocode, string | number, string>[]>(
() => [
{
field: "id",
headerName: "ID",
width: 30,
sortable: false,
valueGetter: ({ row }) => row.id,
},
{
field: "codeword",
headerName: "Кодовое слово",
width: 160,
sortable: false,
valueGetter: ({ row }) => row.codeword,
},
{
field: "factor",
headerName: "Коэф. скидки",
width: 120,
sortable: false,
valueGetter: ({ row }) => Math.round(row.bonus.discount.factor * 1000) / 1000,
},
{
field: "activationCount",
headerName: "Кол-во активаций",
width: 140,
sortable: false,
valueGetter: ({ row }) => row.activationCount,
},
{
field: "dueTo",
headerName: "Истекает",
width: 160,
sortable: false,
valueGetter: ({ row }) => row.dueTo * 1000,
valueFormatter: ({ value }) => `${validity(value)}`,
},
{
field: "description",
headerName: "Описание",
minWidth: 200,
flex: 1,
sortable: false,
valueGetter: ({ row }) => row.description,
},
{
field: "settings",
headerName: "",
width: 60,
sortable: false,
renderCell: (params) => {
return (
<IconButton
onClick={() => {
setStatistics(params.row.id);
promocodeApi.getPromocodeStatistics(params.row.id, 0, 0);
}}
>
<BarChart />
</IconButton>
);
},
},
{
field: "delete",
headerName: "",
width: 60,
sortable: false,
renderCell: (params) => {
return (
<IconButton onClick={() => deletePromocode(params.row.id)}>
<Delete />
</IconButton>
);
},
},
],
[deletePromocode, setStatistics]
);
export function usePromocodeGridColDef(
setEdit: (id: string) => void,
setStatistics: (id: string) => void,
deletePromocode: (id: string) => void
) {
const validity = (value: string | number) => {
if (value === 0) {
return "неоганичен";
} else {
return new Date(value).toLocaleString();
}
};
return useMemo<GridColDef<Promocode, string | number, string>[]>(
() => [
{
field: "id",
headerName: "ID",
width: 30,
sortable: false,
valueGetter: ({ row }) => row.id,
},
{
field: "codeword",
headerName: "Кодовое слово",
width: 160,
sortable: false,
valueGetter: ({ row }) => row.codeword,
},
{
field: "factor",
headerName: "Коэф. скидки",
width: 120,
sortable: false,
valueGetter: ({ row }) =>
Math.round(row.bonus.discount.factor * 1000) / 1000,
},
{
field: "activationCount",
headerName: "Кол-во активаций",
width: 140,
sortable: false,
valueGetter: ({ row }) => row.activationCount,
},
{
field: "dueTo",
headerName: "Истекает",
width: 160,
sortable: false,
valueGetter: ({ row }) => row.dueTo * 1000,
valueFormatter: ({ value }) => `${validity(value)}`,
},
{
field: "description",
headerName: "Описание",
minWidth: 200,
flex: 1,
sortable: false,
valueGetter: ({ row }) => row.description,
},
{
field: "edit",
headerName: "",
width: 60,
sortable: false,
renderCell: (params) => {
return (
<IconButton
onClick={() => {
setEdit(params.row.id);
}}
>
<Edit />
</IconButton>
);
},
},
{
field: "settings",
headerName: "",
width: 60,
sortable: false,
renderCell: (params) => {
return (
<IconButton
onClick={() => {
setStatistics(params.row.id);
promocodeApi.getPromocodeStatistics(params.row.id, 0, 0);
}}
>
<BarChart />
</IconButton>
);
},
},
{
field: "delete",
headerName: "",
width: 60,
sortable: false,
renderCell: (params) => {
return (
<IconButton onClick={() => deletePromocode(params.row.id)}>
<Delete />
</IconButton>
);
},
},
],
[deletePromocode, setStatistics, setEdit]
);
}

@ -1,70 +1,144 @@
import { useState } from "react";
import moment from "moment";
import { Table, TableBody, TableCell, TableHead, TableRow, Typography, useTheme } from "@mui/material";
import {
Box,
FormControl, MenuItem, Select,
Table,
TableBody,
TableCell,
TableHead,
TableRow,
Typography,
useTheme,
} from "@mui/material";
import { DateFilter } from "./DateFilter";
import { useAllPromocodes } from "@root/api/promocode/swr";
import {useAllPromocodes, useNotActivePromocodes} from "@root/api/promocode/swr";
import { usePromocodeStatistics } from "@root/utils/hooks/usePromocodeStatistics";
import type { Moment } from "moment";
import {SelectChangeEvent} from "@mui/material/Select";
type PropStatistic = {
"id": string,
"Regs": number,
"Money": number,
"codeword": string,
}
export const StatisticsPromocode = () => {
const [from, setFrom] = useState<Moment | null>(moment(moment().subtract(4, "weeks")));
const [to, setTo] = useState<Moment | null>(moment());
const promocodes = useAllPromocodes();
const promocodeStatistics = usePromocodeStatistics({ to, from });
const theme = useTheme();
const [from, setFrom] = useState<Moment | null>(
moment(moment().subtract(4, "weeks"))
);
const [to, setTo] = useState<Moment | null>(moment());
const [active, setActive] = useState(true);
const promocodes = useAllPromocodes();
const promocodesNot = useNotActivePromocodes();
const promocodeStatistics = usePromocodeStatistics({ to, from });
const theme = useTheme();
return (
<>
<Typography sx={{ marginTop: "30px" }}>Статистика промокодов</Typography>
<DateFilter from={from} to={to} setFrom={setFrom} setTo={setTo} />
<Table
sx={{
width: "80%",
border: "2px solid",
borderColor: theme.palette.secondary.main,
bgcolor: theme.palette.content.main,
color: "white",
marginTop: "30px",
}}
>
<TableHead>
<TableRow
sx={{
borderBottom: "2px solid",
borderColor: theme.palette.grayLight.main,
height: "100px",
}}
>
<TableCell sx={{ color: "inherit" }} align="center">
Промокод
</TableCell>
<TableCell sx={{ color: "inherit" }} align="center">
Регистации
</TableCell>
<TableCell sx={{ color: "inherit" }} align="center">
Внесено
</TableCell>
</TableRow>
</TableHead>
{Object.entries(promocodeStatistics).map(([key, { Regs, Money }]) => (
<TableBody key={key}>
<TableRow>
<TableCell sx={{ color: "inherit" }} align="center">
{promocodes.find(({ id }) => id === key)?.codeword ?? ""}
</TableCell>
<TableCell sx={{ color: "inherit" }} align="center">
{Regs}
</TableCell>
<TableCell sx={{ color: "inherit" }} align="center">
{(Money / 100).toFixed(2)}
</TableCell>
</TableRow>
</TableBody>
))}
</Table>
</>
);
const filterPromo = active ? promocodes : promocodesNot;
console.log(promocodes, "active");
console.log(promocodesNot);
const filteredPromoStatistics = () => {
const copyPromocodeStatistics:PropStatistic[] = [];
Object.entries(promocodeStatistics).map(([key, { Regs, Money }]) => {
for(const i in filterPromo){
if(filterPromo[i].id === key) {
copyPromocodeStatistics.push(
{
"id": key,
"Regs": Regs,
"Money": Money,
"codeword": filterPromo[i].codeword,
}
);
}}
});
return copyPromocodeStatistics;
};
const filteredStat = filteredPromoStatistics();
return (
<>
<Typography sx={{ marginTop: "30px" }}>Статистика промокодов</Typography>
<DateFilter from={from} to={to} setFrom={setFrom} setTo={setTo} />
<Box sx={{marginTop: "55px", width: "80%", display: "flex"}}>
<FormControl variant="standard" sx={{ m: 1, minWidth: 120 }}>
<Select
labelId="demo-simple-select-standard-label"
id="demo-simple-select-standard"
sx={{color: "white",
backgroundColor: "transparent",
padding: "5px",
border: "1px solid white",
borderRadius: "4px",
".MuiSelect-icon": {
color: "white"
}
}}
value={active? "true" : "false"}
onChange={(event: SelectChangeEvent) => {
setActive((event.target.value) === "true" ? true : false);
}}
label="Age"
>
<MenuItem value={"true"}>Активные</MenuItem>
<MenuItem value={"false"}>Неактивные</MenuItem>
</Select>
</FormControl>
</Box>
<Table
sx={{
width: "80%",
border: "2px solid",
borderColor: theme.palette.secondary.main,
bgcolor: theme.palette.content.main,
color: "white",
marginTop: "30px",
}}
>
<TableHead>
<TableRow
sx={{
borderBottom: "2px solid",
borderColor: theme.palette.grayLight.main,
height: "100px",
}}
>
<TableCell sx={{ color: "inherit" }} align="center">
Промокод
</TableCell>
<TableCell sx={{ color: "inherit" }} align="center">
Регистации
</TableCell>
<TableCell sx={{ color: "inherit" }} align="center">
Внесено
</TableCell>
</TableRow>
</TableHead>
{filteredStat.map((stat) => (
<TableBody>
<TableRow>
<TableCell sx={{ color: "inherit" }} align="center">
{stat?.codeword}
</TableCell>
<TableCell sx={{ color: "inherit" }} align="center">
{stat?.Regs}
</TableCell>
<TableCell sx={{ color: "inherit" }} align="center">
{(stat?.Money / 100).toFixed(2)}
</TableCell>
</TableRow>
</TableBody>
))}
</Table>
</>
);
};

10
src/test/test.tsx Normal file

@ -0,0 +1,10 @@
export const Test = () => {
console.log(1);
let a;
return <div></div>;
};