feat: new API requests

This commit is contained in:
IlyaDoronin 2023-09-01 16:17:24 +03:00
parent 258c7caaa8
commit 100d6657da
23 changed files with 833 additions and 478 deletions

@ -40,7 +40,7 @@ export const getAccountInfo = async (
): Promise<[Account | null, string?]> => { ): Promise<[Account | null, string?]> => {
try { try {
const accountInfoResponse = await makeRequest<never, Account>({ const accountInfoResponse = await makeRequest<never, Account>({
url: `/account${baseUrl}/${id}`, url: `${baseUrl}/account/${id}`,
method: "GET", method: "GET",
useToken: true, useToken: true,
}); });

72
src/api/auth.ts Normal file

@ -0,0 +1,72 @@
import { makeRequest } from "@frontend/kitui";
import { parseAxiosError } from "@root/utils/parse-error";
import type {
LoginRequest,
RegisterRequest,
RegisterResponse,
} from "@frontend/kitui";
const baseUrl =
process.env.NODE_ENV === "production"
? "/auth"
: "https://admin.pena.digital/auth";
export const signin = async (
login: string,
password: string
): Promise<[RegisterResponse | null, string?]> => {
try {
const signinResponse = await makeRequest<LoginRequest, RegisterResponse>({
url: baseUrl + "/login",
body: { login, password },
useToken: false,
});
return [signinResponse];
} catch (nativeError) {
const [error] = parseAxiosError(nativeError);
return [null, `Ошибка авторизации. ${error}`];
}
};
export const register = async (
login: string,
password: string,
phoneNumber: string = "--"
): Promise<[RegisterResponse | null, string?]> => {
try {
const registerResponse = await makeRequest<
RegisterRequest,
RegisterResponse
>({
url: baseUrl + "/register",
body: { login, password, phoneNumber },
useToken: false,
});
return [registerResponse];
} catch (nativeError) {
const [error] = parseAxiosError(nativeError);
return [null, `Ошибка регистрации. ${error}`];
}
};
export const logout = async (): Promise<[unknown, string?]> => {
try {
const logoutResponse = await makeRequest<never, unknown>({
url: baseUrl + "/logout",
method: "post",
contentType: true,
});
return [logoutResponse];
} catch (nativeError) {
const [error] = parseAxiosError(nativeError);
return [null, `Ошибка выхода из аккаунта. ${error}`];
}
};

@ -3,7 +3,11 @@ import { makeRequest } from "@frontend/kitui";
import { parseAxiosError } from "@root/utils/parse-error"; import { parseAxiosError } from "@root/utils/parse-error";
import type { Discount } from "@frontend/kitui"; import type { Discount } from "@frontend/kitui";
import type { CreateDiscountBody, DiscountType } from "@root/model/discount"; import type {
CreateDiscountBody,
DiscountType,
GetDiscountResponse,
} from "@root/model/discount";
const baseUrl = const baseUrl =
process.env.NODE_ENV === "production" process.env.NODE_ENV === "production"
@ -194,3 +198,21 @@ export const patchDiscount = async (
return [null, `Ошибка изменения скидки. ${error}`]; return [null, `Ошибка изменения скидки. ${error}`];
} }
}; };
export const requestDiscounts = async (): Promise<
[GetDiscountResponse | null, string?]
> => {
try {
const discountsResponse = await makeRequest<never, GetDiscountResponse>({
url: baseUrl + "/discounts",
method: "get",
useToken: true,
});
return [discountsResponse];
} catch (nativeError) {
const [error] = parseAxiosError(nativeError);
return [null, `Ошибка получения скидок. ${error}`];
}
};

92
src/api/privilegies.ts Normal file

@ -0,0 +1,92 @@
import { makeRequest } from "@frontend/kitui";
import { parseAxiosError } from "@root/utils/parse-error";
import { PrivilegeWithAmount } from "@frontend/kitui";
import type { TMockData } from "./roles";
type SeverPrivilegiesResponse = {
templategen: PrivilegeWithAmount[];
};
const baseUrl =
process.env.NODE_ENV === "production"
? "/strator"
: "https://admin.pena.digital/strator";
export const getRoles = async (): Promise<[TMockData | null, string?]> => {
try {
const rolesResponse = await makeRequest<never, TMockData>({
method: "get",
url: baseUrl + "/role",
});
return [rolesResponse];
} catch (nativeError) {
const [error] = parseAxiosError(nativeError);
return [null, `Ошибка запроса ролей. ${error}`];
}
};
export const putPrivilegie = async (
body: Omit<PrivilegeWithAmount, "_id" | "updatedAt">
): Promise<[unknown, string?]> => {
try {
const putedPrivilegie = await makeRequest<
Omit<PrivilegeWithAmount, "_id" | "updatedAt">,
unknown
>({
url: baseUrl + "/privilege",
method: "put",
body,
});
return [putedPrivilegie];
} catch (nativeError) {
const [error] = parseAxiosError(nativeError);
return [null, `Ошибка изменения привилегии. ${error}`];
}
};
export const requestServicePrivilegies = async (): Promise<
[SeverPrivilegiesResponse | null, string?]
> => {
try {
const privilegiesResponse = await makeRequest<
never,
SeverPrivilegiesResponse
>({
url: baseUrl + "/privilege/service",
method: "get",
});
return [privilegiesResponse];
} catch (nativeError) {
const [error] = parseAxiosError(nativeError);
return [null, `Ошибка запроса привилегий. ${error}`];
}
};
export const requestPrivilegies = async (
signal: AbortSignal | undefined
): Promise<[PrivilegeWithAmount[], string?]> => {
try {
const privilegiesResponse = await makeRequest<never, PrivilegeWithAmount[]>(
{
url: baseUrl + "/privilege",
method: "get",
useToken: true,
signal,
}
);
return [privilegiesResponse];
} catch (nativeError) {
const [error] = parseAxiosError(nativeError);
return [[], `Ошибка запроса привилегий. ${error}`];
}
};

@ -1,3 +1,7 @@
import { makeRequest } from "@frontend/kitui";
import { parseAxiosError } from "@root/utils/parse-error";
export const MOCK_DATA_USERS = [ export const MOCK_DATA_USERS = [
{ {
key: 0, key: 0,
@ -31,6 +35,11 @@ export type UserType = {
updatedAt: string; updatedAt: string;
}; };
const baseUrl =
process.env.NODE_ENV === "production"
? "/role"
: "https://admin.pena.digital/role";
export const getRoles_mock = (): Promise<TMockData> => { export const getRoles_mock = (): Promise<TMockData> => {
return new Promise((resolve) => { return new Promise((resolve) => {
setTimeout(() => { setTimeout(() => {
@ -38,3 +47,18 @@ export const getRoles_mock = (): Promise<TMockData> => {
}, 1000); }, 1000);
}); });
}; };
export const deleteRole = async (id: string): Promise<[unknown, string?]> => {
try {
const deleteRoleResponse = await makeRequest({
url: `${baseUrl}/${id}`,
method: "delete",
});
return [deleteRoleResponse];
} catch (nativeError) {
const [error] = parseAxiosError(nativeError);
return [null, `Ошибка удаления роли. ${error}`];
}
};

@ -2,14 +2,49 @@ import { makeRequest } from "@frontend/kitui";
import { parseAxiosError } from "@root/utils/parse-error"; import { parseAxiosError } from "@root/utils/parse-error";
import type { PrivilegeWithAmount } from "@frontend/kitui";
import type { Tariff } from "@frontend/kitui"; import type { Tariff } from "@frontend/kitui";
import type { EditTariffRequestBody } from "@root/model/tariff"; import type { EditTariffRequestBody } from "@root/model/tariff";
type CreateTariffBackendRequest = {
name: string;
price: number;
isCustom: boolean;
privilegies: Omit<PrivilegeWithAmount, "_id" | "updatedAt">[];
};
type GetTariffsResponse = {
totalPages: number;
tariffs: Tariff[];
};
const baseUrl = const baseUrl =
process.env.NODE_ENV === "production" process.env.NODE_ENV === "production"
? "/strator" ? "/strator"
: "https://admin.pena.digital/strator"; : "https://admin.pena.digital/strator";
export const createTariff = async (
body: CreateTariffBackendRequest
): Promise<[unknown, string?]> => {
try {
const createdTariffResponse = await makeRequest<CreateTariffBackendRequest>(
{
url: baseUrl + "/tariff/",
method: "post",
body,
}
);
debugger;
return [createdTariffResponse];
} catch (nativeError) {
const [error] = parseAxiosError(nativeError);
return [null, `Ошибка создания тарифа. ${error}`];
}
};
export const putTariff = async (tariff: Tariff): Promise<[null, string?]> => { export const putTariff = async (tariff: Tariff): Promise<[null, string?]> => {
try { try {
const putedTariffResponse = await makeRequest<EditTariffRequestBody, null>({ const putedTariffResponse = await makeRequest<EditTariffRequestBody, null>({
@ -49,22 +84,19 @@ export const deleteTariff = async (
} }
}; };
export async function deleteManyTariffs(tariffIds: string[]) { export const requestTariffs = async (
const results = await Promise.allSettled( page: number
tariffIds.map((tariffId) => deleteTariff(tariffId)) ): Promise<[GetTariffsResponse | null, string?]> => {
); try {
const tariffsResponse = await makeRequest<never, GetTariffsResponse>({
let deletedCount = 0; url: baseUrl + `/tariff/?page=${page}&limit=${100}`,
let errorCount = 0; method: "get",
const errors: unknown[] = [];
results.forEach((result) => {
if (result.status === "fulfilled") deletedCount++;
else {
errorCount++;
errors.push(result.reason);
}
}); });
return { deletedCount, errorCount, errors }; return [tariffsResponse];
} catch (nativeError) {
const [error] = parseAxiosError(nativeError);
return [null, `Ошибка запроса тарифов. ${error}`];
} }
};

@ -4,6 +4,11 @@ import { parseAxiosError } from "@root/utils/parse-error";
import type { UserType } from "@root/api/roles"; import type { UserType } from "@root/api/roles";
type RegisteredUsersResponse = {
tatalPages: number;
users: UserType[];
};
const baseUrl = const baseUrl =
process.env.NODE_ENV === "production" process.env.NODE_ENV === "production"
? "/user" ? "/user"
@ -26,3 +31,43 @@ export const getUserInfo = async (
return [null, `Ошибка получения информации о пользователе. ${error}`]; return [null, `Ошибка получения информации о пользователе. ${error}`];
} }
}; };
export const getRegisteredUsers = async (): Promise<
[RegisteredUsersResponse | null, string?]
> => {
try {
const registeredUsersResponse = await makeRequest<
never,
RegisteredUsersResponse
>({
method: "get",
url: baseUrl + "/",
});
return [registeredUsersResponse];
} catch (nativeError) {
const [error] = parseAxiosError(nativeError);
return [null, `Ошибка при получении пользователей. ${error}`];
}
};
export const getManagersList = async (): Promise<
[RegisteredUsersResponse | null, string?]
> => {
try {
const managersListResponse = await makeRequest<
never,
RegisteredUsersResponse
>({
method: "get",
url: baseUrl + "/",
});
return [managersListResponse];
} catch (nativeError) {
const [error] = parseAxiosError(nativeError);
return [null, `Ошибка при получении менеджеров. ${error}`];
}
};

68
src/api/verification.ts Normal file

@ -0,0 +1,68 @@
import { makeRequest } from "@frontend/kitui";
import { parseAxiosError } from "@root/utils/parse-error";
type File = {
name: "inn" | "rule" | "egrule" | "certificate";
url: string;
};
export type Verification = {
_id: string;
accepted: boolean;
status: "org" | "nko";
updated_at: string;
comment: string;
files: File[];
};
type PatchVerificationBody = {
id: string;
status: "org" | "nko";
comment: string;
accepted: boolean;
};
const baseUrl =
process.env.NODE_ENV === "production"
? "/verification"
: "https://admin.pena.digital/verification";
export const verification = async (
userId: string
): Promise<[Verification | null, string?]> => {
try {
const verificationResponse = await makeRequest<never, Verification>({
method: "get",
url: baseUrl + `/verification/${userId}`,
});
return [verificationResponse];
} catch (nativeError) {
const [error] = parseAxiosError(nativeError);
return [null, `Ошибка верификации. ${error}`];
}
};
export const patchVerification = async (
body: PatchVerificationBody
): Promise<[unknown, string?]> => {
try {
const patchedVerificationResponse = await makeRequest<
PatchVerificationBody,
unknown
>({
method: "patch",
useToken: true,
url: baseUrl + `/verification/verification`,
body,
});
return [patchedVerificationResponse];
} catch (nativeError) {
const [error] = parseAxiosError(nativeError);
return [null, `Ошибка изменения верификации. ${error}`];
}
};

@ -44,9 +44,7 @@ export default function Cart() {
async function handleCalcCartClick() { async function handleCalcCartClick() {
await requestPrivilegies(); await requestPrivilegies();
try { await requestDiscounts();
discounts = await requestDiscounts();
} catch { }
const cartTariffs = tariffs.filter(tariff => selectedTariffIds.includes(tariff._id)); const cartTariffs = tariffs.filter(tariff => selectedTariffIds.includes(tariff._id));

@ -3,12 +3,18 @@ import { enqueueSnackbar } from "notistack";
import { useTheme } from "@mui/material/styles"; import { useTheme } from "@mui/material/styles";
import { Formik, Field, Form, FormikHelpers } from "formik"; import { Formik, Field, Form, FormikHelpers } from "formik";
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
import { Box, Checkbox, Typography, FormControlLabel, Button } from "@mui/material"; import {
Box,
Checkbox,
Typography,
FormControlLabel,
Button,
} from "@mui/material";
import Logo from "@pages/Logo"; import Logo from "@pages/Logo";
import OutlinedInput from "@kitUI/outlinedInput"; import OutlinedInput from "@kitUI/outlinedInput";
import EmailOutlinedIcon from "@mui/icons-material/EmailOutlined"; import EmailOutlinedIcon from "@mui/icons-material/EmailOutlined";
import LockOutlinedIcon from "@mui/icons-material/LockOutlined"; import LockOutlinedIcon from "@mui/icons-material/LockOutlined";
import { makeRequest } from "@frontend/kitui"; import { signin } from "@root/api/auth";
interface Values { interface Values {
email: string; email: string;
@ -44,30 +50,29 @@ const SigninForm = () => {
password: "", password: "",
}; };
const onSignFormSubmit = (values: Values, formikHelpers: FormikHelpers<Values>) => { const onSignFormSubmit = async (
values: Values,
formikHelpers: FormikHelpers<Values>
) => {
formikHelpers.setSubmitting(true); formikHelpers.setSubmitting(true);
makeRequest({
url: "https://admin.pena.digital/auth/login", const [_, signinError] = await signin(values.email, values.password);
body: {
login: values.email,
password: values.password,
},
useToken: false,
})
.then((e) => {
navigate("/users");
})
.catch((e) => {
console.log(e);
enqueueSnackbar(e.message ? e.message : `Unknown error`);
})
.finally(() => {
formikHelpers.setSubmitting(false); formikHelpers.setSubmitting(false);
});
if (signinError) {
return enqueueSnackbar(signinError);
}
navigate("/users");
}; };
return ( return (
<Formik initialValues={initialValues} validate={validate} onSubmit={onSignFormSubmit}> <Formik
initialValues={initialValues}
validate={validate}
onSubmit={onSignFormSubmit}
>
{(props) => ( {(props) => (
<Form> <Form>
<Box <Box
@ -105,7 +110,14 @@ const SigninForm = () => {
Мы рады что вы выбрали нас! Мы рады что вы выбрали нас!
</Typography> </Typography>
</Box> </Box>
<Box sx={{ display: "flex", alignItems: "center", marginTop: "15px", "> *": { marginRight: "10px" } }}> <Box
sx={{
display: "flex",
alignItems: "center",
marginTop: "15px",
"> *": { marginRight: "10px" },
}}
>
<EmailOutlinedIcon htmlColor={theme.palette.golden.main} /> <EmailOutlinedIcon htmlColor={theme.palette.golden.main} />
<Field <Field
as={OutlinedInput} as={OutlinedInput}
@ -120,7 +132,14 @@ const SigninForm = () => {
} }
/> />
</Box> </Box>
<Box sx={{ display: "flex", alignItems: "center", marginTop: "15px", "> *": { marginRight: "10px" } }}> <Box
sx={{
display: "flex",
alignItems: "center",
marginTop: "15px",
"> *": { marginRight: "10px" },
}}
>
<LockOutlinedIcon htmlColor={theme.palette.golden.main} /> <LockOutlinedIcon htmlColor={theme.palette.golden.main} />
<Field <Field
as={OutlinedInput} as={OutlinedInput}
@ -165,7 +184,9 @@ const SigninForm = () => {
/> />
</Box> </Box>
<Link to="/restore" style={{ textDecoration: "none" }}> <Link to="/restore" style={{ textDecoration: "none" }}>
<Typography color={theme.palette.golden.main}>Забыли пароль?</Typography> <Typography color={theme.palette.golden.main}>
Забыли пароль?
</Typography>
</Link> </Link>
<Button <Button
type="submit" type="submit"
@ -184,9 +205,13 @@ const SigninForm = () => {
display: "flex", display: "flex",
}} }}
> >
<Typography color={theme.palette.secondary.main}>У вас нет аккаунта?&nbsp;</Typography> <Typography color={theme.palette.secondary.main}>
У вас нет аккаунта?&nbsp;
</Typography>
<Link to="/signup" style={{ textDecoration: "none" }}> <Link to="/signup" style={{ textDecoration: "none" }}>
<Typography color={theme.palette.golden.main}>Зарегестрируйтесь</Typography> <Typography color={theme.palette.golden.main}>
Зарегестрируйтесь
</Typography>
</Link> </Link>
</Box> </Box>
</Box> </Box>

@ -9,7 +9,7 @@ import OutlinedInput from "@kitUI/outlinedInput";
import Logo from "@pages/Logo/index"; import Logo from "@pages/Logo/index";
import EmailOutlinedIcon from "@mui/icons-material/EmailOutlined"; import EmailOutlinedIcon from "@mui/icons-material/EmailOutlined";
import LockOutlinedIcon from "@mui/icons-material/LockOutlined"; import LockOutlinedIcon from "@mui/icons-material/LockOutlined";
import { makeRequest } from "@frontend/kitui"; import { register } from "@root/api/auth";
interface Values { interface Values {
email: string; email: string;
@ -50,31 +50,21 @@ const SignUp = () => {
repeatPassword: "", repeatPassword: "",
}} }}
validate={validate} validate={validate}
onSubmit={(values, formikHelpers) => { onSubmit={async (values, formikHelpers) => {
formikHelpers.setSubmitting(true); formikHelpers.setSubmitting(true);
makeRequest({
url: "https://admin.pena.digital/auth/register", const [_, registerError] = await register(
body: { values.email,
login: values.email, values.repeatPassword
email: values.email,
password: values.repeatPassword,
phoneNumber: "--",
},
useToken: false,
})
.then((e) => {
navigate("/users");
})
.catch((e) => {
console.log(e);
enqueueSnackbar(
e.response && e.response.data && e.response.data.message ? e.response.data.message : `Unknown error`,
{ variant: "error" } // Устанавливаем вариант уведомления на "error"
); );
})
.finally(() => {
formikHelpers.setSubmitting(false); formikHelpers.setSubmitting(false);
});
if (registerError) {
return enqueueSnackbar(registerError);
}
navigate("/users");
}} }}
> >
{(props) => ( {(props) => (
@ -118,7 +108,14 @@ const SignUp = () => {
Мы рады что вы выбрали нас! Мы рады что вы выбрали нас!
</Typography> </Typography>
</Box> </Box>
<Box sx={{ display: "flex", alignItems: "center", marginTop: "15px", "> *": { marginRight: "10px" } }}> <Box
sx={{
display: "flex",
alignItems: "center",
marginTop: "15px",
"> *": { marginRight: "10px" },
}}
>
<EmailOutlinedIcon htmlColor={theme.palette.golden.main} /> <EmailOutlinedIcon htmlColor={theme.palette.golden.main} />
<Field <Field
as={OutlinedInput} as={OutlinedInput}
@ -134,7 +131,14 @@ const SignUp = () => {
} }
/> />
</Box> </Box>
<Box sx={{ display: "flex", alignItems: "center", marginTop: "15px", "> *": { marginRight: "10px" } }}> <Box
sx={{
display: "flex",
alignItems: "center",
marginTop: "15px",
"> *": { marginRight: "10px" },
}}
>
<LockOutlinedIcon htmlColor={theme.palette.golden.main} /> <LockOutlinedIcon htmlColor={theme.palette.golden.main} />
<Field <Field
sx={{}} sx={{}}
@ -152,7 +156,14 @@ const SignUp = () => {
} }
/> />
</Box> </Box>
<Box sx={{ display: "flex", alignItems: "center", marginTop: "15px", "> *": { marginRight: "10px" } }}> <Box
sx={{
display: "flex",
alignItems: "center",
marginTop: "15px",
"> *": { marginRight: "10px" },
}}
>
<LockOutlinedIcon htmlColor={theme.palette.golden.main} /> <LockOutlinedIcon htmlColor={theme.palette.golden.main} />
<Field <Field
as={OutlinedInput} as={OutlinedInput}
@ -161,10 +172,14 @@ const SignUp = () => {
variant="filled" variant="filled"
label="Повторите пароль" label="Повторите пароль"
id="repeatPassword" id="repeatPassword"
error={props.touched.repeatPassword && !!props.errors.repeatPassword} error={
props.touched.repeatPassword &&
!!props.errors.repeatPassword
}
helperText={ helperText={
<Typography sx={{ fontSize: "12px", width: "200px" }}> <Typography sx={{ fontSize: "12px", width: "200px" }}>
{props.touched.repeatPassword && props.errors.repeatPassword} {props.touched.repeatPassword &&
props.errors.repeatPassword}
</Typography> </Typography>
} }
/> />
@ -182,7 +197,9 @@ const SignUp = () => {
Войти Войти
</Button> </Button>
<Link to="/signin" style={{ textDecoration: "none" }}> <Link to="/signin" style={{ textDecoration: "none" }}>
<Typography color={theme.palette.golden.main}>У меня уже есть аккаунт</Typography> <Typography color={theme.palette.golden.main}>
У меня уже есть аккаунт
</Typography>
</Link> </Link>
</Box> </Box>
</Box> </Box>

@ -2,18 +2,13 @@ import { useRef, useState } from "react";
import { enqueueSnackbar } from "notistack"; import { enqueueSnackbar } from "notistack";
import { Box, IconButton, TextField, Tooltip, Typography } from "@mui/material"; import { Box, IconButton, TextField, Tooltip, Typography } from "@mui/material";
import ModeEditOutlineOutlinedIcon from "@mui/icons-material/ModeEditOutlineOutlined"; import ModeEditOutlineOutlinedIcon from "@mui/icons-material/ModeEditOutlineOutlined";
import { PrivilegeWithAmount, makeRequest } from "@frontend/kitui"; import { PrivilegeWithAmount } from "@frontend/kitui";
import { putPrivilegie } from "@root/api/privilegies";
interface CardPrivilegie { interface CardPrivilegie {
privilege: PrivilegeWithAmount; privilege: PrivilegeWithAmount;
} }
const baseUrl =
process.env.NODE_ENV === "production"
? "/strator"
: "https://admin.pena.digital/strator";
export const СardPrivilegie = ({ privilege }: CardPrivilegie) => { export const СardPrivilegie = ({ privilege }: CardPrivilegie) => {
const [inputOpen, setInputOpen] = useState<boolean>(false); const [inputOpen, setInputOpen] = useState<boolean>(false);
const [inputValue, setInputValue] = useState<string>(""); const [inputValue, setInputValue] = useState<string>("");
@ -25,11 +20,8 @@ export const СardPrivilegie = ({ privilege }: CardPrivilegie) => {
mb: "за МБ", mb: "за МБ",
}; };
const PutPrivilegies = () => { const putPrivilegies = async () => {
makeRequest<Omit<PrivilegeWithAmount, "_id" | "updatedAt">>({ const [_, putedPrivilegieError] = await putPrivilegie({
url: baseUrl + "/privilege/",
method: "put",
body: {
name: privilege.name, name: privilege.name,
privilegeId: privilege.privilegeId, privilegeId: privilege.privilegeId,
serviceKey: privilege.serviceKey, serviceKey: privilege.serviceKey,
@ -38,21 +30,20 @@ export const СardPrivilegie = ({ privilege }: CardPrivilegie) => {
type: privilege.type, type: privilege.type,
value: privilege.value, value: privilege.value,
price: Number(inputValue), price: Number(inputValue),
}, });
})
.then(() => { if (putedPrivilegieError) {
return enqueueSnackbar(putedPrivilegieError);
}
priceRef.current.innerText = "price: " + inputValue; priceRef.current.innerText = "price: " + inputValue;
setInputValue(""); setInputValue("");
setInputOpen(false); setInputOpen(false);
})
.catch((error) => {
enqueueSnackbar(error.message);
});
}; };
const requestOnclickEnter = (event: any) => { const requestOnclickEnter = (event: any) => {
if (event.key === "Enter" && inputValue !== "") { if (event.key === "Enter" && inputValue !== "") {
PutPrivilegies(); putPrivilegies();
setInputOpen(false); setInputOpen(false);
} }
}; };
@ -94,7 +85,9 @@ export const СardPrivilegie = ({ privilege }: CardPrivilegie) => {
}} }}
placement="top" placement="top"
title={ title={
<Typography sx={{ fontSize: "16px" }}>{privilege.description}</Typography> <Typography sx={{ fontSize: "16px" }}>
{privilege.description}
</Typography>
} }
> >
<IconButton disableRipple> <IconButton disableRipple>
@ -157,7 +150,9 @@ export const СardPrivilegie = ({ privilege }: CardPrivilegie) => {
price: {privilege.price} price: {privilege.price}
</div> </div>
)} )}
<Typography sx={{ color: "white" }}>{translationType[privilege.type]}</Typography> <Typography sx={{ color: "white" }}>
{translationType[privilege.type]}
</Typography>
</Box> </Box>
</Box> </Box>
); );

@ -10,7 +10,8 @@ import {
TextField, TextField,
} from "@mui/material"; } from "@mui/material";
import { MOCK_DATA_USERS } from "@root/api/roles"; import { MOCK_DATA_USERS } from "@root/api/roles";
import { makeRequest } from "@frontend/kitui"; import { deleteRole } from "@root/api/roles";
import { enqueueSnackbar } from "notistack";
const ITEM_HEIGHT = 48; const ITEM_HEIGHT = 48;
const ITEM_PADDING_TOP = 8; const ITEM_PADDING_TOP = 8;
@ -22,9 +23,6 @@ const MenuProps = {
}, },
}; };
const baseUrl =
process.env.NODE_ENV === "production" ? "" : "https://admin.pena.digital";
export default function DeleteForm() { export default function DeleteForm() {
const [personName, setPersonName] = useState<string[]>([]); const [personName, setPersonName] = useState<string[]>([]);
const [roleId, setRoleId] = useState<string>(); const [roleId, setRoleId] = useState<string>();
@ -36,9 +34,14 @@ export default function DeleteForm() {
setPersonName(typeof value === "string" ? value.split(",") : value); setPersonName(typeof value === "string" ? value.split(",") : value);
}; };
const rolesDelete = (id = "") => { const rolesDelete = async (id = "") => {
makeRequest({ url: baseUrl + "/role/" + id, method: "delete" }); const [_, deletedRoleError] = await deleteRole(id);
if (deletedRoleError) {
return enqueueSnackbar(deletedRoleError);
}
}; };
return ( return (
<> <>
<Button <Button

@ -22,11 +22,14 @@ export default function DiscountDataGrid({ selectedRows }: Props) {
return enqueueSnackbar("Скидка не найдена"); return enqueueSnackbar("Скидка не найдена");
} }
try { const [_, changedDiscountError] = await changeDiscount(String(id), {
await changeDiscount(String(id), { ...discount, Deprecated: isActive }); ...discount,
Deprecated: isActive,
});
if (changedDiscountError) {
done += 1; done += 1;
} catch { } else {
fatal += 1; fatal += 1;
} }
} }

@ -1,25 +1,25 @@
import { useState } from "react"; import { useState } from "react";
import { Typography, Container, Button, Select, MenuItem, FormControl, InputLabel, useTheme, Box } from "@mui/material"; import {
Typography,
Container,
Button,
Select,
MenuItem,
FormControl,
InputLabel,
useTheme,
Box,
} from "@mui/material";
import { enqueueSnackbar } from "notistack"; import { enqueueSnackbar } from "notistack";
import { CustomTextField } from "@root/kitUI/CustomTextField"; import { CustomTextField } from "@root/kitUI/CustomTextField";
import { requestTariffs } from "@root/services/tariffs.service"; import { requestTariffs } from "@root/services/tariffs.service";
import { createTariff } from "@root/api/tariffs";
import { import {
findPrivilegeById, findPrivilegeById,
usePrivilegeStore, usePrivilegeStore,
} from "@root/stores/privilegesStore"; } from "@root/stores/privilegesStore";
import { PrivilegeWithAmount, makeRequest } from "@frontend/kitui";
type CreateTariffBackendRequest = {
name: string;
price: number;
isCustom: boolean;
privilegies: Omit<PrivilegeWithAmount, "_id" | "updatedAt">[];
};
const baseUrl = process.env.NODE_ENV === "production" ? "/strator" : "https://admin.pena.digital/strator";
export default function CreateTariff() { export default function CreateTariff() {
const theme = useTheme(); const theme = useTheme();
@ -53,12 +53,9 @@ export default function CreateTariff() {
return true; return true;
}; };
const createTariffBackend = () => { const createTariffBackend = async () => {
if (checkFulledFields() && privilege !== null) { if (checkFulledFields() && privilege !== null) {
makeRequest<CreateTariffBackendRequest>({ const [_, createdTariffError] = await createTariff({
url: baseUrl + "/tariff/",
method: "post",
body: {
name: nameField, name: nameField,
price: Number(customPriceField) * 100, price: Number(customPriceField) * 100,
isCustom: false, isCustom: false,
@ -74,14 +71,13 @@ export default function CreateTariff() {
amount: Number(amountField), amount: Number(amountField),
}, },
], ],
},
})
.then(() => {
requestTariffs();
})
.catch(() => {
enqueueSnackbar("что-то пошло не так");
}); });
if (createdTariffError) {
return enqueueSnackbar(createdTariffError);
}
requestTariffs();
} }
}; };
// const createTariffFrontend = () => { // const createTariffFrontend = () => {

@ -5,13 +5,33 @@ import Modal from "@mui/material/Modal";
import { closeDeleteTariffDialog, useTariffStore } from "@root/stores/tariffs"; import { closeDeleteTariffDialog, useTariffStore } from "@root/stores/tariffs";
import { requestTariffs } from "@root/services/tariffs.service"; import { requestTariffs } from "@root/services/tariffs.service";
import { enqueueSnackbar } from "notistack"; import { enqueueSnackbar } from "notistack";
import { deleteManyTariffs } from "@root/api/tariffs"; import { deleteTariff } from "@root/api/tariffs";
import { devlog } from "@frontend/kitui"; import { devlog } from "@frontend/kitui";
export default function DeleteModal() { export default function DeleteModal() {
const deleteTariffIds = useTariffStore(state => state.deleteTariffIds); const deleteTariffIds = useTariffStore(state => state.deleteTariffIds);
async function deleteManyTariffs(tariffIds: string[]) {
const results = await Promise.allSettled(
tariffIds.map((tariffId) => deleteTariff(tariffId))
);
let deletedCount = 0;
let errorCount = 0;
const errors: unknown[] = [];
results.forEach((result) => {
if (result.status === "fulfilled") deletedCount++;
else {
errorCount++;
errors.push(result.reason);
}
});
return { deletedCount, errorCount, errors };
}
async function handleTariffDeleteClick() { async function handleTariffDeleteClick() {
if (!deleteTariffIds?.length) return; if (!deleteTariffIds?.length) return;

@ -24,29 +24,16 @@ import ClearIcon from "@mui/icons-material/Clear";
import ConditionalRender from "@root/pages/Setting/ConditionalRender"; import ConditionalRender from "@root/pages/Setting/ConditionalRender";
import ModalUser from "@root/pages/dashboard/ModalUser"; import ModalUser from "@root/pages/dashboard/ModalUser";
import ServiceUsersDG from "./ServiceUsersDG"; import ServiceUsersDG from "./ServiceUsersDG";
import { getRegisteredUsers, getManagersList } from "@root/api/user";
import { getRoles } from "@root/api/privilegies";
import { getRoles_mock, TMockData } from "../../../api/roles"; import { getRoles_mock, TMockData } from "../../../api/roles";
import theme from "../../../theme"; import theme from "../../../theme";
import type { UserType } from "../../../api/roles"; import type { UserType } from "../../../api/roles";
import { makeRequest } from "@frontend/kitui";
type RegisteredUsersResponse = {
tatalPages: number;
users: UserType[];
};
const baseUrl =
process.env.NODE_ENV === "production" ? "" : "https://admin.pena.digital";
const Users: React.FC = () => { const Users: React.FC = () => {
// makeRequest({
// url: "https://admin.pena.digital/strator/account",
// method: "get",
// bearer: true,
// contentType: true,
// })
const radioboxes = ["admin", "manager", "user"]; const radioboxes = ["admin", "manager", "user"];
const [selectedValue, setSelectedValue] = React.useState("admin"); const [selectedValue, setSelectedValue] = React.useState("admin");
@ -109,47 +96,23 @@ const Users: React.FC = () => {
}, [userId]); }, [userId]);
useEffect(() => { useEffect(() => {
async function axiosRoles() { getManagersList().then(([managersListResponse]) => {
try { if (managersListResponse) {
const rolesResponse = await makeRequest<never, TMockData>({ setManager(managersListResponse.users);
method: "get", }
url: baseUrl + "/strator/role/",
}); });
getRegisteredUsers().then(([registeredUsersResponse]) => {
if (registeredUsersResponse) {
setUsers(registeredUsersResponse.users);
}
});
getRoles().then(([rolesResponse]) => {
if (rolesResponse) {
setRoles(rolesResponse); setRoles(rolesResponse);
} catch (error) {
console.error("Ошибка при получении ролей!");
} }
}
async function gettingRegisteredUsers() {
try {
const { users } = await makeRequest<never, RegisteredUsersResponse>({
method: "get",
url: baseUrl + "/user/",
}); });
setUsers(users);
} catch (error) {
console.error("Ошибка при получении пользователей!");
}
}
async function gettingListManagers() {
try {
const { users } = await makeRequest<never, RegisteredUsersResponse>({
method: "get",
url: baseUrl + "/user/",
});
setManager(users);
} catch (error) {
console.error("Ошибка при получении менеджеров!");
}
}
gettingListManagers();
gettingRegisteredUsers();
axiosRoles();
}, [selectedValue]); }, [selectedValue]);
const [selectedTariffs, setSelectedTariffs] = useState<GridSelectionModel>( const [selectedTariffs, setSelectedTariffs] = useState<GridSelectionModel>(

@ -3,10 +3,10 @@ import { Box, IconButton, Typography } from "@mui/material";
import theme from "../../../theme"; import theme from "../../../theme";
import ExitToAppOutlinedIcon from "@mui/icons-material/ExitToAppOutlined"; import ExitToAppOutlinedIcon from "@mui/icons-material/ExitToAppOutlined";
import Logo from "../../Logo"; import Logo from "../../Logo";
import { clearAuthToken, makeRequest } from "@frontend/kitui"; import { clearAuthToken } from "@frontend/kitui";
import { logout } from "@root/api/auth";
const Header: React.FC = () => { const Header: React.FC = () => {
return ( return (
<React.Fragment> <React.Fragment>
<Box <Box
@ -52,10 +52,7 @@ const Header: React.FC = () => {
<IconButton <IconButton
onClick={() => { onClick={() => {
makeRequest({ logout().then(clearAuthToken);
url: "https://admin.pena.digital/auth/logout",
contentType: true,
}).then(() => clearAuthToken());
}} }}
sx={{ sx={{
display: "flex", display: "flex",

@ -1,37 +1,15 @@
import { useState, useEffect } from "react"; import { useState, useEffect } from "react";
import { Box, Typography, TextField, Button } from "@mui/material"; import { Box, Typography, TextField, Button } from "@mui/material";
import { verification, patchVerification } from "@root/api/verification";
import { enqueueSnackbar } from "notistack";
import type { ChangeEvent } from "react"; import type { ChangeEvent } from "react";
import { makeRequest } from "@frontend/kitui"; import type { Verification } from "@root/api/verification";
type File = {
name: "inn" | "rule" | "egrule" | "certificate";
url: string;
};
type Verification = {
_id: string;
accepted: boolean;
status: "org" | "nko";
updated_at: string;
comment: string;
files: File[];
};
type PatchVerificationBody = {
id: string;
status: "org" | "nko";
comment: string;
accepted: boolean;
};
type VerificationTabProps = { type VerificationTabProps = {
userId: string; userId: string;
}; };
const baseUrl =
process.env.NODE_ENV === "production" ? "" : "https://hub.pena.digital";
export const VerificationTab = ({ userId }: VerificationTabProps) => { export const VerificationTab = ({ userId }: VerificationTabProps) => {
const [isLoading, setIsLoading] = useState<boolean>(true); const [isLoading, setIsLoading] = useState<boolean>(true);
const [user, setUser] = useState<Verification | null>(null); const [user, setUser] = useState<Verification | null>(null);
@ -39,17 +17,20 @@ export const VerificationTab = ({ userId }: VerificationTabProps) => {
const requestVefification = async () => { const requestVefification = async () => {
setIsLoading(true); setIsLoading(true);
try {
const verification = await makeRequest<never, Verification>({ const [verificationResponse, verificationError] = await verification(
method: "get", userId
url: baseUrl + `/verification/verification/${userId}`, );
});
setUser(verification);
setComment(verification.comment);
} catch (error) {
console.error("Error fetching verification:", error);
} finally {
setIsLoading(false); setIsLoading(false);
if (verificationError) {
return console.error("Error verifying:", verificationError);
}
if (verificationResponse) {
setUser(verificationResponse);
setComment(verificationResponse.comment);
} }
}; };
@ -62,23 +43,18 @@ export const VerificationTab = ({ userId }: VerificationTabProps) => {
return; return;
} }
try { const [_, patchVerificationError] = await patchVerification({
await makeRequest<PatchVerificationBody, never>({
method: "patch",
useToken: true,
url: baseUrl + `/verification/verification`,
body: {
accepted, accepted,
comment, comment,
id: user._id, id: user._id,
status: user.status, status: user.status,
},
}); });
await requestVefification(); if (patchVerificationError) {
} catch (error) { return console.error("Error verifying:", patchVerificationError);
console.error("Error verifying:", error);
} }
await requestVefification();
}; };
return ( return (
@ -93,7 +69,11 @@ export const VerificationTab = ({ userId }: VerificationTabProps) => {
{user?.accepted ? "Верификация пройдена" : "Не верифицирован"} {user?.accepted ? "Верификация пройдена" : "Не верифицирован"}
</Typography> </Typography>
{isLoading ? ( {isLoading ? (
<Typography sx={{ fontWeight: "bold", fontSize: "18px", marginBottom: "25px" }}>Загрузка данных...</Typography> <Typography
sx={{ fontWeight: "bold", fontSize: "18px", marginBottom: "25px" }}
>
Загрузка данных...
</Typography>
) : user && user.files.length > 0 ? ( ) : user && user.files.length > 0 ? (
user.files.map(({ name, url }, index) => ( user.files.map(({ name, url }, index) => (
<Box sx={{ marginBottom: "25px" }} key={name + url}> <Box sx={{ marginBottom: "25px" }} key={name + url}>
@ -122,13 +102,18 @@ export const VerificationTab = ({ userId }: VerificationTabProps) => {
</Box> </Box>
)) ))
) : ( ) : (
<Typography sx={{ fontWeight: "bold", fontSize: "18px", marginBottom: "25px" }}> <Typography
sx={{ fontWeight: "bold", fontSize: "18px", marginBottom: "25px" }}
>
Пользователь не загружал данные Пользователь не загружал данные
</Typography> </Typography>
)} )}
{user?.comment && ( {user?.comment && (
<Box sx={{ marginBottom: "15px" }}> <Box sx={{ marginBottom: "15px" }}>
<Typography component="span" sx={{ fontWeight: "bold", marginBottom: "10px" }}> <Typography
component="span"
sx={{ fontWeight: "bold", marginBottom: "10px" }}
>
Комментарий: Комментарий:
</Typography> </Typography>
<Typography component="span"> {user.comment}</Typography> <Typography component="span"> {user.comment}</Typography>
@ -145,13 +130,23 @@ export const VerificationTab = ({ userId }: VerificationTabProps) => {
maxWidth: "500px", maxWidth: "500px",
marginBottom: "10px", marginBottom: "10px",
}} }}
onChange={(event: ChangeEvent<HTMLTextAreaElement>) => setComment(event.target.value)} onChange={(event: ChangeEvent<HTMLTextAreaElement>) =>
setComment(event.target.value)
}
/> />
<Box sx={{ display: "flex", columnGap: "10px" }}> <Box sx={{ display: "flex", columnGap: "10px" }}>
<Button variant="text" sx={{ background: "#9A9AAF" }} onClick={() => verify(false)}> <Button
variant="text"
sx={{ background: "#9A9AAF" }}
onClick={() => verify(false)}
>
Отклонить Отклонить
</Button> </Button>
<Button variant="text" sx={{ background: "#9A9AAF" }} onClick={() => verify(true)}> <Button
variant="text"
sx={{ background: "#9A9AAF" }}
onClick={() => verify(true)}
>
Подтвердить Подтвердить
</Button> </Button>
</Box> </Box>

@ -1,12 +1,7 @@
import { setDiscounts } from "@root/stores/discounts"; import { setDiscounts } from "@root/stores/discounts";
import type { GetDiscountResponse } from "@root/model/discount"; import { requestDiscounts as requestDiscountsRequest } from "@root/api/discounts";
import { Discount, makeRequest } from "@frontend/kitui"; import type { Discount } from "@frontend/kitui";
const baseUrl =
process.env.NODE_ENV === "production"
? "/price"
: "https://admin.pena.digital/price";
const filterDiscounts = (discounts: Discount[]) => { const filterDiscounts = (discounts: Discount[]) => {
const activeDiscounts = discounts.filter((discount) => !discount.Deprecated); const activeDiscounts = discounts.filter((discount) => !discount.Deprecated);
@ -15,17 +10,19 @@ const filterDiscounts = (discounts: Discount[]) => {
}; };
export const requestDiscounts = async (): Promise<Discount[]> => { export const requestDiscounts = async (): Promise<Discount[]> => {
try { const [discounts, discountsError] = await requestDiscountsRequest();
const { Discounts } = await makeRequest<never, GetDiscountResponse>({
url: baseUrl + "/discounts",
method: "get",
useToken: true,
});
filterDiscounts(Discounts); if (discountsError) {
console.error(discountsError);
return Discounts return [];
} catch {
throw new Error("Ошибка при получении скидок");
} }
if (discounts) {
filterDiscounts(discounts.Discounts);
return discounts.Discounts;
}
return [];
}; };

@ -1,16 +1,8 @@
import { resetPrivilegeArray } from "@root/stores/privilegesStore"; import { resetPrivilegeArray } from "@root/stores/privilegesStore";
import { exampleCartValues } from "@stores/mocks/exampleCartValues"; import { exampleCartValues } from "@stores/mocks/exampleCartValues";
import { requestServicePrivilegies } from "@root/api/privilegies";
import { PrivilegeWithAmount, makeRequest } from "@frontend/kitui"; import type { PrivilegeWithAmount } from "@frontend/kitui";
type SeverPrivilegiesResponse = {
templategen: PrivilegeWithAmount[];
};
const baseUrl =
process.env.NODE_ENV === "production"
? "/strator"
: "https://admin.pena.digital/strator";
const mutatePrivilegies = (privilegies: PrivilegeWithAmount[]) => { const mutatePrivilegies = (privilegies: PrivilegeWithAmount[]) => {
let extracted: PrivilegeWithAmount[] = []; let extracted: PrivilegeWithAmount[] = [];
@ -34,12 +26,14 @@ const mutatePrivilegies = (privilegies: PrivilegeWithAmount[]) => {
}; };
export const requestPrivilegies = async () => { export const requestPrivilegies = async () => {
await makeRequest<never, SeverPrivilegiesResponse>({ const [privilegiesResponse, privilegiesError] =
url: baseUrl + "/privilege/service", await requestServicePrivilegies();
method: "get",
}) if (privilegiesError) {
.then(({ templategen }) => mutatePrivilegies(templategen)) return console.error(privilegiesError);
.catch(() => { }
console.log("Ошибка при получении привилегий");
}); if (privilegiesResponse) {
mutatePrivilegies(privilegiesResponse.templategen);
}
}; };

@ -1,20 +1,10 @@
import { Tariff, makeRequest } from "@frontend/kitui";
import { updateTariffs } from "@root/stores/tariffs"; import { updateTariffs } from "@root/stores/tariffs";
import { requestTariffs as requestTariffsRequest } from "@root/api/tariffs";
import type { Tariff } from "@frontend/kitui";
type GetTariffsResponse = {
totalPages: number;
tariffs: Tariff[];
};
const baseUrl =
process.env.NODE_ENV === "production"
? "/strator"
: "https://admin.pena.digital/strator";
const mutateTariffs = (tariffs: Tariff[]) => { const mutateTariffs = (tariffs: Tariff[]) => {
const nonDeletedTariffs = tariffs const nonDeletedTariffs = tariffs.filter(({ isDeleted }) => !isDeleted);
.filter(({ isDeleted }) => !isDeleted);
updateTariffs(nonDeletedTariffs); updateTariffs(nonDeletedTariffs);
}; };
@ -23,21 +13,24 @@ export const requestTariffs = async (
page: number = 1, page: number = 1,
existingTariffs: Tariff[] = [] existingTariffs: Tariff[] = []
): Promise<void> => { ): Promise<void> => {
try { const [tariffsResponse, tariffsResponseError] = await requestTariffsRequest(
const { tariffs, totalPages } = await makeRequest< page
never, );
GetTariffsResponse
>({
url: baseUrl + `/tariff/?page=${page}&limit=${100}`,
method: "get",
});
if (page < totalPages) { if (tariffsResponseError) {
return requestTariffs(page + 1, [...existingTariffs, ...tariffs]); console.error(tariffsResponseError);
return;
} }
mutateTariffs([...existingTariffs, ...tariffs]); if (tariffsResponse) {
} catch { if (page < tariffsResponse.totalPages) {
throw new Error("Ошибка при получении тарифов"); return requestTariffs(page + 1, [
...existingTariffs,
...tariffsResponse.tariffs,
]);
}
mutateTariffs([...existingTariffs, ...tariffsResponse.tariffs]);
} }
}; };

@ -1,24 +1,28 @@
import { PrivilegeWithAmount, makeRequest } from "@frontend/kitui";
import { useEffect } from "react"; import { useEffect } from "react";
import { requestPrivilegies } from "@root/api/privilegies";
export default function usePrivileges({ onError, onNewPrivileges }: { import type { PrivilegeWithAmount } from "@frontend/kitui";
export default function usePrivileges({
onError,
onNewPrivileges,
}: {
onNewPrivileges: (response: PrivilegeWithAmount[]) => void; onNewPrivileges: (response: PrivilegeWithAmount[]) => void;
onError?: (error: any) => void; onError?: (error: any) => void;
}) { }) {
useEffect(() => { useEffect(() => {
const controller = new AbortController(); const controller = new AbortController();
makeRequest<never, PrivilegeWithAmount[]>({ requestPrivilegies(controller.signal).then(
url: "https://admin.pena.digital/strator/privilege", ([privilegiesResponse, privilegiesError]) => {
method: "get", if (privilegiesError) {
useToken: true, return onError?.(privilegiesError);
signal: controller.signal, }
}).then(result => {
onNewPrivileges(result); onNewPrivileges(privilegiesResponse);
}).catch(error => { }
onError?.(error); );
});
return () => controller.abort(); return () => controller.abort();
}, [onError, onNewPrivileges]); }, [onError, onNewPrivileges]);