From 0ccd035c0355be694b298bd17f3ca8b8ddcbf29e Mon Sep 17 00:00:00 2001 From: Yaroslav Usenko Date: Tue, 17 Dec 2024 14:35:11 +0200 Subject: [PATCH] Fix ping-pong function in chat ws --- .../StatusCheckboxGroup.tsx | 118 +++++----- .../hooks/useGetStatusesFullInfo.ts | 4 +- src/components/LogInModal/LogInModal.tsx | 68 +++--- .../CabinetAuthButton/CabinetAuthButton.tsx | 44 ++-- src/components/NotFound/NotFound.tsx | 56 ++--- src/components/SignUpModal/SignUpModal.tsx | 216 +++++++++--------- .../AccountDetailStep/AccountDetailStep.tsx | 86 +++---- src/components/SimpleTicket/SimpleTicket.tsx | 80 +++---- src/components/Ticket/Ticket.tsx | 22 +- .../components/TicketHeader/TicketHeader.tsx | 8 +- src/components/TicketRow/TicketRow.tsx | 108 ++++----- src/components/TicketRow/styles/useStyles.ts | 70 +++--- src/context/AuthContext/AuthContext.tsx | 22 +- src/context/AuthContext/hooks/useGetUser.ts | 107 +++++---- .../NotificationContext.tsx | 84 +++---- src/layouts/MainLayout/MainLayout.tsx | 60 ++--- .../MainLayout/components/Header/Header.tsx | 4 +- .../components/AuthActions/AuthActions.tsx | 18 +- .../MainLayout/components/Sidebar/Sidebar.tsx | 30 +-- .../components/CommonDrawer/CommonDrawer.tsx | 72 +++--- .../components/MobileDrawer/MobileDrawer.tsx | 70 +++--- .../SidebarActions/SidebarActions.tsx | 16 +- .../AdditionActions/AdditionActions.tsx | 60 ++--- .../GeneralActions/GeneralActions.tsx | 122 +++++----- .../NestedList/useGetListItemArray.tsx | 54 ++--- .../hooks/useRenderElements.tsx | 58 ++--- .../CreateTicketForm/CreateTicketForm.tsx | 106 ++++----- .../FacultySelect/FacultySelect.tsx | 70 +++--- .../components/FormActions/FormActions.tsx | 52 ++--- .../components/QueueSelect/QueueSelect.tsx | 86 +++---- .../TicketBodyTextField.tsx | 70 +++--- .../TicketTitleInput/TicketTitleInput.tsx | 58 ++--- src/pages/FullTicketInfo/FullTicketInfo.tsx | 20 +- .../FullTicketAdditionInfo.tsx | 8 +- .../FullTicketComments/FullTicketComments.tsx | 2 +- .../components/Action/Action.tsx | 112 ++++----- .../FullTicketHeader/FullTicketHeader.tsx | 30 +-- .../hooks/useCommentsConnection.ts | 83 +++---- .../NotificationTile/NotificationTile.tsx | 46 ++-- src/pages/Profile/Profile.tsx | 174 +++++++------- .../PasswordChangeSection.tsx | 44 ++-- .../ProfileHeader/ProfileHeader.tsx | 64 +++--- .../components/ProfileInput/ProfileInput.tsx | 36 +-- .../components/RolesSelect/RolesSelect.tsx | 76 +++--- src/pages/Queue/Queue.tsx | 124 +++++----- .../FacultySelect/FacultySelect.tsx | 60 ++--- src/pages/Queue/components/Scope/Scope.tsx | 58 ++--- .../ScopeTicketList/ScopeTicketList.tsx | 142 ++++++------ src/router/AdminRoute/AdminRoute.tsx | 14 +- src/router/PermissionRote/PermissionRote.tsx | 18 +- src/router/PrivateRoute/PrivateRoute.tsx | 14 +- src/router/Router.tsx | 94 ++++---- src/shared/functions/checkIsAdmin.ts | 18 +- src/shared/functions/clearLocalStorage.ts | 12 +- src/shared/functions/decodeJwt.ts | 34 +-- .../functions/manipulateLocalStorage.ts | 49 ++-- src/shared/hooks/useChangeURL.ts | 26 +-- src/shared/hooks/useCheckStatus.ts | 2 +- src/store/api/useBaseQuery.ts | 72 +++--- 59 files changed, 1763 insertions(+), 1768 deletions(-) diff --git a/src/components/FilterPanel/components/StatusCheckboxGroup/StatusCheckboxGroup.tsx b/src/components/FilterPanel/components/StatusCheckboxGroup/StatusCheckboxGroup.tsx index a9a3355..3331a5e 100644 --- a/src/components/FilterPanel/components/StatusCheckboxGroup/StatusCheckboxGroup.tsx +++ b/src/components/FilterPanel/components/StatusCheckboxGroup/StatusCheckboxGroup.tsx @@ -1,79 +1,79 @@ -import { FC, useEffect, useRef, useState } from "react"; -import { useTranslation } from "react-i18next"; +import { FC, useEffect, useRef, useState } from 'react' +import { useTranslation } from 'react-i18next' -import Box from "@mui/material/Box"; -import Button from "@mui/material/Button"; -import Divider from "@mui/material/Divider"; -import IconButton from "@mui/material/IconButton"; -import useMediaQuery from "@mui/material/useMediaQuery"; -import useTheme from "@mui/material/styles/useTheme"; +import Box from '@mui/material/Box' +import Button from '@mui/material/Button' +import Divider from '@mui/material/Divider' +import IconButton from '@mui/material/IconButton' +import useTheme from '@mui/material/styles/useTheme' +import useMediaQuery from '@mui/material/useMediaQuery' -import FilterAltIcon from "@mui/icons-material/FilterAlt"; +import FilterAltIcon from '@mui/icons-material/FilterAlt' -import { CustomCheckbox } from "./components/CustomCheckbox"; -import { VerticalDivider } from "components/VerticalDivider"; +import { VerticalDivider } from 'components/VerticalDivider' +import { CustomCheckbox } from './components/CustomCheckbox' -import { useGetStatusesFullInfo } from "./hooks/useGetStatusesFullInfo"; -import IPalette from "theme/IPalette.interface"; -import { dimensions, urlKeys } from "constants"; -import { useChangeURL } from "hooks/index"; +import { dimensions, urlKeys } from 'constants/index' +import { useChangeURL } from 'hooks/index' +import IPalette from 'theme/IPalette.interface' +import { useGetStatusesFullInfo } from './hooks/useGetStatusesFullInfo' interface StatusCheckboxGroupProps { - isAllStatuses: boolean; + isAllStatuses: boolean } const StatusCheckboxGroup: FC = ({ isAllStatuses, }) => { - const { t } = useTranslation(); - const { palette }: IPalette = useTheme(); + const { t } = useTranslation() + const { palette }: IPalette = useTheme() const matches = useMediaQuery( `(max-width: ${dimensions.BREAK_POINTS.STATUSES_FILTER}px)` - ); + ) - const [isOpen, setIsOpen] = useState(false); - const iconButtonRef = useRef(null); - const boxRef = useRef(null); + const [isOpen, setIsOpen] = useState(false) + const iconButtonRef = useRef(null) + const boxRef = useRef(null) - const putStatusesInURL = useChangeURL(); + const putStatusesInURL = useChangeURL() - const [statusesFullInfo, checked] = useGetStatusesFullInfo(isAllStatuses); - const isAllUnchecked: boolean = checked && !checked.some(value => value); + const [statusesFullInfo, checked] = useGetStatusesFullInfo(isAllStatuses) + const isAllUnchecked: boolean = checked && !checked.some(value => value) useEffect(() => { const handleClickOutside = event => { const isIconButtonClicked = - iconButtonRef.current && iconButtonRef.current.contains(event.target); + iconButtonRef.current && iconButtonRef.current.contains(event.target) const isBoxClicked = - boxRef.current && boxRef.current.contains(event.target); + boxRef.current && boxRef.current.contains(event.target) if (!isIconButtonClicked && !isBoxClicked) { - setIsOpen(false); + setIsOpen(false) } - }; + } - document.addEventListener("click", handleClickOutside); + document.addEventListener('click', handleClickOutside) return () => { - document.removeEventListener("click", handleClickOutside); - }; - }, [iconButtonRef, boxRef]); + document.removeEventListener('click', handleClickOutside) + } + }, [iconButtonRef, boxRef]) const handleParentChange = () => { - const updatedChecked = checked.map(() => false); + const updatedChecked = checked.map(() => false) 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 handleFilterOpen = () => { - setIsOpen(prevState => !prevState); - }; + setIsOpen(prevState => !prevState) + } return ( <> @@ -81,7 +81,7 @@ const StatusCheckboxGroup: FC = ({ = ({ - + {statusesFullInfo.map(status => { - return ; + return })} ) ) : ( - + - + {statusesFullInfo.map(status => { - return ; + return })} )} - ); -}; + ) +} -export { StatusCheckboxGroup }; +export { StatusCheckboxGroup } diff --git a/src/components/FilterPanel/components/StatusCheckboxGroup/hooks/useGetStatusesFullInfo.ts b/src/components/FilterPanel/components/StatusCheckboxGroup/hooks/useGetStatusesFullInfo.ts index 2959bf6..f201928 100644 --- a/src/components/FilterPanel/components/StatusCheckboxGroup/hooks/useGetStatusesFullInfo.ts +++ b/src/components/FilterPanel/components/StatusCheckboxGroup/hooks/useGetStatusesFullInfo.ts @@ -3,9 +3,9 @@ import { useSearchParams } from 'react-router-dom' import useTheme from '@mui/material/styles/useTheme' -import IPalette from 'theme/IPalette.interface' -import { statuses, urlKeys } from 'constants' +import { statuses, urlKeys } from 'constants/index' import { useChangeURL } from 'hooks/index' +import IPalette from 'theme/IPalette.interface' export interface IStatus { id: number diff --git a/src/components/LogInModal/LogInModal.tsx b/src/components/LogInModal/LogInModal.tsx index 51d4991..e0281e4 100644 --- a/src/components/LogInModal/LogInModal.tsx +++ b/src/components/LogInModal/LogInModal.tsx @@ -1,60 +1,60 @@ -import { useState, FC, Dispatch, SetStateAction } from "react"; +import { Dispatch, FC, SetStateAction, useState } from 'react' -import Modal from "@mui/material/Modal"; -import Box from "@mui/material/Box"; -import useMediaQuery from "@mui/material/useMediaQuery"; -import useTheme from "@mui/material/styles/useTheme"; +import Box from '@mui/material/Box' +import Modal from '@mui/material/Modal' +import useTheme from '@mui/material/styles/useTheme' +import useMediaQuery from '@mui/material/useMediaQuery' -import { SendEmailStep } from "./components/SendEmailStep"; -import { LoginStep } from "./components/LoginStep/LoginStep"; -import { ConfirmStep } from "./components/ConfirmStep"; +import { ConfirmStep } from './components/ConfirmStep' +import { LoginStep } from './components/LoginStep/LoginStep' +import { SendEmailStep } from './components/SendEmailStep' -import { dimensions } from "constants"; -import IPalette from "theme/IPalette.interface"; +import { dimensions } from 'constants/index' +import IPalette from 'theme/IPalette.interface' interface LogInModalProps { - open: boolean; - setOpen: Dispatch>; - handleSignUn: () => void; + open: boolean + setOpen: Dispatch> + handleSignUn: () => void } const LogInModal: FC = ({ open, setOpen, handleSignUn }) => { - const { palette }: IPalette = useTheme(); + const { palette }: IPalette = useTheme() const matches = useMediaQuery( `(max-width: ${dimensions.BREAK_POINTS.LOGIN_MODAL}px)` - ); + ) - const [activeStep, setActiveStep] = useState(0); + const [activeStep, setActiveStep] = useState(0) const handleClose = (): void => { - setOpen(false); - setActiveStep(0); - }; + setOpen(false) + setActiveStep(0) + } const wrapperStyle = { - flexDirection: "column", - alignItems: "center", - position: "absolute", - top: "50%", - left: "50%", - transform: "translate(-50%, -50%)", + flexDirection: 'column', + alignItems: 'center', + position: 'absolute', + top: '50%', + left: '50%', + transform: 'translate(-50%, -50%)', borderRadius: 4, gap: matches ? 3 : 4, - width: matches ? "90vw" : 450, + width: matches ? '90vw' : 450, bgcolor: palette.grey.border, border: `2px solid ${palette.grey.active}`, - p: matches ? "24px" : "32px 56px", - }; + p: matches ? '24px' : '32px 56px', + } return ( <> - + {activeStep === 0 && ( = ({ open, setOpen, handleSignUn }) => { - ); -}; + ) +} -export { LogInModal }; +export { LogInModal } diff --git a/src/components/LogInModal/components/LoginStep/components/CabinetAuthButton/CabinetAuthButton.tsx b/src/components/LogInModal/components/LoginStep/components/CabinetAuthButton/CabinetAuthButton.tsx index 68df174..0330b2f 100644 --- a/src/components/LogInModal/components/LoginStep/components/CabinetAuthButton/CabinetAuthButton.tsx +++ b/src/components/LogInModal/components/LoginStep/components/CabinetAuthButton/CabinetAuthButton.tsx @@ -1,12 +1,12 @@ -import { useTranslation } from "react-i18next"; +import { useTranslation } from 'react-i18next' -import Button from "@mui/material/Button"; +import Button from '@mui/material/Button' -import { general } from "constants"; +import { general } from 'constants/index' const CabinetAuthButton = () => { - const { t } = useTranslation(); - let authWindow: Window | null; + const { t } = useTranslation() + let authWindow: Window | null const popupWindow = ( url: string, @@ -15,43 +15,43 @@ const CabinetAuthButton = () => { h: number ) => { if (!window || !window.top) { - console.error("Window object or its top property is null or undefined"); - return null; + console.error('Window object or its top property is null or undefined') + return null } - const x = window.top.outerWidth / 2 + window.top.screenX - w / 2; - const y = window.top.outerHeight / 2 + window.top.screenY - h / 2; + const x = window.top.outerWidth / 2 + window.top.screenX - w / 2 + const y = window.top.outerHeight / 2 + window.top.screenY - h / 2 return window.open( url, windowName, `width=${w}, height=${h}, top=${y}, left=${x}` - ); - }; + ) + } const openAuth = () => { if (authWindow && !authWindow.closed) { - authWindow.focus(); + authWindow.focus() } else { authWindow = popupWindow( `https://cabinet.sumdu.edu.ua/index/service/${general.TRES_TOKEN}`, - "_self", + '_self', general.CABINET_POPUP_WIDTH, general.CABINET_POPUP_HEIGHT - ); + ) } - }; + } return ( - ); -}; + ) +} -export { CabinetAuthButton }; +export { CabinetAuthButton } diff --git a/src/components/NotFound/NotFound.tsx b/src/components/NotFound/NotFound.tsx index cd8f79f..e887af8 100644 --- a/src/components/NotFound/NotFound.tsx +++ b/src/components/NotFound/NotFound.tsx @@ -1,41 +1,41 @@ -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 Grid from "@mui/material/Grid"; -import Typography from "@mui/material/Typography"; -import useMediaQuery from "@mui/material/useMediaQuery"; -import useTheme from "@mui/material/styles/useTheme"; +import Grid from '@mui/material/Grid' +import useTheme from '@mui/material/styles/useTheme' +import Typography from '@mui/material/Typography' +import useMediaQuery from '@mui/material/useMediaQuery' -import notFound from "../../assets/not_found.svg"; -import { dimensions, endpoints } from "constants"; -import IPalette from "theme/IPalette.interface"; +import { dimensions, endpoints } from 'constants/index' +import IPalette from 'theme/IPalette.interface' +import notFound from '../../assets/not_found.svg' interface NotFoundProps { - size?: number; - title?: "tickets" | "notifications"; - withPostscript?: boolean; + size?: number + title?: 'tickets' | 'notifications' + withPostscript?: boolean } const NotFound: FC = ({ size = dimensions.NOT_FOUND_SIZE, - title = "tickets", + title = 'tickets', withPostscript = false, }) => { - const { t } = useTranslation(); - const { palette }: IPalette = useTheme(); + const { t } = useTranslation() + const { palette }: IPalette = useTheme() const matches = useMediaQuery( `(min-width: ${dimensions.BREAK_POINTS.NOT_FOUND}px)` - ); + ) return ( @@ -51,7 +51,7 @@ const NotFound: FC = ({ fontSize: { xs: 24, sm: 32 }, fontWeight: 500, ml: 1, - textAlign: "center", + textAlign: 'center', }} > {t(`common.notFound.${title}Title`)} @@ -61,27 +61,27 @@ const NotFound: FC = ({ - {t("common.notFound.postscript") + " "} + {t('common.notFound.postscript') + ' '} - {t("common.notFound.createLink")} + {t('common.notFound.createLink')} )} - ); -}; + ) +} -export { NotFound }; +export { NotFound } diff --git a/src/components/SignUpModal/SignUpModal.tsx b/src/components/SignUpModal/SignUpModal.tsx index 6ac336e..a45ebe9 100644 --- a/src/components/SignUpModal/SignUpModal.tsx +++ b/src/components/SignUpModal/SignUpModal.tsx @@ -1,117 +1,117 @@ import { - FormEvent, - useState, - FC, Dispatch, + FC, + FormEvent, SetStateAction, useEffect, -} from "react"; -import { useTranslation } from "react-i18next"; - -import Box from "@mui/material/Box"; -import Stepper from "@mui/material/Stepper"; -import Step from "@mui/material/Step"; -import StepLabel from "@mui/material/StepLabel"; -import Grid from "@mui/material/Grid"; -import Modal from "@mui/material/Modal"; -import useTheme from "@mui/material/styles/useTheme"; -import Typography from "@mui/material/Typography"; -import useMediaQuery from "@mui/material/useMediaQuery"; - -import { AccountDetailStep } from "./components/AccountDetailStep"; -import { Actions } from "./components/Actions"; -import { PersonalInfoStep } from "./components/PersonalInfoStep"; -import { VerificationStep } from "./components/VerificationStep"; - -import { useRegistrationMutation } from "api/registration.api"; -import IPalette from "theme/IPalette.interface"; -import { dimensions } from "constants"; + useState, +} from 'react' +import { useTranslation } from 'react-i18next' + +import Box from '@mui/material/Box' +import Grid from '@mui/material/Grid' +import Modal from '@mui/material/Modal' +import Step from '@mui/material/Step' +import StepLabel from '@mui/material/StepLabel' +import Stepper from '@mui/material/Stepper' +import useTheme from '@mui/material/styles/useTheme' +import Typography from '@mui/material/Typography' +import useMediaQuery from '@mui/material/useMediaQuery' + +import { AccountDetailStep } from './components/AccountDetailStep' +import { Actions } from './components/Actions' +import { PersonalInfoStep } from './components/PersonalInfoStep' +import { VerificationStep } from './components/VerificationStep' + +import { useRegistrationMutation } from 'api/registration.api' +import { dimensions } from 'constants/index' +import IPalette from 'theme/IPalette.interface' interface SignUpModalProps { - open: boolean; - setOpen: Dispatch>; - handleLogIn: () => void; + open: boolean + setOpen: Dispatch> + handleLogIn: () => void } interface ApiResponse { - data?: object; - error?: any; + data?: object + error?: any } export interface ISignUpData { - firstname: string; - lastname: string; - faculty: number | null; - login: string; - email: string; - password: string; - confirmedPassword: string; + firstname: string + lastname: string + faculty: number | null + login: string + email: string + password: string + confirmedPassword: string } const STEPS = { PERSONAL_INFO: 0, ACCOUNT_DETAIL: 1, VERIFICATION: 2, -}; +} const SignUpModal: FC = ({ open, setOpen, handleLogIn }) => { - const { t } = useTranslation(); - const { palette }: IPalette = useTheme(); + const { t } = useTranslation() + const { palette }: IPalette = useTheme() const matches = useMediaQuery( `(max-width: ${dimensions.BREAK_POINTS.SIGNUP_MODAL}px)` - ); + ) const steps = [ - t("signUp.firstStep"), - t("signUp.secondStep"), - t("signUp.thirdStep"), - ]; + t('signUp.firstStep'), + t('signUp.secondStep'), + t('signUp.thirdStep'), + ] - const [registration, { isError }] = useRegistrationMutation(); + const [registration, { isError }] = useRegistrationMutation() const [signUpData, setSignUpData] = useState({ - firstname: "", - lastname: "", + firstname: '', + lastname: '', faculty: null, - login: "", - email: "", - password: "", - confirmedPassword: "", - }); + login: '', + email: '', + password: '', + confirmedPassword: '', + }) - const [secretKey, setSecretKey] = useState(""); - const [hasError, setHasError] = useState(false); - const [activeStep, setActiveStep] = useState(STEPS.PERSONAL_INFO); - const [errorMessage, setErrorMessage] = useState(""); + const [secretKey, setSecretKey] = useState('') + const [hasError, setHasError] = useState(false) + const [activeStep, setActiveStep] = useState(STEPS.PERSONAL_INFO) + const [errorMessage, setErrorMessage] = useState('') const handleClear = (): void => { - setActiveStep(0); + setActiveStep(0) setSignUpData({ - firstname: "", - lastname: "", + firstname: '', + lastname: '', faculty: null, - login: "", - email: "", - password: "", - confirmedPassword: "", - }); - setSecretKey(""); - setHasError(false); - }; + login: '', + email: '', + password: '', + confirmedPassword: '', + }) + setSecretKey('') + setHasError(false) + } const handleClose = (): void => { - setOpen(false); - }; + setOpen(false) + } const handleOpenLogInModal = (): void => { - handleClose(); - handleLogIn(); - }; + handleClose() + handleLogIn() + } const handleSubmit = async (event: FormEvent): Promise => { - event.preventDefault(); + event.preventDefault() - const { firstname, lastname, faculty, login, email, password } = signUpData; + const { firstname, lastname, faculty, login, email, password } = signUpData const response: ApiResponse = await registration({ body: JSON.stringify({ @@ -122,72 +122,72 @@ const SignUpModal: FC = ({ open, setOpen, handleLogIn }) => { email, password, }), - }); + }) if (response.data) { - setActiveStep(prevActiveStep => prevActiveStep + 1); + setActiveStep(prevActiveStep => prevActiveStep + 1) } else { - response?.error?.data && setErrorMessage(response.error.data.detail); - setHasError(true); - setTimeout(() => setHasError(false), 4000); + response?.error?.data && setErrorMessage(response.error.data.detail) + setHasError(true) + setTimeout(() => setHasError(false), 4000) } - }; + } useEffect(() => { if (isError) { - setHasError(true); - setTimeout(() => setHasError(false), 2000); + setHasError(true) + setTimeout(() => setHasError(false), 2000) } - }, [isError]); + }, [isError]) return (
- - {t("signUp.header")} + + {t('signUp.header')} {steps.map(label => { - const stepProps: { completed?: boolean } = {}; + const stepProps: { completed?: boolean } = {} return ( {label} - ); + ) })} {activeStep === STEPS.PERSONAL_INFO && ( = ({ open, setOpen, handleLogIn }) => { - {t("signUp.question")} + {t('signUp.question')} - {t("common.login")} + {t('common.login')} )}
- ); -}; + ) +} -export { SignUpModal }; +export { SignUpModal } diff --git a/src/components/SignUpModal/components/AccountDetailStep/AccountDetailStep.tsx b/src/components/SignUpModal/components/AccountDetailStep/AccountDetailStep.tsx index 0796ad1..cdedb04 100644 --- a/src/components/SignUpModal/components/AccountDetailStep/AccountDetailStep.tsx +++ b/src/components/SignUpModal/components/AccountDetailStep/AccountDetailStep.tsx @@ -1,42 +1,42 @@ -import { Dispatch, FC, SetStateAction, useState } from "react"; -import { useTranslation } from "react-i18next"; -import { NavLink } from "react-router-dom"; +import { Dispatch, FC, SetStateAction, useState } from 'react' +import { useTranslation } from 'react-i18next' +import { NavLink } from 'react-router-dom' -import Typography from "@mui/material/Typography"; -import TextField from "@mui/material/TextField"; -import useTheme from "@mui/material/styles/useTheme"; +import TextField from '@mui/material/TextField' +import Typography from '@mui/material/Typography' +import useTheme from '@mui/material/styles/useTheme' -import { SignUpTextField } from "../SignUpTextField"; +import { SignUpTextField } from '../SignUpTextField' -import { endpoints } from "constants"; -import IPalette from "theme/IPalette.interface"; -import { ISignUpData } from "../../SignUpModal"; +import { endpoints } from 'constants/index' +import IPalette from 'theme/IPalette.interface' +import { ISignUpData } from '../../SignUpModal' interface AccountDetailStepProps { - signUpData: ISignUpData; - setSignUpData: Dispatch>; - errorMessage: string; + signUpData: ISignUpData + setSignUpData: Dispatch> + errorMessage: string } const ACTION_TYPES = { - LOGIN: "login", - EMAIL: "email", - PASSWORD: "password", -}; + LOGIN: 'login', + EMAIL: 'email', + PASSWORD: 'password', +} const AccountDetailStep: FC = ({ signUpData, setSignUpData, errorMessage, }) => { - const { t } = useTranslation(); - const { palette }: IPalette = useTheme(); + const { t } = useTranslation() + const { palette }: IPalette = useTheme() - const [isConfirmed, setIsConfirmed] = useState(true); + const [isConfirmed, setIsConfirmed] = useState(true) const checkError = (word: string) => { - return errorMessage.includes(word); - }; + return errorMessage.includes(word) + } const renderSignUpTextField = ( type: string, @@ -48,9 +48,9 @@ const AccountDetailStep: FC = ({ value={value} setValue={setValue} hasError={checkError(type)} - helperText={checkError(type) ? errorMessage : ""} + helperText={checkError(type) ? errorMessage : ''} /> - ); + ) return ( <> @@ -70,29 +70,29 @@ const AccountDetailStep: FC = ({ setSignUpData )} { - const newPassword = event.target.value; + const newPassword = event.target.value setSignUpData(prevState => ({ ...prevState, confirmedPassword: newPassword, - })); - setIsConfirmed(signUpData.password === newPassword); + })) + setIsConfirmed(signUpData.password === newPassword) }} error={!isConfirmed} required - autoComplete={"new-confirmPassword"} + autoComplete={'new-confirmPassword'} fullWidth - type="password" + type='password' sx={{ - ".MuiFormLabel-root": { + '.MuiFormLabel-root': { top: 4, }, - ".MuiInputBase-input": { - p: "12px 14px", + '.MuiInputBase-input': { + p: '12px 14px', }, }} /> @@ -100,23 +100,23 @@ const AccountDetailStep: FC = ({ fontSize={14} sx={{ mt: 2, - width: "100%", - textAlign: "center", + width: '100%', + textAlign: 'center', color: palette.whiteAlpha.default, }} > - {t("privacyPolicy.postscript.1")} + {t('privacyPolicy.postscript.1')} - {t("privacyPolicy.postscript.link")} + {t('privacyPolicy.postscript.link')} - {t("privacyPolicy.postscript.2")} + {t('privacyPolicy.postscript.2')} - ); -}; + ) +} -export { AccountDetailStep }; +export { AccountDetailStep } diff --git a/src/components/SimpleTicket/SimpleTicket.tsx b/src/components/SimpleTicket/SimpleTicket.tsx index d27128d..19c9d50 100644 --- a/src/components/SimpleTicket/SimpleTicket.tsx +++ b/src/components/SimpleTicket/SimpleTicket.tsx @@ -1,67 +1,67 @@ -import { ForwardRefExoticComponent, RefAttributes, forwardRef } from "react"; -import { useNavigate } from "react-router-dom"; +import { ForwardRefExoticComponent, RefAttributes, forwardRef } from 'react' +import { useNavigate } from 'react-router-dom' -import Box from "@mui/material/Box"; -import Typography from "@mui/material/Typography"; -import useTheme from "@mui/material/styles/useTheme"; +import Box from '@mui/material/Box' +import Typography from '@mui/material/Typography' +import useTheme from '@mui/material/styles/useTheme' -import { Badge } from "components/Badge"; +import { Badge } from 'components/Badge' -import { endpoints } from "constants"; -import { useFormatDate } from "hooks/index"; -import IPalette from "theme/IPalette.interface"; -import { ITicket } from "./ticket.interface"; +import { endpoints } from 'constants/index' +import { useFormatDate } from 'hooks/index' +import IPalette from 'theme/IPalette.interface' +import { ITicket } from './ticket.interface' interface SimpleTicketProps { - ticket: ITicket; + ticket: ITicket } const SimpleTicket: ForwardRefExoticComponent< - Omit & RefAttributes + Omit & RefAttributes > = forwardRef(({ ticket }, ref) => { - const { palette }: IPalette = useTheme(); - const navigate = useNavigate(); + const { palette }: IPalette = useTheme() + const navigate = useNavigate() - const formattedDate: string = ticket?.date && useFormatDate(ticket.date); + const formattedDate: string = ticket?.date && useFormatDate(ticket.date) const handleClick = (): void => { - navigate(`${endpoints.FULL_TICKET}/${ticket.ticket_id}`); - }; + navigate(`${endpoints.FULL_TICKET}/${ticket.ticket_id}`) + } return ( {ticket.subject} @@ -81,15 +81,15 @@ const SimpleTicket: ForwardRefExoticComponent< {ticket.body} - + {ticket.faculty.name} @@ -112,7 +112,7 @@ const SimpleTicket: ForwardRefExoticComponent< - ); -}); + ) +}) -export { SimpleTicket }; +export { SimpleTicket } diff --git a/src/components/Ticket/Ticket.tsx b/src/components/Ticket/Ticket.tsx index 5924102..e0b531a 100644 --- a/src/components/Ticket/Ticket.tsx +++ b/src/components/Ticket/Ticket.tsx @@ -1,29 +1,29 @@ -import { MouseEvent, useState, FC, ComponentType, useEffect, memo } from 'react' +import { ComponentType, FC, memo, MouseEvent, useEffect, useState } 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 Divider from '@mui/material/Divider' import { SlideProps } from '@mui/material/Slide' +import useTheme from '@mui/material/styles/useTheme' -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 { SnackbarNotification } from 'components/SnackbarNotification' +import { TicketActions } from './components/TicketActions' +import { TicketBody } from './components/TicketBody' +import { TicketHeader } from './components/TicketHeader' import { useToggleBookmarkMutation, useToggleLikeMutation, } from 'api/tickets.api' -import { endpoints, toggleOptions } from 'constants' +import { endpoints, toggleOptions } from 'constants/index' +import { useAuth } from 'context/AuthContext/AuthContext' +import { getUser } from 'functions/manipulateLocalStorage' import { useCheckStatus, useFormatDate } from 'hooks/index' +import { useToggleAction } from 'hooks/useToggleAction' 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 diff --git a/src/components/Ticket/components/TicketHeader/TicketHeader.tsx b/src/components/Ticket/components/TicketHeader/TicketHeader.tsx index 2619197..ae892f0 100644 --- a/src/components/Ticket/components/TicketHeader/TicketHeader.tsx +++ b/src/components/Ticket/components/TicketHeader/TicketHeader.tsx @@ -7,13 +7,13 @@ 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 IPalette from 'theme/IPalette.interface' -import { endpoints, statuses } from 'constants' -import { useAuth } from 'context/AuthContext/AuthContext' import { useFormatName } from 'components/Ticket/hooks/useFormatName' +import { endpoints, statuses } from 'constants/index' +import { useAuth } from 'context/AuthContext/AuthContext' +import IPalette from 'theme/IPalette.interface' export interface IAssignee { faculty: { faculty_id: number; name: string } diff --git a/src/components/TicketRow/TicketRow.tsx b/src/components/TicketRow/TicketRow.tsx index 638fccf..be00089 100644 --- a/src/components/TicketRow/TicketRow.tsx +++ b/src/components/TicketRow/TicketRow.tsx @@ -1,83 +1,83 @@ -import { MouseEvent, FC, useState, Dispatch, SetStateAction } from "react"; -import { useNavigate } from "react-router-dom"; -import { useTranslation } from "react-i18next"; +import { Dispatch, FC, MouseEvent, SetStateAction, useState } from 'react' +import { useTranslation } from 'react-i18next' +import { useNavigate } from 'react-router-dom' -import Grid from "@mui/material/Grid"; -import Box from "@mui/material/Box"; -import Typography from "@mui/material/Typography"; -import Tooltip from "@mui/material/Tooltip"; -import useTheme from "@mui/material/styles/useTheme"; -import useMediaQuery from "@mui/material/useMediaQuery"; +import Box from '@mui/material/Box' +import Grid from '@mui/material/Grid' +import Tooltip from '@mui/material/Tooltip' +import Typography from '@mui/material/Typography' +import useTheme from '@mui/material/styles/useTheme' +import useMediaQuery from '@mui/material/useMediaQuery' -import { TicketActions } from "./components/TicketActions"; -import { AdditionalInfo } from "./components/AdditionalInfo"; -import { DeletionActions } from "./components/DeletionActions"; +import { AdditionalInfo } from './components/AdditionalInfo' +import { DeletionActions } from './components/DeletionActions' +import { TicketActions } from './components/TicketActions' -import { dimensions, endpoints } from "constants"; -import { useCheckScope } from "hooks/index"; -import IPalette from "theme/IPalette.interface"; -import { ITicket } from "./ticket.interface"; -import { useStyles } from "./styles/useStyles"; +import { dimensions, endpoints } from 'constants/index' +import { useCheckScope } from 'hooks/index' +import IPalette from 'theme/IPalette.interface' +import { useStyles } from './styles/useStyles' +import { ITicket } from './ticket.interface' interface TicketRowProps { - ticket: ITicket; - additionalAction?: string; - isHaveBookmarks?: boolean; - handleDelete: ((ticketId: number[]) => void) | null; - handleRestore: ((ticketId: number) => void) | null; - setDeletedList: Dispatch> | null; + ticket: ITicket + additionalAction?: string + isHaveBookmarks?: boolean + handleDelete: ((ticketId: number[]) => void) | null + handleRestore: ((ticketId: number) => void) | null + setDeletedList: Dispatch> | null } const TicketRow: FC = ({ ticket, - additionalAction = "", + additionalAction = '', isHaveBookmarks = false, handleDelete, handleRestore, setDeletedList, }) => { - const { i18n } = useTranslation(); - const { palette }: IPalette = useTheme(); - const navigate = useNavigate(); + const { i18n } = useTranslation() + const { palette }: IPalette = useTheme() + const navigate = useNavigate() const matches = useMediaQuery( `(min-width: ${dimensions.BREAK_POINTS.SIMPLE_TICKET}px)` - ); + ) const [isBookmarked, setIsBookmarked] = useState( ticket.is_bookmarked - ); + ) const [ticketRowStyles, gridColumnStyles, tooltipStyles] = useStyles({ ticketStatus: ticket.status.name, isHaveBookmarks, matches, language: i18n.language, - }); + }) - const isSent = additionalAction === "sent"; - const isDeleted = additionalAction === "deleted"; + const isSent = additionalAction === 'sent' + const isDeleted = additionalAction === 'deleted' const { icon, tooltipText }: { icon: JSX.Element; tooltipText: string } = - useCheckScope(ticket.queue?.scope); + useCheckScope(ticket.queue?.scope) 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') ) { - navigate(`${endpoints.FULL_TICKET}/${ticket.ticket_id}`); + navigate(`${endpoints.FULL_TICKET}/${ticket.ticket_id}`) } - }; + } return ( @@ -93,11 +93,11 @@ const TicketRow: FC = ({ setIsBookmarked={setIsBookmarked} /> - {ticket.subject} + {ticket.subject} {ticket.body} @@ -117,14 +117,14 @@ const TicketRow: FC = ({ @@ -139,17 +139,17 @@ const TicketRow: FC = ({ {ticket.subject} @@ -176,7 +176,7 @@ const TicketRow: FC = ({ ticketId={ticket.ticket_id} /> - ); -}; + ) +} -export { TicketRow }; +export { TicketRow } diff --git a/src/components/TicketRow/styles/useStyles.ts b/src/components/TicketRow/styles/useStyles.ts index 5af9f49..aa4bb5f 100644 --- a/src/components/TicketRow/styles/useStyles.ts +++ b/src/components/TicketRow/styles/useStyles.ts @@ -1,14 +1,14 @@ -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 { useCheckStatus } from "hooks/index"; +import { statuses } from 'constants/index' +import { useCheckStatus } from 'hooks/index' +import IPalette from 'theme/IPalette.interface' interface StyleProps { - ticketStatus: string; - isHaveBookmarks: boolean; - matches: boolean; - language: string; + ticketStatus: string + isHaveBookmarks: boolean + matches: boolean + language: string } const useStyles = ({ @@ -17,61 +17,61 @@ const useStyles = ({ matches, language, }: StyleProps) => { - const { palette }: IPalette = useTheme(); + const { palette }: IPalette = useTheme() - const color: string = useCheckStatus(ticketStatus); + const color: string = useCheckStatus(ticketStatus) const ticketRowStyles = { gap: 1, - flexWrap: "no-wrap", - "& > div, button": { + flexWrap: 'no-wrap', + '& > div, button': { bgcolor: ticketStatus === statuses.NEW ? palette.grey.divider : palette.grey.card, border: `2px solid ${palette.grey.border}`, - overflow: "hidden", + overflow: 'hidden', }, - "& > .MuiGrid-root > .MuiBox-root": { - p: isHaveBookmarks ? "16px" : "16px 16px 16px 8px", + '& > .MuiGrid-root > .MuiBox-root': { + p: isHaveBookmarks ? '16px' : '16px 16px 16px 8px', }, - }; + } const gridColumnStyles = { - display: matches ? "grid" : "flex", - flexDirection: "column", - alignItems: "center", + display: matches ? 'grid' : 'flex', + flexDirection: 'column', + alignItems: 'center', gridTemplateColumns: - language === "en" + language === 'en' ? `${ - isHaveBookmarks ? "48px" : "0px" + isHaveBookmarks ? '48px' : '0px' } minmax(30px, 1fr) minmax(40px, 3fr) 25px 45px 100px` : `${ - isHaveBookmarks ? "48px" : "0px" + isHaveBookmarks ? '48px' : '0px' } minmax(30px, 0.9fr) minmax(40px, 3fr) 25px 45px 115px`, gap: 2, borderLeft: `8px solid ${color}`, - "& .MuiTypography-root": { - overflow: "hidden", - whiteSpace: "nowrap", - textOverflow: "ellipsis", + '& .MuiTypography-root': { + overflow: 'hidden', + whiteSpace: 'nowrap', + textOverflow: 'ellipsis', }, - }; + } const tooltipStyles = { - display: "flex", - alignItems: "center", - justifyContent: "center", + display: 'flex', + alignItems: 'center', + justifyContent: 'center', width: 24, height: 24, bgcolor: palette.grey.active, borderRadius: 1, - ".MuiSvgIcon-root": { + '.MuiSvgIcon-root': { fontSize: 16, }, - }; + } - return [ticketRowStyles, gridColumnStyles, tooltipStyles]; -}; + return [ticketRowStyles, gridColumnStyles, tooltipStyles] +} -export { useStyles }; +export { useStyles } diff --git a/src/context/AuthContext/AuthContext.tsx b/src/context/AuthContext/AuthContext.tsx index 68363d4..71148dc 100644 --- a/src/context/AuthContext/AuthContext.tsx +++ b/src/context/AuthContext/AuthContext.tsx @@ -1,28 +1,28 @@ +import { SerializedError } from '@reduxjs/toolkit' +import { FetchBaseQueryError } from '@reduxjs/toolkit/dist/query' import { + Dispatch, ReactNode, + SetStateAction, createContext, useContext, - useState, useEffect, - Dispatch, - SetStateAction, + useState, } from 'react' -import { FetchBaseQueryError } from '@reduxjs/toolkit/dist/query' -import { SerializedError } from '@reduxjs/toolkit' import { useNavigate, useSearchParams } from 'react-router-dom' -import { - getAccessToken, - getIsTokensExpired, -} from 'functions/manipulateLocalStorage' -import { clearLocalStorage } from 'functions/index' import { useCabinetLoginMutation, useCabinetLogoutMutation, useLoginMutation, } from 'api/auth.api' +import { general } from 'constants/index' +import { clearLocalStorage } from 'functions/index' +import { + getAccessToken, + getIsTokensExpired, +} from 'functions/manipulateLocalStorage' import { useGetUser } from './hooks/useGetUser' -import { general } from 'constants' interface AuthContextProps { isAuth: boolean diff --git a/src/context/AuthContext/hooks/useGetUser.ts b/src/context/AuthContext/hooks/useGetUser.ts index 7d4d600..e9f630b 100644 --- a/src/context/AuthContext/hooks/useGetUser.ts +++ b/src/context/AuthContext/hooks/useGetUser.ts @@ -1,99 +1,96 @@ -import { Dispatch, SetStateAction, useCallback } from "react"; -import { FetchBaseQueryError } from "@reduxjs/toolkit/dist/query"; -import { SerializedError } from "@reduxjs/toolkit"; +import { SerializedError } from '@reduxjs/toolkit' +import { FetchBaseQueryError } from '@reduxjs/toolkit/dist/query' +import { Dispatch, SetStateAction, useCallback } from 'react' -import { ILoginInfo } from "../AuthContext"; -import { decodeJwt } from "functions/index"; -import { getUser as getLocalStorageUser } from "functions/manipulateLocalStorage"; -import { useGetProfileMutation } from "api/profile.api"; -import { storage } from "constants"; +import { useGetProfileMutation } from 'api/profile.api' +import { storage } from 'constants/index' +import { decodeJwt } from 'functions/index' +import { getUser as getLocalStorageUser } from 'functions/manipulateLocalStorage' +import { ILoginInfo } from '../AuthContext' interface UserInfoProps { data?: { - firstname: string; - lastname: string; - login: string; + firstname: string + lastname: string + login: string faculty: { - faculty_id: number; - name: string; - }; + faculty_id: number + name: string + } group: { - group_id: number; - name: string; - }; - phone: null; - email: null; - registration_date: string; + group_id: number + name: string + } + phone: null + email: null + registration_date: string role: { - name: string; - permission_list: string[]; - role_id: number; - }; - }; - error?: FetchBaseQueryError | SerializedError; + name: string + permission_list: string[] + role_id: number + } + } + error?: FetchBaseQueryError | SerializedError } const useGetUser = (setIsAuth: Dispatch>) => { - const [getProfile] = useGetProfileMutation(); + const [getProfile] = useGetProfileMutation() const getUser = useCallback((loginInfo: ILoginInfo) => { try { const getUserData = async (accessToken: string) => { - decodeJwt(accessToken); + decodeJwt(accessToken) - const user = getLocalStorageUser(); - const userId = user?.userId; + const user = getLocalStorageUser() + const userId = user?.userId const { data: userInfo }: UserInfoProps = await getProfile({ userId: userId, - }); + }) if (userInfo?.faculty?.faculty_id) { - user[storage.USER.FACULTY_ID] = userInfo.faculty.faculty_id; + user[storage.USER.FACULTY_ID] = userInfo.faculty.faculty_id } if (userInfo?.firstname && userInfo?.lastname) { - user[ - storage.USER.NAME - ] = `${userInfo.firstname} ${userInfo.lastname}`; + user[storage.USER.NAME] = `${userInfo.firstname} ${userInfo.lastname}` } if (userInfo?.login) { - user[storage.USER.LOGIN] = userInfo.login; + user[storage.USER.LOGIN] = userInfo.login } if (userInfo?.role) { - const role = storage.USER.ROLE; + const role = storage.USER.ROLE - user[role.FIELD_KEY] = {}; - user[role.FIELD_KEY][role.ID] = userInfo.role.role_id; - user[role.FIELD_KEY][role.NAME] = userInfo.role.name; - user[role.FIELD_KEY][role.PERMISSIONS] = - userInfo.role.permission_list; + user[role.FIELD_KEY] = {} + user[role.FIELD_KEY][role.ID] = userInfo.role.role_id + user[role.FIELD_KEY][role.NAME] = userInfo.role.name + user[role.FIELD_KEY][role.PERMISSIONS] = userInfo.role.permission_list } - localStorage.setItem(storage.USER.FIELD_KEY, JSON.stringify(user)); + localStorage.setItem(storage.USER.FIELD_KEY, JSON.stringify(user)) - setIsAuth(true); - }; + setIsAuth(true) + } - if (typeof loginInfo === "string") { - getUserData(loginInfo); - } else if (typeof loginInfo === "object") { + if (typeof loginInfo === 'string') { + getUserData(loginInfo) + } else if (typeof loginInfo === 'object') { if (loginInfo?.refresh_token) { - localStorage.setItem(storage.REFRESH_TOKEN, loginInfo?.refresh_token); + localStorage.setItem(storage.REFRESH_TOKEN, loginInfo?.refresh_token) } if (loginInfo?.access_token) { - getUserData(loginInfo?.access_token); + getUserData(loginInfo?.access_token) } } } catch { - alert("Something went wrong!"); + alert('Something went wrong!') } - }, []); + }, []) - return getUser; -}; + return getUser +} -export { useGetUser }; +export { useGetUser } diff --git a/src/context/NotificationContext/NotificationContext.tsx b/src/context/NotificationContext/NotificationContext.tsx index beb6b41..d1f0e44 100644 --- a/src/context/NotificationContext/NotificationContext.tsx +++ b/src/context/NotificationContext/NotificationContext.tsx @@ -1,89 +1,89 @@ +import { SerializedError } from '@reduxjs/toolkit' +import { FetchBaseQueryError } from '@reduxjs/toolkit/dist/query' import { - useEffect, - useState, + Dispatch, ReactNode, + SetStateAction, createContext, useContext, - Dispatch, - SetStateAction, -} from "react"; -import { FetchBaseQueryError } from "@reduxjs/toolkit/dist/query"; -import { SerializedError } from "@reduxjs/toolkit"; + useEffect, + useState, +} from 'react' -import { useAuth } from "../AuthContext/AuthContext"; -import { useGetNotificationsMutation } from "api/notifications.api"; -import { handleWebSocketMessage } from "./functions/handleWebSocketMessage"; -import { stackCommentNotifications } from "./functions/stackCommentNotifications"; -import { useWebSocket } from "./hooks/useWebSocket"; -import { endpoints } from "constants"; +import { useGetNotificationsMutation } from 'api/notifications.api' +import { endpoints } from 'constants/index' +import { useAuth } from '../AuthContext/AuthContext' +import { handleWebSocketMessage } from './functions/handleWebSocketMessage' +import { stackCommentNotifications } from './functions/stackCommentNotifications' +import { useWebSocket } from './hooks/useWebSocket' interface NotificationContextProps { - notifications: INotification[]; - setNotifications: Dispatch>; - countOfNotification: number; + notifications: INotification[] + setNotifications: Dispatch> + countOfNotification: number } export interface INotification { - body: string; - body_ua: string; - ticket_id: number; - user_id: number; - count?: number; + body: string + body_ua: string + ticket_id: number + user_id: number + count?: number } type ApiResponse = { data?: { - notifications: INotification[]; - }; - error?: FetchBaseQueryError | SerializedError; -}; + notifications: INotification[] + } + error?: FetchBaseQueryError | SerializedError +} -const NotificationContext = createContext({} as NotificationContextProps); +const NotificationContext = createContext({} as NotificationContextProps) -export default NotificationContext; +export default NotificationContext export const NotificationProvider = ({ children }: { children: ReactNode }) => { - const { isAuth } = useAuth(); - const [notifications, setNotifications] = useState([]); + const { isAuth } = useAuth() + const [notifications, setNotifications] = useState([]) useWebSocket(endpoints.WS_URL, isAuth, data => handleWebSocketMessage(data, setNotifications) - ); + ) - const [getNotifications] = useGetNotificationsMutation({}); + const [getNotifications] = useGetNotificationsMutation({}) useEffect(() => { isAuth && getNotifications({}) .then((res: ApiResponse) => { - const notificationsData = res?.data?.notifications; + const notificationsData = res?.data?.notifications if (notificationsData) { - const stackComments = stackCommentNotifications(notificationsData); + const stackComments = stackCommentNotifications(notificationsData) setNotifications(prevNotifications => [ ...stackComments, ...prevNotifications, - ]); + ]) } }) .catch(err => { - console.error(err); - }); - }, [isAuth]); + console.error(err) + }) + }, [isAuth]) const contextData = { notifications, setNotifications, countOfNotification: notifications.length, - }; + } return ( {children} - ); -}; + ) +} export const useNotification = () => { - return useContext(NotificationContext); -}; + return useContext(NotificationContext) +} diff --git a/src/layouts/MainLayout/MainLayout.tsx b/src/layouts/MainLayout/MainLayout.tsx index 49780a9..20d022b 100644 --- a/src/layouts/MainLayout/MainLayout.tsx +++ b/src/layouts/MainLayout/MainLayout.tsx @@ -1,30 +1,30 @@ -import { useState, FC, Suspense, lazy } from "react"; -import { Outlet } from "react-router-dom"; +import { FC, Suspense, lazy, useState } from 'react' +import { Outlet } from 'react-router-dom' -import Box from "@mui/material/Box"; -import useTheme from "@mui/material/styles/useTheme"; +import Box from '@mui/material/Box' +import useTheme from '@mui/material/styles/useTheme' -import { ErrorBoundary } from "components/ErrorBoundary"; -import { Loader } from "components/Loader"; +import { ErrorBoundary } from 'components/ErrorBoundary' +import { Loader } from 'components/Loader' -import IPalette from "theme/IPalette.interface"; -import { dimensions } from "constants"; +import { dimensions } from 'constants/index' +import IPalette from 'theme/IPalette.interface' -const Header = lazy(() => import("./components/Header")); -const Sidebar = lazy(() => import("./components/Sidebar")); +const Header = lazy(() => import('./components/Header')) +const Sidebar = lazy(() => import('./components/Sidebar')) const MainLayout: FC = () => { - const [mobileOpen, setMobileOpen] = useState(false); - const { palette }: IPalette = useTheme(); + const [mobileOpen, setMobileOpen] = useState(false) + const { palette }: IPalette = useTheme() - const drawerWidth = dimensions.DRAWER_WIDTH; + const drawerWidth = dimensions.DRAWER_WIDTH const handleDrawerToggle = (): void => { - setMobileOpen(!mobileOpen); - }; + setMobileOpen(!mobileOpen) + } return ( - +
{ handleDrawerToggle={handleDrawerToggle} /> .MuiGrid-root": { - flexWrap: { sm: "wrap", xs: "nowrap" }, + '& > .MuiGrid-root': { + flexWrap: { sm: 'wrap', xs: 'nowrap' }, }, - "& > .MuiGrid-root > .MuiBox-root:first-of-type": { - position: "fixed", + '& > .MuiGrid-root > .MuiBox-root:first-of-type': { + position: 'fixed', left: { xs: 0, md: drawerWidth }, right: 0, - p: { xs: "16px 16px 8px", sm: "16px 24px" }, + p: { xs: '16px 16px 8px', sm: '16px 24px' }, bgcolor: palette.grey.background, zIndex: 100, - "& > .MuiTypography-root": { + '& > .MuiTypography-root': { fontSize: { xs: 30, sm: 40 }, mb: { xs: 2, sm: 0 }, }, }, - "& > .MuiGrid-root > .MuiBox-root:nth-of-type(2)": { + '& > .MuiGrid-root > .MuiBox-root:nth-of-type(2)': { pt: { xs: 16, sm: 17 }, }, }} @@ -68,7 +68,7 @@ const MainLayout: FC = () => { - ); -}; + ) +} -export { MainLayout }; +export { MainLayout } diff --git a/src/layouts/MainLayout/components/Header/Header.tsx b/src/layouts/MainLayout/components/Header/Header.tsx index 41db15e..5e19534 100644 --- a/src/layouts/MainLayout/components/Header/Header.tsx +++ b/src/layouts/MainLayout/components/Header/Header.tsx @@ -8,12 +8,12 @@ import IconButton from '@mui/material/IconButton' import Toolbar from '@mui/material/Toolbar' import useTheme from '@mui/material/styles/useTheme' -import MenuIcon from '@mui/icons-material/Menu' import ArrowBackIcon from '@mui/icons-material/ArrowBack' +import MenuIcon from '@mui/icons-material/Menu' import { AuthZone } from './components/AuthZone' -import { dimensions, endpoints } from 'constants' +import { dimensions, endpoints } from 'constants/index' import IPalette from 'theme/IPalette.interface' interface HeaderProps { diff --git a/src/layouts/MainLayout/components/Header/components/AuthZone/components/AuthActions/AuthActions.tsx b/src/layouts/MainLayout/components/Header/components/AuthZone/components/AuthActions/AuthActions.tsx index c4a3176..ecf34bc 100644 --- a/src/layouts/MainLayout/components/Header/components/AuthZone/components/AuthActions/AuthActions.tsx +++ b/src/layouts/MainLayout/components/Header/components/AuthZone/components/AuthActions/AuthActions.tsx @@ -3,27 +3,27 @@ import { useTranslation } from 'react-i18next' import { Link, useNavigate } from 'react-router-dom' import Avatar from '@mui/material/Avatar' -import Button from '@mui/material/Button' import Box from '@mui/material/Box' +import Button from '@mui/material/Button' import Divider from '@mui/material/Divider' import IconButton from '@mui/material/IconButton' +import useTheme from '@mui/material/styles/useTheme' import Typography from '@mui/material/Typography' import useMediaQuery from '@mui/material/useMediaQuery' -import useTheme from '@mui/material/styles/useTheme' -import LogoutIcon from '@mui/icons-material/Logout' import AccountBoxIcon from '@mui/icons-material/AccountBox' +import LogoutIcon from '@mui/icons-material/Logout' -import { VerticalDivider } from 'components/VerticalDivider' import { CustomTooltip } from 'components/CustomTooltip' +import { VerticalDivider } from 'components/VerticalDivider' -import Logo from '../../../../../../../../assets/logo.svg' -import admin from '../../../../../../../../assets/admin.webp' -import { dimensions, endpoints, permissions } from 'constants' -import { getUser, getUserRole } from 'functions/manipulateLocalStorage' +import { dimensions, endpoints, permissions } from 'constants/index' import { useAuth } from 'context/AuthContext/AuthContext' -import IPalette from 'theme/IPalette.interface' import { checkIsAdmin } from 'functions/index' +import { getUser, getUserRole } from 'functions/manipulateLocalStorage' +import IPalette from 'theme/IPalette.interface' +import admin from '../../../../../../../../assets/admin.webp' +import Logo from '../../../../../../../../assets/logo.svg' const AuthActions: FC = () => { const { t } = useTranslation() diff --git a/src/layouts/MainLayout/components/Sidebar/Sidebar.tsx b/src/layouts/MainLayout/components/Sidebar/Sidebar.tsx index 38e53bc..78b4d5c 100644 --- a/src/layouts/MainLayout/components/Sidebar/Sidebar.tsx +++ b/src/layouts/MainLayout/components/Sidebar/Sidebar.tsx @@ -1,33 +1,33 @@ -import { FC, lazy } from "react"; +import { FC, lazy } from 'react' -import Box from "@mui/material/Box"; +import Box from '@mui/material/Box' -import MobileDrawer from "./components/MobileDrawer"; +import MobileDrawer from './components/MobileDrawer' -import { dimensions } from "constants"; +import { dimensions } from 'constants/index' -const CommonDrawer = lazy(() => import("./components/CommonDrawer")); +const CommonDrawer = lazy(() => import('./components/CommonDrawer')) interface SidebarProps { - mobileOpen: boolean; - handleDrawerToggle: () => void; + mobileOpen: boolean + handleDrawerToggle: () => void } const Sidebar: FC = ({ mobileOpen, handleDrawerToggle }) => { const container: (() => HTMLElement) | undefined = - window !== undefined ? () => window.document.body : undefined; + window !== undefined ? () => window.document.body : undefined - const drawerWidth = dimensions.DRAWER_WIDTH; + const drawerWidth = dimensions.DRAWER_WIDTH return ( {mobileOpen ? ( = ({ mobileOpen, handleDrawerToggle }) => { )} - ); -}; + ) +} -export { Sidebar }; +export { Sidebar } diff --git a/src/layouts/MainLayout/components/Sidebar/components/CommonDrawer/CommonDrawer.tsx b/src/layouts/MainLayout/components/Sidebar/components/CommonDrawer/CommonDrawer.tsx index 3a6f01e..25cde6a 100644 --- a/src/layouts/MainLayout/components/Sidebar/components/CommonDrawer/CommonDrawer.tsx +++ b/src/layouts/MainLayout/components/Sidebar/components/CommonDrawer/CommonDrawer.tsx @@ -1,43 +1,43 @@ -import { FC } from "react"; -import { Link } from "react-router-dom"; +import { FC } from 'react' +import { Link } from 'react-router-dom' -import Drawer from "@mui/material/Drawer"; -import Avatar from "@mui/material/Avatar"; -import Grid from "@mui/material/Grid"; -import Toolbar from "@mui/material/Toolbar"; -import Typography from "@mui/material/Typography"; -import useTheme from "@mui/material/styles/useTheme"; +import Avatar from '@mui/material/Avatar' +import Drawer from '@mui/material/Drawer' +import Grid from '@mui/material/Grid' +import Toolbar from '@mui/material/Toolbar' +import Typography from '@mui/material/Typography' +import useTheme from '@mui/material/styles/useTheme' -import { SidebarActions } from "../SidebarActions"; +import { SidebarActions } from '../SidebarActions' -import Logo from "../../../../../../assets/logo.svg"; -import IPalette from "theme/IPalette.interface"; -import { dimensions, endpoints } from "constants"; +import { dimensions, endpoints } from 'constants/index' +import IPalette from 'theme/IPalette.interface' +import Logo from '../../../../../../assets/logo.svg' const CommonDrawer: FC = () => { - const { palette }: IPalette = useTheme(); + const { palette }: IPalette = useTheme() - const drawerWidth = dimensions.DRAWER_WIDTH; + const drawerWidth = dimensions.DRAWER_WIDTH return ( div": { - "&::-webkit-scrollbar": { + '& > div': { + '&::-webkit-scrollbar': { width: 3, }, - "&::-webkit-scrollbar-track": { - backgroundColor: "inherit", + '&::-webkit-scrollbar-track': { + backgroundColor: 'inherit', }, - "&::-webkit-scrollbar-thumb": { + '&::-webkit-scrollbar-thumb': { backgroundColor: palette.grey[400], borderRadius: 2, }, @@ -47,25 +47,25 @@ const CommonDrawer: FC = () => { > - + - - + + TreS @@ -76,7 +76,7 @@ const CommonDrawer: FC = () => { - ); -}; + ) +} -export { CommonDrawer }; +export { CommonDrawer } diff --git a/src/layouts/MainLayout/components/Sidebar/components/MobileDrawer/MobileDrawer.tsx b/src/layouts/MainLayout/components/Sidebar/components/MobileDrawer/MobileDrawer.tsx index a45bfab..1912db4 100644 --- a/src/layouts/MainLayout/components/Sidebar/components/MobileDrawer/MobileDrawer.tsx +++ b/src/layouts/MainLayout/components/Sidebar/components/MobileDrawer/MobileDrawer.tsx @@ -1,22 +1,22 @@ -import { FC } from "react"; +import { FC } from 'react' -import Drawer from "@mui/material/Drawer"; -import Avatar from "@mui/material/Avatar"; -import Grid from "@mui/material/Grid"; -import Toolbar from "@mui/material/Toolbar"; -import Typography from "@mui/material/Typography"; -import useTheme from "@mui/material/styles/useTheme"; +import Avatar from '@mui/material/Avatar' +import Drawer from '@mui/material/Drawer' +import Grid from '@mui/material/Grid' +import Toolbar from '@mui/material/Toolbar' +import Typography from '@mui/material/Typography' +import useTheme from '@mui/material/styles/useTheme' -import { SidebarActions } from "../SidebarActions"; +import { SidebarActions } from '../SidebarActions' -import Logo from "../../../../../../assets/logo.svg"; -import IPalette from "theme/IPalette.interface"; -import { dimensions } from "constants"; +import { dimensions } from 'constants/index' +import IPalette from 'theme/IPalette.interface' +import Logo from '../../../../../../assets/logo.svg' interface MobileDrawerProps { - container: (() => HTMLElement) | undefined; - mobileOpen: boolean; - handleDrawerToggle: () => void; + container: (() => HTMLElement) | undefined + mobileOpen: boolean + handleDrawerToggle: () => void } const MobileDrawer: FC = ({ @@ -24,32 +24,32 @@ const MobileDrawer: FC = ({ mobileOpen, handleDrawerToggle, }) => { - const { palette }: IPalette = useTheme(); - const drawerWidth = dimensions.DRAWER_WIDTH; + const { palette }: IPalette = useTheme() + const drawerWidth = dimensions.DRAWER_WIDTH return ( div": { - "&::-webkit-scrollbar": { + '& > div': { + '&::-webkit-scrollbar': { width: 3, }, - "&::-webkit-scrollbar-track": { - backgroundColor: "inherit", + '&::-webkit-scrollbar-track': { + backgroundColor: 'inherit', }, - "&::-webkit-scrollbar-thumb": { + '&::-webkit-scrollbar-thumb': { backgroundColor: palette.whiteAlpha.default, borderRadius: 2, }, @@ -58,20 +58,20 @@ const MobileDrawer: FC = ({ > - - - + + + TreS @@ -81,7 +81,7 @@ const MobileDrawer: FC = ({ - ); -}; + ) +} -export { MobileDrawer }; +export { MobileDrawer } diff --git a/src/layouts/MainLayout/components/Sidebar/components/SidebarActions/SidebarActions.tsx b/src/layouts/MainLayout/components/Sidebar/components/SidebarActions/SidebarActions.tsx index 0b03463..8e33e47 100644 --- a/src/layouts/MainLayout/components/Sidebar/components/SidebarActions/SidebarActions.tsx +++ b/src/layouts/MainLayout/components/Sidebar/components/SidebarActions/SidebarActions.tsx @@ -1,20 +1,20 @@ -import { useEffect, useState, FC } from 'react' -import { useLocation } from 'react-router-dom' +import { FC, useEffect, useState } from 'react' import { useTranslation } from 'react-i18next' +import { useLocation } from 'react-router-dom' +import Box from '@mui/material/Box' import Button from '@mui/material/Button' -import Grid from '@mui/material/Grid' import Divider from '@mui/material/Divider' -import Box from '@mui/material/Box' +import Grid from '@mui/material/Grid' import useTheme from '@mui/material/styles/useTheme' -import { GeneralActions } from './components/GeneralActions' -import { AdditionActions } from './components/AdditionActions' import { VerticalDivider } from '../../../../../../components/VerticalDivider' +import { AdditionActions } from './components/AdditionActions' +import { GeneralActions } from './components/GeneralActions' -import { endpoints } from 'constants' -import IPalette from 'theme/IPalette.interface' +import { endpoints } from 'constants/index' import { useAuth } from 'context/AuthContext/AuthContext' +import IPalette from 'theme/IPalette.interface' const SidebarActions: FC = () => { const { pathname } = useLocation() diff --git a/src/layouts/MainLayout/components/Sidebar/components/SidebarActions/components/AdditionActions/AdditionActions.tsx b/src/layouts/MainLayout/components/Sidebar/components/SidebarActions/components/AdditionActions/AdditionActions.tsx index 3672615..727a794 100644 --- a/src/layouts/MainLayout/components/Sidebar/components/SidebarActions/components/AdditionActions/AdditionActions.tsx +++ b/src/layouts/MainLayout/components/Sidebar/components/SidebarActions/components/AdditionActions/AdditionActions.tsx @@ -1,43 +1,43 @@ -import { FC } from "react"; -import { useNavigate } from "react-router-dom"; -import { useTranslation } from "react-i18next"; +import { FC } from 'react' +import { useTranslation } from 'react-i18next' +import { useNavigate } from 'react-router-dom' -import List from "@mui/material/List"; -import Button from "@mui/material/Button"; -import useMediaQuery from "@mui/material/useMediaQuery"; +import Button from '@mui/material/Button' +import List from '@mui/material/List' +import useMediaQuery from '@mui/material/useMediaQuery' -import { dimensions, endpoints } from "constants"; -import { useAuth } from "context/AuthContext/AuthContext"; +import { dimensions, endpoints } from 'constants/index' +import { useAuth } from 'context/AuthContext/AuthContext' interface AdditionActionsProps { - selectedKey: string; - setSelectedKey: (key: string) => void; + selectedKey: string + setSelectedKey: (key: string) => void } const AdditionActions: FC = () => { - const { t } = useTranslation(); - const navigate = useNavigate(); + const { t } = useTranslation() + const navigate = useNavigate() const matches = useMediaQuery( `(max-width: ${dimensions.BREAK_POINTS.ADDITION_ACTIONS}px)` - ); + ) - const { isAuth } = useAuth(); + const { isAuth } = useAuth() const handleRedirect = (): void => { - navigate(endpoints.CREATE_TICKET); - }; + navigate(endpoints.CREATE_TICKET) + } return ( li > a > div": { - borderRadius: "8px", + '& > li > a > div': { + borderRadius: '8px', }, - "& > li": { - padding: "4px 16px", + '& > li': { + padding: '4px 16px', }, - "& > li > a": { - width: "100%", + '& > li > a': { + width: '100%', }, }} > @@ -45,20 +45,20 @@ const AdditionActions: FC = () => { )} - ); -}; + ) +} -export { AdditionActions }; +export { AdditionActions } diff --git a/src/layouts/MainLayout/components/Sidebar/components/SidebarActions/components/GeneralActions/GeneralActions.tsx b/src/layouts/MainLayout/components/Sidebar/components/SidebarActions/components/GeneralActions/GeneralActions.tsx index 6e9cdde..e37e95c 100644 --- a/src/layouts/MainLayout/components/Sidebar/components/SidebarActions/components/GeneralActions/GeneralActions.tsx +++ b/src/layouts/MainLayout/components/Sidebar/components/SidebarActions/components/GeneralActions/GeneralActions.tsx @@ -1,88 +1,88 @@ -import { useEffect, useState, FC, Dispatch, SetStateAction, lazy } from "react"; -import { useTranslation } from "react-i18next"; - -import List from "@mui/material/List"; -import ListItem from "@mui/material/ListItem"; -import ListItemButton from "@mui/material/ListItemButton"; -import ListItemIcon from "@mui/material/ListItemIcon"; -import ListItemText from "@mui/material/ListItemText"; -import Badge from "@mui/material/Badge"; -import IconButton from "@mui/material/IconButton"; - -import SourceOutlinedIcon from "@mui/icons-material/SourceOutlined"; -import SourceRoundedIcon from "@mui/icons-material/SourceRounded"; -import NotificationsOutlinedIcon from "@mui/icons-material/NotificationsOutlined"; -import NotificationsIcon from "@mui/icons-material/Notifications"; -import ArticleIcon from "@mui/icons-material/Article"; -import ArticleOutlinedIcon from "@mui/icons-material/ArticleOutlined"; -import GridViewIcon from "@mui/icons-material/GridView"; -import GridViewSharpIcon from "@mui/icons-material/GridViewSharp"; -import ExpandLess from "@mui/icons-material/ExpandLess"; -import ExpandMore from "@mui/icons-material/ExpandMore"; -import InsertChartIcon from "@mui/icons-material/InsertChart"; -import InsertChartOutlinedIcon from "@mui/icons-material/InsertChartOutlined"; - -import { NavbarListItem } from "./components/NavbarListItem"; - -import { endpoints } from "constants"; -import { useAuth } from "context/AuthContext/AuthContext"; -import { checkIsAdmin } from "functions/index"; -import { useNotification } from "context/NotificationContext/NotificationContext"; - -const NestedList = lazy(() => import("./components/NestedList")); +import { Dispatch, FC, SetStateAction, lazy, useEffect, useState } from 'react' +import { useTranslation } from 'react-i18next' + +import Badge from '@mui/material/Badge' +import IconButton from '@mui/material/IconButton' +import List from '@mui/material/List' +import ListItem from '@mui/material/ListItem' +import ListItemButton from '@mui/material/ListItemButton' +import ListItemIcon from '@mui/material/ListItemIcon' +import ListItemText from '@mui/material/ListItemText' + +import ArticleIcon from '@mui/icons-material/Article' +import ArticleOutlinedIcon from '@mui/icons-material/ArticleOutlined' +import ExpandLess from '@mui/icons-material/ExpandLess' +import ExpandMore from '@mui/icons-material/ExpandMore' +import GridViewIcon from '@mui/icons-material/GridView' +import GridViewSharpIcon from '@mui/icons-material/GridViewSharp' +import InsertChartIcon from '@mui/icons-material/InsertChart' +import InsertChartOutlinedIcon from '@mui/icons-material/InsertChartOutlined' +import NotificationsIcon from '@mui/icons-material/Notifications' +import NotificationsOutlinedIcon from '@mui/icons-material/NotificationsOutlined' +import SourceOutlinedIcon from '@mui/icons-material/SourceOutlined' +import SourceRoundedIcon from '@mui/icons-material/SourceRounded' + +import { NavbarListItem } from './components/NavbarListItem' + +import { endpoints } from 'constants/index' +import { useAuth } from 'context/AuthContext/AuthContext' +import { useNotification } from 'context/NotificationContext/NotificationContext' +import { checkIsAdmin } from 'functions/index' + +const NestedList = lazy(() => import('./components/NestedList')) interface GeneralActionsProps { - selectedKey: string; - setSelectedKey: Dispatch>; + selectedKey: string + setSelectedKey: Dispatch> } const GeneralActions: FC = ({ selectedKey, setSelectedKey, }) => { - const { t } = useTranslation(); + const { t } = useTranslation() - const { isAuth } = useAuth(); - const { countOfNotification } = useNotification(); + const { isAuth } = useAuth() + const { countOfNotification } = useNotification() - const isAdmin = checkIsAdmin(); + const isAdmin = checkIsAdmin() - const [open, setOpen] = useState(false); + const [open, setOpen] = useState(false) const handleClick = (): void => { - setOpen(!open); - }; + setOpen(!open) + } const handleListItemClick = (key: string): void => { - setSelectedKey(key); - }; + setSelectedKey(key) + } function notificationsLabel(count: number): string { if (count === 0) { - return "no notifications"; + return 'no notifications' } if (count > 99) { - return "more than 99 notifications"; + return 'more than 99 notifications' } - return `${count} notifications`; + return `${count} notifications` } useEffect(() => { - setOpen(false); - }, [isAuth]); + setOpen(false) + }, [isAuth]) return ( <> li > a": { - width: "100%", + '& > li > a': { + width: '100%', }, }} > = ({ activeIcon={} disableIcon={} /> - + {open ? : } - + {open ? : } @@ -107,7 +107,7 @@ const GeneralActions: FC = ({ {isAdmin && ( <> = ({ disableIcon={} /> = ({ )} = ({ span": { color: "white" } }} + color='primary' + sx={{ '& > span': { color: 'white' } }} > )} - ); -}; + ) +} -export { GeneralActions }; +export { GeneralActions } diff --git a/src/layouts/MainLayout/components/Sidebar/components/SidebarActions/components/GeneralActions/components/NestedList/useGetListItemArray.tsx b/src/layouts/MainLayout/components/Sidebar/components/SidebarActions/components/GeneralActions/components/NestedList/useGetListItemArray.tsx index 0b02312..0ff50a6 100644 --- a/src/layouts/MainLayout/components/Sidebar/components/SidebarActions/components/GeneralActions/components/NestedList/useGetListItemArray.tsx +++ b/src/layouts/MainLayout/components/Sidebar/components/SidebarActions/components/GeneralActions/components/NestedList/useGetListItemArray.tsx @@ -1,46 +1,46 @@ -import { useTranslation } from "react-i18next"; +import { useTranslation } from 'react-i18next' -import FolderIcon from "@mui/icons-material/Folder"; -import FolderOpenIcon from "@mui/icons-material/FolderOpen"; -import DeleteOutlineIcon from "@mui/icons-material/DeleteOutline"; -import DeleteIcon from "@mui/icons-material/Delete"; -import BookmarkBorderIcon from "@mui/icons-material/BookmarkBorder"; -import BookmarkIcon from "@mui/icons-material/Bookmark"; -import StarBorderIcon from "@mui/icons-material/StarBorder"; -import StarIcon from "@mui/icons-material/Star"; +import BookmarkIcon from '@mui/icons-material/Bookmark' +import BookmarkBorderIcon from '@mui/icons-material/BookmarkBorder' +import DeleteIcon from '@mui/icons-material/Delete' +import DeleteOutlineIcon from '@mui/icons-material/DeleteOutline' +import FolderIcon from '@mui/icons-material/Folder' +import FolderOpenIcon from '@mui/icons-material/FolderOpen' +import StarIcon from '@mui/icons-material/Star' +import StarBorderIcon from '@mui/icons-material/StarBorder' -import { endpoints } from "constants"; -import { checkIsAdmin } from "functions/index"; +import { endpoints } from 'constants/index' +import { checkIsAdmin } from 'functions/index' interface ListItem { - text: string; - icon: JSX.Element; - endpoint: string; - isHaveNewMessage: boolean; + text: string + icon: JSX.Element + endpoint: string + isHaveNewMessage: boolean } const useGetListItemsArray = (selectedKey: string): ListItem[] => { - const { t } = useTranslation(); + const { t } = useTranslation() - const isAdmin = checkIsAdmin(); + const isAdmin = checkIsAdmin() const listItemsArrayForUser = [ { - text: t("sidebar.myTickets.sent"), + text: t('sidebar.myTickets.sent'), icon: selectedKey === endpoints.SENT ? : , endpoint: endpoints.SENT, isHaveNewMessage: false, }, { - text: t("sidebar.myTickets.followed"), + text: t('sidebar.myTickets.followed'), icon: selectedKey === endpoints.FOLLOWED ? : , endpoint: endpoints.FOLLOWED, isHaveNewMessage: false, }, { - text: t("sidebar.myTickets.bookmarks"), + text: t('sidebar.myTickets.bookmarks'), icon: selectedKey === endpoints.BOOKMARKS ? ( @@ -51,7 +51,7 @@ const useGetListItemsArray = (selectedKey: string): ListItem[] => { isHaveNewMessage: false, }, { - text: t("sidebar.myTickets.deleted"), + text: t('sidebar.myTickets.deleted'), icon: selectedKey === endpoints.DELETED ? ( @@ -61,19 +61,19 @@ const useGetListItemsArray = (selectedKey: string): ListItem[] => { endpoint: endpoints.DELETED, isHaveNewMessage: false, }, - ]; + ] const listItemsArrayForAdmin = [ { - text: t("sidebar.myTickets.received"), + text: t('sidebar.myTickets.received'), icon: , endpoint: endpoints.RECEIVED, isHaveNewMessage: false, }, ...listItemsArrayForUser, - ]; + ] - return isAdmin ? listItemsArrayForAdmin : listItemsArrayForUser; -}; + return isAdmin ? listItemsArrayForAdmin : listItemsArrayForUser +} -export default useGetListItemsArray; +export default useGetListItemsArray diff --git a/src/layouts/MyTicketsLayout/hooks/useRenderElements.tsx b/src/layouts/MyTicketsLayout/hooks/useRenderElements.tsx index 4234a6c..9349949 100644 --- a/src/layouts/MyTicketsLayout/hooks/useRenderElements.tsx +++ b/src/layouts/MyTicketsLayout/hooks/useRenderElements.tsx @@ -1,26 +1,26 @@ -import { Dispatch, SetStateAction } from "react"; +import { Dispatch, SetStateAction } from 'react' -import FormGroup from "@mui/material/FormGroup"; -import useMediaQuery from "@mui/material/useMediaQuery"; +import FormGroup from '@mui/material/FormGroup' +import useMediaQuery from '@mui/material/useMediaQuery' -import { NotFound } from "components/NotFound"; -import { SkeletonTicketRow } from "components/SkeletonTicketRow"; -import { TicketRow } from "components/TicketRow"; -import { CustomPagination } from "components/CustomPagination"; +import { CustomPagination } from 'components/CustomPagination' +import { NotFound } from 'components/NotFound' +import { SkeletonTicketRow } from 'components/SkeletonTicketRow' +import { TicketRow } from 'components/TicketRow' -import { ITicket } from "components/TicketRow/ticket.interface"; -import { dimensions } from "constants"; +import { ITicket } from 'components/TicketRow/ticket.interface' +import { dimensions } from 'constants/index' interface RenderElementsProps { - tickets: ITicket[]; - title: string; - isHaveBookmarks: boolean; - handleDelete: ((ticketIdList: number[]) => void) | null; - handleRestore: ((ticketIdList: number) => void) | null; - setDeletedList: Dispatch> | null; - totalPage: number; - currentPage: number; - isLoading: boolean; + tickets: ITicket[] + title: string + isHaveBookmarks: boolean + handleDelete: ((ticketIdList: number[]) => void) | null + handleRestore: ((ticketIdList: number) => void) | null + setDeletedList: Dispatch> | null + totalPage: number + currentPage: number + isLoading: boolean } const useRenderElements = ({ @@ -36,13 +36,13 @@ const useRenderElements = ({ }: RenderElementsProps) => { const matches = useMediaQuery( `(min-width: ${dimensions.BREAK_POINTS.SIMPLE_TICKET}px)` - ); + ) const renderSkeletonTickets = () => ( @@ -54,14 +54,14 @@ const useRenderElements = ({ /> ))} - ); + ) const renderTickets = () => ( <> @@ -81,11 +81,11 @@ const useRenderElements = ({ )} - ); + ) - const renderNotFound = () => !isLoading && ; + const renderNotFound = () => !isLoading && - return { renderSkeletonTickets, renderTickets, renderNotFound }; -}; + return { renderSkeletonTickets, renderTickets, renderNotFound } +} -export { useRenderElements }; +export { useRenderElements } diff --git a/src/pages/CreateTicketForm/CreateTicketForm.tsx b/src/pages/CreateTicketForm/CreateTicketForm.tsx index 13118a9..28e4066 100644 --- a/src/pages/CreateTicketForm/CreateTicketForm.tsx +++ b/src/pages/CreateTicketForm/CreateTicketForm.tsx @@ -1,100 +1,100 @@ -import { useState, FC } from "react"; -import { useTranslation } from "react-i18next"; -import { useForm } from "react-hook-form"; -import { FetchBaseQueryError } from "@reduxjs/toolkit/dist/query"; -import { SerializedError } from "@reduxjs/toolkit"; +import { SerializedError } from '@reduxjs/toolkit' +import { FetchBaseQueryError } from '@reduxjs/toolkit/dist/query' +import { FC, useState } from 'react' +import { useForm } from 'react-hook-form' +import { useTranslation } from 'react-i18next' -import Grid from "@mui/material/Grid"; -import Typography from "@mui/material/Typography"; -import useTheme from "@mui/material/styles/useTheme"; +import Grid from '@mui/material/Grid' +import Typography from '@mui/material/Typography' +import useTheme from '@mui/material/styles/useTheme' -import { FacultySelect } from "./components/FacultySelect"; -import { QueueSelect } from "./components/QueueSelect"; -import { TicketTitleInput } from "./components/TicketTitleInput"; -import { TicketBodyTextField } from "./components/TicketBodyTextField"; -import { FormActions } from "./components/FormActions"; -import { TicketVisibilityOptions } from "./components/TicketVisibilityOptions"; +import { FacultySelect } from './components/FacultySelect' +import { FormActions } from './components/FormActions' +import { QueueSelect } from './components/QueueSelect' +import { TicketBodyTextField } from './components/TicketBodyTextField' +import { TicketTitleInput } from './components/TicketTitleInput' +import { TicketVisibilityOptions } from './components/TicketVisibilityOptions' -import { useCreateTicketMutation } from "api/tickets.api"; -import IPalette from "theme/IPalette.interface"; -import { getUser } from "functions/manipulateLocalStorage"; -import { createFormKeys } from "constants"; +import { useCreateTicketMutation } from 'api/tickets.api' +import { createFormKeys } from 'constants/index' +import { getUser } from 'functions/manipulateLocalStorage' +import IPalette from 'theme/IPalette.interface' type ApiResponse = { data?: { - ticket_id: number; - }; - error?: FetchBaseQueryError | SerializedError; -}; + ticket_id: number + } + error?: FetchBaseQueryError | SerializedError +} const CreateTicketForm: FC = () => { - const { t } = useTranslation(); - const { palette }: IPalette = useTheme(); + const { t } = useTranslation() + const { palette }: IPalette = useTheme() - const { facultyId } = getUser(); + const { facultyId } = getUser() - const [ticketId, setTicketId] = useState(null); + const [ticketId, setTicketId] = useState(null) - const [createTicket] = useCreateTicketMutation(); + const [createTicket] = useCreateTicketMutation() const { register, handleSubmit, setValue, formState, watch, reset } = useForm({ defaultValues: { faculty: facultyId, - subject: "", - body: "", + subject: '', + body: '', anonymous: false, hidden: false, }, - }); + }) - const faculty = watch(createFormKeys.FACULTY, facultyId); - const queue = watch(createFormKeys.QUEUE); - const anonymous = watch(createFormKeys.ANONYMOUS); - const hidden = watch(createFormKeys.HIDDEN); + const faculty = watch(createFormKeys.FACULTY, facultyId) + const queue = watch(createFormKeys.QUEUE) + const anonymous = watch(createFormKeys.ANONYMOUS) + const hidden = watch(createFormKeys.HIDDEN) - const { errors } = formState; + const { errors } = formState const handleClear = (): void => { reset({ faculty: facultyId, - subject: "", - body: "", + subject: '', + body: '', anonymous: false, hidden: false, queue: queue, - }); - }; + }) + } const onSubmit = (data: ICreateTicketRequestBody): void => { createTicket({ body: JSON.stringify(data) }).then( (response: ApiResponse) => { if (response && response?.data && response?.data?.ticket_id) { - setTicketId(response?.data?.ticket_id); + setTicketId(response?.data?.ticket_id) } } - ); - handleClear(); - }; + ) + handleClear() + } return ( - - - {t("createTicket.heading")} + + + {t('createTicket.heading')} -
+ div > h3": { + '& > div > h3': { mb: 1, }, - "& > div > div > div > fieldset": { + '& > div > div > div > fieldset': { border: `3px solid ${palette.grey.divider}`, }, - "& > div > div > .MuiOutlinedInput-root:hover .MuiOutlinedInput-notchedOutline": + '& > div > div > .MuiOutlinedInput-root:hover .MuiOutlinedInput-notchedOutline': { borderColor: palette.primary.main, }, @@ -131,7 +131,7 @@ const CreateTicketForm: FC = () => {
- ); -}; + ) +} -export { CreateTicketForm }; +export { CreateTicketForm } diff --git a/src/pages/CreateTicketForm/components/FacultySelect/FacultySelect.tsx b/src/pages/CreateTicketForm/components/FacultySelect/FacultySelect.tsx index ceeda0d..f08e513 100644 --- a/src/pages/CreateTicketForm/components/FacultySelect/FacultySelect.tsx +++ b/src/pages/CreateTicketForm/components/FacultySelect/FacultySelect.tsx @@ -1,65 +1,65 @@ -import { FC, memo } from "react"; -import { useTranslation } from "react-i18next"; -import { UseFormRegister, UseFormSetValue } from "react-hook-form"; +import { FC, memo } from 'react' +import { UseFormRegister, UseFormSetValue } from 'react-hook-form' +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 Typography from "@mui/material/Typography"; -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 Typography from '@mui/material/Typography' +import useTheme from '@mui/material/styles/useTheme' -import { Loader } from "components/Loader"; +import { Loader } from 'components/Loader' -import IPalette from "theme/IPalette.interface"; -import { useGetFacultiesQuery } from "api/meta.api"; -import { createFormKeys } from "constants"; +import { useGetFacultiesQuery } from 'api/meta.api' +import { createFormKeys } from 'constants/index' +import IPalette from 'theme/IPalette.interface' interface FacultySelectProps { - facultyId: number; - register: UseFormRegister; - setValue: UseFormSetValue; + facultyId: number + register: UseFormRegister + setValue: UseFormSetValue } interface IFaculty { - faculty_id: number; - name: string; + faculty_id: number + name: string } const FacultySelect: FC = memo( ({ facultyId, register, setValue }) => { - const { t } = useTranslation(); - const { palette }: IPalette = useTheme(); + const { t } = useTranslation() + const { palette }: IPalette = useTheme() - const { data, isLoading, isSuccess } = useGetFacultiesQuery({}); + const { data, isLoading, isSuccess } = useGetFacultiesQuery({}) const handleChange = (event: SelectChangeEvent) => { - const selectedFaculty = parseInt(event.target.value); - setValue(createFormKeys.FACULTY, selectedFaculty); - }; + const selectedFaculty = parseInt(event.target.value) + setValue(createFormKeys.FACULTY, selectedFaculty) + } return ( - {t("createTicket.faculty")} + {t('createTicket.faculty')} - {isLoading && } + {isLoading && } {isSuccess && ( = memo( )} - ); + ) } -); +) -export { QueueSelect }; +export { QueueSelect } diff --git a/src/pages/CreateTicketForm/components/TicketBodyTextField/TicketBodyTextField.tsx b/src/pages/CreateTicketForm/components/TicketBodyTextField/TicketBodyTextField.tsx index 585d513..5e781a5 100644 --- a/src/pages/CreateTicketForm/components/TicketBodyTextField/TicketBodyTextField.tsx +++ b/src/pages/CreateTicketForm/components/TicketBodyTextField/TicketBodyTextField.tsx @@ -1,19 +1,19 @@ -import { ChangeEvent, FC } from "react"; -import { useTranslation } from "react-i18next"; -import { FieldErrors, UseFormRegister, UseFormWatch } from "react-hook-form"; +import { ChangeEvent, FC } from 'react' +import { FieldErrors, UseFormRegister, UseFormWatch } from 'react-hook-form' +import { useTranslation } from 'react-i18next' -import Box from "@mui/material/Box"; -import TextField from "@mui/material/TextField"; -import Typography from "@mui/material/Typography"; -import useTheme from "@mui/material/styles/useTheme"; +import Box from '@mui/material/Box' +import TextField from '@mui/material/TextField' +import Typography from '@mui/material/Typography' +import useTheme from '@mui/material/styles/useTheme' -import IPalette from "theme/IPalette.interface"; -import { createFormKeys, general } from "constants"; +import { createFormKeys, general } from 'constants/index' +import IPalette from 'theme/IPalette.interface' interface TicketBodyTextFieldProps { - register: UseFormRegister; - errors: FieldErrors; - watch: UseFormWatch; + register: UseFormRegister + errors: FieldErrors + watch: UseFormWatch } const TicketBodyTextField: FC = ({ @@ -21,25 +21,25 @@ const TicketBodyTextField: FC = ({ errors, watch, }) => { - const { t } = useTranslation(); - const { palette }: IPalette = useTheme(); + const { t } = useTranslation() + const { palette }: IPalette = useTheme() - const placeholderText: string = t("createTicket.ticketBodyPlaceholder"); + const placeholderText: string = t('createTicket.ticketBodyPlaceholder') - const body = watch(createFormKeys.BODY, ""); + const body = watch(createFormKeys.BODY, '') const handleChange = (event: ChangeEvent) => { - register(createFormKeys.BODY).onChange(event); - }; + register(createFormKeys.BODY).onChange(event) + } return ( - - {t("createTicket.ticketBody")} + + {t('createTicket.ticketBody')} = ({ onChange={handleChange} error={!!errors.body || body.length > general.MAX_BODY_LENGTH} sx={{ - overflow: "hidden", + overflow: 'hidden', bgcolor: palette.grey.card, - ".MuiOutlinedInput-root": { - p: "0 0 24px", + '.MuiOutlinedInput-root': { + p: '0 0 24px', }, - "& > .MuiOutlinedInput-root > textarea": { - p: "12px 16px 0", - "&::-webkit-scrollbar": { + '& > .MuiOutlinedInput-root > textarea': { + p: '12px 16px 0', + '&::-webkit-scrollbar': { width: 4, }, - "&::-webkit-scrollbar-track": { + '&::-webkit-scrollbar-track': { backgroundColor: palette.grey.border, }, - "&::-webkit-scrollbar-thumb": { - backgroundColor: "rgba(255, 255, 255, 0.36)", + '&::-webkit-scrollbar-thumb': { + backgroundColor: 'rgba(255, 255, 255, 0.36)', borderRadius: 4, }, }, @@ -71,7 +71,7 @@ const TicketBodyTextField: FC = ({ /> = ({ {body.length} / {general.MAX_BODY_LENGTH} - ); -}; + ) +} -export { TicketBodyTextField }; +export { TicketBodyTextField } diff --git a/src/pages/CreateTicketForm/components/TicketTitleInput/TicketTitleInput.tsx b/src/pages/CreateTicketForm/components/TicketTitleInput/TicketTitleInput.tsx index bcfeb4c..cba8b26 100644 --- a/src/pages/CreateTicketForm/components/TicketTitleInput/TicketTitleInput.tsx +++ b/src/pages/CreateTicketForm/components/TicketTitleInput/TicketTitleInput.tsx @@ -1,19 +1,19 @@ -import { ChangeEvent, FC } from "react"; -import { useTranslation } from "react-i18next"; -import { FieldErrors, UseFormRegister, UseFormWatch } from "react-hook-form"; +import { ChangeEvent, FC } from 'react' +import { FieldErrors, UseFormRegister, UseFormWatch } from 'react-hook-form' +import { useTranslation } from 'react-i18next' -import TextField from "@mui/material/TextField"; -import Box from "@mui/material/Box"; -import Typography from "@mui/material/Typography"; -import useTheme from "@mui/material/styles/useTheme"; +import Box from '@mui/material/Box' +import TextField from '@mui/material/TextField' +import Typography from '@mui/material/Typography' +import useTheme from '@mui/material/styles/useTheme' -import IPalette from "theme/IPalette.interface"; -import { createFormKeys, general } from "constants"; +import { createFormKeys, general } from 'constants/index' +import IPalette from 'theme/IPalette.interface' interface TicketTitleInputProps { - register: UseFormRegister; - errors: FieldErrors; - watch: UseFormWatch; + register: UseFormRegister + errors: FieldErrors + watch: UseFormWatch } const TicketTitleInput: FC = ({ @@ -21,28 +21,28 @@ const TicketTitleInput: FC = ({ errors, watch, }) => { - const { t } = useTranslation(); - const { palette }: IPalette = useTheme(); + const { t } = useTranslation() + const { palette }: IPalette = useTheme() - const placeholderText: string = t("createTicket.ticketTitlePlaceholder"); + const placeholderText: string = t('createTicket.ticketTitlePlaceholder') - const title = watch(createFormKeys.SUBJECT, ""); + const title = watch(createFormKeys.SUBJECT, '') const handleChange = (event: ChangeEvent) => { - register(createFormKeys.SUBJECT).onChange(event); - }; + register(createFormKeys.SUBJECT).onChange(event) + } return ( - {t("createTicket.ticketTitle")} + {t('createTicket.ticketTitle')} = ({ error={!!errors.subject || title.length > general.MAX_TITLE_LENGTH} sx={{ bgcolor: palette.grey.card, - "& .MuiInputBase-input": { p: "13px 66px 13px 8.5px" }, + '& .MuiInputBase-input': { p: '13px 66px 13px 8.5px' }, }} /> = ({ {title.length} / {general.MAX_TITLE_LENGTH} - ); -}; + ) +} -export { TicketTitleInput }; +export { TicketTitleInput } diff --git a/src/pages/FullTicketInfo/FullTicketInfo.tsx b/src/pages/FullTicketInfo/FullTicketInfo.tsx index 425c72c..e07833e 100644 --- a/src/pages/FullTicketInfo/FullTicketInfo.tsx +++ b/src/pages/FullTicketInfo/FullTicketInfo.tsx @@ -1,32 +1,32 @@ -import { useEffect, FC, useState } from 'react' +import { FC, useEffect, useState } from 'react' import { useLocation } from 'react-router-dom' import Grid from '@mui/material/Grid' import useTheme from '@mui/material/styles/useTheme' import { Loader } from '../../components/Loader' -import { ActionPanel } from './components/ActionPanel' import { MarkdownWithStyles } from '../../utils/markdown' -import { FullTicketHeader } from './components/FullTicketHeader' -import { FullTicketComments } from './components/FullTicketComments' +import { ActionPanel } from './components/ActionPanel' import { FullTicketAdditionInfo } from './components/FullTicketAdditionInfo' +import { FullTicketComments } from './components/FullTicketComments' import { FullTicketFiles } from './components/FullTicketFiles' +import { FullTicketHeader } from './components/FullTicketHeader' -import { useShowTicketMutation } from 'api/tickets.api' -import { checkIsAdmin } from 'functions/index' -import IPalette from 'theme/IPalette.interface' import { useAdminShowTicketMutation, useAdminUpdateTicketMutation, } from 'api/admin.api' -import { getUser } from 'functions/manipulateLocalStorage' import { + useShowTicketMutation, useToggleBookmarkMutation, useToggleLikeMutation, } from 'api/tickets.api' -import { useCommentsConnection } from './hooks/useCommentsConnection' +import { toggleOptions } from 'constants/index' +import { checkIsAdmin } from 'functions/index' +import { getUser } from 'functions/manipulateLocalStorage' import { useToggleAction } from 'hooks/index' -import { toggleOptions } from 'constants' +import IPalette from 'theme/IPalette.interface' +import { useCommentsConnection } from './hooks/useCommentsConnection' export interface IPerson { color: string diff --git a/src/pages/FullTicketInfo/components/FullTicketAdditionInfo/FullTicketAdditionInfo.tsx b/src/pages/FullTicketInfo/components/FullTicketAdditionInfo/FullTicketAdditionInfo.tsx index c6d3c5d..4f33ca8 100644 --- a/src/pages/FullTicketInfo/components/FullTicketAdditionInfo/FullTicketAdditionInfo.tsx +++ b/src/pages/FullTicketInfo/components/FullTicketAdditionInfo/FullTicketAdditionInfo.tsx @@ -1,16 +1,16 @@ import { FC, useEffect } from 'react' -import { NavLink } from 'react-router-dom' 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 IPalette from 'theme/IPalette.interface' -import { formatDate } from 'functions/index' -import { endpoints } from 'constants' import { ICreator } from 'components/Ticket/components/TicketBody/TicketBody' +import { endpoints } from 'constants/index' +import { formatDate } from 'functions/index' +import IPalette from 'theme/IPalette.interface' interface FullTicketAdditionInfoProps { creator: ICreator | null diff --git a/src/pages/FullTicketInfo/components/FullTicketComments/FullTicketComments.tsx b/src/pages/FullTicketInfo/components/FullTicketComments/FullTicketComments.tsx index ba9c469..4f3edcc 100644 --- a/src/pages/FullTicketInfo/components/FullTicketComments/FullTicketComments.tsx +++ b/src/pages/FullTicketInfo/components/FullTicketComments/FullTicketComments.tsx @@ -28,7 +28,7 @@ import { useEditCommentMutation, } from 'api/comments.api' import { useGetFullHistoryMutation } from 'api/tickets.api' -import { permissions } from 'constants' +import { permissions } from 'constants/index' import { getRandomNickColor } from 'functions/index' import { getUser, getUserRole } from 'functions/manipulateLocalStorage' import { useRandomNick } from 'hooks/index' diff --git a/src/pages/FullTicketInfo/components/FullTicketComments/components/Action/Action.tsx b/src/pages/FullTicketInfo/components/FullTicketComments/components/Action/Action.tsx index 06c2688..a6645e4 100644 --- a/src/pages/FullTicketInfo/components/FullTicketComments/components/Action/Action.tsx +++ b/src/pages/FullTicketInfo/components/FullTicketComments/components/Action/Action.tsx @@ -1,57 +1,57 @@ -import { ForwardRefExoticComponent, RefAttributes, forwardRef } from "react"; -import { NavLink } from "react-router-dom"; +import { ForwardRefExoticComponent, RefAttributes, forwardRef } from 'react' +import { NavLink } from 'react-router-dom' -import { TFunction } from "i18next"; +import { TFunction } from 'i18next' -import Box from "@mui/material/Grid"; -import Typography from "@mui/material/Typography"; -import { useTheme } from "@mui/material"; +import { useTheme } from '@mui/material' +import Box from '@mui/material/Grid' +import Typography from '@mui/material/Typography' -import IPalette from "theme/IPalette.interface"; -import { endpoints } from "constants"; -import { useFormatDate } from "hooks/index"; +import { endpoints } from 'constants/index' +import { useFormatDate } from 'hooks/index' +import IPalette from 'theme/IPalette.interface' export type IAction = { - color: string; - nick: string; - action_id: string; + color: string + nick: string + action_id: string author: { - user_id: number; - firstname: string; - lastname: string; - login: string; - faculty: { faculty_id: number; name: string }; - group: { group_id: number; name: string }; - }; - creation_date: string; - field_name: string; - file_meta_action: string; - new_value: string; - old_value: string; - value: string; - ticket_id: number; - type_: "action"; -}; + user_id: number + firstname: string + lastname: string + login: string + faculty: { faculty_id: number; name: string } + group: { group_id: number; name: string } + } + creation_date: string + field_name: string + file_meta_action: string + new_value: string + old_value: string + value: string + ticket_id: number + type_: 'action' +} interface ActionProps { - action: IAction; - translator: TFunction<"translation", undefined, "translation">; - lang: string; + action: IAction + translator: TFunction<'translation', undefined, 'translation'> + lang: string } const Action: ForwardRefExoticComponent< - Omit & RefAttributes + Omit & RefAttributes > = forwardRef(({ action, translator: translator, lang }, ref) => { - const { palette }: IPalette = useTheme(); + const { palette }: IPalette = useTheme() - const formattedDate: string = useFormatDate(action.creation_date, "full"); + const formattedDate: string = useFormatDate(action.creation_date, 'full') const getActionText = () => { - if (lang === "ua") { + if (lang === 'ua') { return ( <> - {action.field_name === "file" ? ( - action.file_meta_action === "upload" ? ( + {action.field_name === 'file' ? ( + action.file_meta_action === 'upload' ? ( <>{` ${formattedDate} завантажив(-ла) файл ${action.value}`} ) : ( <>{` ${formattedDate} видалив(-ла) файл ${action.value}`} @@ -61,15 +61,15 @@ const Action: ForwardRefExoticComponent< {` ${formattedDate} змінив ${translator( `fullTicket.comments.${action.field_name}` )} з `} - {action.field_name === "status" ? ( + {action.field_name === 'status' ? ( <> - + {translator( `ticketStatus.${action.old_value.toLowerCase()}` )} {` на `} - + {translator( `ticketStatus.${action.new_value.toLowerCase()}` )} @@ -77,52 +77,52 @@ const Action: ForwardRefExoticComponent< ) : ( <> - {action.old_value} + {action.old_value} {` на `} - {action.new_value} + {action.new_value} )} )} - ); + ) } return ( <> - {action.field_name === "file" ? ( + {action.field_name === 'file' ? ( <>{` on ${formattedDate} has ${action.file_meta_action} a file ${action.value}`} ) : ( <> {` on ${formattedDate} changed the ${action.field_name} from `} - {action.old_value} + {action.old_value} {` to `} - {action.new_value} + {action.new_value} )} - ); - }; + ) + } return ( - + - ); -}); + ) +}) -export { Action }; +export { Action } diff --git a/src/pages/FullTicketInfo/components/FullTicketHeader/FullTicketHeader.tsx b/src/pages/FullTicketInfo/components/FullTicketHeader/FullTicketHeader.tsx index 4c3547d..6f0ba68 100644 --- a/src/pages/FullTicketInfo/components/FullTicketHeader/FullTicketHeader.tsx +++ b/src/pages/FullTicketInfo/components/FullTicketHeader/FullTicketHeader.tsx @@ -1,44 +1,44 @@ -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 { MutationTrigger } from '@reduxjs/toolkit/dist/query/react/buildHooks' +import { FC, useEffect, useState } from 'react' +import { useTranslation } from 'react-i18next' import { NavLink, useNavigate } from 'react-router-dom' +import Avatar from '@mui/material/Avatar' import Box from '@mui/material/Box' -import IconButton from '@mui/material/IconButton' import Button from '@mui/material/Button' +import Grid from '@mui/material/Grid' +import IconButton from '@mui/material/IconButton' 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 EditIcon from '@mui/icons-material/Edit' +import RedoIcon from '@mui/icons-material/Redo' import { VerticalDivider } from 'components/VerticalDivider' +import { AssigneeSelect } from './components/AssigneeSelect' +import { DialogPopup } from './components/DialogPopup' 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 { useAdminRemoveTicketMutation } from 'api/admin.api' +import { endpoints, roles } from 'constants/index' import { checkIsAdmin } from 'functions/index' import { getUser } from 'functions/manipulateLocalStorage' -import { endpoints, roles } from 'constants' -import { useAdminRemoveTicketMutation } from 'api/admin.api' +import IPalette from 'theme/IPalette.interface' -import styles from './FullTicketHeader.module.css' -import { IAction } from '../FullTicketComments/components/Action/Action' import { useGetStatusesQuery } from 'api/meta.api' import { useCheckStatus } from 'hooks/index' +import { IAction } from '../FullTicketComments/components/Action/Action' +import styles from './FullTicketHeader.module.css' interface FullTicketHeaderProps { assigneeId: number diff --git a/src/pages/FullTicketInfo/hooks/useCommentsConnection.ts b/src/pages/FullTicketInfo/hooks/useCommentsConnection.ts index 97bca4a..471fd78 100644 --- a/src/pages/FullTicketInfo/hooks/useCommentsConnection.ts +++ b/src/pages/FullTicketInfo/hooks/useCommentsConnection.ts @@ -1,72 +1,73 @@ -import { useEffect, useState } from "react"; +import { useEffect, useState } from 'react' -import { getAccessToken } from "functions/manipulateLocalStorage"; -import { useAuth } from "context/AuthContext/AuthContext"; -import { IComment } from "../components/FullTicketComments/components/Comment/Comment"; -import { IAction } from "../components/FullTicketComments/components/Action/Action"; -import { endpoints } from "constants"; -import { useMessageHandler } from "./useMessageHandler"; +import { endpoints } from 'constants/index' +import { useAuth } from 'context/AuthContext/AuthContext' +import { getAccessToken } from 'functions/manipulateLocalStorage' +import { IAction } from '../components/FullTicketComments/components/Action/Action' +import { IComment } from '../components/FullTicketComments/components/Comment/Comment' +import { useMessageHandler } from './useMessageHandler' const useCommentsConnection = (ticketId: number) => { - const { isAuth } = useAuth(); + const { isAuth } = useAuth() - const [createdComment, setCreatedComment] = useState(null); - const [changedComment, setChangedComment] = useState(null); - const [action, setAction] = useState(null); - const [deleteId, setDeleteId] = useState(null); - const [ws, setWs] = useState(null); - const [isFirstLoad, setIsFirstLoad] = useState(true); + const [createdComment, setCreatedComment] = useState(null) + const [changedComment, setChangedComment] = useState(null) + const [action, setAction] = useState(null) + const [deleteId, setDeleteId] = useState(null) + const [ws, setWs] = useState(null) + const [isFirstLoad, setIsFirstLoad] = useState(true) const messageHandler = useMessageHandler({ setAction, setCreatedComment, setChangedComment, setDeleteId, - }); + }) const ping = () => { - if (!ws) return; - if (ws.readyState !== 1) return; - ws.send("PING"); - setTimeout(ping, isFirstLoad ? 25000 : 60000); - setIsFirstLoad(false); - }; + if (!ws) return + if (ws.readyState !== 1) return + ws.send('PING') + } const openConnection = (webSocket: WebSocket) => { - const accessToken = getAccessToken() || ""; - webSocket?.send(accessToken); - webSocket?.send("CHAT"); - webSocket?.send(ticketId.toString()); - ping(); - }; + const accessToken = getAccessToken() || '' + webSocket?.send(accessToken) + webSocket?.send('CHAT') + webSocket?.send(ticketId.toString()) + } useEffect(() => { if (isAuth && !ws) { - const newWs = new WebSocket(endpoints.WS_URL); - setWs(newWs); + const newWs = new WebSocket(endpoints.WS_URL) + setWs(newWs) - newWs.addEventListener("open", () => { - openConnection(newWs); - }); - newWs.addEventListener("message", messageHandler); + newWs.addEventListener('open', () => { + openConnection(newWs) + newWs.send('PING') + setIsFirstLoad(false) + }) + newWs.addEventListener('message', messageHandler) + } else if (isAuth && ws) { + setInterval(ping, isFirstLoad ? 25000 : 60000) } else if (!isAuth && ws) { - ws.close(); - setWs(null); + ws.close() + setWs(null) } return () => { if (ws) { - ws.close(); + ws.close() } - }; - }, [isAuth, ws, ticketId]); + } + }, [isAuth, ws, ticketId]) return { createdComment, changedComment, deleteId, action, - }; -}; + } +} -export { useCommentsConnection }; +export { useCommentsConnection } diff --git a/src/pages/Notifications/components/NotificationTile/NotificationTile.tsx b/src/pages/Notifications/components/NotificationTile/NotificationTile.tsx index 8be8250..58a9dc9 100644 --- a/src/pages/Notifications/components/NotificationTile/NotificationTile.tsx +++ b/src/pages/Notifications/components/NotificationTile/NotificationTile.tsx @@ -1,21 +1,21 @@ -import { FC } from "react"; -import { Link } from "react-router-dom"; +import { FC } from 'react' +import { Link } from 'react-router-dom' -import Box from "@mui/material/Box"; -import Badge from "@mui/material/Badge"; -import useTheme from "@mui/material/styles/useTheme"; +import Badge from '@mui/material/Badge' +import Box from '@mui/material/Box' +import useTheme from '@mui/material/styles/useTheme' -import ChatIcon from "@mui/icons-material/Chat"; +import ChatIcon from '@mui/icons-material/Chat' -import { endpoints } from "constants"; -import IPalette from "theme/IPalette.interface"; +import { endpoints } from 'constants/index' +import IPalette from 'theme/IPalette.interface' interface NotificationTileProps { - ticketId: number; - description: string; - count: number | undefined; - handleClick: (index: number) => void; - index: number; + ticketId: number + description: string + count: number | undefined + handleClick: (index: number) => void + index: number } const NotificationTile: FC = ({ @@ -25,16 +25,16 @@ const NotificationTile: FC = ({ handleClick, index, }) => { - const { palette }: IPalette = useTheme(); + const { palette }: IPalette = useTheme() return ( handleClick(index)} sx={{ - display: "flex", - justifyContent: "space-between", - alignItems: "center", + display: 'flex', + justifyContent: 'space-between', + alignItems: 'center', gap: 2, bgcolor: palette.grey.card, border: `2px solid ${palette.grey.button}`, @@ -42,7 +42,7 @@ const NotificationTile: FC = ({ borderRadius: 1, }} > - + {description} @@ -51,8 +51,8 @@ const NotificationTile: FC = ({ badgeContent={count} sx={{ mr: 1.3, - "& > span": { - color: "white", + '& > span': { + color: 'white', bgcolor: palette.grey.active, }, }} @@ -60,7 +60,7 @@ const NotificationTile: FC = ({ )} - ); -}; + ) +} -export { NotificationTile }; +export { NotificationTile } diff --git a/src/pages/Profile/Profile.tsx b/src/pages/Profile/Profile.tsx index 613364d..200d73c 100644 --- a/src/pages/Profile/Profile.tsx +++ b/src/pages/Profile/Profile.tsx @@ -1,141 +1,139 @@ -import { FC, useState, useEffect } from "react"; -import { useTranslation } from "react-i18next"; -import { useLocation } from "react-router-dom"; -import { useForm } from "react-hook-form"; -import { FetchBaseQueryError } from "@reduxjs/toolkit/dist/query"; -import { SerializedError } from "@reduxjs/toolkit"; - -import Box from "@mui/material/Box"; -import Grid from "@mui/material/Grid"; -import Typography from "@mui/material/Typography"; - -import { PasswordChangeSection } from "./components/PasswordChangeSection"; -import { ProfileHeader } from "./components/ProfileHeader"; -import { ProfileFullInfo } from "./components/ProfileFullInfo"; -import { ProfileActions } from "./components/ProfileActions"; +import { SerializedError } from '@reduxjs/toolkit' +import { FetchBaseQueryError } from '@reduxjs/toolkit/dist/query' +import { FC, useEffect, useState } from 'react' +import { useForm } from 'react-hook-form' +import { useTranslation } from 'react-i18next' +import { useLocation } from 'react-router-dom' + +import Box from '@mui/material/Box' +import Grid from '@mui/material/Grid' +import Typography from '@mui/material/Typography' + +import { PasswordChangeSection } from './components/PasswordChangeSection' +import { ProfileActions } from './components/ProfileActions' +import { ProfileFullInfo } from './components/ProfileFullInfo' +import { ProfileHeader } from './components/ProfileHeader' import { useGetProfileMutation, useUpdateProfileMutation, -} from "api/profile.api"; +} from 'api/profile.api' +import { permissions, profileFormKeys, roles, storage } from 'constants/index' +import { checkIsAdmin } from 'functions/index' import { changeUserField, getUser, getUserRole, -} from "functions/manipulateLocalStorage"; -import { checkIsAdmin } from "functions/index"; -import admin from "../../assets/admin.webp"; -import { permissions, profileFormKeys, roles, storage } from "constants"; +} from 'functions/manipulateLocalStorage' +import admin from '../../assets/admin.webp' type ApiResponse = { data?: { - email: string; - faculty: { faculty_id: number; name: string }; - firstname: string; - group: { group_id: number; name: string }; - lastname: string; - login: string; - phone: string; - registration_date: string; + email: string + faculty: { faculty_id: number; name: string } + firstname: string + group: { group_id: number; name: string } + lastname: string + login: string + phone: string + registration_date: string role: { - name: string; - permission_list: string[]; - role_id: number; - }; - }; - error?: FetchBaseQueryError | SerializedError; -}; + name: string + permission_list: string[] + role_id: number + } + } + error?: FetchBaseQueryError | SerializedError +} export interface ProfileUpdateBody { - firstname?: string; - lastname?: string; - login?: string; - phone?: string; - password?: string; - role?: number; + firstname?: string + lastname?: string + login?: string + phone?: string + password?: string + role?: number } const Profile: FC = () => { - const { t } = useTranslation(); - const { pathname } = useLocation(); + const { t } = useTranslation() + const { pathname } = useLocation() - const [isEditMode, setIsEditMode] = useState(false); + const [isEditMode, setIsEditMode] = useState(false) - const { userId: myId } = getUser(); - const { permissionList } = getUserRole(); - const isCanChangeProfile = permissionList.includes( - permissions.UPDATE_PROFILE - ); + const { userId: myId } = getUser() + const { permissionList } = getUserRole() + const isCanChangeProfile = permissionList.includes(permissions.UPDATE_PROFILE) - const isAdmin = checkIsAdmin(roles.CHIEF_ADMIN); - const userId = parseInt(pathname.split("/")[2]); - const isMyProfile = userId === myId; + const isAdmin = checkIsAdmin(roles.CHIEF_ADMIN) + const userId = parseInt(pathname.split('/')[2]) + const isMyProfile = userId === myId - const [getUserProfile, { data, isSuccess }] = useGetProfileMutation(); + const [getUserProfile, { data, isSuccess }] = useGetProfileMutation() const [updateProfile, { isSuccess: isProfileUpdated }] = - useUpdateProfileMutation(); + useUpdateProfileMutation() const { register, handleSubmit, setValue, getValues, reset, watch } = - useForm(); + useForm() - const role = watch(profileFormKeys.ROLE); + const role = watch(profileFormKeys.ROLE) const avatar = - (isMyProfile && isAdmin) || data?.role?.role_id >= 9 ? admin : ""; + (isMyProfile && isAdmin) || data?.role?.role_id >= 9 ? admin : '' const getProfile = () => { getUserProfile({ userId: userId }).then((response: ApiResponse) => { if (response?.data) { - const { firstname, lastname, login, phone, role } = response.data; + const { firstname, lastname, login, phone, role } = response.data - setValue(profileFormKeys.FIRSTNAME, firstname); - setValue(profileFormKeys.LASTNAME, lastname); - setValue(profileFormKeys.LOGIN, login); - setValue(profileFormKeys.PHONE, phone); - setValue(profileFormKeys.ROLE, role.role_id); + setValue(profileFormKeys.FIRSTNAME, firstname) + setValue(profileFormKeys.LASTNAME, lastname) + setValue(profileFormKeys.LOGIN, login) + setValue(profileFormKeys.PHONE, phone) + setValue(profileFormKeys.ROLE, role.role_id) } - }); - }; + }) + } useEffect(() => { - getProfile(); - }, [userId]); + getProfile() + }, [userId]) useEffect(() => { - isProfileUpdated && getProfile(); - }, [isProfileUpdated]); + isProfileUpdated && getProfile() + }, [isProfileUpdated]) const onSubmit = (data: ProfileUpdateBody): void => { - updateProfile({ body: JSON.stringify(data) }); + updateProfile({ body: JSON.stringify(data) }) - handelReset(); - changeUserField(storage.USER.NAME, `${data.firstname} ${data.lastname}`); - }; + handelReset() + changeUserField(storage.USER.NAME, `${data.firstname} ${data.lastname}`) + } const handelReset = (): void => { - setIsEditMode(false); - reset(); - }; + setIsEditMode(false) + reset() + } const handelChangePassword = (): void => { - const newPassword = getValues("password"); + const newPassword = getValues('password') - updateProfile({ body: JSON.stringify({ password: newPassword }) }); - setValue("password", ""); - }; + updateProfile({ body: JSON.stringify({ password: newPassword }) }) + setValue('password', '') + } return ( - {t("profile.heading")} + {t('profile.heading')} {isSuccess && (
{ )}
- ); -}; + ) +} -export { Profile }; +export { Profile } diff --git a/src/pages/Profile/components/PasswordChangeSection/PasswordChangeSection.tsx b/src/pages/Profile/components/PasswordChangeSection/PasswordChangeSection.tsx index 310943e..1632a83 100644 --- a/src/pages/Profile/components/PasswordChangeSection/PasswordChangeSection.tsx +++ b/src/pages/Profile/components/PasswordChangeSection/PasswordChangeSection.tsx @@ -1,20 +1,20 @@ -import { FC, useState } from "react"; -import { useTranslation } from "react-i18next"; +import { FC, useState } from 'react' +import { useTranslation } from 'react-i18next' -import Box from "@mui/material/Grid"; -import Typography from "@mui/material/Typography"; -import Button from "@mui/material/Button"; +import Button from '@mui/material/Button' +import Box from '@mui/material/Grid' +import Typography from '@mui/material/Typography' -import { PasswordField } from "components/PasswordField"; +import { PasswordField } from 'components/PasswordField' -import { UseFormSetValue } from "react-hook-form"; -import { profileFormKeys } from "constants"; -import { ProfileUpdateBody } from "pages/Profile/Profile"; +import { profileFormKeys } from 'constants/index' +import { ProfileUpdateBody } from 'pages/Profile/Profile' +import { UseFormSetValue } from 'react-hook-form' interface PasswordChangeSectionProps { - password: string; - setValue: UseFormSetValue; - handelChangePassword: () => void; + password: string + setValue: UseFormSetValue + handelChangePassword: () => void } const PasswordChangeSection: FC = ({ @@ -22,13 +22,13 @@ const PasswordChangeSection: FC = ({ setValue, handelChangePassword, }) => { - const { t } = useTranslation(); + const { t } = useTranslation() - const [showPassword, setShowPassword] = useState(false); + const [showPassword, setShowPassword] = useState(false) return ( - - {t("profile.passwordTitle")} + + {t('profile.passwordTitle')} @@ -36,17 +36,17 @@ const PasswordChangeSection: FC = ({ } showPassword={showPassword} setShowPassword={setShowPassword} - placeholder="profile.editMode.password" + placeholder='profile.editMode.password' /> - ); -}; + ) +} -export { PasswordChangeSection }; +export { PasswordChangeSection } diff --git a/src/pages/Profile/components/ProfileHeader/ProfileHeader.tsx b/src/pages/Profile/components/ProfileHeader/ProfileHeader.tsx index f57b661..b697350 100644 --- a/src/pages/Profile/components/ProfileHeader/ProfileHeader.tsx +++ b/src/pages/Profile/components/ProfileHeader/ProfileHeader.tsx @@ -1,23 +1,23 @@ -import { FC } from "react"; -import { FieldValues, UseFormRegister, UseFormWatch } from "react-hook-form"; +import { FC } from 'react' +import { FieldValues, UseFormRegister, UseFormWatch } from 'react-hook-form' -import Box from "@mui/material/Box"; -import Avatar from "@mui/material/Avatar"; -import Typography from "@mui/material/Typography"; -import useTheme from "@mui/material/styles/useTheme"; +import Avatar from '@mui/material/Avatar' +import Box from '@mui/material/Box' +import Typography from '@mui/material/Typography' +import useTheme from '@mui/material/styles/useTheme' -import { ProfileInput } from "../ProfileInput"; +import { ProfileInput } from '../ProfileInput' -import { profileFormKeys } from "constants"; -import IPalette from "theme/IPalette.interface"; -import { ProfileUpdateBody } from "pages/Profile/Profile"; +import { profileFormKeys } from 'constants/index' +import { ProfileUpdateBody } from 'pages/Profile/Profile' +import IPalette from 'theme/IPalette.interface' interface ProfileHeaderProps { - avatar: string; - isEditMode: boolean; - data: any; - register: UseFormRegister; - watch: UseFormWatch; + avatar: string + isEditMode: boolean + data: any + register: UseFormRegister + watch: UseFormWatch } const ProfileHeader: FC = ({ @@ -27,14 +27,14 @@ const ProfileHeader: FC = ({ register, watch, }) => { - const { palette }: IPalette = useTheme(); + const { palette }: IPalette = useTheme() - const { firstname, lastname, login } = data; + const { firstname, lastname, login } = data const renderFullName = () => ( = ({ > {`${firstname} ${lastname}`} - ); + ) const renderLogin = () => ( - {"@" + login} + {'@' + login} - ); + ) return ( @@ -66,14 +66,14 @@ const ProfileHeader: FC = ({ /> {isEditMode ? ( - + = ({ )} - ); -}; + ) +} -export { ProfileHeader }; +export { ProfileHeader } diff --git a/src/pages/Profile/components/ProfileInput/ProfileInput.tsx b/src/pages/Profile/components/ProfileInput/ProfileInput.tsx index 05a28c4..11bae85 100644 --- a/src/pages/Profile/components/ProfileInput/ProfileInput.tsx +++ b/src/pages/Profile/components/ProfileInput/ProfileInput.tsx @@ -1,17 +1,17 @@ -import { FC } from "react"; -import { useTranslation } from "react-i18next"; -import { FieldValues, UseFormRegister, UseFormWatch } from "react-hook-form"; +import { FC } from 'react' +import { FieldValues, UseFormRegister, UseFormWatch } from 'react-hook-form' +import { useTranslation } from 'react-i18next' -import TextField from "@mui/material/TextField"; +import TextField from '@mui/material/TextField' -import { profileFormKeys } from "constants"; -import { ProfileUpdateBody } from "pages/Profile/Profile"; +import { profileFormKeys } from 'constants/index' +import { ProfileUpdateBody } from 'pages/Profile/Profile' interface ProfileInputProps { - register: UseFormRegister; - defaultValue: string | undefined; - watch: UseFormWatch; - inputType: string; + register: UseFormRegister + defaultValue: string | undefined + watch: UseFormWatch + inputType: string } const ProfileInput: FC = ({ @@ -20,23 +20,23 @@ const ProfileInput: FC = ({ watch, inputType, }) => { - const { t } = useTranslation(); + const { t } = useTranslation() - const profileKey = profileFormKeys[inputType.toUpperCase()]; - const value = watch(profileKey, defaultValue); - const placeholder = t(`profile.editMode.${inputType}`); + const profileKey = profileFormKeys[inputType.toUpperCase()] + const value = watch(profileKey, defaultValue) + const placeholder = t(`profile.editMode.${inputType}`) return ( - ); -}; + ) +} -export { ProfileInput }; +export { ProfileInput } diff --git a/src/pages/Profile/components/RolesSelect/RolesSelect.tsx b/src/pages/Profile/components/RolesSelect/RolesSelect.tsx index fac545d..d769e43 100644 --- a/src/pages/Profile/components/RolesSelect/RolesSelect.tsx +++ b/src/pages/Profile/components/RolesSelect/RolesSelect.tsx @@ -1,31 +1,31 @@ -import { FC } from "react"; -import { UseFormRegister, UseFormSetValue } from "react-hook-form"; +import { FC } from 'react' +import { UseFormRegister, UseFormSetValue } from 'react-hook-form' -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 { useGetRolesQuery } from "api/meta.api"; -import { profileFormKeys } from "constants"; -import { useAdminUpdateProfileMutation } from "api/admin.api"; -import { ProfileUpdateBody } from "pages/Profile/Profile"; +import { useAdminUpdateProfileMutation } from 'api/admin.api' +import { useGetRolesQuery } from 'api/meta.api' +import { profileFormKeys } from 'constants/index' +import { ProfileUpdateBody } from 'pages/Profile/Profile' +import IPalette from 'theme/IPalette.interface' interface RolesSelectProps { - userId: number; - userRole: number | undefined; - register: UseFormRegister; - setValue: UseFormSetValue; + userId: number + userRole: number | undefined + register: UseFormRegister + setValue: UseFormSetValue } interface IRole { - role_id: number; - name: string; + role_id: number + name: string } const RolesSelect: FC = ({ @@ -34,46 +34,46 @@ const RolesSelect: FC = ({ register, setValue, }) => { - const { palette }: IPalette = useTheme(); + const { palette }: IPalette = useTheme() - const { data, isLoading, isSuccess } = useGetRolesQuery({}); - const [adminUpdateProfile] = useAdminUpdateProfileMutation(); + const { data, isLoading, isSuccess } = useGetRolesQuery({}) + const [adminUpdateProfile] = useAdminUpdateProfileMutation() const handleChange = (event: SelectChangeEvent): void => { - const selectedRole: number = parseInt(event.target.value); - setValue(profileFormKeys.ROLE, selectedRole); + const selectedRole: number = parseInt(event.target.value) + setValue(profileFormKeys.ROLE, selectedRole) const adminProfileUpdateBody = JSON.stringify({ user_id: userId, role_id: selectedRole, - }); + }) adminUpdateProfile({ body: adminProfileUpdateBody, - }); - }; + }) + } return ( - {isLoading && } + {isLoading && } {isSuccess && ( )} - ); -}; + ) +} -export { RolesSelect }; +export { RolesSelect } diff --git a/src/pages/Queue/Queue.tsx b/src/pages/Queue/Queue.tsx index dfa53fe..13898be 100644 --- a/src/pages/Queue/Queue.tsx +++ b/src/pages/Queue/Queue.tsx @@ -1,44 +1,44 @@ -import { FC, useCallback, useEffect, useState } from "react"; -import { useTranslation } from "react-i18next"; -import { FetchBaseQueryError } from "@reduxjs/toolkit/dist/query"; -import { SerializedError } from "@reduxjs/toolkit"; -import { useSearchParams } from "react-router-dom"; +import { SerializedError } from '@reduxjs/toolkit' +import { FetchBaseQueryError } from '@reduxjs/toolkit/dist/query' +import { FC, useCallback, useEffect, useState } from 'react' +import { useTranslation } from 'react-i18next' +import { useSearchParams } 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 { Scope } from "./components/Scope"; -import { FacultySelect } from "./components/FacultySelect"; +import { FacultySelect } from './components/FacultySelect' +import { Scope } from './components/Scope' -import IPalette from "theme/IPalette.interface"; -import { getUser } from "functions/manipulateLocalStorage"; -import { urlKeys } from "constants"; -import { useGetQueuesByFacultyMutation } from "api/meta.api"; +import { useGetQueuesByFacultyMutation } from 'api/meta.api' +import { urlKeys } from 'constants/index' +import { getUser } from 'functions/manipulateLocalStorage' +import IPalette from 'theme/IPalette.interface' export type ApiResponse = { - data?: { queues_list: IQueue[] }; - error?: FetchBaseQueryError | SerializedError; -}; + data?: { queues_list: IQueue[] } + error?: FetchBaseQueryError | SerializedError +} export interface IQueue { - queue_id: number; - faculty: number; - name: string; - scope: string; + queue_id: number + faculty: number + name: string + scope: string } export interface IScope { - name: string; - title: string; - queues: IQueue[]; + name: string + title: string + queues: IQueue[] } -const scopeNames = ["Reports", "Q/A", "Suggestion"]; +const scopeNames = ['Reports', 'Q/A', 'Suggestion'] const Queue: FC = () => { - const { t, i18n } = useTranslation(); - const { palette }: IPalette = useTheme(); - const [searchParams] = useSearchParams(); + const { t, i18n } = useTranslation() + const { palette }: IPalette = useTheme() + const [searchParams] = useSearchParams() const [scopesList, setScopesList] = useState( scopeNames.map(name => ({ @@ -46,13 +46,13 @@ const Queue: FC = () => { title: t(`queue.scopes.${name.toLowerCase()}Title`), queues: [], })) - ); + ) - const { facultyId } = getUser(); - const urlFaculty = parseInt(searchParams.get(urlKeys.FACULTY) || "", 10); - const faculty = urlFaculty || facultyId; + const { facultyId } = getUser() + const urlFaculty = parseInt(searchParams.get(urlKeys.FACULTY) || '', 10) + const faculty = urlFaculty || facultyId - const [getQueues] = useGetQueuesByFacultyMutation({}); + const [getQueues] = useGetQueuesByFacultyMutation({}) const updateScopesListTitle = useCallback(() => { setScopesList(prevScopesList => @@ -60,17 +60,17 @@ const Queue: FC = () => { ...prevScope, title: t(`queue.scopes.${prevScope.name.toLowerCase()}Title`), })) - ); - }, [i18n.language]); + ) + }, [i18n.language]) useEffect(() => { - updateScopesListTitle(); - }, [updateScopesListTitle]); + updateScopesListTitle() + }, [updateScopesListTitle]) useEffect(() => { getQueues({ body: JSON.stringify({ faculty: faculty }) }).then( (res: ApiResponse) => { - const queuesData = res.data && res.data.queues_list; + const queuesData = res.data && res.data.queues_list if (queuesData) { setScopesList(prevScopesList => @@ -80,50 +80,50 @@ const Queue: FC = () => { (queue: IQueue) => queue.scope === scope.name ), })) - ); + ) } } - ); - }, [faculty]); + ) + }, [faculty]) return ( - - {t("queue.heading")} + + {t('queue.heading')} {scopesList.map((scope: IScope) => { - return ; + return })} - ); -}; + ) +} -export { Queue }; +export { Queue } diff --git a/src/pages/Queue/components/FacultySelect/FacultySelect.tsx b/src/pages/Queue/components/FacultySelect/FacultySelect.tsx index f6eaf58..1a87791 100644 --- a/src/pages/Queue/components/FacultySelect/FacultySelect.tsx +++ b/src/pages/Queue/components/FacultySelect/FacultySelect.tsx @@ -1,55 +1,55 @@ -import { FC } from "react"; +import { FC } from 'react' -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 { useGetFacultiesQuery } from "api/meta.api"; -import { urlKeys } from "constants"; -import { useChangeURL } from "hooks/index"; +import { useGetFacultiesQuery } from 'api/meta.api' +import { urlKeys } from 'constants/index' +import { useChangeURL } from 'hooks/index' +import IPalette from 'theme/IPalette.interface' interface FacultySelectProps { - facultyId: number; - faculty: number; + facultyId: number + faculty: number } interface faculty { - faculty_id: number; - name: string; + faculty_id: number + name: string } const FacultySelect: FC = ({ facultyId, faculty }) => { - const { palette }: IPalette = useTheme(); + const { palette }: IPalette = useTheme() - const { data, isLoading, isSuccess } = useGetFacultiesQuery({}); + const { data, isLoading, isSuccess } = useGetFacultiesQuery({}) - const putFacultyInURL = useChangeURL(); + const putFacultyInURL = useChangeURL() const handleChange = (event: SelectChangeEvent): void => { - const selectedFaculty = event.target.value; + const selectedFaculty = event.target.value - putFacultyInURL(urlKeys.FACULTY, selectedFaculty); - }; + putFacultyInURL(urlKeys.FACULTY, selectedFaculty) + } return ( - {isLoading && } + {isLoading && } {isSuccess && ( )} - ); -}; + ) +} -export { FacultySelect }; +export { FacultySelect } diff --git a/src/pages/Queue/components/Scope/Scope.tsx b/src/pages/Queue/components/Scope/Scope.tsx index ecab794..adfb2d5 100644 --- a/src/pages/Queue/components/Scope/Scope.tsx +++ b/src/pages/Queue/components/Scope/Scope.tsx @@ -1,50 +1,50 @@ -import { FC, useState } from "react"; +import { FC, useState } from 'react' -import Box from "@mui/material/Box"; -import Card from "@mui/material/Card"; -import Divider from "@mui/material/Divider"; -import useTheme from "@mui/material/styles/useTheme"; -import Typography from "@mui/material/Typography"; -import useMediaQuery from "@mui/material/useMediaQuery"; +import Box from '@mui/material/Box' +import Card from '@mui/material/Card' +import Divider from '@mui/material/Divider' +import useTheme from '@mui/material/styles/useTheme' +import Typography from '@mui/material/Typography' +import useMediaQuery from '@mui/material/useMediaQuery' -import { QueueButtonsList } from "./components/QueueButtonsList"; -import { ScopeTicketList } from "./components/ScopeTicketList"; -import { NotFound } from "components/NotFound"; -import { ScopeLabel } from "components/ScopeLabel"; +import { NotFound } from 'components/NotFound' +import { ScopeLabel } from 'components/ScopeLabel' +import { QueueButtonsList } from './components/QueueButtonsList' +import { ScopeTicketList } from './components/ScopeTicketList' -import IPalette from "theme/IPalette.interface"; -import { dimensions } from "constants"; -import { IScope } from "pages/Queue/Queue"; +import { dimensions } from 'constants/index' +import { IScope } from 'pages/Queue/Queue' +import IPalette from 'theme/IPalette.interface' interface ScopeProps { - scope: IScope; - facultyId: number; + scope: IScope + facultyId: number } const Scope: FC = ({ scope, facultyId }) => { const matches = useMediaQuery( `(min-width: ${dimensions.BREAK_POINTS.QUEUE}px)` - ); - const { palette }: IPalette = useTheme(); + ) + const { palette }: IPalette = useTheme() const [queues, setQueues] = useState( scope.queues.length ? scope.queues.map(queue => queue.queue_id) : [] - ); + ) return ( .MuiBox-root": { - p: "20px 16px", + '& > .MuiBox-root': { + p: '20px 16px', }, }} > - - {scope.title} + + {scope.title} @@ -71,7 +71,7 @@ const Scope: FC = ({ scope, facultyId }) => { )} - ); -}; + ) +} -export { Scope }; +export { Scope } diff --git a/src/pages/Queue/components/Scope/components/ScopeTicketList/ScopeTicketList.tsx b/src/pages/Queue/components/Scope/components/ScopeTicketList/ScopeTicketList.tsx index 72e976d..21d8d35 100644 --- a/src/pages/Queue/components/Scope/components/ScopeTicketList/ScopeTicketList.tsx +++ b/src/pages/Queue/components/Scope/components/ScopeTicketList/ScopeTicketList.tsx @@ -1,38 +1,38 @@ +import axios from 'axios' import { FC, + MutableRefObject, + useCallback, useEffect, - useState, useRef, - useCallback, - MutableRefObject, -} from "react"; -import axios from "axios"; + useState, +} from 'react' -import Box from "@mui/material/Box"; -import Grid from "@mui/material/Grid"; -import useTheme from "@mui/material/styles/useTheme"; +import Box from '@mui/material/Box' +import Grid from '@mui/material/Grid' +import useTheme from '@mui/material/styles/useTheme' -import { SimpleTicket } from "components/SimpleTicket/SimpleTicket"; -import { NotFound } from "components/NotFound"; +import { NotFound } from 'components/NotFound' +import { SimpleTicket } from 'components/SimpleTicket/SimpleTicket' -import { ITicket } from "components/Ticket/ticket.interface"; -import IPalette from "theme/IPalette.interface"; -import { endpoints, storage } from "constants"; +import { ITicket } from 'components/Ticket/ticket.interface' +import { endpoints, storage } from 'constants/index' +import IPalette from 'theme/IPalette.interface' interface ScopeTicketListProps { - scope: string; - queues: number[]; - facultyId: number; + scope: string + queues: number[] + facultyId: number } interface RequestQueuesParams { - scope?: string; - queue?: number[]; - assignee?: number; - status?: number[]; - items_count?: number; - faculty?: number; - start_page?: number; + scope?: string + queue?: number[] + assignee?: number + status?: number[] + items_count?: number + faculty?: number + start_page?: number } const ScopeTicketList: FC = ({ @@ -40,39 +40,39 @@ const ScopeTicketList: FC = ({ queues, facultyId, }) => { - const { palette }: IPalette = useTheme(); + const { palette }: IPalette = useTheme() - const [tickets, setTickets] = useState([]); - const [prevQueues, setPrevQueues] = useState([]); - const [currentPage, setCurrentPage] = useState(1); - const [isLoading, setIsLoading] = useState(false); - const [hasMore, setHasMore] = useState(false); + const [tickets, setTickets] = useState([]) + const [prevQueues, setPrevQueues] = useState([]) + const [currentPage, setCurrentPage] = useState(1) + const [isLoading, setIsLoading] = useState(false) + const [hasMore, setHasMore] = useState(false) - const containerRef = useRef(null); - const observer: MutableRefObject = useRef(); + const containerRef = useRef(null) + const observer: MutableRefObject = useRef() const lastTicketElementRef: any = useCallback( (node: HTMLElement) => { - if (isLoading) return; - if (observer.current) observer.current.disconnect(); + if (isLoading) return + if (observer.current) observer.current.disconnect() observer.current = new IntersectionObserver(entries => { if (entries[0].isIntersecting && hasMore) { - setCurrentPage(prevPage => prevPage + 1); + setCurrentPage(prevPage => prevPage + 1) } - }); + }) - if (node) observer.current.observe(node); + if (node) observer.current.observe(node) }, [isLoading, hasMore] - ); + ) useEffect(() => { - setIsLoading(true); + setIsLoading(true) - const isQueuesChanged = prevQueues.toString() !== queues.toString(); + const isQueuesChanged = prevQueues.toString() !== queues.toString() - setPrevQueues(queues); + setPrevQueues(queues) const requestParams: RequestQueuesParams = { assignee: -1, @@ -81,23 +81,23 @@ const ScopeTicketList: FC = ({ faculty: facultyId, items_count: Math.floor(window.innerHeight / 140), start_page: isQueuesChanged ? 1 : currentPage, - }; + } if (isQueuesChanged && currentPage !== 1) { - setCurrentPage(1); + setCurrentPage(1) - const container = containerRef.current; + const container = containerRef.current if (isQueuesChanged && container) { - container.scrollTop = 0; + container.scrollTop = 0 } } else { axios({ - method: "POST", + method: 'POST', url: `${endpoints.BASE_URL}/admin/tickets/ticket_list`, data: requestParams, headers: { - "Content-Type": "application/json", + 'Content-Type': 'application/json', Authorization: `Bearer ${localStorage.getItem(storage.ACCESS_TOKEN)}`, }, }) @@ -106,15 +106,15 @@ const ScopeTicketList: FC = ({ currentPage === 1 ? [...response.data.ticket_list] : [...prevTickets, ...response.data.ticket_list] - ); - setHasMore(currentPage < response.data.total_pages); - setIsLoading(false); + ) + setHasMore(currentPage < response.data.total_pages) + setIsLoading(false) }) .catch(error => { - console.error(error); - }); + console.error(error) + }) } - }, [queues, currentPage]); + }, [queues, currentPage]) return ( @@ -125,26 +125,26 @@ const ScopeTicketList: FC = ({ container gap={2} sx={{ - scrollBehavior: "smooth", - alignContent: "start", - height: "calc(100vh - 380px)", - overflowY: "auto", - "&::-webkit-scrollbar": { - width: "6px", + scrollBehavior: 'smooth', + alignContent: 'start', + height: 'calc(100vh - 380px)', + overflowY: 'auto', + '&::-webkit-scrollbar': { + width: '6px', }, - "&::-webkit-scrollbar-thumb": { + '&::-webkit-scrollbar-thumb': { background: palette.grey.border, - borderRadius: "2px", + borderRadius: '2px', }, - "&::-webkit-scrollbar-thumb:hover": { + '&::-webkit-scrollbar-thumb:hover': { background: palette.grey.active, }, - "&": { - scrollbarWidth: "thin", - scrollbarColor: "#555 #212125", + '&': { + scrollbarWidth: 'thin', + scrollbarColor: '#555 #212125', }, - "&:hover": { - scrollbarColor: "#555 #212125", + '&:hover': { + scrollbarColor: '#555 #212125', }, }} > @@ -156,10 +156,10 @@ const ScopeTicketList: FC = ({ ticket={ticket} key={ticket.ticket_id} /> - ); + ) } - return ; + return })}
@@ -169,7 +169,7 @@ const ScopeTicketList: FC = ({ )} - ); -}; + ) +} -export { ScopeTicketList }; +export { ScopeTicketList } diff --git a/src/router/AdminRoute/AdminRoute.tsx b/src/router/AdminRoute/AdminRoute.tsx index ebe35ca..1d0930c 100644 --- a/src/router/AdminRoute/AdminRoute.tsx +++ b/src/router/AdminRoute/AdminRoute.tsx @@ -1,12 +1,12 @@ -import { Navigate, Outlet } from "react-router"; +import { Navigate, Outlet } from 'react-router' -import { endpoints } from "constants"; -import { checkIsAdmin } from "functions/index"; +import { endpoints } from 'constants/index' +import { checkIsAdmin } from 'functions/index' const AdminRoute = () => { - const isAdmin = checkIsAdmin(); + const isAdmin = checkIsAdmin() - return isAdmin ? : ; -}; + return isAdmin ? : +} -export { AdminRoute }; +export { AdminRoute } diff --git a/src/router/PermissionRote/PermissionRote.tsx b/src/router/PermissionRote/PermissionRote.tsx index 5f85f83..43baac6 100644 --- a/src/router/PermissionRote/PermissionRote.tsx +++ b/src/router/PermissionRote/PermissionRote.tsx @@ -1,21 +1,21 @@ -import { Navigate, Outlet } from "react-router"; +import { Navigate, Outlet } from 'react-router' -import { endpoints } from "constants"; -import { getUserRole } from "functions/manipulateLocalStorage"; +import { endpoints } from 'constants/index' +import { getUserRole } from 'functions/manipulateLocalStorage' interface PermissionRoteProps { - permission: string; + permission: string } const PermissionRote = ({ permission }: PermissionRoteProps) => { - const { permissionList } = getUserRole() || []; - const isHavePermission = permissionList.includes(permission); + const { permissionList } = getUserRole() || [] + const isHavePermission = permissionList.includes(permission) return isHavePermission ? ( ) : ( - ); -}; + ) +} -export { PermissionRote }; +export { PermissionRote } diff --git a/src/router/PrivateRoute/PrivateRoute.tsx b/src/router/PrivateRoute/PrivateRoute.tsx index 5df4271..941fb30 100644 --- a/src/router/PrivateRoute/PrivateRoute.tsx +++ b/src/router/PrivateRoute/PrivateRoute.tsx @@ -1,12 +1,12 @@ -import { Navigate, Outlet } from "react-router"; +import { Navigate, Outlet } from 'react-router' -import { endpoints } from "constants"; -import { useAuth } from "context/AuthContext/AuthContext"; +import { endpoints } from 'constants/index' +import { useAuth } from 'context/AuthContext/AuthContext' const PrivateRoute = () => { - const { isAuth } = useAuth(); + const { isAuth } = useAuth() - return isAuth ? : ; -}; + return isAuth ? : +} -export { PrivateRoute }; +export { PrivateRoute } diff --git a/src/router/Router.tsx b/src/router/Router.tsx index e6ae7eb..1184e28 100644 --- a/src/router/Router.tsx +++ b/src/router/Router.tsx @@ -1,69 +1,69 @@ -import { FC, useEffect, lazy, Suspense } from "react"; +import { FC, lazy, Suspense, useEffect } from 'react' import { Route, Routes, useLocation, useNavigate, useSearchParams, -} from "react-router-dom"; +} from 'react-router-dom' -import { Loader } from "components/Loader"; -import PrivacyPolicy from "pages/PrivacyPolicy"; +import { Loader } from 'components/Loader' +import PrivacyPolicy from 'pages/PrivacyPolicy' -import { endpoints, permissions } from "constants"; -import { useAuth } from "context/AuthContext/AuthContext"; -import { useAccessRenewMutation } from "api/profile.api"; +import { useAccessRenewMutation } from 'api/profile.api' +import { endpoints, permissions } from 'constants/index' +import { useAuth } from 'context/AuthContext/AuthContext' -const Layout = lazy(() => import("layouts/MainLayout")); -const GeneralTickets = lazy(() => import("pages/GeneralTickets")); -const Received = lazy(() => import("pages/Received")); -const Sent = lazy(() => import("pages/Sent")); -const Followed = lazy(() => import("pages/Followed")); -const Bookmarks = lazy(() => import("pages/Bookmarks")); -const Deleted = lazy(() => import("pages/Deleted")); -const Profile = lazy(() => import("pages/Profile")); -const Queue = lazy(() => import("pages/Queue")); -const Notifications = lazy(() => import("pages/Notifications")); -const ErrorPage = lazy(() => import("pages/ErrorPage")); -const FullTicketInfo = lazy(() => import("pages/FullTicketInfo")); -const Statistic = lazy(() => import("pages/Statistic")); -const CreateTicketForm = lazy(() => import("pages/CreateTicketForm")); -const PermissionDenied = lazy(() => import("pages/PermissionDenied")); +const Layout = lazy(() => import('layouts/MainLayout')) +const GeneralTickets = lazy(() => import('pages/GeneralTickets')) +const Received = lazy(() => import('pages/Received')) +const Sent = lazy(() => import('pages/Sent')) +const Followed = lazy(() => import('pages/Followed')) +const Bookmarks = lazy(() => import('pages/Bookmarks')) +const Deleted = lazy(() => import('pages/Deleted')) +const Profile = lazy(() => import('pages/Profile')) +const Queue = lazy(() => import('pages/Queue')) +const Notifications = lazy(() => import('pages/Notifications')) +const ErrorPage = lazy(() => import('pages/ErrorPage')) +const FullTicketInfo = lazy(() => import('pages/FullTicketInfo')) +const Statistic = lazy(() => import('pages/Statistic')) +const CreateTicketForm = lazy(() => import('pages/CreateTicketForm')) +const PermissionDenied = lazy(() => import('pages/PermissionDenied')) -const PrivateRoute = lazy(() => import("./PrivateRoute")); -const PermissionRote = lazy(() => import("./PermissionRote")); -const AdminRoute = lazy(() => import("./AdminRoute")); +const PrivateRoute = lazy(() => import('./PrivateRoute')) +const PermissionRote = lazy(() => import('./PermissionRote')) +const AdminRoute = lazy(() => import('./AdminRoute')) type ApiResponse = { - data?: { access_token: string }; - error?: any; -}; + data?: { access_token: string } + error?: any +} const Router: FC = () => { - const { isAuth, registerUser } = useAuth(); + const { isAuth, registerUser } = useAuth() - const navigate = useNavigate(); - const { pathname, search } = useLocation(); + const navigate = useNavigate() + const { pathname, search } = useLocation() - const [searchParams] = useSearchParams(); + const [searchParams] = useSearchParams() - const [resetPassword] = useAccessRenewMutation({}); + const [resetPassword] = useAccessRenewMutation({}) useEffect(() => { - if (pathname === "/") { - navigate(endpoints.GENERAL_TICKETS); - } else if (searchParams.has("reset_token")) { - const resetToken = searchParams.get("reset_token"); + if (pathname === '/') { + navigate(endpoints.GENERAL_TICKETS) + } else if (searchParams.has('reset_token')) { + const resetToken = searchParams.get('reset_token') resetPassword(resetToken).then((res: ApiResponse) => { - const accessToken = res?.data && res?.data?.access_token; + const accessToken = res?.data && res?.data?.access_token - registerUser(accessToken); - }); + registerUser(accessToken) + }) - navigate(endpoints.GENERAL_TICKETS); + navigate(endpoints.GENERAL_TICKETS) } - }, [pathname, search, isAuth]); + }, [pathname, search, isAuth]) return ( @@ -105,12 +105,12 @@ const Router: FC = () => { path={endpoints.PERMISSION_DENIED} element={} /> - } /> + } /> } /> - } /> + } /> - ); -}; + ) +} -export { Router }; +export { Router } diff --git a/src/shared/functions/checkIsAdmin.ts b/src/shared/functions/checkIsAdmin.ts index f61b130..eb254f3 100644 --- a/src/shared/functions/checkIsAdmin.ts +++ b/src/shared/functions/checkIsAdmin.ts @@ -1,20 +1,20 @@ -import { getUser } from "./manipulateLocalStorage"; -import { roles } from "constants"; +import { roles } from 'constants/index' +import { getUser } from './manipulateLocalStorage' const checkIsAdmin = (role = roles.ADMIN) => { - let isAdmin = false; + let isAdmin = false try { - const user = getUser(); + const user = getUser() if (user?.role?.name?.includes(role)) { - isAdmin = true; + isAdmin = true } } catch (error) { - console.error(error); + console.error(error) } - return isAdmin; -}; + return isAdmin +} -export { checkIsAdmin }; +export { checkIsAdmin } diff --git a/src/shared/functions/clearLocalStorage.ts b/src/shared/functions/clearLocalStorage.ts index d415006..f726c3d 100644 --- a/src/shared/functions/clearLocalStorage.ts +++ b/src/shared/functions/clearLocalStorage.ts @@ -1,12 +1,12 @@ -import { storage } from "constants"; +import { storage } from 'constants/index' const clearLocalStorage = (isRemoveRefreshToken = true) => { if (isRemoveRefreshToken) { - localStorage.removeItem(storage.REFRESH_TOKEN); + localStorage.removeItem(storage.REFRESH_TOKEN) } - localStorage.removeItem(storage.ACCESS_TOKEN); - localStorage.removeItem(storage.USER.FIELD_KEY); -}; + localStorage.removeItem(storage.ACCESS_TOKEN) + localStorage.removeItem(storage.USER.FIELD_KEY) +} -export { clearLocalStorage }; +export { clearLocalStorage } diff --git a/src/shared/functions/decodeJwt.ts b/src/shared/functions/decodeJwt.ts index ebafa1d..180cb35 100644 --- a/src/shared/functions/decodeJwt.ts +++ b/src/shared/functions/decodeJwt.ts @@ -1,30 +1,30 @@ -import jwt_decode from "jwt-decode"; +import jwt_decode from 'jwt-decode' -import { storage } from "constants"; -import { changeUserField } from "./manipulateLocalStorage"; +import { storage } from 'constants/index' +import { changeUserField } from './manipulateLocalStorage' interface IJwtDecodeData { - role: string; - token_id: string; - token_type: string; - user_id: number; - exp: number; - iat: number; - iss: string; - jti: string; - sub: string; + role: string + token_id: string + token_type: string + user_id: number + exp: number + iat: number + iss: string + jti: string + sub: string } const decodeJwt = (jwt: string | null) => { - const jwtDecodeData: "" | IJwtDecodeData | null = jwt && jwt_decode(jwt); + const jwtDecodeData: '' | IJwtDecodeData | null = jwt && jwt_decode(jwt) if (jwt) { - localStorage.setItem(storage.ACCESS_TOKEN, jwt); + localStorage.setItem(storage.ACCESS_TOKEN, jwt) } if (jwtDecodeData && jwtDecodeData?.user_id) { - changeUserField(storage.USER.ID, jwtDecodeData.user_id); + changeUserField(storage.USER.ID, jwtDecodeData.user_id) } -}; +} -export { decodeJwt }; +export { decodeJwt } diff --git a/src/shared/functions/manipulateLocalStorage.ts b/src/shared/functions/manipulateLocalStorage.ts index fb54f1c..6abe71f 100644 --- a/src/shared/functions/manipulateLocalStorage.ts +++ b/src/shared/functions/manipulateLocalStorage.ts @@ -1,59 +1,58 @@ -import jwtDecode from "jwt-decode"; +import jwtDecode from 'jwt-decode' -import { IJwtDecodeData } from "api/useBaseQuery"; -import { storage } from "constants"; +import { IJwtDecodeData } from 'api/useBaseQuery' +import { storage } from 'constants/index' export const getUser = () => { try { - const user = localStorage.getItem(storage.USER.FIELD_KEY); + const user = localStorage.getItem(storage.USER.FIELD_KEY) if (user == null) { - return {}; + return {} } - return JSON.parse(user); + return JSON.parse(user) } catch (error) { - console.error(error); + console.error(error) } -}; +} export const getUserRole = () => { const user = getUser() ?? { role: { - name: "", + name: '', permissions: [], roleId: -1, }, - }; + } - return user?.role; -}; + return user?.role +} export const changeUserField = (fieldName, newValue) => { - const user = getUser() ?? {}; + const user = getUser() ?? {} - user[fieldName] = newValue; + user[fieldName] = newValue - localStorage.setItem(storage.USER.FIELD_KEY, JSON.stringify(user)); -}; + localStorage.setItem(storage.USER.FIELD_KEY, JSON.stringify(user)) +} -export const getAccessToken = () => localStorage.getItem(storage.ACCESS_TOKEN); +export const getAccessToken = () => localStorage.getItem(storage.ACCESS_TOKEN) -export const getRefreshToken = () => - localStorage.getItem(storage.REFRESH_TOKEN); +export const getRefreshToken = () => localStorage.getItem(storage.REFRESH_TOKEN) export const getIsTokensExpired = () => { - let isAccessExpired = true; + let isAccessExpired = true - const accessToken = getAccessToken(); + const accessToken = getAccessToken() if (accessToken) { - const decodeData: IJwtDecodeData = jwtDecode(accessToken); + const decodeData: IJwtDecodeData = jwtDecode(accessToken) if (Date.now() < decodeData.exp * 1000) { - isAccessExpired = false; + isAccessExpired = false } } - return isAccessExpired; -}; + return isAccessExpired +} diff --git a/src/shared/hooks/useChangeURL.ts b/src/shared/hooks/useChangeURL.ts index 83094f5..efaa763 100644 --- a/src/shared/hooks/useChangeURL.ts +++ b/src/shared/hooks/useChangeURL.ts @@ -1,39 +1,39 @@ -import { useSearchParams } from "react-router-dom"; +import { useSearchParams } from 'react-router-dom' -import { urlKeys } from "constants"; +import { urlKeys } from 'constants/index' const useChangeURL = (): (( urlKey: string, value: string, isReturnToStart?: boolean ) => void) => { - const [searchParams, setSearchParams] = useSearchParams(); + const [searchParams, setSearchParams] = useSearchParams() const changeURL = ( urlKey: string, value: string, isReturnToStart: boolean = false ): void => { - const params = new URLSearchParams(searchParams.toString()); + const params = new URLSearchParams(searchParams.toString()) if (params.has(urlKey)) { - params.set(urlKey, value); + params.set(urlKey, value) } else { - params.append(urlKey, value); + params.append(urlKey, value) } if (isReturnToStart) { if (params.has(urlKeys.CURRENT_PAGE)) { - params.set(urlKeys.CURRENT_PAGE, "1"); + params.set(urlKeys.CURRENT_PAGE, '1') } else { - params.append(urlKeys.CURRENT_PAGE, "1"); + params.append(urlKeys.CURRENT_PAGE, '1') } } - setSearchParams(params.toString()); - }; + setSearchParams(params.toString()) + } - return changeURL; -}; + return changeURL +} -export { useChangeURL }; +export { useChangeURL } diff --git a/src/shared/hooks/useCheckStatus.ts b/src/shared/hooks/useCheckStatus.ts index ad273df..5fd575a 100644 --- a/src/shared/hooks/useCheckStatus.ts +++ b/src/shared/hooks/useCheckStatus.ts @@ -1,7 +1,7 @@ import useTheme from '@mui/material/styles/useTheme' +import { statuses } from 'constants/index' import IPalette from 'theme/IPalette.interface' -import { statuses } from 'constants' const useCheckStatus = (status: string): string => { const { palette }: IPalette = useTheme() diff --git a/src/store/api/useBaseQuery.ts b/src/store/api/useBaseQuery.ts index 8b0be77..26bf8f0 100644 --- a/src/store/api/useBaseQuery.ts +++ b/src/store/api/useBaseQuery.ts @@ -3,89 +3,89 @@ import { FetchArgs, FetchBaseQueryError, fetchBaseQuery, -} from "@reduxjs/toolkit/dist/query"; -import axios from "axios"; -import jwtDecode from "jwt-decode"; +} from '@reduxjs/toolkit/dist/query' +import axios from 'axios' +import jwtDecode from 'jwt-decode' +import { endpoints, storage } from 'constants/index' +import { clearLocalStorage } from 'functions/index' import { getAccessToken, getRefreshToken, -} from "functions/manipulateLocalStorage"; -import { endpoints, storage } from "constants"; -import { clearLocalStorage } from "functions/index"; +} from 'functions/manipulateLocalStorage' export interface IJwtDecodeData { - role: string; - token_id: string; - token_type: string; - user_id: number; - exp: number; - iat: number; - iss: string; - jti: string; - sub: string; + role: string + token_id: string + token_type: string + user_id: number + exp: number + iat: number + iss: string + jti: string + sub: string } const baseQuery = fetchBaseQuery({ baseUrl: endpoints.BASE_URL, prepareHeaders: headers => { - const token = getAccessToken(); + const token = getAccessToken() if (token) { - headers.set("Authorization", `Bearer ${token}`); + headers.set('Authorization', `Bearer ${token}`) } - if (!headers.get("Content-Type")) { - headers.set("Content-Type", "application/json"); + if (!headers.get('Content-Type')) { + headers.set('Content-Type', 'application/json') } - if (headers.get("Content-Type") === "multipart/form-data") { - headers.delete("Content-Type"); + if (headers.get('Content-Type') === 'multipart/form-data') { + headers.delete('Content-Type') } - return headers; + return headers }, -}); +}) const baseQueryWithReauth: BaseQueryFn< string | FetchArgs, unknown, FetchBaseQueryError > = async (args, api, extraOptions) => { - let result = await baseQuery(args, api, extraOptions); + let result = await baseQuery(args, api, extraOptions) if (result.error && result.error.status === 401) { - const refreshToken = getRefreshToken(); + const refreshToken = getRefreshToken() if (refreshToken) { - const decodeRefreshToken: IJwtDecodeData = jwtDecode(refreshToken); - const expirationTime = decodeRefreshToken.exp * 1000; + const decodeRefreshToken: IJwtDecodeData = jwtDecode(refreshToken) + const expirationTime = decodeRefreshToken.exp * 1000 if (Date.now() >= expirationTime) { - clearLocalStorage(); + clearLocalStorage() } const refreshResult = await axios({ url: `${endpoints.BASE_URL}auth/token/refresh`, - method: "POST", + method: 'POST', headers: { Authorization: `Bearer ${refreshToken}`, }, - }); + }) if (refreshResult?.data?.access_token) { localStorage.setItem( storage.ACCESS_TOKEN, refreshResult.data.access_token - ); + ) - result = await baseQuery(args, api, extraOptions); + result = await baseQuery(args, api, extraOptions) } else { - clearLocalStorage(false); + clearLocalStorage(false) } } } - return result; -}; + return result +} -export default baseQueryWithReauth; +export default baseQueryWithReauth