From 51962f6243113e322e54aa4e7237f262d427ae51 Mon Sep 17 00:00:00 2001 From: Bastien DUMONT <bdumont@grandlyon.com> Date: Tue, 19 Sep 2023 14:51:56 +0000 Subject: [PATCH] feat(login): stay on page after refresh --- .env.template | 1 - .vscode/settings.json | 4 +- package.json | 1 + src/API.ts | 26 ++++++ src/App.tsx | 13 ++- src/components/Consents/Consents.tsx | 12 +-- src/components/Layout/layout.module.scss | 4 +- src/components/Loader/loader.scss | 4 +- src/components/Login/Login.tsx | 5 +- .../Newsletter/ImagePicker/ImagePicker.tsx | 6 +- src/components/Newsletter/Newsletter.tsx | 17 ++-- src/components/Popups/Popups.tsx | 13 ++- src/components/Prices/PriceSection.tsx | 6 +- src/components/Routes/Router.tsx | 32 +++---- src/components/SideBar/SideBar.tsx | 25 ++++-- src/hooks/useAuth.ts | 50 ----------- src/hooks/useFindUser.ts | 31 ------- src/hooks/userContext.ts | 9 -- yarn.lock | 84 ++++++++++++++++++- 19 files changed, 176 insertions(+), 167 deletions(-) create mode 100644 src/API.ts delete mode 100644 src/hooks/useAuth.ts delete mode 100644 src/hooks/useFindUser.ts delete mode 100644 src/hooks/userContext.ts diff --git a/.env.template b/.env.template index 232b9048..e63fc882 100644 --- a/.env.template +++ b/.env.template @@ -19,7 +19,6 @@ CLIENT_SECRET= AUTH_URL= TOKEN_URL= USERINFO_URL= -LOGOUT_URL= # Access to the database DATABASE_USER= diff --git a/.vscode/settings.json b/.vscode/settings.json index 9d92bf0c..537a52d4 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -34,8 +34,8 @@ "editor.defaultFormatter": "esbenp.prettier-vscode", "peacock.color": "#2aa63d", "sonarlint.connectedMode.project": { - "connectionId": "Sonar", - "projectKey": "web-et-numerique-factory-llle-project-backoffice-client" + "connectionId": "sonarqube-forge-grandlyon", + "projectKey": "web-et-numerique-llle-project-backoffice-client" }, "cSpell.words": [ "backoffice", diff --git a/package.json b/package.json index 53d9a24e..ba1fc249 100644 --- a/package.json +++ b/package.json @@ -46,6 +46,7 @@ "react": "^17.0.2", "react-dom": "^17.0.2", "react-draft-wysiwyg": "^1.15.0", + "react-query": "^3.39.3", "react-router-dom": "^6.0.0", "react-scripts": "^5.0.1", "react-toastify": "^9.0.0", diff --git a/src/API.ts b/src/API.ts new file mode 100644 index 00000000..e8e2df1f --- /dev/null +++ b/src/API.ts @@ -0,0 +1,26 @@ +import axios from 'axios' +import { useQuery } from 'react-query' +import { toast } from 'react-toastify' +import { User } from './models/user.model' + +const fetchWhoAmI = async () => { + const { data } = await axios.get<User | null>('/api/common/WhoAmI') + return data +} + +export const useWhoAmI = () => { + return useQuery({ + queryKey: ['WhoAmI'], + queryFn: fetchWhoAmI, + retry: false, + onError: error => { + console.error('error whoami', error) + toast.error('Accès refusé, veuillez vous connecter') + }, + refetchOnMount: false, + }) +} + +export const fetchLogout = async () => { + return await axios.get('/Logout') +} diff --git a/src/App.tsx b/src/App.tsx index 292c788d..980923de 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,22 +1,21 @@ +import { QueryClient, QueryClientProvider } from 'react-query' import { BrowserRouter } from 'react-router-dom' import { ToastContainer } from 'react-toastify' import 'react-toastify/dist/ReactToastify.css' import Layout from './components/Layout/Layout' import Router from './components/Routes/Router' -import useFindUser from './hooks/useFindUser' -import { UserContext } from './hooks/userContext' -function App() { - const { user, setUser, isLoading } = useFindUser() +const queryClient = new QueryClient() +function App() { return ( <BrowserRouter> - <UserContext.Provider value={{ user, setUser, isLoading }}> + <QueryClientProvider client={queryClient}> <Layout> <Router /> </Layout> - </UserContext.Provider> - <ToastContainer theme="colored" /> + <ToastContainer theme="colored" /> + </QueryClientProvider> </BrowserRouter> ) } diff --git a/src/components/Consents/Consents.tsx b/src/components/Consents/Consents.tsx index 23cee711..d14ab99d 100644 --- a/src/components/Consents/Consents.tsx +++ b/src/components/Consents/Consents.tsx @@ -13,15 +13,9 @@ import 'ag-grid-community/dist/styles/ag-grid.css' import 'ag-grid-community/dist/styles/ag-theme-alpine-dark.css' import { AgGridReact } from 'ag-grid-react' import { DateTime } from 'luxon' -import React, { - useCallback, - useContext, - useEffect, - useMemo, - useState, -} from 'react' +import React, { useCallback, useEffect, useMemo, useState } from 'react' +import { useWhoAmI } from '../../API' import { getAxiosXSRFHeader } from '../../axios.config' -import { UserContext, UserContextProps } from '../../hooks/userContext' import { IConsent } from '../../models/consent.model' import { ConsentService } from '../../services/consent.service' import DowloadModal from './DowloadModal' @@ -39,7 +33,7 @@ const Consents: React.FC = () => { const [page, setPage] = useState<number>(0) const [rowsPerPage, setRowsPerPage] = useState<number>(50) const [totalRows, setTotalRows] = useState<number>(50) - const { user }: Partial<UserContextProps> = useContext(UserContext) + const { data: user } = useWhoAmI() const consentService = useMemo(() => { return new ConsentService() }, []) diff --git a/src/components/Layout/layout.module.scss b/src/components/Layout/layout.module.scss index e4a59aad..8735c26f 100644 --- a/src/components/Layout/layout.module.scss +++ b/src/components/Layout/layout.module.scss @@ -3,6 +3,8 @@ .root { display: flex; + background: $dark-bg; + height: 100vh; } .wrapper { @@ -11,9 +13,7 @@ 0px 5px 5px rgb(0 0 0 / 20%), 0px 3px 14px rgb(0 0 0 / 12%), 0px 8px 10px rgb(0 0 0 / 14%); - background: $dark-bg; overflow-y: scroll; - height: 100vh; @media screen and (max-width: $width-tablet) { margin-left: 0; diff --git a/src/components/Loader/loader.scss b/src/components/Loader/loader.scss index 872512dc..0f9e2144 100644 --- a/src/components/Loader/loader.scss +++ b/src/components/Loader/loader.scss @@ -1,9 +1,8 @@ @import '../../styles/config/colors.scss'; .loader-container { - width: 100%; - height: 80vh; display: flex; + height: 100%; overflow: hidden; } .loader { @@ -23,7 +22,6 @@ background: -o-linear-gradient(left, $gold 10%, rgba(255, 255, 255, 0) 42%); background: -ms-linear-gradient(left, $gold 10%, rgba(255, 255, 255, 0) 42%); background: linear-gradient(to right, $gold 10%, rgba(255, 255, 255, 0) 42%); - position: relative; -webkit-animation: load3 1.4s infinite linear; animation: load3 1.4s infinite linear; -webkit-transform: translateZ(0); diff --git a/src/components/Login/Login.tsx b/src/components/Login/Login.tsx index 1f20b820..1d7b3016 100644 --- a/src/components/Login/Login.tsx +++ b/src/components/Login/Login.tsx @@ -1,9 +1,10 @@ import React from 'react' -import { useAuth } from '../../hooks/useAuth' import './login.scss' const Login: React.FC = () => { - const { loginUser } = useAuth() + const loginUser = () => { + window.location.href = '/OAuth2Login' + } return ( <div className="login"> diff --git a/src/components/Newsletter/ImagePicker/ImagePicker.tsx b/src/components/Newsletter/ImagePicker/ImagePicker.tsx index fa7946a0..6a58e17e 100644 --- a/src/components/Newsletter/ImagePicker/ImagePicker.tsx +++ b/src/components/Newsletter/ImagePicker/ImagePicker.tsx @@ -1,7 +1,7 @@ import Pagination from '@material-ui/lab/Pagination' -import React, { useContext, useEffect, useState } from 'react' +import React, { useEffect, useState } from 'react' +import { useWhoAmI } from '../../../API' import { getAxiosXSRFHeader } from '../../../axios.config' -import { UserContext, UserContextProps } from '../../../hooks/userContext' import { NewsletterService } from '../../../services/newsletter.service' import { EditorType } from '../CustomEditor' import Modal from '../Modal/Modal' @@ -16,12 +16,12 @@ const ImagePicker: React.FC<ImagePickerProps> = ({ imageURL, handleChange, }) => { + const { data: user } = useWhoAmI() const [imageNames, setImageNames] = useState<string[][]>([]) const [selectedImageURL, setSelectedImageURL] = useState<string>( imageURL && imageURL !== null ? imageURL : '' ) const [openModal, setOpenModal] = useState<boolean>(false) - const { user }: Partial<UserContextProps> = useContext(UserContext) const [currentPage, setCurrentPage] = useState(1) const [pageCount, setPageCount] = useState<number>(1) const [preSelectImage, setPreSelectImage] = useState<string>('') diff --git a/src/components/Newsletter/Newsletter.tsx b/src/components/Newsletter/Newsletter.tsx index 8d2fbf56..63a192db 100644 --- a/src/components/Newsletter/Newsletter.tsx +++ b/src/components/Newsletter/Newsletter.tsx @@ -1,12 +1,6 @@ -import React, { - useCallback, - useContext, - useEffect, - useMemo, - useState, -} from 'react' +import React, { useCallback, useEffect, useMemo, useState } from 'react' +import { useWhoAmI } from '../../API' import { getAxiosXSRFHeader } from '../../axios.config' -import { UserContext, UserContextProps } from '../../hooks/userContext' import { IMailSubject } from '../../models/mailSubject.model' import { IMonthlyInfo } from '../../models/monthlyInfo.model' import { IMonthlyNews } from '../../models/monthlyNews.model' @@ -30,9 +24,9 @@ export type ContentItems = | '' const Newsletter: React.FC = () => { - /** - * Display previous month until the newsletter is sent on the 3rd day of the month - */ + const { data: user } = useWhoAmI() + + /** Display previous month until the newsletter is sent on the 3rd day of the month */ const getCurrentNewsletterDate = (): Date => { const today = new Date() const currentDay = today.getDate() @@ -57,7 +51,6 @@ const Newsletter: React.FC = () => { const [isLoading, setIsLoading] = useState<boolean>(false) const [warningModal, setWarningModal] = useState<boolean>(false) const [toDelete, setToDelete] = useState<ContentItems>('') - const { user }: Partial<UserContextProps> = useContext(UserContext) const newsletterService = useMemo(() => { return new NewsletterService() }, []) diff --git a/src/components/Popups/Popups.tsx b/src/components/Popups/Popups.tsx index f5a8a2eb..5f868efb 100644 --- a/src/components/Popups/Popups.tsx +++ b/src/components/Popups/Popups.tsx @@ -1,9 +1,9 @@ import { DateTime } from 'luxon' -import React, { useCallback, useContext, useEffect, useState } from 'react' +import React, { useCallback, useEffect, useState } from 'react' import 'react-draft-wysiwyg/dist/react-draft-wysiwyg.css' +import { useWhoAmI } from '../../API' import { getAxiosXSRFHeader } from '../../axios.config' import { CheckboxType } from '../../enum/checkboxType.enum' -import { UserContext, UserContextProps } from '../../hooks/userContext' import { ICustomPopup, PopupDuration } from '../../models/customPopup.model' import { Option, @@ -34,6 +34,8 @@ const OPTIONS: Option[] = [ ] const Popups: React.FC = () => { + const { data: user } = useWhoAmI() + const [refreshData, setRefreshData] = useState(false) const [isLoading, setIsLoading] = useState(false) const [partnersInfo, setPartnersInfo] = useState<IPartnersInfo>({ @@ -54,16 +56,12 @@ const Popups: React.FC = () => { duration: 0, }) - const { user }: Partial<UserContextProps> = useContext(UserContext) - const isPartnerNotificationOn = () => partnersInfo.enedis_failure || partnersInfo.egl_failure || partnersInfo.grdf_failure - /** - * Only one type of popup can be enabled - */ + /** Only one type of popup can be enabled */ const isPageValid = () => !(isPartnerNotificationOn() && customPopup.popupEnabled) @@ -105,6 +103,7 @@ const Popups: React.FC = () => { })) } + // clean this const handleCancel = useCallback(() => { setRefreshData(true) }, [setRefreshData]) diff --git a/src/components/Prices/PriceSection.tsx b/src/components/Prices/PriceSection.tsx index 9b67c826..8e6d6d87 100644 --- a/src/components/Prices/PriceSection.tsx +++ b/src/components/Prices/PriceSection.tsx @@ -1,13 +1,13 @@ import dayjs from 'dayjs' import timezone from 'dayjs/plugin/timezone' import utc from 'dayjs/plugin/utc' -import React, { useCallback, useContext, useEffect, useState } from 'react' +import React, { useCallback, useEffect, useState } from 'react' import 'react-draft-wysiwyg/dist/react-draft-wysiwyg.css' +import { useWhoAmI } from '../../API' import arrowDown from '../../assets/icons/down-arrow.png' import { getAxiosXSRFHeader } from '../../axios.config' import { FluidType } from '../../enum/fluidTypes' import { FrequencyInMonth } from '../../enum/frequency.enum' -import { UserContext, UserContextProps } from '../../hooks/userContext' import { IPrice } from '../../models/price.model' import { PricesService } from '../../services/prices.service' import Loader from '../Loader/Loader' @@ -23,6 +23,7 @@ interface PriceSectionProps { } const PriceSection: React.FC<PriceSectionProps> = ({ fluid, frequency }) => { + const { data: user } = useWhoAmI() const [prices, setPrices] = useState<IPrice[]>([]) const [nextPrice, setNextPrice] = useState<IPrice>() const [isLoading, setIsLoading] = useState<boolean>(false) @@ -35,7 +36,6 @@ const PriceSection: React.FC<PriceSectionProps> = ({ fluid, frequency }) => { startDate: '', endDate: null, }) - const { user }: Partial<UserContextProps> = useContext(UserContext) const maxPerList = 8 const handlePriceSelection = useCallback((val: string) => { diff --git a/src/components/Routes/Router.tsx b/src/components/Routes/Router.tsx index 7a048cc8..7a723f12 100644 --- a/src/components/Routes/Router.tsx +++ b/src/components/Routes/Router.tsx @@ -1,7 +1,7 @@ -import React, { useContext } from 'react' import { Navigate, Route, Routes } from 'react-router-dom' -import { UserContext } from '../../hooks/userContext' +import { useWhoAmI } from '../../API' import Consents from '../Consents/Consents' +import Loader from '../Loader/Loader' import Login from '../Login/Login' import Newsletter from '../Newsletter/Newsletter' import Popups from '../Popups/Popups' @@ -36,32 +36,32 @@ export const routes = Object.keys(links).map(key => ({ adminOnly: links[key].adminOnly, })) -const Router: React.FC = () => { - const { user } = useContext(UserContext) +const Router = () => { + const { data: user, isLoading } = useWhoAmI() - return ( - <Routes> - {user ? ( + if (isLoading) return <Loader /> + + if (user) { + return ( + <Routes> <> <Route path={links.newsletter.path} element={<Newsletter />} /> <Route path={links.prices.path} element={<Prices />} /> - <Route path={links.popups.path} element={<Popups />} /> + <Route path="/popups" element={<Popups />} /> {user.isAdmin && ( <Route path={links.consents.path} element={<Consents />} /> )} + <Route path="/login" element={<Login />} /> <Route path="*" element={<Navigate replace to={links.newsletter.path} />} /> </> - ) : ( - <> - <Route path="/login" element={<Login />} /> - <Route path="*" element={<Navigate replace to="/login" />} /> - </> - )} - </Routes> - ) + </Routes> + ) + } + + return <Login /> } export default Router diff --git a/src/components/SideBar/SideBar.tsx b/src/components/SideBar/SideBar.tsx index e55ec3a6..a00cda24 100644 --- a/src/components/SideBar/SideBar.tsx +++ b/src/components/SideBar/SideBar.tsx @@ -1,14 +1,25 @@ -import React, { useContext } from 'react' -import { NavLink } from 'react-router-dom' +import React from 'react' +import { useMutation, useQueryClient } from 'react-query' +import { NavLink, useNavigate } from 'react-router-dom' +import { fetchLogout, useWhoAmI } from '../../API' import logo from '../../assets/icons/ecolyo-logo.svg' -import { useAuth } from '../../hooks/useAuth' -import { UserContext } from '../../hooks/userContext' import { routes } from '../Routes/Router' import './sidebar.scss' const SideBar: React.FC = () => { - const { user } = useContext(UserContext) - const { logoutUser } = useAuth() + const queryClient = useQueryClient() + const navigate = useNavigate() + const { data: user } = useWhoAmI() + + const { mutate: logout } = useMutation({ + mutationFn: fetchLogout, + onSuccess: () => { + queryClient.clear() + navigate('/login') + }, + }) + + if (!user) return <div /> return ( <nav className="menu"> @@ -37,7 +48,7 @@ const SideBar: React.FC = () => { </div> <div className="bottom"> {user ? ( - <button className="btnValid" onClick={logoutUser}> + <button className="btnValid" onClick={() => logout()}> Logout </button> ) : ( diff --git a/src/hooks/useAuth.ts b/src/hooks/useAuth.ts deleted file mode 100644 index dd4cc745..00000000 --- a/src/hooks/useAuth.ts +++ /dev/null @@ -1,50 +0,0 @@ -import axios from 'axios' -import { useContext, useState } from 'react' -import { useNavigate } from 'react-router-dom' -import { links } from '../components/Routes/Router' -import { UserContext } from './userContext' - -interface Auth { - loginUser: () => Promise<void> - error: unknown - logoutUser: () => void -} -export const useAuth = (): Auth => { - const navigate = useNavigate() - const { setUser } = useContext(UserContext) - const [error, setError] = useState<unknown>(null) - - //login user - const loginUser = async (): Promise<void> => { - try { - window.location.href = '/OAuth2Login' - await setUserContext() - } catch (e) { - setError(e) - } - } - - const logoutUser = async (): Promise<void> => { - try { - if (setUser) setUser(null) - window.location.href = '/Logout' - } catch (e) { - setError(e) - } - } - - //set user in context and push them home - const setUserContext = async (): Promise<void> => { - try { - const { data } = await axios.get(`/api/common/WhoAmI`) - if (data && setUser) { - setUser(data) - navigate(links.newsletter.path) - } - } catch (e) { - setError(e) - } - } - - return { loginUser, error, logoutUser } -} diff --git a/src/hooks/useFindUser.ts b/src/hooks/useFindUser.ts deleted file mode 100644 index 201bd31a..00000000 --- a/src/hooks/useFindUser.ts +++ /dev/null @@ -1,31 +0,0 @@ -import axios from 'axios' -import { useEffect, useState } from 'react' -import { toast } from 'react-toastify' -import { User } from '../models/user.model' - -const useFindUser = () => { - const [user, setUser] = useState<User | null>(null) - const [isLoading, setLoading] = useState<boolean>(true) - - useEffect(() => { - async function findUser() { - try { - const { data } = await axios.get(`/api/common/WhoAmI`) - if (data) { - setUser(data) - setLoading(false) - } - } catch (error) { - toast.error('Accès refusé, veuillez vous connecter') - } - } - findUser() - }, []) - return { - user, - setUser, - isLoading, - } -} - -export default useFindUser diff --git a/src/hooks/userContext.ts b/src/hooks/userContext.ts deleted file mode 100644 index e2f69367..00000000 --- a/src/hooks/userContext.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { createContext, Dispatch, SetStateAction } from 'react' -import { User } from '../models/user.model' - -export interface UserContextProps { - user: User | null - setUser: Dispatch<SetStateAction<User | null>> - isLoading: boolean -} -export const UserContext = createContext<Partial<UserContextProps>>({}) diff --git a/yarn.lock b/yarn.lock index c71cbde7..34b8d452 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1189,6 +1189,13 @@ dependencies: regenerator-runtime "^0.13.4" +"@babel/runtime@^7.6.2", "@babel/runtime@^7.7.2": + version "7.22.15" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.22.15.tgz#38f46494ccf6cf020bd4eed7124b425e83e523b8" + integrity sha512-T0O+aa+4w0u06iNmapipJXMV4HoUir03hpx3/YqXXhu9xim3w+dVphjFWl1OH8NbZHw5Lbm9k45drDkgq2VNNA== + dependencies: + regenerator-runtime "^0.14.0" + "@babel/template@^7.18.10": version "7.18.10" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.18.10.tgz#6f9134835970d1dbf0835c0d100c9f38de0c5e71" @@ -3264,7 +3271,7 @@ bfj@^7.0.2: hoopy "^0.1.4" tryer "^1.0.1" -big-integer@^1.6.44: +big-integer@^1.6.16, big-integer@^1.6.44: version "1.6.51" resolved "https://registry.yarnpkg.com/big-integer/-/big-integer-1.6.51.tgz#0df92a5d9880560d3ff2d5fd20245c889d130686" integrity sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg== @@ -3346,6 +3353,20 @@ braces@^3.0.2, braces@~3.0.2: dependencies: fill-range "^7.0.1" +broadcast-channel@^3.4.1: + version "3.7.0" + resolved "https://registry.yarnpkg.com/broadcast-channel/-/broadcast-channel-3.7.0.tgz#2dfa5c7b4289547ac3f6705f9c00af8723889937" + integrity sha512-cIAKJXAxGJceNZGTZSBzMxzyOn72cVgPnKx4dc6LRjQgbaJUQqhy5rzL3zbMxkMWsGKkv2hSFkPRMEXfoMZ2Mg== + dependencies: + "@babel/runtime" "^7.7.2" + detect-node "^2.1.0" + js-sha3 "0.8.0" + microseconds "0.2.0" + nano-time "1.0.0" + oblivious-set "1.0.0" + rimraf "3.0.2" + unload "2.2.0" + browser-process-hrtime@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz#3c9b4b7d782c8121e56f10106d84c0d0ffc94626" @@ -4126,7 +4147,7 @@ detect-newline@^3.0.0: resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== -detect-node@^2.0.4: +detect-node@^2.0.4, detect-node@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.1.0.tgz#c9c70775a49c3d03bc2c06d9a73be550f978f8b1" integrity sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g== @@ -6470,6 +6491,11 @@ jest@^27.4.3: import-local "^3.0.2" jest-cli "^27.5.1" +js-sha3@0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.8.0.tgz#b9b7a5da73afad7dedd0f8c463954cbde6818840" + integrity sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q== + "js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" @@ -6866,6 +6892,14 @@ makeerror@1.0.12: dependencies: tmpl "1.0.5" +match-sorter@^6.0.2: + version "6.3.1" + resolved "https://registry.yarnpkg.com/match-sorter/-/match-sorter-6.3.1.tgz#98cc37fda756093424ddf3cbc62bfe9c75b92bda" + integrity sha512-mxybbo3pPNuA+ZuCUhm5bwNkXrJTbsk5VWbR5wiwz/GC6LIiegBGn2w3O08UG/jdbYLinw51fSQ5xNU1U3MgBw== + dependencies: + "@babel/runtime" "^7.12.5" + remove-accents "0.4.2" + mdn-data@2.0.14: version "2.0.14" resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.14.tgz#7113fc4281917d63ce29b43446f701e68c25ba50" @@ -6916,6 +6950,11 @@ micromatch@^4.0.2, micromatch@^4.0.4, micromatch@^4.0.5: braces "^3.0.2" picomatch "^2.3.1" +microseconds@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/microseconds/-/microseconds-0.2.0.tgz#233b25f50c62a65d861f978a4a4f8ec18797dc39" + integrity sha512-n7DHHMjR1avBbSpsTBj6fmMGh2AGrifVV4e+WYc3Q9lO+xnSZ3NyhcBND3vzzatt05LFhoKFRxrIyklmLlUtyA== + mime-db@1.52.0, "mime-db@>= 1.43.0 < 2": version "1.52.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" @@ -7011,6 +7050,13 @@ multicast-dns@^7.2.5: dns-packet "^5.2.2" thunky "^1.0.2" +nano-time@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/nano-time/-/nano-time-1.0.0.tgz#b0554f69ad89e22d0907f7a12b0993a5d96137ef" + integrity sha512-flnngywOoQ0lLQOTRNexn2gGSNuM9bKj9RZAWSzhQ+UJYaAFG9bac4DW9VHjUAzrOaIcajHybCTHe/bkvozQqA== + dependencies: + big-integer "^1.6.16" + nanoid@^3.3.4: version "3.3.4" resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.4.tgz#730b67e3cd09e2deacf03c027c81c9d9dbc5e8ab" @@ -7184,6 +7230,11 @@ object.values@^1.1.0, object.values@^1.1.5: define-properties "^1.1.3" es-abstract "^1.19.1" +oblivious-set@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/oblivious-set/-/oblivious-set-1.0.0.tgz#c8316f2c2fb6ff7b11b6158db3234c49f733c566" + integrity sha512-z+pI07qxo4c2CulUHCDf9lcqDlMSo72N/4rLUpRXf6fu+q8vjt8y0xS+Tlf8NTJDdTXHbdeO1n3MlbctwEoXZw== + obuf@^1.0.0, obuf@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e" @@ -8305,6 +8356,15 @@ react-is@^18.0.0: resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b" integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w== +react-query@^3.39.3: + version "3.39.3" + resolved "https://registry.yarnpkg.com/react-query/-/react-query-3.39.3.tgz#4cea7127c6c26bdea2de5fb63e51044330b03f35" + integrity sha512-nLfLz7GiohKTJDuT4us4X3h/8unOh+00MLb2yJoGTPjxKs2bc1iDhkNx2bd5MKklXnOD3NrVZ+J2UXujA5In4g== + dependencies: + "@babel/runtime" "^7.5.5" + broadcast-channel "^3.4.1" + match-sorter "^6.0.2" + react-refresh@^0.11.0: version "0.11.0" resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.11.0.tgz#77198b944733f0f1f1a90e791de4541f9f074046" @@ -8465,6 +8525,11 @@ regenerator-runtime@^0.13.4, regenerator-runtime@^0.13.9: resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52" integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA== +regenerator-runtime@^0.14.0: + version "0.14.0" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz#5e19d68eb12d486f797e15a3c6a918f7cec5eb45" + integrity sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA== + regenerator-transform@^0.15.0: version "0.15.0" resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.15.0.tgz#cbd9ead5d77fae1a48d957cf889ad0586adb6537" @@ -8520,6 +8585,11 @@ relateurl@^0.2.7: resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9" integrity sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog== +remove-accents@0.4.2: + version "0.4.2" + resolved "https://registry.yarnpkg.com/remove-accents/-/remove-accents-0.4.2.tgz#0a43d3aaae1e80db919e07ae254b285d9e1c7bb5" + integrity sha512-7pXIJqJOq5tFgG1A2Zxti3Ht8jJF337m4sowbuHsW30ZnkQFnDzy9qBNhgzX8ZLW4+UBcXiiR7SwR6pokHsxiA== + renderkid@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/renderkid/-/renderkid-3.0.0.tgz#5fd823e4d6951d37358ecc9a58b1f06836b6268a" @@ -8612,7 +8682,7 @@ reusify@^1.0.4: resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== -rimraf@^3.0.0, rimraf@^3.0.2: +rimraf@3.0.2, rimraf@^3.0.0, rimraf@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== @@ -9570,6 +9640,14 @@ universalify@^2.0.0: resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ== +unload@2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/unload/-/unload-2.2.0.tgz#ccc88fdcad345faa06a92039ec0f80b488880ef7" + integrity sha512-B60uB5TNBLtN6/LsgAf3udH9saB5p7gqJwcFfbOEZ8BcBHnGwCf6G/TGiEqkRAxX7zAFIUtzdrXQSdL3Q/wqNA== + dependencies: + "@babel/runtime" "^7.6.2" + detect-node "^2.0.4" + unpipe@1.0.0, unpipe@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" -- GitLab