Merge branch 'dev' into 'main'

Users: replacing table with dataGrid &&

See merge request frontend/admin!12
This commit is contained in:
Mikhail 2023-05-16 16:57:44 +00:00
commit 28fdd70cab
15 changed files with 716 additions and 597 deletions

@ -1,4 +1,3 @@
import makeRequest from "@root/kitUI/makeRequest";
import {
GetMessagesRequest,
GetMessagesResponse,
@ -9,10 +8,11 @@ import {
import { authStore } from "@root/stores/auth";
import ReconnectingEventSource from "reconnecting-eventsource";
// const { makeRequest } = authStore();
const supportApiUrl = "https://admin.pena.digital/heruvym";
const makeRequest = authStore.getState().makeRequest;
export function subscribeToAllTickets({
onMessage,
onError,
@ -58,15 +58,12 @@ export async function getTickets({
body: GetTicketsRequest;
signal: AbortSignal;
}): Promise<GetTicketsResponse> {
return makeRequest({
return makeRequest<GetTicketsRequest, GetTicketsResponse>({
url: `${supportApiUrl}/getTickets`,
method: "POST",
useToken: true,
body,
signal,
}).then((response) => {
const result = (response as any).data as GetTicketsResponse;
return result;
});
}
@ -77,19 +74,16 @@ export async function getTicketMessages({
body: GetMessagesRequest;
signal: AbortSignal;
}): Promise<GetMessagesResponse> {
return makeRequest({
return makeRequest<GetMessagesRequest, GetMessagesResponse>({
url: `${supportApiUrl}/getMessages`,
method: "POST",
useToken: true,
body,
signal,
}).then((response) => {
const result = (response as any).data as GetMessagesResponse;
return result;
});
}
export async function sendTicketMessage({ body }: { body: SendTicketMessageRequest }) {
export async function sendTicketMessage({ body }: { body: SendTicketMessageRequest; }) {
return makeRequest({
url: `${supportApiUrl}/send`,
method: "POST",

@ -0,0 +1,52 @@
import { useEffect, useState } from "react";
import axios from "axios";
export type Privilege = {
createdAt: string;
description: string;
isDeleted: boolean;
name: string;
price: string;
privilegeId: string;
serviceKey: string;
type: string;
updatedAt: string;
value: string;
_id: string;
};
type UsePrivilegies = {
privilegies: Record<"Шаблонизатор", Privilege[]> | undefined;
isError: boolean;
isLoading: boolean;
errorMessage: string;
};
export const usePrivilegies = (): UsePrivilegies => {
const [privilegies, setPrivilegies] = useState<Record<string, Privilege[]>>();
const [isLoading, setIsLoading] = useState(false);
const [isError, setIsError] = useState(false);
const [errorMessage, setErrorMessage] = useState("");
useEffect(() => {
const getPrivilegies = async () => {
const { data } = await axios<Record<string, Privilege[]>>({
method: "get",
url: "https://admin.pena.digital/strator/privilege/service",
});
return data;
};
setIsLoading(true);
getPrivilegies()
.then(setPrivilegies)
.catch(() => {
setIsError(true);
setErrorMessage("Ошибка при получении привилегий");
})
.finally(() => setIsLoading(false));
}, []);
return { privilegies, isError, isLoading, errorMessage };
};

19
src/kitUI/Article.tsx Normal file

@ -0,0 +1,19 @@
import React from "react";
import { Box, Typography } from "@mui/material";
type ArticleProps = {
header: JSX.Element;
body: JSX.Element;
isBoby?: boolean;
};
export const Article = ({ header, body, isBoby = false }: ArticleProps) => {
return (
<Box component="section">
<Box>
<Typography variant="h1">{header}</Typography>
</Box>
{isBoby ? <Box>{body}</Box> : <React.Fragment />}
</Box>
);
};

@ -1,58 +0,0 @@
import axios from "axios";
interface MakeRequest {
method?: string;
url: string;
body?: unknown;
useToken?: boolean;
contentType?: boolean;
signal?: AbortSignal;
}
export default (props: MakeRequest) => {
return new Promise(async (resolve, reject) => {
await makeRequest(props)
.then((r) => resolve(r))
.catch((r) => reject(r));
});
};
function makeRequest({ method = "post", url, body, useToken = true, signal, contentType = false }: MakeRequest) {
//В случае 401 рефреш должен попробовать вызваться 1 раз
let counterRefresh = true;
let headers: any = {};
if (useToken) headers["Authorization"] = localStorage.getItem("AT");
if (contentType) headers["Content-Type"] = "application/json";
return axios({
url: url,
method: method,
headers: headers,
data: body,
signal,
})
.then((response) => {
if (response.data && response.data.accessToken) {
localStorage.setItem("AT", response.data.accessToken);
}
return response;
})
.catch((error) => {
if (error.response.status == 401 && counterRefresh) {
refresh().then((response) => {
if (response.data && response.data.accessToken) localStorage.setItem("AT", response.data.accessToken);
counterRefresh = false;
});
} else {
throw error;
}
throw error;
});
}
function refresh() {
return axios("https://admin.pena.digital/auth/refresh", {
headers: {
Authorization: localStorage.getItem("AT"),
"Content-Type": "application/json",
},
});
}

@ -1,28 +1,21 @@
export const SERVICE_LIST = [
{
serviceKey: "templategen",
displayName: "Шаблонизатор документов"
displayName: "Шаблонизатор документов",
},
{
serviceKey: "squiz",
displayName: "Опросник"
displayName: "Опросник",
},
{
serviceKey: "dwarfener",
displayName: "Сокращатель ссылок"
}
displayName: "Сокращатель ссылок",
},
] as const;
export type ServiceType = typeof SERVICE_LIST[number]["serviceKey"];
export type ServiceType = (typeof SERVICE_LIST)[number]["serviceKey"];
export type PrivilegeType =
| "unlim"
| "gencount"
| "activequiz"
| "abcount"
| "extended";
export type PrivilegeType = "unlim" | "gencount" | "activequiz" | "abcount" | "extended";
export interface Privilege {
serviceKey: ServiceType;

@ -0,0 +1,117 @@
import ModeEditOutlineOutlinedIcon from "@mui/icons-material/ModeEditOutlineOutlined";
import { Box, IconButton, TextField, Tooltip, Typography } from "@mui/material";
import axios from "axios";
import { useState } from "react";
interface CardPrivilegie {
name: string;
type: string;
price: string;
description: string;
}
export const СardPrivilegie = ({ name, type, price, description }: CardPrivilegie) => {
const [inputOpen, setInputOpen] = useState<boolean>(false);
const [inputValue, setInputValue] = useState<string>("");
const PutPrivilegies = () => {
axios({
method: "put",
url: "https://admin.pena.digital/strator/privilege/service",
data: {
price: inputValue,
},
});
};
const requestOnclickEnter = (event: any) => {
if (event.key === "Enter" && inputValue !== "") {
PutPrivilegies();
setInputValue("");
setInputOpen(false);
}
};
const onCloseInput = (event: any) => {
if (event.key === "Escape") {
setInputOpen(false);
}
};
return (
<Box
key={type}
sx={{
px: "20px",
py: "25px",
backgroundColor: "#F1F2F6",
display: "flex",
alignItems: "center",
}}
>
<Box sx={{ display: "flex" }}>
<Box sx={{ width: "200px", borderRight: "1px solid black" }}>
<Typography
variant="h6"
sx={{
color: "#fe9903",
whiteSpace: "nowrap",
}}
>
{name}
</Typography>
<Tooltip placement="top" title={description}>
<IconButton>
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M9.25 9.25H10V14.5H10.75"
stroke="#7E2AEA"
stroke-width="1.5"
stroke-linecap="round"
stroke-linejoin="round"
/>
<path
d="M9.8125 7C10.4338 7 10.9375 6.49632 10.9375 5.875C10.9375 5.25368 10.4338 4.75 9.8125 4.75C9.19118 4.75 8.6875 5.25368 8.6875 5.875C8.6875 6.49632 9.19118 7 9.8125 7Z"
fill="#7E2AEA"
/>
</svg>
</IconButton>
</Tooltip>
<IconButton onClick={() => setInputOpen(!inputOpen)}>
<ModeEditOutlineOutlinedIcon />
</IconButton>
</Box>
</Box>
<Box sx={{ width: "600px", display: "flex", justifyContent: "space-around" }}>
{inputOpen ? (
<TextField
onKeyDown={onCloseInput}
onKeyPress={requestOnclickEnter}
placeholder="введите число"
fullWidth
onChange={(event) => setInputValue(event.target.value)}
sx={{
alignItems: "center",
width: "400px",
"& .MuiInputBase-root": {
backgroundColor: "#F2F3F7",
height: "48px",
},
}}
inputProps={{
sx: {
borderRadius: "10px",
fontSize: "18px",
lineHeight: "21px",
py: 0,
},
}}
/>
) : (
<Typography sx={{ color: "black", mr: "5px" }}>price: {price}</Typography>
)}
<Typography sx={{ color: "black" }}>{type}</Typography>
</Box>
</Box>
);
};

@ -0,0 +1,139 @@
import { useState } from "react";
import { Box, SxProps, Theme, Typography, useMediaQuery, useTheme } from "@mui/material";
import { СardPrivilegie } from "./CardPrivilegie";
import { usePrivilegies } from "@root/hooks/privilege.hook";
interface CustomWrapperProps {
text: string;
sx?: SxProps<Theme>;
result?: boolean;
}
export const PrivilegiesWrapper = ({ text, sx, result }: CustomWrapperProps) => {
const theme = useTheme();
const upMd = useMediaQuery(theme.breakpoints.up("md"));
const upSm = useMediaQuery(theme.breakpoints.up("sm"));
const [isExpanded, setIsExpanded] = useState<boolean>(false);
const { privilegies, isError, isLoading, errorMessage } = usePrivilegies();
return (
<Box
sx={{
width: "100%",
overflow: "hidden",
borderRadius: "12px",
boxShadow: `0px 100px 309px rgba(210, 208, 225, 0.24),
0px 41.7776px 129.093px rgba(210, 208, 225, 0.172525),
0px 22.3363px 69.0192px rgba(210, 208, 225, 0.143066),
0px 12.5216px 38.6916px rgba(210, 208, 225, 0.12),
0px 6.6501px 20.5488px rgba(210, 208, 225, 0.0969343),
0px 2.76726px 8.55082px rgba(210, 208, 225, 0.067
4749)`,
...sx,
}}
>
<Box
sx={{
border: "1px solid white",
"&:first-of-type": {
borderTopLeftRadius: "12px ",
borderTopRightRadius: "12px",
},
"&:last-of-type": {
borderBottomLeftRadius: "12px",
borderBottomRightRadius: "12px",
},
"&:not(:last-of-type)": {
borderBottom: `1px solid gray`,
},
}}
>
<Box
onClick={() => setIsExpanded((prev) => !prev)}
sx={{
height: "88px",
px: "20px",
display: "flex",
alignItems: "center",
justifyContent: "space-between",
cursor: "pointer",
userSelect: "none",
}}
>
<Typography
sx={{
width: "100%",
display: "flex",
justifyContent: "center",
fontSize: "18px",
lineHeight: upMd ? undefined : "19px",
fontWeight: 400,
color: "#FFFFFF",
px: 0,
}}
>
{text}
</Typography>
<Box
sx={{
display: "flex",
height: "100%",
alignItems: "center",
}}
>
{result ? (
<>
<svg width="30" height="31" viewBox="0 0 30 31" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect y="0.8125" width="30" height="30" rx="6" fill="#252734" />
<path
d="M7.5 19.5625L15 12.0625L22.5 19.5625"
stroke="#7E2AEA"
stroke-width="1.5"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
<Box
sx={{
borderLeft: upSm ? "1px solid #9A9AAF" : "none",
pl: upSm ? "2px" : 0,
height: "50%",
display: "flex",
justifyContent: "center",
alignItems: "center",
}}
/>
</>
) : (
<svg width="30" height="31" viewBox="0 0 30 31" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect y="0.8125" width="30" height="30" rx="6" fill="#252734" />
<path
d="M7.5 19.5625L15 12.0625L22.5 19.5625"
stroke="#fe9903"
stroke-width="1.5"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
)}
</Box>
</Box>
{isExpanded &&
(isError ? (
<Typography>errorMessage</Typography>
) : (
privilegies?.Шаблонизатор.map(({ name, type, price, description }) => (
<СardPrivilegie key={type} name={name} type={type} price={price} description={description} />
))
))}
</Box>
</Box>
);
};

@ -2,10 +2,11 @@ import { AccordionDetails, Table, TableBody, TableCell, TableHead, TableRow, Typ
import FormDeleteRoles from "./FormDeleteRoles";
import FormCreateRoles from "./FormCreateRoles";
import { PrivilegiesWrapper } from "./PrivilegiesWrapper";
import theme from "../../theme";
export const SettingRoles = () => {
export const SettingRoles = (): JSX.Element => {
return (
<AccordionDetails>
<Table
@ -99,6 +100,7 @@ export const SettingRoles = () => {
</TableRow>
</TableBody>
</Table>
<PrivilegiesWrapper text="Привелегии" sx={{ mt: "50px" }} />
</AccordionDetails>
);
};

@ -0,0 +1,45 @@
import { GridColDef, GridSelectionModel, GridToolbar } from "@mui/x-data-grid";
import { Skeleton } from "@mui/material";
import DataGrid from "@kitUI/datagrid";
import type { UsersType } from "@root/api/roles";
const columns: GridColDef[] = [
{ field: "login", headerName: "Логин", width: 100 },
{ field: "email", headerName: "E-mail", width: 200 },
{ field: "phoneNumber", headerName: "Номер телефона", width: 200 },
{ field: "isDeleted", headerName: "Удалено", width: 100 },
{ field: "createdAt", headerName: "Дата создания", width: 200 },
];
interface Props {
handleSelectionChange: (selectionModel: GridSelectionModel) => void;
users: UsersType | undefined;
}
export default function ServiceUsersDG({ handleSelectionChange, users }: Props) {
if (!users) {
return <Skeleton>Loading...</Skeleton>;
}
const gridData = users.map((user) => ({
login: user.login,
email: user.email,
phoneNumber: user.phoneNumber,
isDeleted: `${user.isDeleted ? "true" : "false"}`,
createdAt: user.createdAt,
}));
return (
<DataGrid
sx={{ maxWidth: "90%", mt: "30px" }}
getRowId={(users: any) => users.login}
checkboxSelection={true}
rows={gridData}
columns={columns}
components={{ Toolbar: GridToolbar }}
onSelectionModelChange={handleSelectionChange}
/>
);
}

@ -10,11 +10,11 @@ import { getTicketMessages, sendTicketMessage, subscribeToTicketMessages } from
import { enqueueSnackbar } from "notistack";
import { useTicketStore } from "@root/stores/tickets";
import { throttle } from "@root/utils/throttle";
import { authStore } from "@root/stores/auth";
export default function Chat() {
const { token } = authStore();
const token = authStore(state => state.token);
const theme = useTheme();
const upMd = useMediaQuery(theme.breakpoints.up("md"));
const tickets = useTicketStore(state => state.tickets);
@ -30,12 +30,7 @@ export default function Chat() {
const ticket = tickets.find(ticket => ticket.id === ticketId);
useEffect(function scrollOnNewMessage() {
scrollToBottom();
}, [messages]);
useEffect(
function fetchTicketMessages() {
useEffect(function fetchTicketMessages() {
if (!ticketId) return;
const getTicketsBody: GetMessagesRequest = {
@ -52,6 +47,7 @@ export default function Chat() {
}).then(result => {
console.log("GetMessagesResponse", result);
if (result?.length > 0) {
if (chatBoxRef.current && chatBoxRef.current.scrollTop < 1) chatBoxRef.current.scrollTop = 1;
addOrUpdateMessages(result);
setMessageFetchState("idle");
} else setMessageFetchState("all fetched");
@ -62,14 +58,11 @@ export default function Chat() {
return () => {
controller.abort();
clearMessageState();
};
}, [messageApiPage, messagesPerPage, ticketId]);
useEffect(function subscribeToMessages() {
if (!ticketId) return;
if (!token) return;
if (!ticketId || !token) return;
const unsubscribe = subscribeToTicketMessages({
ticketId,
@ -94,7 +87,7 @@ export default function Chat() {
clearMessageState();
setIsPreventAutoscroll(false);
};
}, [ticketId]);
}, [ticketId, token]);
useEffect(function attachScrollHandler() {
if (!chatBoxRef.current) return;
@ -108,7 +101,6 @@ export default function Chat() {
if (messagesFetchStateRef.current !== "idle") return;
if (chatBox.scrollTop < chatBox.clientHeight) {
if (chatBox.scrollTop < 1) chatBox.scrollTop = 1;
incrementMessageApiPage();
}
};
@ -159,7 +151,7 @@ export default function Chat() {
setMessageField("");
}
function handleAddAttachment() {}
function handleAddAttachment() { }
function handleTextfieldKeyPress(e: KeyboardEvent) {
if (e.key === "Enter" && !e.shiftKey) {
@ -168,8 +160,6 @@ export default function Chat() {
}
}
const sortedMessages = messages.sort(sortMessagesByTime);
return (
<Box sx={{
border: "1px solid",
@ -184,9 +174,7 @@ export default function Chat() {
alignItems: "center",
gap: "8px",
}}>
{ticket ?
<>
<Typography>{ticket.title}</Typography>
<Typography>{ticket ? ticket.title : "Выберите тикет"}</Typography>
<Box
ref={chatBoxRef}
sx={{
@ -201,10 +189,11 @@ export default function Chat() {
colorScheme: "dark",
}}
>
{sortedMessages.map(message =>
{ticket && messages.map(message =>
<Message key={message.id} message={message} isSelf={ticket.user !== message.user_id} />
)}
</Box>
{ticket &&
<TextField
value={messageField}
onChange={e => setMessageField(e.target.value)}
@ -250,15 +239,7 @@ export default function Chat() {
}
}}
/>
</>
:
<Typography>Выберите тикет</Typography>}
}
</Box>
);
}
function sortMessagesByTime(message1: TicketMessage, message2: TicketMessage) {
const date1 = new Date(message1.created_at).getTime();
const date2 = new Date(message2.created_at).getTime();
return date1 - date2;
}

@ -7,7 +7,7 @@ import { getTickets, subscribeToAllTickets } from "@root/api/tickets";
import { GetTicketsRequest, Ticket } from "@root/model/ticket";
import { clearTickets, setTicketsFetchState, updateTickets, useTicketStore } from "@root/stores/tickets";
import { enqueueSnackbar } from "notistack";
import {clearMessageState } from "@root/stores/messages";
import { clearMessageState } from "@root/stores/messages";
import { authStore } from "@root/stores/auth";
@ -16,7 +16,7 @@ export default function Support() {
const upMd = useMediaQuery(theme.breakpoints.up("md"));
const ticketsPerPage = useTicketStore(state => state.ticketsPerPage);
const ticketApiPage = useTicketStore(state => state.apiPage);
const { token } = authStore();
const token = authStore(state => state.token);
useEffect(function fetchTickets() {
const getTicketsBody: GetTicketsRequest = {
@ -69,7 +69,7 @@ export default function Support() {
clearMessageState();
clearTickets();
};
}, []);
}, [token]);
return (
<Box sx={{

@ -1,28 +1,33 @@
import Cart from "@root/kitUI/Cart/Cart";
import { useState } from "react";
import { Container, Typography } from "@mui/material";
import { GridSelectionModel } from "@mui/x-data-grid";
import Cart from "@root/kitUI/Cart/Cart";
import PrivilegesDG from "./privilegesDG";
import TariffsDG from "./tariffsDG";
import CreateTariff from "./CreateTariff";
import { GridSelectionModel } from "@mui/x-data-grid";
import { useState } from "react";
export default function Tariffs() {
const [selectedTariffs, setSelectedTariffs] = useState<GridSelectionModel>([]);
return (
<Container sx={{
<Container
sx={{
width: "90%",
display: "flex",
flexDirection: "column",
justifyContent: "center",
alignItems: "center",
}}>
}}
>
<Typography variant="h6">Список привелегий</Typography>
<PrivilegesDG />
<CreateTariff />
<Typography variant="h6" mt="20px">Список тарифов</Typography>
<TariffsDG handleSelectionChange={selectionModel => setSelectedTariffs(selectionModel)} />
<Typography variant="h6" mt="20px">
Список тарифов
</Typography>
<TariffsDG handleSelectionChange={(selectionModel) => setSelectedTariffs(selectionModel)} />
<Cart selectedTariffs={selectedTariffs} />
</Container>
);

@ -1,20 +1,21 @@
import * as React from "react";
import { GridColDef, GridSelectionModel, GridToolbar } from "@mui/x-data-grid";
import DataGrid from "@kitUI/datagrid";
import { useTariffStore } from "@root/stores/tariffs";
import { SERVICE_LIST } from "@root/model/tariff";
const columns: GridColDef[] = [
{ field: 'id', headerName: 'ID', width: 100 },
{ field: 'name', headerName: 'Название тарифа', width: 150 },
{ field: 'serviceName', headerName: 'Сервис', width: 150 },//инфо из гитлаба.
{ field: 'privilege', headerName: 'Привелегия', width: 150 },
{ field: 'amount', headerName: 'Количество', width: 110 },
{ field: 'type', headerName: 'Единица', width: 100 },
{ field: 'pricePerUnit', headerName: 'Цена за ед.', width: 100 },
{ field: 'isCustomPrice', headerName: 'Кастомная цена', width: 130 },
{ field: 'total', headerName: 'Сумма', width: 130 },
{ field: "id", headerName: "ID", width: 100 },
{ field: "name", headerName: "Название тарифа", width: 150 },
{ field: "serviceName", headerName: "Сервис", width: 150 }, //инфо из гитлаба.
{ field: "privilege", headerName: "Привелегия", width: 150 },
{ field: "amount", headerName: "Количество", width: 110 },
{ field: "type", headerName: "Единица", width: 100 },
{ field: "pricePerUnit", headerName: "Цена за ед.", width: 100 },
{ field: "isCustomPrice", headerName: "Кастомная цена", width: 130 },
{ field: "total", headerName: "Сумма", width: 130 },
];
interface Props {
@ -22,12 +23,12 @@ interface Props {
}
export default function TariffsDG({ handleSelectionChange }: Props) {
const tariffs = useTariffStore(state => state.tariffs);
const tariffs = useTariffStore((state) => state.tariffs);
const gridData = tariffs.map(tariff => ({
const gridData = tariffs.map((tariff) => ({
id: tariff.id,
name: tariff.name,
serviceName: SERVICE_LIST.find(service => service.serviceKey === tariff.privilege.serviceKey)?.displayName,
serviceName: SERVICE_LIST.find((service) => service.serviceKey === tariff.privilege.serviceKey)?.displayName,
privilege: `(${tariff.privilege.privilegeId}) ${tariff.privilege.description}`,
amount: tariff.amount,
type: tariff.privilege.type === "count" ? "день" : "шт.",

@ -1,26 +1,37 @@
import * as React from "react";
import { useState, useEffect } from "react";
import { useNavigate } from "react-router-dom";
import { Box, Typography, TextField, Button } from "@mui/material";
import Table from "@mui/material/Table";
import TableHead from "@mui/material/TableHead";
import TableBody from "@mui/material/TableBody";
import TableCell from "@mui/material/TableCell";
import TableRow from "@mui/material/TableRow";
import Radio from "@mui/material/Radio";
import Skeleton from "@mui/material/Skeleton";
import Accordion from "@mui/material/Accordion";
import AccordionSummary from "@mui/material/AccordionSummary";
import AccordionDetails from "@mui/material/AccordionDetails";
import axios from "axios";
import {
AccordionDetails,
AccordionSummary,
Accordion,
Skeleton,
Radio,
Box,
Typography,
TextField,
Button,
Table,
TableHead,
TableBody,
TableCell,
TableRow,
} from "@mui/material";
import { GridSelectionModel } from "@mui/x-data-grid";
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
import ClearIcon from "@mui/icons-material/Clear";
import ConditionalRender from "@root/pages/Setting/ConditionalRender";
import ServiceUsersDG from "./ServiceUsersDG";
import { authStore } from "@stores/auth";
import { getRoles_mock, TMockData } from "../../../api/roles";
import type { UsersType } from "../../../api/roles";
import theme from "../../../theme";
import axios from "axios";
import {authStore} from "@stores/auth";
import ConditionalRender from "@root/pages/Setting/ConditionalRender";
import type { UsersType } from "../../../api/roles";
const Users: React.FC = () => {
const { makeRequest } = authStore();
@ -75,35 +86,48 @@ const Users: React.FC = () => {
const [users, setUsers] = React.useState<UsersType>();
const [manager, setManager] = React.useState<UsersType>();
React.useEffect(() => {
const axiosRoles = async () => {
useEffect(() => {
async function axiosRoles() {
try {
const { data } = await axios({
method: "get",
url: "https://admin.pena.digital/strator/role/",
});
setRoles(data);
};
const gettingRegisteredUsers = async () => {
} catch (error) {
console.error("Ошибка при получении ролей!");
}
}
async function gettingRegisteredUsers() {
try {
const { data } = await axios({
method: "get",
url: "https://hub.pena.digital/user/",
});
setUsers(data);
};
} catch (error) {
console.error("Ошибка при получении пользователей!");
}
}
const gettingListManagers = async () => {
async function gettingListManagers() {
try {
const { data } = await axios({
method: "get",
url: "https://admin.pena.digital/user/",
url: "https://hub.pena.digital/user/",
});
setManager(data);
};
} catch (error) {
console.error("Ошибка при получении менеджеров!");
}
}
gettingListManagers();
gettingRegisteredUsers();
axiosRoles();
}, []);
}, [selectedValue]);
const [selectedTariffs, setSelectedTariffs] = useState<GridSelectionModel>([]);
return (
<React.Fragment>
<Button
@ -390,219 +414,24 @@ const Users: React.FC = () => {
</Box>
</Box>
</Box>
<Table
sx={{
width: "90%",
border: "2px solid",
borderColor: theme.palette.grayLight.main,
marginTop: "35px",
}}
aria-label="simple table"
>
<TableHead>
<TableRow
sx={{
borderBottom: "2px solid",
borderColor: theme.palette.grayLight.main,
height: "100px",
}}
>
<TableCell sx={{ textAlign: "center" }}>
<Typography
variant="h4"
sx={{
color: theme.palette.secondary.main,
}}
>
login
</Typography>
</TableCell>
<TableCell sx={{ textAlign: "center" }}>
<Typography
variant="h4"
sx={{
color: theme.palette.secondary.main,
}}
>
email
</Typography>
</TableCell>
<TableCell sx={{ textAlign: "center" }}>
<Typography
variant="h4"
sx={{
color: theme.palette.secondary.main,
}}
>
phoneNumber
</Typography>
</TableCell>
<TableCell sx={{ textAlign: "center" }}>
<Typography
variant="h4"
sx={{
color: theme.palette.secondary.main,
}}
>
isDeleted
</Typography>
</TableCell>
<TableCell sx={{ textAlign: "center" }}>
<Typography
variant="h4"
sx={{
color: theme.palette.secondary.main,
}}
>
createdAt
</Typography>
</TableCell>
</TableRow>
</TableHead>
<TableBody>
<Box component="section" sx={{ width: "90%", mt: "45px", display: "flex", justifyContent: "center" }}>
<ConditionalRender
isLoading={false}
role={selectedValue}
childrenManager={
<>
{manager &&
manager.map(({ login, email, phoneNumber, isDeleted, createdAt }) => (
<TableRow
key={createdAt}
sx={{
borderBottom: "2px solid",
borderColor: theme.palette.grayLight.main,
height: "100px",
}}
>
<TableCell sx={{ textAlign: "center" }}>
<Typography
variant="h4"
sx={{
color: theme.palette.secondary.main,
}}
>
{login}
</Typography>
</TableCell>
<TableCell sx={{ textAlign: "center" }}>
<Typography
variant="h4"
sx={{
color: theme.palette.secondary.main,
}}
>
{email}
</Typography>
</TableCell>
<TableCell sx={{ textAlign: "center" }}>
<Typography
variant="h4"
sx={{
color: theme.palette.secondary.main,
}}
>
{phoneNumber}
</Typography>
</TableCell>
<TableCell sx={{ textAlign: "center" }}>
<Typography
variant="h4"
sx={{
color: theme.palette.secondary.main,
}}
>
{isDeleted ? "true" : "false"}
</Typography>
</TableCell>
<TableCell sx={{ textAlign: "center" }}>
<Typography
variant="h4"
sx={{
color: theme.palette.secondary.main,
}}
>
{createdAt}
</Typography>
</TableCell>
</TableRow>
))}
</>
<ServiceUsersDG
users={manager}
handleSelectionChange={(selectionModel) => setSelectedTariffs(selectionModel)}
/>
}
childrenUser={
<>
{users &&
users.map(({ login, email, phoneNumber, isDeleted, createdAt }) => (
<TableRow
key={createdAt}
sx={{
borderBottom: "2px solid",
borderColor: theme.palette.grayLight.main,
height: "100px",
}}
>
<TableCell sx={{ textAlign: "center" }}>
<Typography
variant="h4"
sx={{
color: theme.palette.secondary.main,
}}
>
{login}
</Typography>
</TableCell>
<TableCell sx={{ textAlign: "center" }}>
<Typography
variant="h4"
sx={{
color: theme.palette.secondary.main,
}}
>
{email}
</Typography>
</TableCell>
<TableCell sx={{ textAlign: "center" }}>
<Typography
variant="h4"
sx={{
color: theme.palette.secondary.main,
}}
>
{phoneNumber}
</Typography>
</TableCell>
<TableCell sx={{ textAlign: "center" }}>
<Typography
variant="h4"
sx={{
color: theme.palette.secondary.main,
}}
>
{isDeleted ? "true" : "false"}
</Typography>
</TableCell>
<TableCell sx={{ textAlign: "center" }}>
<Typography
variant="h4"
sx={{
color: theme.palette.secondary.main,
}}
>
{createdAt}
</Typography>
</TableCell>
</TableRow>
))}
</>
<ServiceUsersDG
users={users}
handleSelectionChange={(selectionModel) => setSelectedTariffs(selectionModel)}
/>
}
/>
</TableBody>
</Table>
</Box>
</React.Fragment>
);
};

@ -58,10 +58,10 @@ export const incrementMessageApiPage = () => {
useMessageStore.setState({ apiPage: state.apiPage + 1 });
};
export const setIsPreventAutoscroll = (isPreventAutoscroll: boolean) => useMessageStore.setState({ isPreventAutoscroll });
function sortMessagesByTime(ticket1: TicketMessage, ticket2: TicketMessage) {
const date1 = new Date(ticket1.created_at).getTime();
const date2 = new Date(ticket2.created_at).getTime();
return date1 - date2;
}
export const setIsPreventAutoscroll = (isPreventAutoscroll: boolean) => useMessageStore.setState({ isPreventAutoscroll });