diff --git a/public/locales/en/translation.json b/public/locales/en/translation.json index e0e8229..6b3c324 100644 --- a/public/locales/en/translation.json +++ b/public/locales/en/translation.json @@ -44,7 +44,8 @@ "report": "Report", "suggestion": "Suggestion", "question": "Question" - } + }, + "deleteAllButton": "Delete All selected tickets" }, "dialog": { "deleteFile": { @@ -74,7 +75,7 @@ "confirm": { "header": "Confirm", "description": "Go to the provided email address and use the link to restore access to your account.", - "close": "Close" + "closed": "Closed" } }, "signUp": { @@ -189,6 +190,7 @@ "author": "Author", "faculty": "Faculty", "dateOfCreation": "Date of creation", + "acceptChanges": "Accept changes", "admin": { "selectAssignee": "Select assignee" }, @@ -203,7 +205,8 @@ "send": "send", "edit": "edit", "reply": "reply", - "delete": "delete" + "delete": "delete", + "messagePlaceholder": "message" }, "dialog": { "title": "Delete ticket", @@ -242,7 +245,7 @@ "open": "Open", "waiting": "Waiting", "rejected": "Rejected", - "close": "Close" + "closed": "Closed" }, "ticketStatus": { "new": "New", @@ -250,7 +253,7 @@ "open": "Open", "waiting": "Waiting", "rejected": "Rejected", - "close": "Close" + "closed": "Closed" }, "statistic": { "heading": "Statistic", diff --git a/public/locales/ua/translation.json b/public/locales/ua/translation.json index 38988b0..185a9d8 100644 --- a/public/locales/ua/translation.json +++ b/public/locales/ua/translation.json @@ -44,7 +44,8 @@ "report": "Скарга", "suggestion": "Пропозиція", "question": "Питання" - } + }, + "deleteAllButton": "Видалити всі обрані звернення" }, "dialog": { "deleteFile": { @@ -74,7 +75,7 @@ "confirm": { "header": "Підтвердження", "description": "Перейдіть за вказаною електронною адресою та скористайтеся посиланням, щоб відновити доступ до свого облікового запису.", - "close": "Закрити" + "closed": "Закрити" } }, "signUp": { @@ -189,6 +190,7 @@ "author": "Автор", "faculty": "Факультет", "dateOfCreation": "Дата створення", + "acceptChanges": "Прийняти зміни", "admin": { "selectAssignee": "Оберіть відповідального" }, @@ -203,7 +205,8 @@ "send": "відправити", "edit": "редагувати", "reply": "переслати", - "delete": "видалити" + "delete": "видалити", + "messagePlaceholder": "повідомлення" }, "dialog": { "title": "Видалити звернення", @@ -242,7 +245,7 @@ "open": "Відкриті", "waiting": "Очікуються", "rejected": "Відхилені", - "close": "Вирішені" + "closed": "Вирішені" }, "ticketStatus": { "new": "Новий", @@ -250,7 +253,7 @@ "open": "Відкритий", "waiting": "Очікується", "rejected": "Відхилений", - "close": "Вирішений" + "closed": "Вирішений" }, "statistic": { "heading": "Статистика", diff --git a/src/components/FilterPanel/components/StatusCheckboxGroup/hooks/useGetStatusesFullInfo.ts b/src/components/FilterPanel/components/StatusCheckboxGroup/hooks/useGetStatusesFullInfo.ts index 57369fd..2959bf6 100644 --- a/src/components/FilterPanel/components/StatusCheckboxGroup/hooks/useGetStatusesFullInfo.ts +++ b/src/components/FilterPanel/components/StatusCheckboxGroup/hooks/useGetStatusesFullInfo.ts @@ -1,27 +1,27 @@ -import { ChangeEvent } from "react"; -import { useSearchParams } from "react-router-dom"; +import { ChangeEvent } from 'react' +import { useSearchParams } from 'react-router-dom' -import useTheme from "@mui/material/styles/useTheme"; +import useTheme from '@mui/material/styles/useTheme' -import IPalette from "theme/IPalette.interface"; -import { statuses, urlKeys } from "constants"; -import { useChangeURL } from "hooks/index"; +import IPalette from 'theme/IPalette.interface' +import { statuses, urlKeys } from 'constants' +import { useChangeURL } from 'hooks/index' export interface IStatus { - id: number; - name: string; - color: string; - checked: boolean; - onChange: (event: ChangeEvent, checked: boolean) => void; + id: number + name: string + color: string + checked: boolean + onChange: (event: ChangeEvent, checked: boolean) => void } export const useGetStatusesFullInfo = ( isAllStatuses: boolean ): [IStatus[], boolean[]] => { - const { palette }: IPalette = useTheme(); + const { palette }: IPalette = useTheme() - const [searchParams] = useSearchParams(); - const putStatusesInURL = useChangeURL(); + const [searchParams] = useSearchParams() + const putStatusesInURL = useChangeURL() const getStatusObject = ( id: number, @@ -34,48 +34,48 @@ export const useGetStatusesFullInfo = ( color: palette.semantic[color], checked, onChange: handleChange(id), - }); + }) const handleChange = (index: number) => (event: ChangeEvent): void => { - const updatedChecked = [...checked]; - updatedChecked[index] = event.target.checked; + const updatedChecked = [...checked] + updatedChecked[index] = event.target.checked const selectedStatuses = statusesFullInfo .filter(status => updatedChecked[status.id]) .map(status => status.name.toLowerCase()) - .join(","); + .join(',') - putStatusesInURL(urlKeys.STATUSES, selectedStatuses, true); - }; + putStatusesInURL(urlKeys.STATUSES, selectedStatuses, true) + } const COMMON_STATUSES = [ - { id: 0, name: statuses.ACCEPTED, color: "warning" }, - { id: 1, name: statuses.OPEN, color: "info" }, - { id: 2, name: statuses.WAITING, color: "waiting" }, - { id: 3, name: statuses.CLOSE, color: "success" }, - { id: 4, name: statuses.REJECTED, color: "error" }, - ]; + { id: 0, name: statuses.ACCEPTED, color: 'warning' }, + { id: 1, name: statuses.OPEN, color: 'info' }, + { id: 2, name: statuses.WAITING, color: 'waiting' }, + { id: 3, name: statuses.CLOSED, color: 'success' }, + { id: 4, name: statuses.REJECTED, color: 'error' }, + ] const ADDITIONAL_STATUSES = isAllStatuses - ? [{ id: 5, name: statuses.NEW, color: "new" }] - : []; + ? [{ id: 5, name: statuses.NEW, color: 'new' }] + : [] - const statusesList = [...COMMON_STATUSES, ...ADDITIONAL_STATUSES]; + const statusesList = [...COMMON_STATUSES, ...ADDITIONAL_STATUSES] - const statusesName = statusesList.map(status => status.name); + const statusesName = statusesList.map(status => status.name) const statusesQueryParams: string[] | undefined = - searchParams.get(urlKeys.STATUSES)?.split(",") ?? []; + searchParams.get(urlKeys.STATUSES)?.split(',') ?? [] const checked: boolean[] = statusesQueryParams ? statusesName.map(status => statusesQueryParams.includes(status)) - : statusesName.map(() => false); + : statusesName.map(() => false) const statusesFullInfo = statusesList.map(status => getStatusObject(status.id, status.name, status.color, !!checked[status.id]) - ); + ) - return [statusesFullInfo, checked]; -}; + return [statusesFullInfo, checked] +} diff --git a/src/components/LogInModal/components/ConfirmStep/ConfirmStep.tsx b/src/components/LogInModal/components/ConfirmStep/ConfirmStep.tsx index 4c5d500..9375d89 100644 --- a/src/components/LogInModal/components/ConfirmStep/ConfirmStep.tsx +++ b/src/components/LogInModal/components/ConfirmStep/ConfirmStep.tsx @@ -1,47 +1,47 @@ -import { FC, Dispatch, SetStateAction } from "react"; -import { useTranslation } from "react-i18next"; +import { FC, Dispatch, SetStateAction } from 'react' +import { useTranslation } from 'react-i18next' -import useTheme from "@mui/material/styles/useTheme"; -import Button from "@mui/material/Button"; -import Typography from "@mui/material/Typography"; -import Grid from "@mui/material/Grid"; -import { Theme, SxProps } from "@mui/material/styles"; +import useTheme from '@mui/material/styles/useTheme' +import Button from '@mui/material/Button' +import Typography from '@mui/material/Typography' +import Grid from '@mui/material/Grid' +import { Theme, SxProps } from '@mui/material/styles' -import IPalette from "theme/IPalette.interface"; +import IPalette from 'theme/IPalette.interface' interface ConfirmStepProps { - setOpen: Dispatch>; - wrapperStyle: SxProps; + setOpen: Dispatch> + wrapperStyle: SxProps } const ConfirmStep: FC = ({ setOpen, wrapperStyle }) => { - const { t } = useTranslation(); - const { palette }: IPalette = useTheme(); + const { t } = useTranslation() + const { palette }: IPalette = useTheme() const handleClose = () => { - setOpen(false); - }; + setOpen(false) + } return ( - - {t("login.confirm.header")} + + {t('login.confirm.header')} - {t("login.confirm.description")} + {t('login.confirm.description')} - - ); -}; + ) +} -export { ConfirmStep }; +export { ConfirmStep } diff --git a/src/components/Ticket/Ticket.tsx b/src/components/Ticket/Ticket.tsx index e5fbd2f..5924102 100644 --- a/src/components/Ticket/Ticket.tsx +++ b/src/components/Ticket/Ticket.tsx @@ -1,90 +1,83 @@ -import { - MouseEvent, - useState, - FC, - ComponentType, - useEffect, - memo, -} from "react"; -import { useNavigate } from "react-router-dom"; - -import Divider from "@mui/material/Divider"; -import Box from "@mui/material/Box"; -import Card from "@mui/material/Card"; -import useTheme from "@mui/material/styles/useTheme"; -import { SlideProps } from "@mui/material/Slide"; - -import { TicketHeader } from "./components/TicketHeader"; -import { TicketBody } from "./components/TicketBody"; -import { TicketActions } from "./components/TicketActions"; -import { SnackbarNotification } from "components/SnackbarNotification"; -import { SlideNotification } from "components/SlideNotification"; +import { MouseEvent, useState, FC, ComponentType, useEffect, memo } from 'react' +import { useNavigate } from 'react-router-dom' + +import Divider from '@mui/material/Divider' +import Box from '@mui/material/Box' +import Card from '@mui/material/Card' +import useTheme from '@mui/material/styles/useTheme' +import { SlideProps } from '@mui/material/Slide' + +import { TicketHeader } from './components/TicketHeader' +import { TicketBody } from './components/TicketBody' +import { TicketActions } from './components/TicketActions' +import { SnackbarNotification } from 'components/SnackbarNotification' +import { SlideNotification } from 'components/SlideNotification' import { useToggleBookmarkMutation, useToggleLikeMutation, -} from "api/tickets.api"; -import { endpoints, toggleOptions } from "constants"; -import { useCheckStatus, useFormatDate } from "hooks/index"; -import IPalette from "theme/IPalette.interface"; -import { ITicket } from "./ticket.interface"; -import { getUser } from "functions/manipulateLocalStorage"; -import { useAuth } from "context/AuthContext/AuthContext"; -import { useToggleAction } from "hooks/useToggleAction"; +} from 'api/tickets.api' +import { endpoints, toggleOptions } from 'constants' +import { useCheckStatus, useFormatDate } from 'hooks/index' +import IPalette from 'theme/IPalette.interface' +import { ITicket } from './ticket.interface' +import { getUser } from 'functions/manipulateLocalStorage' +import { useAuth } from 'context/AuthContext/AuthContext' +import { useToggleAction } from 'hooks/useToggleAction' interface TicketProps { - ticket: ITicket; - ticketsPerRow: number; + ticket: ITicket + ticketsPerRow: number } const Ticket: FC = memo(({ ticket, ticketsPerRow }) => { - const { palette }: IPalette = useTheme(); - const { isAuth } = useAuth(); - const navigate = useNavigate(); + const { palette }: IPalette = useTheme() + const { isAuth } = useAuth() + const navigate = useNavigate() - const { userId } = getUser(); - const creatorId = ticket?.creator?.user_id; - const isMyTicket = userId === creatorId; - const isHiddenTicket = isMyTicket && ticket.hidden; + const { userId } = getUser() + const creatorId = ticket?.creator?.user_id + const isMyTicket = userId === creatorId + const isHiddenTicket = isMyTicket && ticket.hidden - const [open, setOpen] = useState(false); + const [open, setOpen] = useState(false) const [transition, setTransition] = useState< ComponentType | undefined - >(undefined); + >(undefined) - const [upvotes, setUpvotes] = useState(ticket.upvotes); - const [isLiked, setIsLiked] = useState(false); - const [isFollowed, setIsFollowed] = useState(false); + const [upvotes, setUpvotes] = useState(ticket.upvotes) + const [isLiked, setIsLiked] = useState(false) + const [isFollowed, setIsFollowed] = useState(false) - const color: string = useCheckStatus(ticket.status.name); - const formattedDate: string = ticket?.date && useFormatDate(ticket.date); + const color: string = useCheckStatus(ticket.status.name) + const formattedDate: string = ticket?.date && useFormatDate(ticket.date) useEffect(() => { - ticket.is_liked && setIsLiked(true); - ticket.is_followed && setIsFollowed(true); - }, [ticket.is_liked, ticket.is_followed]); + ticket.is_liked && setIsLiked(true) + ticket.is_followed && setIsFollowed(true) + }, [ticket.is_liked, ticket.is_followed]) //================ refactor this ======================= // - type TransitionProps = Omit; + type TransitionProps = Omit function TransitionRight(props: TransitionProps, variant: string) { - return ; + return } const handleSnackbarClick = (Transition: ComponentType) => { - setTransition(() => Transition); - setOpen(true); - }; + setTransition(() => Transition) + setOpen(true) + } const handleClose = (_: React.SyntheticEvent | Event, reason: string) => { - if (reason === "timeout") setOpen(false); - }; + if (reason === 'timeout') setOpen(false) + } //================ refactor this ======================= // - const [toggleLike] = useToggleLikeMutation(); - const [toggleFollowed] = useToggleBookmarkMutation(); + const [toggleLike] = useToggleLikeMutation() + const [toggleFollowed] = useToggleBookmarkMutation() - const likeOption = !isLiked ? toggleOptions.LIKE : toggleOptions.UNLIKE; + const likeOption = !isLiked ? toggleOptions.LIKE : toggleOptions.UNLIKE const likeOptions = { toggleMutation: toggleLike, @@ -94,18 +87,18 @@ const Ticket: FC = memo(({ ticket, ticketsPerRow }) => { dependencies: [isLiked], callback: () => { setUpvotes((prevUpvote: number) => - likeOption === "like" ? prevUpvote + 1 : prevUpvote - 1 - ); + likeOption === 'like' ? prevUpvote + 1 : prevUpvote - 1 + ) - handleSnackbarClick(props => TransitionRight(props, likeOption)); + handleSnackbarClick(props => TransitionRight(props, likeOption)) }, - }; + } - const handleToggleLike = useToggleAction(likeOptions); + const handleToggleLike = useToggleAction(likeOptions) const followedOption = !isFollowed ? toggleOptions.BOOKMARK - : toggleOptions.UNBOOKMARK; + : toggleOptions.UNBOOKMARK const followedOptions = { toggleMutation: toggleFollowed, @@ -114,70 +107,70 @@ const Ticket: FC = memo(({ ticket, ticketsPerRow }) => { ticketId: ticket.ticket_id, dependencies: [isFollowed], callback: () => { - handleSnackbarClick(props => TransitionRight(props, followedOption)); + handleSnackbarClick(props => TransitionRight(props, followedOption)) }, - }; + } - const handleToggleFollowed = useToggleAction(followedOptions); + const handleToggleFollowed = useToggleAction(followedOptions) //================ refactor this ======================= // const handleClick = (event: MouseEvent): void => { - const { target } = event; + const { target } = event if ( target instanceof HTMLElement && - target.tagName !== "path" && - !target.closest(".evadeItem") + target.tagName !== 'path' && + !target.closest('.evadeItem') ) { - isAuth && navigate(`${endpoints.FULL_TICKET}/${ticket.ticket_id}`); + isAuth && navigate(`${endpoints.FULL_TICKET}/${ticket.ticket_id}`) } - }; + } return ( div > div": { + '& > div > div': { p: 2, }, - "& > div > hr": { + '& > div > hr': { borderRadius: 2, border: `1px solid ${palette.grey.border}`, ml: 2, mr: 2, }, - "&::before": isHiddenTicket + '&::before': isHiddenTicket ? { content: "''", - position: "absolute", + position: 'absolute', top: 0, left: 0, - width: "100%", - height: "100%", - bgcolor: "rgba(0, 0, 0, 0.4)", + width: '100%', + height: '100%', + bgcolor: 'rgba(0, 0, 0, 0.4)', zIndex: 2, } : {}, - "&::after": isHiddenTicket + '&::after': isHiddenTicket ? { content: "'🤫'", - textAlign: "center", + textAlign: 'center', fontSize: 170, - position: "absolute", - top: "53%", - left: "50%", - transform: "translate(-50%, -50%)", - filter: "grayscale(80%)", + position: 'absolute', + top: '53%', + left: '50%', + transform: 'translate(-50%, -50%)', + filter: 'grayscale(80%)', opacity: 0.15, zIndex: 3, } @@ -186,9 +179,9 @@ const Ticket: FC = memo(({ ticket, ticketsPerRow }) => { > @@ -224,7 +217,7 @@ const Ticket: FC = memo(({ ticket, ticketsPerRow }) => { /> - ); -}); + ) +}) -export { Ticket }; +export { Ticket } diff --git a/src/components/Ticket/components/TicketHeader/TicketHeader.tsx b/src/components/Ticket/components/TicketHeader/TicketHeader.tsx index b858c03..2619197 100644 --- a/src/components/Ticket/components/TicketHeader/TicketHeader.tsx +++ b/src/components/Ticket/components/TicketHeader/TicketHeader.tsx @@ -1,53 +1,53 @@ -import { FC } from "react"; -import { useTranslation } from "react-i18next"; -import { NavLink } from "react-router-dom"; +import { FC } from 'react' +import { useTranslation } from 'react-i18next' +import { NavLink } from 'react-router-dom' -import Box from "@mui/material/Box"; -import Grid from "@mui/material/Grid"; -import Typography from "@mui/material/Typography"; -import useTheme from "@mui/material/styles/useTheme"; +import Box from '@mui/material/Box' +import Grid from '@mui/material/Grid' +import Typography from '@mui/material/Typography' +import useTheme from '@mui/material/styles/useTheme' -import { ScopeLabel } from "components/ScopeLabel"; -import { Badge } from "components/Badge"; +import { ScopeLabel } from 'components/ScopeLabel' +import { Badge } from 'components/Badge' -import IPalette from "theme/IPalette.interface"; -import { endpoints, statuses } from "constants"; -import { useAuth } from "context/AuthContext/AuthContext"; -import { useFormatName } from "components/Ticket/hooks/useFormatName"; +import IPalette from 'theme/IPalette.interface' +import { endpoints, statuses } from 'constants' +import { useAuth } from 'context/AuthContext/AuthContext' +import { useFormatName } from 'components/Ticket/hooks/useFormatName' export interface IAssignee { - faculty: { faculty_id: number; name: string }; - firstname: string; - group: { group_id: number; name: string }; - lastname: string; - login: string; - user_id: number; + faculty: { faculty_id: number; name: string } + firstname: string + group: { group_id: number; name: string } + lastname: string + login: string + user_id: number } interface TicketHeaderProps { - scope: string; - color: string; - subject: string; - status: string; - assignee: IAssignee; + scope: string + color: string + subject: string + status: string + assignee: IAssignee } interface AssigneeLabelProps { - assigneeName: string; + assigneeName: string } const AssigneeLabel: FC = ({ assigneeName }) => { - const { palette }: IPalette = useTheme(); + const { palette }: IPalette = useTheme() return ( {assigneeName} - ); -}; + ) +} const TicketHeader: FC = ({ color, @@ -56,28 +56,28 @@ const TicketHeader: FC = ({ status, assignee, }) => { - const { t } = useTranslation(); + const { t } = useTranslation() - const { isAuth } = useAuth(); + const { isAuth } = useAuth() - const assigneeId = assignee?.user_id; - const assigneeName = useFormatName(assignee); + const assigneeId = assignee?.user_id + const assigneeName = useFormatName(assignee) return ( - + {subject} - + @@ -86,8 +86,8 @@ const TicketHeader: FC = ({ {isAuth ? ( @@ -95,7 +95,7 @@ const TicketHeader: FC = ({ )} - ); -}; + ) +} -export { TicketHeader }; +export { TicketHeader } diff --git a/src/constants/statuses.ts b/src/constants/statuses.ts index 6c4ee5e..65460f6 100644 --- a/src/constants/statuses.ts +++ b/src/constants/statuses.ts @@ -1,10 +1,10 @@ const statuses = { - NEW: "new", - ACCEPTED: "accepted", - OPEN: "open", - WAITING: "waiting", - CLOSE: "close", - REJECTED: "rejected", -}; + NEW: 'new', + ACCEPTED: 'accepted', + OPEN: 'open', + WAITING: 'waiting', + CLOSED: 'closed', + REJECTED: 'rejected', +} -export { statuses }; +export { statuses } diff --git a/src/layouts/MyTicketsLayout/MyTicketsLayout.tsx b/src/layouts/MyTicketsLayout/MyTicketsLayout.tsx index d2924a6..d39b348 100644 --- a/src/layouts/MyTicketsLayout/MyTicketsLayout.tsx +++ b/src/layouts/MyTicketsLayout/MyTicketsLayout.tsx @@ -1,54 +1,54 @@ -import { useEffect, useState, FC } from "react"; -import { useTranslation } from "react-i18next"; -import { useSearchParams } from "react-router-dom"; +import { useEffect, useState, FC } from 'react' +import { useTranslation } from 'react-i18next' +import { useSearchParams } from 'react-router-dom' import { BaseQueryFn, FetchArgs, FetchBaseQueryError, MutationDefinition, -} from "@reduxjs/toolkit/query/react"; -import { SerializedError } from "@reduxjs/toolkit"; -import { MutationTrigger } from "@reduxjs/toolkit/dist/query/react/buildHooks"; +} from '@reduxjs/toolkit/query/react' +import { SerializedError } from '@reduxjs/toolkit' +import { MutationTrigger } from '@reduxjs/toolkit/dist/query/react/buildHooks' -import Box from "@mui/material/Box"; -import Grid from "@mui/material/Grid"; -import Typography from "@mui/material/Typography"; -import Button from "@mui/material/Button"; +import Box from '@mui/material/Box' +import Grid from '@mui/material/Grid' +import Typography from '@mui/material/Typography' +import Button from '@mui/material/Button' -import { FilterPanel } from "components/FilterPanel"; +import { FilterPanel } from 'components/FilterPanel' -import { useGetRequestBody } from "./hooks/useGetRequestBody"; -import { ITicket } from "components/Ticket/ticket.interface"; +import { useGetRequestBody } from './hooks/useGetRequestBody' +import { ITicket } from 'components/Ticket/ticket.interface' import { useDeleteTicketMutation, useUndeleteTicketMutation, -} from "api/tickets.api"; -import { useRenderElements } from "./hooks/useRenderElements"; +} from 'api/tickets.api' +import { useRenderElements } from './hooks/useRenderElements' interface MyTicketsLayoutProps { - title: string; + title: string useGetQuery: MutationTrigger< MutationDefinition< any, BaseQueryFn, never, any, - "api" + 'api' > - >; - isLoading: boolean; - isSuccess: boolean; - option?: "bookmarked" | "followed" | "tickets"; - userId?: boolean | number; - assignee?: number; + > + isLoading: boolean + isSuccess: boolean + option?: 'bookmarked' | 'followed' | 'tickets' + userId?: boolean | number + assignee?: number } interface MyTicketsLayoutInfo { data?: { - ticket_list: ITicket[]; - total_pages: number; - }; - error?: FetchBaseQueryError | SerializedError; + ticket_list: ITicket[] + total_pages: number + } + error?: FetchBaseQueryError | SerializedError } const MyTicketsLayout: FC = ({ @@ -60,57 +60,57 @@ const MyTicketsLayout: FC = ({ userId, assignee, }) => { - const { t } = useTranslation(); + const { t } = useTranslation() - const [tickets, setTickets] = useState([]); - const [totalPage, setTotalPage] = useState(1); - const [deletedList, setDeletedList] = useState([]); + const [tickets, setTickets] = useState([]) + const [totalPage, setTotalPage] = useState(1) + const [deletedList, setDeletedList] = useState([]) const [deleteTicket, { isSuccess: isDeleteSuccess }] = - useDeleteTicketMutation(); + useDeleteTicketMutation() const [undeleteTicket, { isSuccess: isUndeleteSuccess }] = - useUndeleteTicketMutation(); + useUndeleteTicketMutation() - const [searchParams] = useSearchParams(); - const currentPage: number = Number(searchParams.get("current_page")) || 1; + const [searchParams] = useSearchParams() + const currentPage: number = Number(searchParams.get('current_page')) || 1 - const isSentPage = title === "sent"; - const isDeletedPage = title === "deleted"; - const isReceivedPage = title === "received"; + const isSentPage = title === 'sent' + const isDeletedPage = title === 'deleted' + const isReceivedPage = title === 'received' const requestBody = useGetRequestBody({ currentPage, option, userId, assignee, - }); + }) useEffect(() => { const requestProps: { body: string; option?: string } = { body: JSON.stringify(requestBody), - }; + } if (option) { - requestProps.option = option; + requestProps.option = option } useGetQuery(requestProps).then( (res: MyTicketsLayoutInfo): void | PromiseLike => { if (res.data) { - setTickets(res.data.ticket_list); - setTotalPage(res.data.total_pages); + setTickets(res.data.ticket_list) + setTotalPage(res.data.total_pages) } } - ); - }, [searchParams, requestBody, isDeleteSuccess, isUndeleteSuccess]); + ) + }, [searchParams, requestBody, isDeleteSuccess, isUndeleteSuccess]) const handleDelete = (ticketIdList: number[]): void => { - deleteTicket({ body: JSON.stringify({ ticket_id_list: ticketIdList }) }); - }; + deleteTicket({ body: JSON.stringify({ ticket_id_list: ticketIdList }) }) + } const handleRestore = (ticketId: number): void => { - undeleteTicket({ body: JSON.stringify({ ticket_id: ticketId }) }); - }; + undeleteTicket({ body: JSON.stringify({ ticket_id: ticketId }) }) + } const { renderSkeletonTickets, renderTickets, renderNotFound } = useRenderElements({ @@ -123,12 +123,12 @@ const MyTicketsLayout: FC = ({ totalPage, currentPage, isLoading, - }); + }) return ( - + - {t(`${title}.heading`)} + {t(`${title}.heading`)} @@ -136,10 +136,10 @@ const MyTicketsLayout: FC = ({ {isSentPage && deletedList.length > 0 && ( )} @@ -147,7 +147,7 @@ const MyTicketsLayout: FC = ({ {isSuccess && (tickets.length ? renderTickets() : renderNotFound())} - ); -}; + ) +} -export { MyTicketsLayout }; +export { MyTicketsLayout } diff --git a/src/pages/FullTicketInfo/components/FullTicketComments/components/CommentsTextField/CommentsTextField.tsx b/src/pages/FullTicketInfo/components/FullTicketComments/components/CommentsTextField/CommentsTextField.tsx index 57d14f7..2061690 100644 --- a/src/pages/FullTicketInfo/components/FullTicketComments/components/CommentsTextField/CommentsTextField.tsx +++ b/src/pages/FullTicketInfo/components/FullTicketComments/components/CommentsTextField/CommentsTextField.tsx @@ -5,65 +5,65 @@ import { useEffect, useState, KeyboardEvent, -} from "react"; -import { MutationTrigger } from "@reduxjs/toolkit/dist/query/react/buildHooks"; +} from 'react' +import { MutationTrigger } from '@reduxjs/toolkit/dist/query/react/buildHooks' import { BaseQueryFn, FetchArgs, FetchBaseQueryError, MutationDefinition, -} from "@reduxjs/toolkit/dist/query"; +} from '@reduxjs/toolkit/dist/query' -import { useTranslation } from "react-i18next"; +import { useTranslation } from 'react-i18next' -import Box from "@mui/material/Box"; -import Button from "@mui/material/Button"; -import useTheme from "@mui/material/styles/useTheme"; -import TextField from "@mui/material/TextField"; -import { useMediaQuery } from "@mui/material"; +import Box from '@mui/material/Box' +import Button from '@mui/material/Button' +import useTheme from '@mui/material/styles/useTheme' +import TextField from '@mui/material/TextField' +import { useMediaQuery } from '@mui/material' -import SendIcon from "@mui/icons-material/Send"; -import CheckIcon from "@mui/icons-material/Check"; +import SendIcon from '@mui/icons-material/Send' +import CheckIcon from '@mui/icons-material/Check' -import IPalette from "../../../../../../theme/IPalette.interface"; -import { EditedComment, RepliedComment } from "../../FullTicketComments"; -import { dimensions } from "../../../../../../constants"; +import IPalette from '../../../../../../theme/IPalette.interface' +import { EditedComment, RepliedComment } from '../../FullTicketComments' +import { dimensions } from '../../../../../../constants' interface CommentsTextFieldProps { - ticketId: number; - editedComment: EditedComment | null; - setEditedComment: Dispatch>; - repliedComment: RepliedComment | null; - setRepliedComment: Dispatch>; + ticketId: number + editedComment: EditedComment | null + setEditedComment: Dispatch> + repliedComment: RepliedComment | null + setRepliedComment: Dispatch> createComment: MutationTrigger< MutationDefinition< any, BaseQueryFn, never, any, - "api" + 'api' > - >; + > editComment: MutationTrigger< MutationDefinition< any, BaseQueryFn, never, any, - "api" + 'api' > - >; + > } interface CreateCommentBody { - ticket_id: number; - body: string; - reply_to?: string; + ticket_id: number + body: string + reply_to?: string } interface EditCommentBody { - comment_id: string; - body: string; + comment_id: string + body: string } const CommentsTextField: FC = ({ @@ -75,14 +75,16 @@ const CommentsTextField: FC = ({ repliedComment, setRepliedComment, }) => { - const { t } = useTranslation(); + const { t } = useTranslation() const matches = useMediaQuery( `(min-width: ${dimensions.BREAK_POINTS.COMMENTS_TEXTFIELD}px)` - ); + ) - const { palette }: IPalette = useTheme(); + const { palette }: IPalette = useTheme() - const [comment, setComment] = useState(editedComment?.body ?? ""); + const [comment, setComment] = useState(editedComment?.body ?? '') + + const placeholder = t('fullTicket.comments.messagePlaceholder') const sendComment = () => { if (comment) { @@ -90,49 +92,49 @@ const CommentsTextField: FC = ({ const body: EditCommentBody = { comment_id: editedComment.id, body: comment, - }; + } - editComment({ body: JSON.stringify(body) }); - setEditedComment(null); + editComment({ body: JSON.stringify(body) }) + setEditedComment(null) } else { const body: CreateCommentBody = { ticket_id: ticketId, body: comment, - }; + } if (repliedComment?.id) { - body["reply_to"] = repliedComment.id; + body['reply_to'] = repliedComment.id } - createComment({ body: JSON.stringify(body) }); - setRepliedComment(null); - setComment(""); + createComment({ body: JSON.stringify(body) }) + setRepliedComment(null) + setComment('') } } - }; + } useEffect(() => { if (!editedComment) { - setComment(""); + setComment('') } - editedComment?.body && setComment(editedComment.body); - }, [editedComment]); + editedComment?.body && setComment(editedComment.body) + }, [editedComment]) const handleKeyDown = (event: KeyboardEvent) => { - if (event.key === "Enter" && !event.shiftKey) { - event.preventDefault(); - sendComment(); + if (event.key === 'Enter' && !event.shiftKey) { + event.preventDefault() + sendComment() } - }; + } return ( @@ -143,37 +145,37 @@ const CommentsTextField: FC = ({ value={comment} onChange={e => setComment(e.target.value)} onKeyDown={handleKeyDown} - placeholder="Message" + placeholder={placeholder} sx={{ bgcolor: palette.grey.card, - "& .MuiInputBase-root": { - p: "12px", + '& .MuiInputBase-root': { + p: '12px', }, - "& .MuiInputBase-input": { - "&::-webkit-scrollbar": { - width: "4px", + '& .MuiInputBase-input': { + '&::-webkit-scrollbar': { + width: '4px', }, - "&::-webkit-scrollbar-thumb": { + '&::-webkit-scrollbar-thumb': { background: palette.grey.divider, - borderRadius: "4px", + borderRadius: '4px', }, - "&::-webkit-scrollbar-thumb:hover": { - background: "#555", + '&::-webkit-scrollbar-thumb:hover': { + background: '#555', }, }, }} /> - ); -}; + ) +} -export { CommentsTextField }; +export { CommentsTextField } diff --git a/src/pages/FullTicketInfo/components/FullTicketHeader/FullTicketHeader.tsx b/src/pages/FullTicketInfo/components/FullTicketHeader/FullTicketHeader.tsx index b3bee89..4c3547d 100644 --- a/src/pages/FullTicketInfo/components/FullTicketHeader/FullTicketHeader.tsx +++ b/src/pages/FullTicketInfo/components/FullTicketHeader/FullTicketHeader.tsx @@ -1,91 +1,91 @@ -import { FC, useEffect, useState } from "react"; -import { useTranslation } from "react-i18next"; -import { MutationTrigger } from "@reduxjs/toolkit/dist/query/react/buildHooks"; +import { FC, useEffect, useState } from 'react' +import { useTranslation } from 'react-i18next' +import { MutationTrigger } from '@reduxjs/toolkit/dist/query/react/buildHooks' import { BaseQueryFn, FetchArgs, FetchBaseQueryError, MutationDefinition, -} from "@reduxjs/toolkit/dist/query"; -import { NavLink, useNavigate } from "react-router-dom"; - -import Box from "@mui/material/Box"; -import IconButton from "@mui/material/IconButton"; -import Button from "@mui/material/Button"; -import Typography from "@mui/material/Typography"; -import useTheme from "@mui/material/styles/useTheme"; -import Grid from "@mui/material/Grid"; -import Avatar from "@mui/material/Avatar"; - -import RedoIcon from "@mui/icons-material/Redo"; -import EditIcon from "@mui/icons-material/Edit"; -import ContentCopyIcon from "@mui/icons-material/ContentCopy"; -import DeleteIcon from "@mui/icons-material/Delete"; - -import { VerticalDivider } from "components/VerticalDivider"; -import { FacultySelect } from "./components/FacultySelect"; -import { QueueSelect } from "./components/QueueSelect"; -import { StatusSelect } from "./components/StatusSelect"; -import { AssigneeSelect } from "./components/AssigneeSelect"; -import { DialogPopup } from "./components/DialogPopup"; - -import IPalette from "theme/IPalette.interface"; -import { checkIsAdmin } from "functions/index"; -import { getUser } from "functions/manipulateLocalStorage"; -import { endpoints, roles } from "constants"; -import { useAdminRemoveTicketMutation } from "api/admin.api"; - -import styles from "./FullTicketHeader.module.css"; -import { IAction } from "../FullTicketComments/components/Action/Action"; -import { useGetStatusesQuery } from "api/meta.api"; -import { useCheckStatus } from "hooks/index"; +} from '@reduxjs/toolkit/dist/query' +import { NavLink, useNavigate } from 'react-router-dom' + +import Box from '@mui/material/Box' +import IconButton from '@mui/material/IconButton' +import Button from '@mui/material/Button' +import Typography from '@mui/material/Typography' +import useTheme from '@mui/material/styles/useTheme' +import Grid from '@mui/material/Grid' +import Avatar from '@mui/material/Avatar' + +import RedoIcon from '@mui/icons-material/Redo' +import EditIcon from '@mui/icons-material/Edit' +import ContentCopyIcon from '@mui/icons-material/ContentCopy' +import DeleteIcon from '@mui/icons-material/Delete' + +import { VerticalDivider } from 'components/VerticalDivider' +import { FacultySelect } from './components/FacultySelect' +import { QueueSelect } from './components/QueueSelect' +import { StatusSelect } from './components/StatusSelect' +import { AssigneeSelect } from './components/AssigneeSelect' +import { DialogPopup } from './components/DialogPopup' + +import IPalette from 'theme/IPalette.interface' +import { checkIsAdmin } from 'functions/index' +import { getUser } from 'functions/manipulateLocalStorage' +import { endpoints, roles } from 'constants' +import { useAdminRemoveTicketMutation } from 'api/admin.api' + +import styles from './FullTicketHeader.module.css' +import { IAction } from '../FullTicketComments/components/Action/Action' +import { useGetStatusesQuery } from 'api/meta.api' +import { useCheckStatus } from 'hooks/index' interface FullTicketHeaderProps { - assigneeId: number; + assigneeId: number ticketStatus: { - status_id: number; - name: string; - }; + status_id: number + name: string + } ticketQueue: { - queue_id: number; - name: string; - faculty: number; - scope: string; - }; - ticketFaculty: number; + queue_id: number + name: string + faculty: number + scope: string + } + ticketFaculty: number ticketAssignee: { - faculty: { faculty_id: number; name: string }; - firstname: string; - group: { group_id: number; name: string }; - lastname: string; - login: string; - user_id: number; - }; - ticketId: number; - subject: string; + faculty: { faculty_id: number; name: string } + firstname: string + group: { group_id: number; name: string } + lastname: string + login: string + user_id: number + } + ticketId: number + subject: string updateTicket: MutationTrigger< MutationDefinition< any, BaseQueryFn, never, any, - "api" + 'api' > - >; - action: IAction | null; + > + action: IAction | null } interface UpdateTicketBody { - ticket_id: number; - assignee_id?: number; - faculty?: number; - queue?: number; - status?: number; + ticket_id: number + assignee_id?: number + faculty?: number + queue?: number + status?: number } interface IStatus { - status_id: number; - name: string; + status_id: number + name: string } const FullTicketHeader: FC = ({ @@ -99,28 +99,28 @@ const FullTicketHeader: FC = ({ updateTicket, action, }) => { - const { t } = useTranslation(); - const { palette }: IPalette = useTheme(); - const navigate = useNavigate(); + const { t } = useTranslation() + const { palette }: IPalette = useTheme() + const navigate = useNavigate() - const { userId } = getUser(); - const isAssignee = userId == assigneeId; + const { userId } = getUser() + const isAssignee = userId == assigneeId - const isAdmin = checkIsAdmin(); - const isChiefAdmin = checkIsAdmin(roles.CHIEF_ADMIN); + const isAdmin = checkIsAdmin() + const isChiefAdmin = checkIsAdmin(roles.CHIEF_ADMIN) - const [openDialog, setOpenDialog] = useState(false); - const [isCopyLink, setIsCopyLink] = useState(false); - const [queue, setQueue] = useState(ticketQueue?.queue_id || -1); - const [faculty, setFaculty] = useState(ticketFaculty); - const [status, setStatus] = useState(ticketStatus); + const [openDialog, setOpenDialog] = useState(false) + const [isCopyLink, setIsCopyLink] = useState(false) + const [queue, setQueue] = useState(ticketQueue?.queue_id || -1) + const [faculty, setFaculty] = useState(ticketFaculty) + const [status, setStatus] = useState(ticketStatus) const [assignee, setAssignee] = useState( ticketAssignee?.user_id || -1 - ); - const [isEdit, setIsEdit] = useState(false); + ) + const [isEdit, setIsEdit] = useState(false) - const [adminDelete] = useAdminRemoveTicketMutation(); - const statusesQuery = useGetStatusesQuery({}); + const [adminDelete] = useAdminRemoveTicketMutation() + const statusesQuery = useGetStatusesQuery({}) const handleAcceptChanges = () => { const requestBody: UpdateTicketBody = { @@ -129,79 +129,79 @@ const FullTicketHeader: FC = ({ faculty: faculty, queue: queue, status: status.status_id, - }; + } - updateTicket({ body: JSON.stringify(requestBody) }); + updateTicket({ body: JSON.stringify(requestBody) }) - setIsEdit(false); - }; + setIsEdit(false) + } const handleCopyLink = () => { - const currentURL = window.location.href; + const currentURL = window.location.href - navigator.clipboard.writeText(currentURL); + navigator.clipboard.writeText(currentURL) - setIsCopyLink(true); + setIsCopyLink(true) setTimeout(() => { - setIsCopyLink(false); - }, 800); - }; + setIsCopyLink(false) + }, 800) + } useEffect(() => { - if (action?.field_name === "status") { - const statuses = statusesQuery.data.statuses_list; + if (action?.field_name === 'status') { + const statuses = statusesQuery.data.statuses_list if (statuses) { setStatus(() => { const newStatus = statuses.filter( status => status.name === action.new_value - ); + ) - return newStatus[0]; - }); + return newStatus[0] + }) } } - if (action?.field_name === "queue") { + if (action?.field_name === 'queue') { } - if (action?.field_name === "faculty") { + if (action?.field_name === 'faculty') { } - if (action?.field_name === "assignee") { + if (action?.field_name === 'assignee') { } - }, [action]); + }, [action]) const handleAccept = () => { - setOpenDialog(false); + setOpenDialog(false) - adminDelete({ body: JSON.stringify({ ticket_id: ticketId }) }); + adminDelete({ body: JSON.stringify({ ticket_id: ticketId }) }) - navigate(-1); - }; + navigate(-1) + } return ( - + .MuiTypography-root": { + '& > .MuiTypography-root': { fontSize: { xs: 24, md: 28 }, }, }} > = ({ }} /> Copy link - + {subject} {`#${ticketId}`} - + {isAdmin && isEdit ? ( = ({ ) : ( @@ -264,18 +264,18 @@ const FullTicketHeader: FC = ({ }} onClick={() => { setIsEdit(prevState => { - setFaculty(ticketFaculty); - setQueue(ticketQueue?.queue_id || -1); + setFaculty(ticketFaculty) + setQueue(ticketQueue?.queue_id || -1) setStatus(() => { const newStatus = statusesQuery.data.statuses_list.filter( status => status.status_id === ticketStatus?.status_id - ); + ) - return newStatus[0]; - }); + return newStatus[0] + }) - return !prevState; - }); + return !prevState + }) }} > {isEdit ? : } @@ -287,7 +287,7 @@ const FullTicketHeader: FC = ({ borderRadius: 1.5, }} onClick={() => { - setOpenDialog(true); + setOpenDialog(true) }} > {} @@ -297,18 +297,18 @@ const FullTicketHeader: FC = ({ {!isEdit ? ( @@ -346,12 +346,12 @@ const FullTicketHeader: FC = ({ @@ -361,8 +361,8 @@ const FullTicketHeader: FC = ({ )} {isEdit && ( - )} = ({ handleAccept={handleAccept} /> - ); -}; + ) +} -export { FullTicketHeader }; +export { FullTicketHeader } diff --git a/src/pages/FullTicketInfo/components/FullTicketHeader/components/StatusSelect/StatusSelect.tsx b/src/pages/FullTicketInfo/components/FullTicketHeader/components/StatusSelect/StatusSelect.tsx index 440235e..97f1c62 100644 --- a/src/pages/FullTicketInfo/components/FullTicketHeader/components/StatusSelect/StatusSelect.tsx +++ b/src/pages/FullTicketInfo/components/FullTicketHeader/components/StatusSelect/StatusSelect.tsx @@ -1,40 +1,41 @@ -import { FC, Dispatch, SetStateAction } from "react"; -import { UseQueryHookResult } from "@reduxjs/toolkit/dist/query/react/buildHooks"; +import { FC, Dispatch, SetStateAction } from 'react' +import { UseQueryHookResult } from '@reduxjs/toolkit/dist/query/react/buildHooks' import { BaseQueryFn, FetchBaseQueryError, QueryDefinition, -} from "@reduxjs/toolkit/query"; -import { FetchArgs } from "@reduxjs/toolkit/query"; +} from '@reduxjs/toolkit/query' +import { FetchArgs } from '@reduxjs/toolkit/query' +import { useTranslation } from 'react-i18next' -import Box from "@mui/material/Box"; -import FormControl from "@mui/material/FormControl"; -import ListItemText from "@mui/material/ListItemText"; -import MenuItem from "@mui/material/MenuItem"; -import Select, { SelectChangeEvent } from "@mui/material/Select"; -import useTheme from "@mui/material/styles/useTheme"; +import Box from '@mui/material/Box' +import FormControl from '@mui/material/FormControl' +import ListItemText from '@mui/material/ListItemText' +import MenuItem from '@mui/material/MenuItem' +import Select, { SelectChangeEvent } from '@mui/material/Select' +import useTheme from '@mui/material/styles/useTheme' -import { Loader } from "components/Loader"; +import { Loader } from 'components/Loader' -import IPalette from "theme/IPalette.interface"; +import IPalette from 'theme/IPalette.interface' interface StatusSelectProps { - status: IStatus; - setStatus: Dispatch>; + status: IStatus + setStatus: Dispatch> statusesQuery: UseQueryHookResult< QueryDefinition< any, BaseQueryFn, never, any, - "api" + 'api' > - >; + > } interface IStatus { - status_id: number; - name: string; + status_id: number + name: string } const StatusSelect: FC = ({ @@ -42,32 +43,33 @@ const StatusSelect: FC = ({ setStatus, statusesQuery, }) => { - const { palette }: IPalette = useTheme(); + const { t } = useTranslation() + const { palette }: IPalette = useTheme() const handleChange = (event: SelectChangeEvent): void => { - const selectedStatus: number = parseInt(event.target.value); + const selectedStatus: number = parseInt(event.target.value) setStatus( statusesQuery.data.statuses_list.filter( status => status.status_id === selectedStatus )[0] - ); - }; + ) + } return ( - {statusesQuery.isLoading && } + {statusesQuery.isLoading && } {statusesQuery.isSuccess && ( )} - ); -}; + ) +} -export { StatusSelect }; +export { StatusSelect } diff --git a/src/pages/Statistic/components/StatusesStatistic/StatusesStatistic.tsx b/src/pages/Statistic/components/StatusesStatistic/StatusesStatistic.tsx index 7102de3..15cfdec 100644 --- a/src/pages/Statistic/components/StatusesStatistic/StatusesStatistic.tsx +++ b/src/pages/Statistic/components/StatusesStatistic/StatusesStatistic.tsx @@ -1,40 +1,40 @@ -import { FC } from "react"; -import { useTranslation } from "react-i18next"; +import { FC } from 'react' +import { useTranslation } from 'react-i18next' -import { Chart as ChartJS, ArcElement, Tooltip } from "chart.js"; -import { Doughnut } from "react-chartjs-2"; +import { Chart as ChartJS, ArcElement, Tooltip } from 'chart.js' +import { Doughnut } from 'react-chartjs-2' -import Box from "@mui/material/Box"; +import Box from '@mui/material/Box' -import { StatisticCard } from "components/StatisticCard"; -import { StatusTile } from "./components/StatusTile"; +import { StatisticCard } from 'components/StatisticCard' +import { StatusTile } from './components/StatusTile' -import { IPeriodStatus } from "../../Statistic"; -import { statuses } from "constants/statuses"; +import { IPeriodStatus } from '../../Statistic' +import { statuses } from 'constants/statuses' -ChartJS.register(ArcElement, Tooltip); +ChartJS.register(ArcElement, Tooltip) interface StatusesStatisticProps { - statusesStatistic: IPeriodStatus[]; + statusesStatistic: IPeriodStatus[] } const StatusesStatistic: FC = ({ statusesStatistic, }) => { - const { t } = useTranslation(); + const { t } = useTranslation() const ticketsCount = statusesStatistic .map(status => status.tickets_count) - .reduce((partialSum, a) => partialSum + a, 0); + .reduce((partialSum, a) => partialSum + a, 0) const colors = { - [statuses.ACCEPTED]: "224, 156, 54", - [statuses.CLOSE]: "104, 182, 81", - [statuses.NEW]: "255, 255, 255", - [statuses.OPEN]: "41, 130, 211", - [statuses.REJECTED]: "217, 75, 68", - [statuses.WAITING]: "158, 61, 255", - }; + [statuses.ACCEPTED]: '224, 156, 54', + [statuses.CLOSED]: '104, 182, 81', + [statuses.NEW]: '255, 255, 255', + [statuses.OPEN]: '41, 130, 211', + [statuses.REJECTED]: '217, 75, 68', + [statuses.WAITING]: '158, 61, 255', + } const data = { labels: statusesStatistic.map(status => @@ -47,44 +47,44 @@ const StatusesStatistic: FC = ({ status => `rgba(${colors[status.name.toLowerCase()]}, 1)` ), borderWidth: 0, - cutout: "70%", + cutout: '70%', }, ], - }; + } const doughnutLabel = { - id: "doughnutLabel", + id: 'doughnutLabel', beforeDatasetsDraw(chart) { - const { ctx } = chart; - - ctx.save(); - const xCoord = chart.getDatasetMeta(0).data[0].x; - const yCoord = chart.getDatasetMeta(0).data[0].y; - ctx.font = "600 56px Inter"; - ctx.fillStyle = "rgba(255, 255, 255, 0.48)"; - ctx.textAlign = "center"; - ctx.textBaseline = "middle"; - ctx.fillText(ticketsCount, xCoord, yCoord - 10); - - ctx.font = "500 20px Inter"; - ctx.fillStyle = "rgba(255, 255, 255, 0.80)"; - ctx.fillText(t("common.tickets"), xCoord, yCoord + 30); + const { ctx } = chart + + ctx.save() + const xCoord = chart.getDatasetMeta(0).data[0].x + const yCoord = chart.getDatasetMeta(0).data[0].y + ctx.font = '600 56px Inter' + ctx.fillStyle = 'rgba(255, 255, 255, 0.48)' + ctx.textAlign = 'center' + ctx.textBaseline = 'middle' + ctx.fillText(ticketsCount, xCoord, yCoord - 10) + + ctx.font = '500 20px Inter' + ctx.fillStyle = 'rgba(255, 255, 255, 0.80)' + ctx.fillText(t('common.tickets'), xCoord, yCoord + 30) }, - }; + } return ( <> - + {statusesStatistic.map(status => { - const { tickets_count, name, status_id } = status; + const { tickets_count, name, status_id } = status return ( = ({ color={colors[name.toLowerCase()]} key={status_id} /> - ); + ) })} - ); -}; + ) +} -export { StatusesStatistic }; +export { StatusesStatistic } diff --git a/src/shared/hooks/useCheckStatus.ts b/src/shared/hooks/useCheckStatus.ts index 1b45914..ad273df 100644 --- a/src/shared/hooks/useCheckStatus.ts +++ b/src/shared/hooks/useCheckStatus.ts @@ -1,23 +1,23 @@ -import useTheme from "@mui/material/styles/useTheme"; +import useTheme from '@mui/material/styles/useTheme' -import IPalette from "theme/IPalette.interface"; -import { statuses } from "constants"; +import IPalette from 'theme/IPalette.interface' +import { statuses } from 'constants' const useCheckStatus = (status: string): string => { - const { palette }: IPalette = useTheme(); + const { palette }: IPalette = useTheme() const colorsMap = { [statuses.NEW]: palette.common.white, [statuses.ACCEPTED]: palette.semantic.warning, [statuses.OPEN]: palette.semantic.info, [statuses.WAITING]: palette.semantic.waiting, - [statuses.CLOSE]: palette.semantic.success, + [statuses.CLOSED]: palette.semantic.success, [statuses.REJECTED]: palette.semantic.error, - }; + } - const color = colorsMap[status.toLowerCase()]; + const color = colorsMap[status.toLowerCase()] - return color; -}; + return color +} -export { useCheckStatus }; +export { useCheckStatus } diff --git a/src/shared/hooks/useToggleAction.ts b/src/shared/hooks/useToggleAction.ts index e9d0b0f..f36c244 100644 --- a/src/shared/hooks/useToggleAction.ts +++ b/src/shared/hooks/useToggleAction.ts @@ -1,11 +1,11 @@ -import { Dispatch, SetStateAction, useCallback } from "react"; -import { MutationTrigger } from "@reduxjs/toolkit/dist/query/react/buildHooks"; +import { Dispatch, SetStateAction, useCallback } from 'react' +import { MutationTrigger } from '@reduxjs/toolkit/dist/query/react/buildHooks' import { BaseQueryFn, FetchArgs, FetchBaseQueryError, MutationDefinition, -} from "@reduxjs/toolkit/query"; +} from '@reduxjs/toolkit/query' interface toggleActionProps { toggleMutation: MutationTrigger< @@ -14,14 +14,14 @@ interface toggleActionProps { BaseQueryFn, never, any, - "api" + 'api' > - >; - option: string; - setState: Dispatch>; - ticketId: number; - dependencies: any; - callback?: Function; + > + option: string + setState: Dispatch> + ticketId: number + dependencies: any + callback?: Function } const useToggleAction = ({ @@ -36,14 +36,14 @@ const useToggleAction = ({ toggleMutation({ option: option, body: JSON.stringify({ ticket_id: ticketId }), - }); + }) - setState((prevState: boolean) => !prevState); + setState((prevState: boolean) => !prevState) - callback(); - }, [...dependencies]); + callback() + }, [...dependencies, ticketId]) - return handleToggleAction; -}; + return handleToggleAction +} -export { useToggleAction }; +export { useToggleAction }