From 2ae212d46a7c8c333101f39e76435721c8d0d00e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johan=20=C3=96brink?= Date: Fri, 9 Apr 2021 18:31:31 +0200 Subject: [PATCH] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20Timetables=20(#12)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 🎸 Upgraded to api v4 * change: Changed hook from useChildlist to useEtjanstChild * feat: 🎸 Added useSkola24Children * feat: 🎸 Added useTimetable * feat: 🎸 Added back hook for useChildList This hook wraps useEtjanstChildren and useSkola24Children and merges the results --- package.json | 26 +- .../@skolplattformen/embedded-api.js | 2 + src/childlists.test.js | 66 +++ src/childlists.ts | 15 + src/fake.test.js | 4 +- src/hooks.ts | 58 +- src/logout.test.js | 10 +- src/reducers.ts | 8 +- src/store.ts | 8 +- src/types.ts | 11 +- src/useChildList.test.js | 269 +++++++++ ...ist.test.js => useEtjanstChildren.test.js} | 42 +- src/useSkola24Children.test.js | 213 +++++++ src/useTimetable.test.js | 219 ++++++++ yarn.lock | 526 +++++++++++++----- 15 files changed, 1276 insertions(+), 201 deletions(-) create mode 100644 src/childlists.test.js create mode 100644 src/childlists.ts create mode 100644 src/useChildList.test.js rename src/{useChildlist.test.js => useEtjanstChildren.test.js} (81%) create mode 100644 src/useSkola24Children.test.js create mode 100644 src/useTimetable.test.js diff --git a/package.json b/package.json index 1b39e215..17124316 100644 --- a/package.json +++ b/package.json @@ -19,32 +19,32 @@ "publish-package": "npm publish --access public" }, "dependencies": { - "react-redux": "^7.2.2", + "react-redux": "^7.2.3", "redux": "^4.0.5" }, "peerDependencies": { - "@skolplattformen/embedded-api": "^2.0.0", + "@skolplattformen/embedded-api": "^4.0.0", "react": "^16.11.0" }, "devDependencies": { - "@babel/preset-env": "^7.13.10", - "@babel/preset-react": "^7.12.13", + "@babel/preset-env": "^7.13.15", + "@babel/preset-react": "^7.13.13", "@babel/preset-typescript": "^7.13.0", - "@skolplattformen/embedded-api": "^2.0.0", - "@testing-library/jest-dom": "^5.11.9", - "@testing-library/react": "^11.2.5", - "@testing-library/react-hooks": "^5.1.0", - "@types/jest": "^26.0.20", + "@skolplattformen/embedded-api": "^4.0.0", + "@testing-library/jest-dom": "^5.11.10", + "@testing-library/react": "^11.2.6", + "@testing-library/react-hooks": "^5.1.1", + "@types/jest": "^26.0.22", "@types/react": "^16.14.3", "@types/react-redux": "^7.1.16", - "@typescript-eslint/eslint-plugin": "^4.17.0", + "@typescript-eslint/eslint-plugin": "^4.21.0", "babel-jest": "^26.6.3", - "eslint": "^7.21.0", + "eslint": "^7.23.0", "eslint-config-airbnb-typescript": "^12.3.1", "eslint-plugin-import": "^2.22.1", - "eslint-plugin-jest": "^24.2.1", + "eslint-plugin-jest": "^24.3.4", "eslint-plugin-jsx-a11y": "^6.4.1", - "eslint-plugin-react": "^7.22.0", + "eslint-plugin-react": "^7.23.2", "eslint-plugin-react-hooks": "^4.2.0", "events": "^3.3.0", "jest": "^26.6.3", diff --git a/src/__mocks__/@skolplattformen/embedded-api.js b/src/__mocks__/@skolplattformen/embedded-api.js index b676d454..44d2e524 100644 --- a/src/__mocks__/@skolplattformen/embedded-api.js +++ b/src/__mocks__/@skolplattformen/embedded-api.js @@ -15,12 +15,14 @@ const createApi = () => ({ getCalendar: jest.fn(), getChildren: jest.fn(), + getSkola24Children: jest.fn(), getClassmates: jest.fn(), getMenu: jest.fn(), getNews: jest.fn(), getNewsDetails: jest.fn(), getNotifications: jest.fn(), getSchedule: jest.fn(), + getTimetable: jest.fn(), getUser: jest.fn(), }) const init = jest.fn().mockImplementation(() => createApi()) diff --git a/src/childlists.test.js b/src/childlists.test.js new file mode 100644 index 00000000..21436d19 --- /dev/null +++ b/src/childlists.test.js @@ -0,0 +1,66 @@ +import { merge } from './childlists' + +describe('childlists', () => { + describe('merge', () => { + it('works with empty skola24children list', () => { + const etjanstChildren = [ + { name: 'Uwe Übrink (elev)' }, + { name: 'Cassius Übrink (elev)' }, + ] + const skola24Children = [] + + const children = [ + { name: 'Uwe Übrink (elev)' }, + { name: 'Cassius Übrink (elev)' }, + ] + expect(merge(etjanstChildren, skola24Children)).toEqual(children) + }) + it('works with same length skola24children list', () => { + const etjanstChildren = [ + { name: 'Uwe Übrink (elev)' }, + { name: 'Cassius Übrink (elev)' }, + ] + const skola24Children = [ + { firstName: 'Uwe', lastName: 'Vredstein Übrink' }, + { firstName: 'Cassius', lastName: 'Vredstein Übrink' }, + ] + + const children = [ + { name: 'Uwe Übrink (elev)', firstName: 'Uwe', lastName: 'Vredstein Übrink' }, + { name: 'Cassius Übrink (elev)', firstName: 'Cassius', lastName: 'Vredstein Übrink' }, + ] + expect(merge(etjanstChildren, skola24Children)).toEqual(children) + }) + it('works with different length skola24children list', () => { + const etjanstChildren = [ + { name: 'Uwe Übrink (elev)' }, + { name: 'Cassius Übrink (elev)' }, + ] + const skola24Children = [ + { firstName: 'Uwe', lastName: 'Vredstein Übrink' }, + ] + + const children = [ + { name: 'Uwe Übrink (elev)', firstName: 'Uwe', lastName: 'Vredstein Übrink' }, + { name: 'Cassius Übrink (elev)' }, + ] + expect(merge(etjanstChildren, skola24Children)).toEqual(children) + }) + it('works with non matching skola24children list', () => { + const etjanstChildren = [ + { name: 'Uwe Übrink (elev)' }, + { name: 'Cassius Übrink (elev)' }, + ] + const skola24Children = [ + { firstName: 'Uwe', lastName: 'Vredstein Übrink' }, + { firstName: 'Rolph', lastName: 'Gögendorff Bröök' }, + ] + + const children = [ + { name: 'Uwe Übrink (elev)', firstName: 'Uwe', lastName: 'Vredstein Übrink' }, + { name: 'Cassius Übrink (elev)' }, + ] + expect(merge(etjanstChildren, skola24Children)).toEqual(children) + }) + }) +}) diff --git a/src/childlists.ts b/src/childlists.ts new file mode 100644 index 00000000..2e1fbcce --- /dev/null +++ b/src/childlists.ts @@ -0,0 +1,15 @@ +import { Child, EtjanstChild, Skola24Child } from '@skolplattformen/embedded-api' + +// eslint-disable-next-line import/prefer-default-export +export const merge = (etjanstChildren: EtjanstChild[], skola24Children: Skola24Child[]): Child[] => ( + etjanstChildren.map((etjanstChild) => { + const skola24Child: Skola24Child = ( + skola24Children.find((s24c) => s24c.firstName && etjanstChild.name.startsWith(s24c.firstName)) || {} + ) + const child: Child = { + ...etjanstChild, + ...skola24Child, + } + return child + }) +) diff --git a/src/fake.test.js b/src/fake.test.js index a5946da8..42042673 100644 --- a/src/fake.test.js +++ b/src/fake.test.js @@ -4,7 +4,7 @@ import { ApiProvider } from '.' import createStorage from './__mocks__/AsyncStorage' import { useCalendar, - useChildList, + useEtjanstChildren, useClassmates, useMenu, useNews, @@ -69,7 +69,7 @@ describe('hooks with fake data', () => { const { result, waitForNextUpdate, - } = renderHook(() => useChildList(), { wrapper }) + } = renderHook(() => useEtjanstChildren(), { wrapper }) await waitForNextUpdate() await waitForNextUpdate() diff --git a/src/hooks.ts b/src/hooks.ts index 6b318784..83f2de34 100644 --- a/src/hooks.ts +++ b/src/hooks.ts @@ -5,10 +5,13 @@ import { CalendarItem, Child, Classmate, + EtjanstChild, MenuItem, NewsItem, Notification, ScheduleItem, + Skola24Child, + TimetableEntry, User, } from '@skolplattformen/embedded-api' import { @@ -22,6 +25,7 @@ import { import { useApi } from './context' import { loadAction } from './actions' import store from './store' +import { merge } from './childlists' interface StoreSelector { (state: EntityStoreRootState): EntityMap @@ -73,7 +77,15 @@ const hook = ( } useEffect(() => { load() }, [isLoggedIn]) + let mounted: boolean + useEffect(() => { + mounted = true + return () => { mounted = false } + }, []) + const listener = () => { + if (!mounted) return + const newState = select(getState()) if (newState.status !== state.status || newState.data !== state.data @@ -94,14 +106,22 @@ const hook = ( } } -export const useChildList = () => hook( - 'CHILDREN', - 'children', +export const useEtjanstChildren = () => hook( + 'ETJANST_CHILDREN', + 'etjanst_children', [], - (s) => s.children, + (s) => s.etjanstChildren, (api) => () => api.getChildren(), ) +export const useSkola24Children = () => hook( + 'SKOLA24_CHILDREN', + 'skola24_children', + [], + (s) => s.skola24Children, + (api) => () => api.getSkola24Children(), +) + export const useCalendar = (child: Child) => hook( 'CALENDAR', `calendar_${child.id}`, @@ -158,6 +178,14 @@ export const useSchedule = (child: Child, from: string, to: string) => hook () => api.getSchedule(child, from, to), ) +export const useTimetable = (child: Skola24Child, week: number, year: number) => hook( + 'TIMETABLE', + `timetable_${child.personGuid}_${week}_${year}`, + [], + (s) => s.timetable, + (api) => () => api.getTimetable(child, week, year), +) + export const useUser = () => hook( 'USER', 'user', @@ -165,3 +193,25 @@ export const useUser = () => hook( (s) => s.user, (api) => () => api.getUser(), ) + +export const useChildList = (): EntityHookResult => { + const { + data: etjanstData, status, error, reload: etjanstReload, + } = useEtjanstChildren() + const { data: skola24Data, reload: skola24Reload } = useSkola24Children() + + const [data, setData] = useState([]) + const reload = () => { + etjanstReload() + skola24Reload() + } + + useEffect(() => { + if (!etjanstData.length) return + setData(merge(etjanstData, skola24Data)) + }, [etjanstData, skola24Data]) + + return { + data, status, error, reload, + } +} diff --git a/src/logout.test.js b/src/logout.test.js index 649cc031..154de3d7 100644 --- a/src/logout.test.js +++ b/src/logout.test.js @@ -1,7 +1,7 @@ import React from 'react' import { renderHook, act } from '@testing-library/react-hooks' import { ApiProvider } from './provider' -import { useChildList } from './hooks' +import { useEtjanstChildren } from './hooks' import store from './store' import init from './__mocks__/@skolplattformen/embedded-api' import createStorage from './__mocks__/AsyncStorage' @@ -32,7 +32,7 @@ describe('logout - cleanup', () => { }) )) storage = createStorage({ - '123_children': [{ id: 2 }], + '123_etjanst_children': [{ id: 2 }], }, 2) }) afterEach(async () => { @@ -46,7 +46,7 @@ describe('logout - cleanup', () => { api.isLoggedIn = true api.isFake = false - const { waitForNextUpdate: wait1 } = renderHook(() => useChildList(), { wrapper }) + const { waitForNextUpdate: wait1 } = renderHook(() => useEtjanstChildren(), { wrapper }) await wait1() await wait1() @@ -56,14 +56,14 @@ describe('logout - cleanup', () => { api.isLoggedIn = false api.emitter.emit('logout') - const { result } = renderHook(() => useChildList(), { wrapper }) + const { result } = renderHook(() => useEtjanstChildren(), { wrapper }) expect(result.current.data).toHaveLength(0) api.isLoggedIn = true api.emitter.emit('login') - const { result: result2, waitForNextUpdate: wait2 } = renderHook(() => useChildList(), { wrapper }) + const { result: result2, waitForNextUpdate: wait2 } = renderHook(() => useEtjanstChildren(), { wrapper }) await wait2() diff --git a/src/reducers.ts b/src/reducers.ts index d12f5b26..26e827ba 100644 --- a/src/reducers.ts +++ b/src/reducers.ts @@ -1,12 +1,14 @@ import { CalendarItem, - Child, Classmate, + EtjanstChild, + Skola24Child, MenuItem, NewsItem, Notification, ScheduleItem, User, + TimetableEntry, } from '@skolplattformen/embedded-api' import { EntityName, EntityReducer, EntityState } from './types' @@ -65,7 +67,8 @@ const createReducer = (entity: EntityName): EntityReducer => { } export const user = createReducer('USER') -export const children = createReducer('CHILDREN') +export const etjanstChildren = createReducer('ETJANST_CHILDREN') +export const skola24Children = createReducer('SKOLA24_CHILDREN') export const calendar = createReducer('CALENDAR') export const classmates = createReducer('CLASSMATES') export const menu = createReducer('MENU') @@ -73,3 +76,4 @@ export const news = createReducer('NEWS') export const newsDetails = createReducer('NEWS_DETAILS') export const notifications = createReducer('NOTIFICATIONS') export const schedule = createReducer('SCHEDULE') +export const timetable = createReducer('TIMETABLE') diff --git a/src/store.ts b/src/store.ts index eaa5bac0..1b9aa78a 100644 --- a/src/store.ts +++ b/src/store.ts @@ -2,25 +2,29 @@ import { createStore, combineReducers, applyMiddleware } from 'redux' import { apiMiddleware, cacheMiddleware } from './middleware' import { calendar, - children, classmates, + etjanstChildren, menu, news, newsDetails, notifications, schedule, + skola24Children, + timetable, user, } from './reducers' const appReducer = combineReducers({ calendar, - children, classmates, + etjanstChildren, menu, news, newsDetails, notifications, schedule, + skola24Children, + timetable, user, }) const rootReducer: typeof appReducer = (state, action) => { diff --git a/src/types.ts b/src/types.ts index 2ca47303..b2ffdb2e 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,6 +1,7 @@ import { Api, - Child, + EtjanstChild, + Skola24Child, User, CalendarItem, Classmate, @@ -8,6 +9,7 @@ import { NewsItem, Notification, ScheduleItem, + TimetableEntry, } from '@skolplattformen/embedded-api' import { Action, Reducer } from 'redux' @@ -50,6 +52,8 @@ export type EntityActionType = 'GET_FROM_API' | 'STORE_IN_CACHE' | 'CLEAR' export type EntityName = 'USER' +| 'ETJANST_CHILDREN' +| 'SKOLA24_CHILDREN' | 'CHILDREN' | 'CALENDAR' | 'CLASSMATES' @@ -58,6 +62,7 @@ export type EntityName = 'USER' | 'NEWS_DETAILS' | 'NOTIFICATIONS' | 'SCHEDULE' +| 'TIMETABLE' | 'ALL' export interface EntityAction extends Action { entity: EntityName @@ -71,7 +76,8 @@ export interface EntityMap { export type EntityReducer = Reducer, EntityAction> export interface EntityStoreRootState { - children: EntityMap + etjanstChildren: EntityMap + skola24Children: EntityMap user: EntityMap calendar: EntityMap, classmates: EntityMap, @@ -80,6 +86,7 @@ export interface EntityStoreRootState { newsDetails: EntityMap, notifications: EntityMap, schedule: EntityMap, + timetable: EntityMap, } export interface EntityHookResult extends EntityState { diff --git a/src/useChildList.test.js b/src/useChildList.test.js new file mode 100644 index 00000000..4023bf36 --- /dev/null +++ b/src/useChildList.test.js @@ -0,0 +1,269 @@ +import React from 'react' +import { renderHook, act } from '@testing-library/react-hooks' +import { ApiProvider } from './provider' +import { useChildList } from './hooks' +import store from './store' +import init from './__mocks__/@skolplattformen/embedded-api' +import createStorage from './__mocks__/AsyncStorage' +import reporter from './__mocks__/reporter' +import { etjanstChildren } from './reducers' + +const pause = (ms = 0) => new Promise((r) => setTimeout(r, ms)) + +describe('useChildList()', () => { + let api + let storage + let echildrenCache + let skola24Cache + let echildrenResponse + let skola24Response + const wrapper = ({ children }) => ( + + {children} + + ) + beforeEach(() => { + echildrenCache = [{ id: 2, name: 'Uwe Übrink (elev)' }] + skola24Cache = [{ personGuid: '2', firstName: 'Uwe', lastName: 'Vredstein Übrink' }] + + echildrenResponse = [{ id: 1, name: 'Uwe Übrink (elev)' }] + skola24Response = [{ personGuid: '1', firstName: 'Uwe', lastName: 'Vredstein Übrink' }] + + api = init() + api.getPersonalNumber.mockReturnValue('123') + + api.getChildren.mockImplementation(() => ( + new Promise((res) => { + setTimeout(() => res(echildrenResponse), 50) + }) + )) + api.getSkola24Children.mockImplementation(() => ( + new Promise((res) => { + setTimeout(() => res(skola24Response), 50) + }) + )) + storage = createStorage({ + '123_etjanst_children': echildrenCache, + '123_skola24_children': skola24Cache, + }, 2) + }) + afterEach(async () => { + await act(async () => { + await pause(70) + store.dispatch({ entity: 'ALL', type: 'CLEAR' }) + }) + }) + it('returns correct initial value', () => { + const { result } = renderHook(() => useChildList(), { wrapper }) + + expect(result.current.status).toEqual('pending') + }) + it('calls api', async () => { + await act(async () => { + api.isLoggedIn = true + const { waitForNextUpdate } = renderHook(() => useChildList(), { wrapper }) + + await waitForNextUpdate() + await waitForNextUpdate() + + expect(api.getChildren).toHaveBeenCalled() + expect(api.getSkola24Children).toHaveBeenCalled() + }) + }) + it('only calls api once', async () => { + await act(async () => { + api.isLoggedIn = true + renderHook(() => useChildList(), { wrapper }) + const { waitForNextUpdate } = renderHook(() => useChildList(), { wrapper }) + + await waitForNextUpdate() + renderHook(() => useChildList(), { wrapper }) + await waitForNextUpdate() + renderHook(() => useChildList(), { wrapper }) + await waitForNextUpdate() + await waitForNextUpdate() + + const { result } = renderHook(() => useChildList(), { wrapper }) + + expect(api.getChildren).toHaveBeenCalledTimes(1) + expect(api.getSkola24Children).toHaveBeenCalledTimes(1) + expect(result.current.status).toEqual('loaded') + }) + }) + it('calls cache', async () => { + await act(async () => { + api.isLoggedIn = true + const { result, waitForNextUpdate } = renderHook(() => useChildList(), { wrapper }) + + await waitForNextUpdate() + await waitForNextUpdate() + await waitForNextUpdate() + await waitForNextUpdate() + await waitForNextUpdate() + + expect(result.current.data).toEqual([{ + id: 2, + name: 'Uwe Übrink (elev)', + personGuid: '2', + firstName: 'Uwe', + lastName: 'Vredstein Übrink', + }]) + }) + }) + it('updates status to loading', async () => { + await act(async () => { + api.isLoggedIn = true + const { result, waitForNextUpdate } = renderHook(() => useChildList(), { wrapper }) + + await waitForNextUpdate() + await waitForNextUpdate() + + expect(result.current.status).toEqual('loading') + }) + }) + it('updates status to loaded', async () => { + await act(async () => { + api.isLoggedIn = true + const { result, waitForNextUpdate } = renderHook(() => useChildList(), { wrapper }) + + await waitForNextUpdate() + await waitForNextUpdate() + await waitForNextUpdate() + await waitForNextUpdate() + await waitForNextUpdate() + await waitForNextUpdate() + + expect(result.current.status).toEqual('loaded') + }) + }) + it('stores in cache if not fake', async () => { + await act(async () => { + api.isLoggedIn = true + api.isFake = false + + const { waitForNextUpdate } = renderHook(() => useChildList(), { wrapper }) + + await waitForNextUpdate() + await waitForNextUpdate() + await waitForNextUpdate() + await waitForNextUpdate() + await waitForNextUpdate() + await waitForNextUpdate() + await pause(20) + + expect(storage.cache['123_etjanst_children']).toEqual(JSON.stringify(echildrenResponse)) + expect(storage.cache['123_skola24_children']).toEqual(JSON.stringify(skola24Response)) + }) + }) + it('does not store in cache if fake', async () => { + await act(async () => { + api.isLoggedIn = true + api.isFake = true + + const { result, waitForNextUpdate } = renderHook(() => useChildList(), { wrapper }) + + await waitForNextUpdate() + await waitForNextUpdate() + await waitForNextUpdate() + await pause(20) + + expect(result.current.status).toEqual('loaded') + expect(storage.cache['123_etjanst_children']).toEqual(JSON.stringify(echildrenCache)) + expect(storage.cache['123_skola24_children']).toEqual(JSON.stringify(skola24Cache)) + }) + }) + it('retries if etjanst-api fails', async () => { + await act(async () => { + api.isLoggedIn = true + const error = new Error('fail') + api.getChildren.mockRejectedValueOnce(error) + + const { result, waitForNextUpdate } = renderHook(() => useChildList(), { wrapper }) + + await waitForNextUpdate() + await waitForNextUpdate() + await waitForNextUpdate() + + expect(result.current.error).toEqual(error) + expect(result.current.status).toEqual('loading') + expect(result.current.data).toEqual(echildrenCache) + + jest.advanceTimersToNextTimer() + + await waitForNextUpdate() + await waitForNextUpdate() + await waitForNextUpdate() + await waitForNextUpdate() + await waitForNextUpdate() + await waitForNextUpdate() + + expect(result.current.status).toEqual('loaded') + expect(result.current.data).toEqual([{ + id: 1, + name: 'Uwe Übrink (elev)', + personGuid: '1', + firstName: 'Uwe', + lastName: 'Vredstein Übrink', + }]) + }) + }) + it('gives up after 3 retries', async () => { + await act(async () => { + api.isLoggedIn = true + const error = new Error('fail') + api.getChildren.mockRejectedValueOnce(error) + api.getChildren.mockRejectedValueOnce(error) + api.getChildren.mockRejectedValueOnce(error) + + const { result, waitForNextUpdate } = renderHook(() => useChildList(), { wrapper }) + + await waitForNextUpdate() + await waitForNextUpdate() + await waitForNextUpdate() + + expect(result.current.error).toEqual(error) + expect(result.current.status).toEqual('loading') + expect(result.current.data).toEqual(echildrenCache) + + jest.advanceTimersToNextTimer() + + await waitForNextUpdate() + await waitForNextUpdate() + await waitForNextUpdate() + await waitForNextUpdate() + await waitForNextUpdate() + await waitForNextUpdate() + + expect(result.current.error).toEqual(error) + expect(result.current.status).toEqual('error') + expect(result.current.data).toEqual([{ + id: 2, + name: 'Uwe Übrink (elev)', + personGuid: '1', + firstName: 'Uwe', + lastName: 'Vredstein Übrink', + }]) + }) + }) + it('reports if api fails', async () => { + await act(async () => { + api.isLoggedIn = true + const error = new Error('fail') + api.getChildren.mockRejectedValueOnce(error) + + const { result, waitForNextUpdate } = renderHook(() => useChildList(), { wrapper }) + + await waitForNextUpdate() + await waitForNextUpdate() + await waitForNextUpdate() + + expect(result.current.error).toEqual(error) + + expect(reporter.error).toHaveBeenCalledWith(error, 'Error getting ETJANST_CHILDREN from API') + }) + }) +}) diff --git a/src/useChildlist.test.js b/src/useEtjanstChildren.test.js similarity index 81% rename from src/useChildlist.test.js rename to src/useEtjanstChildren.test.js index 1cecbb15..c5bd8d06 100644 --- a/src/useChildlist.test.js +++ b/src/useEtjanstChildren.test.js @@ -1,7 +1,7 @@ import React from 'react' import { renderHook, act } from '@testing-library/react-hooks' import { ApiProvider } from './provider' -import { useChildList } from './hooks' +import { useEtjanstChildren } from './hooks' import store from './store' import init from './__mocks__/@skolplattformen/embedded-api' import createStorage from './__mocks__/AsyncStorage' @@ -9,7 +9,7 @@ import reporter from './__mocks__/reporter' const pause = (ms = 0) => new Promise((r) => setTimeout(r, ms)) -describe('useChildList()', () => { +describe('useEtjanstChildren()', () => { let api let storage let response @@ -32,7 +32,7 @@ describe('useChildList()', () => { }) )) storage = createStorage({ - '123_children': [{ id: 2 }], + '123_etjanst_children': [{ id: 2 }], }, 2) }) afterEach(async () => { @@ -42,14 +42,14 @@ describe('useChildList()', () => { }) }) it('returns correct initial value', () => { - const { result } = renderHook(() => useChildList(), { wrapper }) + const { result } = renderHook(() => useEtjanstChildren(), { wrapper }) expect(result.current.status).toEqual('pending') }) it('calls api', async () => { await act(async () => { api.isLoggedIn = true - const { waitForNextUpdate } = renderHook(() => useChildList(), { wrapper }) + const { waitForNextUpdate } = renderHook(() => useEtjanstChildren(), { wrapper }) await waitForNextUpdate() await waitForNextUpdate() @@ -60,16 +60,16 @@ describe('useChildList()', () => { it('only calls api once', async () => { await act(async () => { api.isLoggedIn = true - renderHook(() => useChildList(), { wrapper }) - const { waitForNextUpdate } = renderHook(() => useChildList(), { wrapper }) + renderHook(() => useEtjanstChildren(), { wrapper }) + const { waitForNextUpdate } = renderHook(() => useEtjanstChildren(), { wrapper }) await waitForNextUpdate() - renderHook(() => useChildList(), { wrapper }) + renderHook(() => useEtjanstChildren(), { wrapper }) await waitForNextUpdate() - renderHook(() => useChildList(), { wrapper }) + renderHook(() => useEtjanstChildren(), { wrapper }) await waitForNextUpdate() - const { result } = renderHook(() => useChildList(), { wrapper }) + const { result } = renderHook(() => useEtjanstChildren(), { wrapper }) expect(api.getChildren).toHaveBeenCalledTimes(1) expect(result.current.status).toEqual('loaded') @@ -78,7 +78,7 @@ describe('useChildList()', () => { it('calls cache', async () => { await act(async () => { api.isLoggedIn = true - const { result, waitForNextUpdate } = renderHook(() => useChildList(), { wrapper }) + const { result, waitForNextUpdate } = renderHook(() => useEtjanstChildren(), { wrapper }) await waitForNextUpdate() await waitForNextUpdate() @@ -89,7 +89,7 @@ describe('useChildList()', () => { it('updates status to loading', async () => { await act(async () => { api.isLoggedIn = true - const { result, waitForNextUpdate } = renderHook(() => useChildList(), { wrapper }) + const { result, waitForNextUpdate } = renderHook(() => useEtjanstChildren(), { wrapper }) await waitForNextUpdate() await waitForNextUpdate() @@ -100,7 +100,7 @@ describe('useChildList()', () => { it('updates status to loaded', async () => { await act(async () => { api.isLoggedIn = true - const { result, waitForNextUpdate } = renderHook(() => useChildList(), { wrapper }) + const { result, waitForNextUpdate } = renderHook(() => useEtjanstChildren(), { wrapper }) await waitForNextUpdate() await waitForNextUpdate() @@ -114,14 +114,14 @@ describe('useChildList()', () => { api.isLoggedIn = true api.isFake = false - const { waitForNextUpdate } = renderHook(() => useChildList(), { wrapper }) + const { waitForNextUpdate } = renderHook(() => useEtjanstChildren(), { wrapper }) await waitForNextUpdate() await waitForNextUpdate() await waitForNextUpdate() await pause(20) - expect(storage.cache['123_children']).toEqual('[{"id":1}]') + expect(storage.cache['123_etjanst_children']).toEqual('[{"id":1}]') }) }) it('does not store in cache if fake', async () => { @@ -129,13 +129,13 @@ describe('useChildList()', () => { api.isLoggedIn = true api.isFake = true - const { waitForNextUpdate } = renderHook(() => useChildList(), { wrapper }) + const { waitForNextUpdate } = renderHook(() => useEtjanstChildren(), { wrapper }) await waitForNextUpdate() await waitForNextUpdate() await pause(20) - expect(storage.cache['123_children']).toEqual('[{"id":2}]') + expect(storage.cache['123_etjanst_children']).toEqual('[{"id":2}]') }) }) it('retries if api fails', async () => { @@ -144,7 +144,7 @@ describe('useChildList()', () => { const error = new Error('fail') api.getChildren.mockRejectedValueOnce(error) - const { result, waitForNextUpdate } = renderHook(() => useChildList(), { wrapper }) + const { result, waitForNextUpdate } = renderHook(() => useEtjanstChildren(), { wrapper }) await waitForNextUpdate() await waitForNextUpdate() @@ -172,7 +172,7 @@ describe('useChildList()', () => { api.getChildren.mockRejectedValueOnce(error) api.getChildren.mockRejectedValueOnce(error) - const { result, waitForNextUpdate } = renderHook(() => useChildList(), { wrapper }) + const { result, waitForNextUpdate } = renderHook(() => useEtjanstChildren(), { wrapper }) await waitForNextUpdate() await waitForNextUpdate() @@ -199,7 +199,7 @@ describe('useChildList()', () => { const error = new Error('fail') api.getChildren.mockRejectedValueOnce(error) - const { result, waitForNextUpdate } = renderHook(() => useChildList(), { wrapper }) + const { result, waitForNextUpdate } = renderHook(() => useEtjanstChildren(), { wrapper }) await waitForNextUpdate() await waitForNextUpdate() @@ -207,7 +207,7 @@ describe('useChildList()', () => { expect(result.current.error).toEqual(error) - expect(reporter.error).toHaveBeenCalledWith(error, 'Error getting CHILDREN from API') + expect(reporter.error).toHaveBeenCalledWith(error, 'Error getting ETJANST_CHILDREN from API') }) }) }) diff --git a/src/useSkola24Children.test.js b/src/useSkola24Children.test.js new file mode 100644 index 00000000..e4ddcefc --- /dev/null +++ b/src/useSkola24Children.test.js @@ -0,0 +1,213 @@ +import React from 'react' +import { renderHook, act } from '@testing-library/react-hooks' +import { ApiProvider } from './provider' +import { useSkola24Children } from './hooks' +import store from './store' +import init from './__mocks__/@skolplattformen/embedded-api' +import createStorage from './__mocks__/AsyncStorage' +import reporter from './__mocks__/reporter' + +const pause = (ms = 0) => new Promise((r) => setTimeout(r, ms)) + +describe('useSkola24Children()', () => { + let api + let storage + let response + const wrapper = ({ children }) => ( + + {children} + + ) + beforeEach(() => { + response = [{ personGuid: '1' }] + api = init() + api.getPersonalNumber.mockReturnValue('123') + api.getSkola24Children.mockImplementation(() => ( + new Promise((res) => { + setTimeout(() => res(response), 50) + }) + )) + storage = createStorage({ + '123_skola24_children': [{ personGuid: '2' }], + }, 2) + }) + afterEach(async () => { + await act(async () => { + await pause(70) + store.dispatch({ entity: 'ALL', type: 'CLEAR' }) + }) + }) + it('returns correct initial value', () => { + const { result } = renderHook(() => useSkola24Children(), { wrapper }) + + expect(result.current.status).toEqual('pending') + }) + it('calls api', async () => { + await act(async () => { + api.isLoggedIn = true + const { waitForNextUpdate } = renderHook(() => useSkola24Children(), { wrapper }) + + await waitForNextUpdate() + await waitForNextUpdate() + + expect(api.getSkola24Children).toHaveBeenCalled() + }) + }) + it('only calls api once', async () => { + await act(async () => { + api.isLoggedIn = true + renderHook(() => useSkola24Children(), { wrapper }) + const { waitForNextUpdate } = renderHook(() => useSkola24Children(), { wrapper }) + + await waitForNextUpdate() + renderHook(() => useSkola24Children(), { wrapper }) + await waitForNextUpdate() + renderHook(() => useSkola24Children(), { wrapper }) + await waitForNextUpdate() + + const { result } = renderHook(() => useSkola24Children(), { wrapper }) + + expect(api.getSkola24Children).toHaveBeenCalledTimes(1) + expect(result.current.status).toEqual('loaded') + }) + }) + it('calls cache', async () => { + await act(async () => { + api.isLoggedIn = true + const { result, waitForNextUpdate } = renderHook(() => useSkola24Children(), { wrapper }) + + await waitForNextUpdate() + await waitForNextUpdate() + + expect(result.current.data).toEqual([{ personGuid: '2' }]) + }) + }) + it('updates status to loading', async () => { + await act(async () => { + api.isLoggedIn = true + const { result, waitForNextUpdate } = renderHook(() => useSkola24Children(), { wrapper }) + + await waitForNextUpdate() + await waitForNextUpdate() + + expect(result.current.status).toEqual('loading') + }) + }) + it('updates status to loaded', async () => { + await act(async () => { + api.isLoggedIn = true + const { result, waitForNextUpdate } = renderHook(() => useSkola24Children(), { wrapper }) + + await waitForNextUpdate() + await waitForNextUpdate() + await waitForNextUpdate() + + expect(result.current.status).toEqual('loaded') + }) + }) + it('stores in cache if not fake', async () => { + await act(async () => { + api.isLoggedIn = true + api.isFake = false + + const { waitForNextUpdate } = renderHook(() => useSkola24Children(), { wrapper }) + + await waitForNextUpdate() + await waitForNextUpdate() + await waitForNextUpdate() + await pause(20) + + expect(storage.cache['123_skola24_children']).toEqual('[{"personGuid":"1"}]') + }) + }) + it('does not store in cache if fake', async () => { + await act(async () => { + api.isLoggedIn = true + api.isFake = true + + const { waitForNextUpdate } = renderHook(() => useSkola24Children(), { wrapper }) + + await waitForNextUpdate() + await waitForNextUpdate() + await pause(20) + + expect(storage.cache['123_skola24_children']).toEqual('[{"personGuid":"2"}]') + }) + }) + it('retries if api fails', async () => { + await act(async () => { + api.isLoggedIn = true + const error = new Error('fail') + api.getSkola24Children.mockRejectedValueOnce(error) + + const { result, waitForNextUpdate } = renderHook(() => useSkola24Children(), { wrapper }) + + await waitForNextUpdate() + await waitForNextUpdate() + await waitForNextUpdate() + + expect(result.current.error).toEqual(error) + expect(result.current.status).toEqual('loading') + expect(result.current.data).toEqual([{ personGuid: '2' }]) + + jest.advanceTimersToNextTimer() + + await waitForNextUpdate() + await waitForNextUpdate() + await waitForNextUpdate() + + expect(result.current.status).toEqual('loaded') + expect(result.current.data).toEqual([{ personGuid: '1' }]) + }) + }) + it('gives up after 3 retries', async () => { + await act(async () => { + api.isLoggedIn = true + const error = new Error('fail') + api.getSkola24Children.mockRejectedValueOnce(error) + api.getSkola24Children.mockRejectedValueOnce(error) + api.getSkola24Children.mockRejectedValueOnce(error) + + const { result, waitForNextUpdate } = renderHook(() => useSkola24Children(), { wrapper }) + + await waitForNextUpdate() + await waitForNextUpdate() + await waitForNextUpdate() + + expect(result.current.error).toEqual(error) + expect(result.current.status).toEqual('loading') + expect(result.current.data).toEqual([{ personGuid: '2' }]) + + jest.advanceTimersToNextTimer() + + await waitForNextUpdate() + await waitForNextUpdate() + await waitForNextUpdate() + + expect(result.current.error).toEqual(error) + expect(result.current.status).toEqual('error') + expect(result.current.data).toEqual([{ personGuid: '2' }]) + }) + }) + it('reports if api fails', async () => { + await act(async () => { + api.isLoggedIn = true + const error = new Error('fail') + api.getSkola24Children.mockRejectedValueOnce(error) + + const { result, waitForNextUpdate } = renderHook(() => useSkola24Children(), { wrapper }) + + await waitForNextUpdate() + await waitForNextUpdate() + await waitForNextUpdate() + + expect(result.current.error).toEqual(error) + + expect(reporter.error).toHaveBeenCalledWith(error, 'Error getting SKOLA24_CHILDREN from API') + }) + }) +}) diff --git a/src/useTimetable.test.js b/src/useTimetable.test.js new file mode 100644 index 00000000..fc76528f --- /dev/null +++ b/src/useTimetable.test.js @@ -0,0 +1,219 @@ +import React from 'react' +import { renderHook, act } from '@testing-library/react-hooks' +import { ApiProvider } from './provider' +import { useTimetable } from './hooks' +import store from './store' +import init from './__mocks__/@skolplattformen/embedded-api' +import createStorage from './__mocks__/AsyncStorage' +import reporter from './__mocks__/reporter' + +const pause = (ms = 0) => new Promise((r) => setTimeout(r, ms)) + +describe('useTimetable(child, week, year)', () => { + let api + let storage + let response + let child + let week + let year + const wrapper = ({ children }) => ( + + {children} + + ) + beforeEach(() => { + response = [{ id: 1 }] + api = init() + api.getPersonalNumber.mockReturnValue('123') + api.getTimetable.mockImplementation(() => ( + new Promise((res) => { + setTimeout(() => res(response), 50) + }) + )) + storage = createStorage({ + '123_timetable_10_15_2021': [{ id: 2 }], + }, 2) + child = { personGuid: '10' } + week = 15 + year = 2021 + }) + afterEach(async () => { + await act(async () => { + await pause(70) + store.dispatch({ entity: 'ALL', type: 'CLEAR' }) + }) + }) + it('returns correct initial value', () => { + const { result } = renderHook(() => useTimetable(child, week, year), { wrapper }) + + expect(result.current.status).toEqual('pending') + }) + it('calls api', async () => { + await act(async () => { + api.isLoggedIn = true + const { waitForNextUpdate } = renderHook(() => useTimetable(child, week, year), { wrapper }) + + await waitForNextUpdate() + await waitForNextUpdate() + + expect(api.getTimetable).toHaveBeenCalled() + }) + }) + it('only calls api once', async () => { + await act(async () => { + api.isLoggedIn = true + renderHook(() => useTimetable(child, week, year), { wrapper }) + const { waitForNextUpdate } = renderHook(() => useTimetable(child, week, year), { wrapper }) + + await waitForNextUpdate() + renderHook(() => useTimetable(child, week, year), { wrapper }) + await waitForNextUpdate() + renderHook(() => useTimetable(child, week, year), { wrapper }) + await waitForNextUpdate() + + const { result } = renderHook(() => useTimetable(child, week, year), { wrapper }) + + expect(api.getTimetable).toHaveBeenCalledTimes(1) + expect(result.current.status).toEqual('loaded') + }) + }) + it('calls cache', async () => { + await act(async () => { + api.isLoggedIn = true + const { result, waitForNextUpdate } = renderHook(() => useTimetable(child, week, year), { wrapper }) + + await waitForNextUpdate() + await waitForNextUpdate() + + expect(result.current.data).toEqual([{ id: 2 }]) + }) + }) + it('updates status to loading', async () => { + await act(async () => { + api.isLoggedIn = true + const { result, waitForNextUpdate } = renderHook(() => useTimetable(child, week, year), { wrapper }) + + await waitForNextUpdate() + await waitForNextUpdate() + + expect(result.current.status).toEqual('loading') + }) + }) + it('updates status to loaded', async () => { + await act(async () => { + api.isLoggedIn = true + const { result, waitForNextUpdate } = renderHook(() => useTimetable(child, week, year), { wrapper }) + + await waitForNextUpdate() + await waitForNextUpdate() + await waitForNextUpdate() + + expect(result.current.status).toEqual('loaded') + }) + }) + it('stores in cache if not fake', async () => { + await act(async () => { + api.isLoggedIn = true + api.isFake = false + + const { waitForNextUpdate } = renderHook(() => useTimetable(child, week, year), { wrapper }) + + await waitForNextUpdate() + await waitForNextUpdate() + await waitForNextUpdate() + await pause(20) + + expect(storage.cache['123_timetable_10_15_2021']).toEqual('[{"id":1}]') + }) + }) + it('does not store in cache if fake', async () => { + await act(async () => { + api.isLoggedIn = true + api.isFake = true + + const { waitForNextUpdate } = renderHook(() => useTimetable(child, week, year), { wrapper }) + + await waitForNextUpdate() + await waitForNextUpdate() + await pause(20) + + expect(storage.cache['123_timetable_10_15_2021']).toEqual('[{"id":2}]') + }) + }) + it('retries if api fails', async () => { + await act(async () => { + api.isLoggedIn = true + const error = new Error('fail') + api.getTimetable.mockRejectedValueOnce(error) + + const { result, waitForNextUpdate } = renderHook(() => useTimetable(child, week, year), { wrapper }) + + await waitForNextUpdate() + await waitForNextUpdate() + await waitForNextUpdate() + + expect(result.current.error).toEqual(error) + expect(result.current.status).toEqual('loading') + expect(result.current.data).toEqual([{ id: 2 }]) + + jest.advanceTimersToNextTimer() + + await waitForNextUpdate() + await waitForNextUpdate() + await waitForNextUpdate() + + expect(result.current.status).toEqual('loaded') + expect(result.current.data).toEqual([{ id: 1 }]) + }) + }) + it('gives up after 3 retries', async () => { + await act(async () => { + api.isLoggedIn = true + const error = new Error('fail') + api.getTimetable.mockRejectedValueOnce(error) + api.getTimetable.mockRejectedValueOnce(error) + api.getTimetable.mockRejectedValueOnce(error) + + const { result, waitForNextUpdate } = renderHook(() => useTimetable(child, week, year), { wrapper }) + + await waitForNextUpdate() + await waitForNextUpdate() + await waitForNextUpdate() + + expect(result.current.error).toEqual(error) + expect(result.current.status).toEqual('loading') + expect(result.current.data).toEqual([{ id: 2 }]) + + jest.advanceTimersToNextTimer() + + await waitForNextUpdate() + await waitForNextUpdate() + await waitForNextUpdate() + + expect(result.current.error).toEqual(error) + expect(result.current.status).toEqual('error') + expect(result.current.data).toEqual([{ id: 2 }]) + }) + }) + it('reports if api fails', async () => { + await act(async () => { + api.isLoggedIn = true + const error = new Error('fail') + api.getTimetable.mockRejectedValueOnce(error) + + const { result, waitForNextUpdate } = renderHook(() => useTimetable(child, week, year), { wrapper }) + + await waitForNextUpdate() + await waitForNextUpdate() + await waitForNextUpdate() + + expect(result.current.error).toEqual(error) + + expect(reporter.error).toHaveBeenCalledWith(error, 'Error getting TIMETABLE from API') + }) + }) +}) diff --git a/yarn.lock b/yarn.lock index 2726e4ff..edd1c395 100644 --- a/yarn.lock +++ b/yarn.lock @@ -16,7 +16,12 @@ dependencies: "@babel/highlight" "^7.12.13" -"@babel/compat-data@^7.13.0", "@babel/compat-data@^7.13.8": +"@babel/compat-data@^7.13.11", "@babel/compat-data@^7.13.12", "@babel/compat-data@^7.13.15": + version "7.13.15" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.13.15.tgz#7e8eea42d0b64fda2b375b22d06c605222e848f4" + integrity sha512-ltnibHKR1VnrU4ymHyQ/CXtNXI6yZC0oJThyW78Hft8XndANwi+9H+UIklBDraIjFEJzw8wmcM427oDd9KS5wA== + +"@babel/compat-data@^7.13.8": version "7.13.8" resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.13.8.tgz#5b783b9808f15cef71547f1b691f34f8ff6003a6" integrity sha512-EaI33z19T4qN3xLXsGf48M2cDqa6ei9tPZlfLdb2HC+e/cFtREiRd8hdSqDbwdLB0/+gLwqJmCYASH0z2bUdog== @@ -75,7 +80,7 @@ "@babel/helper-explode-assignable-expression" "^7.12.13" "@babel/types" "^7.12.13" -"@babel/helper-compilation-targets@^7.13.0", "@babel/helper-compilation-targets@^7.13.10", "@babel/helper-compilation-targets@^7.13.8": +"@babel/helper-compilation-targets@^7.13.0", "@babel/helper-compilation-targets@^7.13.8": version "7.13.10" resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.13.10.tgz#1310a1678cb8427c07a753750da4f8ce442bdd0c" integrity sha512-/Xju7Qg1GQO4mHZ/Kcs6Au7gfafgZnwm+a7sy/ow/tV1sHeraRUHbjdat8/UvDor4Tez+siGKDk6zIKtCPKVJA== @@ -85,6 +90,16 @@ browserslist "^4.14.5" semver "^6.3.0" +"@babel/helper-compilation-targets@^7.13.13": + version "7.13.13" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.13.13.tgz#2b2972a0926474853f41e4adbc69338f520600e5" + integrity sha512-q1kcdHNZehBwD9jYPh3WyXcsFERi39X4I59I3NadciWtNDyZ6x+GboOxncFK0kXlKIv6BJm5acncehXWUjWQMQ== + dependencies: + "@babel/compat-data" "^7.13.12" + "@babel/helper-validator-option" "^7.12.17" + browserslist "^4.14.5" + semver "^6.3.0" + "@babel/helper-create-class-features-plugin@^7.13.0": version "7.13.10" resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.13.10.tgz#073b2bbb925a097643c6fc5770e5f13394e887c9" @@ -104,10 +119,10 @@ "@babel/helper-annotate-as-pure" "^7.12.13" regexpu-core "^4.7.1" -"@babel/helper-define-polyfill-provider@^0.1.5": - version "0.1.5" - resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.1.5.tgz#3c2f91b7971b9fc11fe779c945c014065dea340e" - integrity sha512-nXuzCSwlJ/WKr8qxzW816gwyT6VZgiJG17zR40fou70yfAcqjoNyTLl/DQ+FExw5Hx5KNqshmN8Ldl/r2N7cTg== +"@babel/helper-define-polyfill-provider@^0.2.0": + version "0.2.0" + resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.2.0.tgz#a640051772045fedaaecc6f0c6c69f02bdd34bf1" + integrity sha512-JT8tHuFjKBo8NnaUbblz7mIu1nnvUDiHVjXXkulZULyidvo/7P6TY7+YqpV37IfF+KUFxmlK04elKtGKXaiVgw== dependencies: "@babel/helper-compilation-targets" "^7.13.0" "@babel/helper-module-imports" "^7.12.13" @@ -170,6 +185,13 @@ dependencies: "@babel/types" "^7.12.13" +"@babel/helper-module-imports@^7.13.12": + version "7.13.12" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.13.12.tgz#c6a369a6f3621cb25da014078684da9196b61977" + integrity sha512-4cVvR2/1B693IuOvSI20xqqa/+bl7lqAMR59R4iu39R9aOX8/JoYY1sFaNvUMyMBGnHdwvJgUrzNLoUZxXypxA== + dependencies: + "@babel/types" "^7.13.12" + "@babel/helper-module-transforms@^7.12.13": version "7.12.13" resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.12.13.tgz" @@ -324,10 +346,19 @@ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.13.10.tgz#8f8f9bf7b3afa3eabd061f7a5bcdf4fec3c48409" integrity sha512-0s7Mlrw9uTWkYua7xWr99Wpk2bnGa0ANleKfksYAES8LpWH4gW1OUr42vqKNf0us5UQNfru2wPqMqRITzq/SIQ== -"@babel/plugin-proposal-async-generator-functions@^7.13.8": - version "7.13.8" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.13.8.tgz#87aacb574b3bc4b5603f6fe41458d72a5a2ec4b1" - integrity sha512-rPBnhj+WgoSmgq+4gQUtXx/vOcU+UYtjy1AA/aeD61Hwj410fwYyqfUcRP3lR8ucgliVJL/G7sXcNUecC75IXA== +"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.13.12": + version "7.13.12" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.13.12.tgz#a3484d84d0b549f3fc916b99ee4783f26fabad2a" + integrity sha512-d0u3zWKcoZf379fOeJdr1a5WPDny4aOFZ6hlfKivgK0LY7ZxNfoaHL2fWwdGtHyVvra38FC+HVYkO+byfSA8AQ== + dependencies: + "@babel/helper-plugin-utils" "^7.13.0" + "@babel/helper-skip-transparent-expression-wrappers" "^7.12.1" + "@babel/plugin-proposal-optional-chaining" "^7.13.12" + +"@babel/plugin-proposal-async-generator-functions@^7.13.15": + version "7.13.15" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.13.15.tgz#80e549df273a3b3050431b148c892491df1bcc5b" + integrity sha512-VapibkWzFeoa6ubXy/NgV5U2U4MVnUlvnx6wo1XhlsaTrLYWE0UFpDQsVrmn22q5CzeloqJ8gEMHSKxuee6ZdA== dependencies: "@babel/helper-plugin-utils" "^7.13.0" "@babel/helper-remap-async-to-generator" "^7.13.0" @@ -408,10 +439,10 @@ "@babel/helper-plugin-utils" "^7.13.0" "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" -"@babel/plugin-proposal-optional-chaining@^7.13.8": - version "7.13.8" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.13.8.tgz#e39df93efe7e7e621841babc197982e140e90756" - integrity sha512-hpbBwbTgd7Cz1QryvwJZRo1U0k1q8uyBmeXOSQUjdg/A2TASkhR/rz7AyqZ/kS8kbpsNA80rOYbxySBJAqmhhQ== +"@babel/plugin-proposal-optional-chaining@^7.13.12": + version "7.13.12" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.13.12.tgz#ba9feb601d422e0adea6760c2bd6bbb7bfec4866" + integrity sha512-fcEdKOkIB7Tf4IxrgEVeFC4zeJSTr78no9wTdBuZZbqF64kzllU0ybo2zrzm7gUQfxGhBgq4E39oRs8Zx/RMYQ== dependencies: "@babel/helper-plugin-utils" "^7.13.0" "@babel/helper-skip-transparent-expression-wrappers" "^7.12.1" @@ -735,23 +766,23 @@ dependencies: "@babel/helper-plugin-utils" "^7.12.13" -"@babel/plugin-transform-react-jsx-development@^7.12.12": - version "7.12.12" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.12.12.tgz" - integrity sha512-i1AxnKxHeMxUaWVXQOSIco4tvVvvCxMSfeBMnMM06mpaJt3g+MpxYQQrDfojUQldP1xxraPSJYSMEljoWM/dCg== +"@babel/plugin-transform-react-jsx-development@^7.12.17": + version "7.12.17" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.12.17.tgz#f510c0fa7cd7234153539f9a362ced41a5ca1447" + integrity sha512-BPjYV86SVuOaudFhsJR1zjgxxOhJDt6JHNoD48DxWEIxUCAMjV1ys6DYw4SDYZh0b1QsS2vfIA9t/ZsQGsDOUQ== dependencies: - "@babel/plugin-transform-react-jsx" "^7.12.12" + "@babel/plugin-transform-react-jsx" "^7.12.17" -"@babel/plugin-transform-react-jsx@^7.12.12", "@babel/plugin-transform-react-jsx@^7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.12.13.tgz" - integrity sha512-hhXZMYR8t9RvduN2uW4sjl6MRtUhzNE726JvoJhpjhxKgRUVkZqTsA0xc49ALZxQM7H26pZ/lLvB2Yrea9dllA== +"@babel/plugin-transform-react-jsx@^7.12.17", "@babel/plugin-transform-react-jsx@^7.13.12": + version "7.13.12" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.13.12.tgz#1df5dfaf0f4b784b43e96da6f28d630e775f68b3" + integrity sha512-jcEI2UqIcpCqB5U5DRxIl0tQEProI2gcu+g8VTIqxLO5Iidojb4d77q+fwGseCvd8af/lJ9masp4QWzBXFE2xA== dependencies: "@babel/helper-annotate-as-pure" "^7.12.13" - "@babel/helper-module-imports" "^7.12.13" - "@babel/helper-plugin-utils" "^7.12.13" + "@babel/helper-module-imports" "^7.13.12" + "@babel/helper-plugin-utils" "^7.13.0" "@babel/plugin-syntax-jsx" "^7.12.13" - "@babel/types" "^7.12.13" + "@babel/types" "^7.13.12" "@babel/plugin-transform-react-pure-annotations@^7.12.1": version "7.12.1" @@ -761,10 +792,10 @@ "@babel/helper-annotate-as-pure" "^7.10.4" "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-transform-regenerator@^7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.12.13.tgz" - integrity sha512-lxb2ZAvSLyJ2PEe47hoGWPmW22v7CtSl9jW8mingV4H2sEX/JOcrAj2nPuGWi56ERUm2bUpjKzONAuT6HCn2EA== +"@babel/plugin-transform-regenerator@^7.13.15": + version "7.13.15" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.13.15.tgz#e5eb28945bf8b6563e7f818945f966a8d2997f39" + integrity sha512-Bk9cOLSz8DiurcMETZ8E2YtIVJbFCPGW28DJWUakmyVWtQSm6Wsf0p4B4BfEr/eL2Nkhe/CICiUiMOCi1TPhuQ== dependencies: regenerator-transform "^0.14.2" @@ -835,16 +866,17 @@ "@babel/helper-create-regexp-features-plugin" "^7.12.13" "@babel/helper-plugin-utils" "^7.12.13" -"@babel/preset-env@^7.13.10": - version "7.13.10" - resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.13.10.tgz#b5cde31d5fe77ab2a6ab3d453b59041a1b3a5252" - integrity sha512-nOsTScuoRghRtUsRr/c69d042ysfPHcu+KOB4A9aAO9eJYqrkat+LF8G1yp1HD18QiwixT2CisZTr/0b3YZPXQ== +"@babel/preset-env@^7.13.15": + version "7.13.15" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.13.15.tgz#c8a6eb584f96ecba183d3d414a83553a599f478f" + integrity sha512-D4JAPMXcxk69PKe81jRJ21/fP/uYdcTZ3hJDF5QX2HSI9bBxxYw/dumdR6dGumhjxlprHPE4XWoPaqzZUVy2MA== dependencies: - "@babel/compat-data" "^7.13.8" - "@babel/helper-compilation-targets" "^7.13.10" + "@babel/compat-data" "^7.13.15" + "@babel/helper-compilation-targets" "^7.13.13" "@babel/helper-plugin-utils" "^7.13.0" "@babel/helper-validator-option" "^7.12.17" - "@babel/plugin-proposal-async-generator-functions" "^7.13.8" + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.13.12" + "@babel/plugin-proposal-async-generator-functions" "^7.13.15" "@babel/plugin-proposal-class-properties" "^7.13.0" "@babel/plugin-proposal-dynamic-import" "^7.13.8" "@babel/plugin-proposal-export-namespace-from" "^7.12.13" @@ -854,7 +886,7 @@ "@babel/plugin-proposal-numeric-separator" "^7.12.13" "@babel/plugin-proposal-object-rest-spread" "^7.13.8" "@babel/plugin-proposal-optional-catch-binding" "^7.13.8" - "@babel/plugin-proposal-optional-chaining" "^7.13.8" + "@babel/plugin-proposal-optional-chaining" "^7.13.12" "@babel/plugin-proposal-private-methods" "^7.13.0" "@babel/plugin-proposal-unicode-property-regex" "^7.12.13" "@babel/plugin-syntax-async-generators" "^7.8.4" @@ -892,7 +924,7 @@ "@babel/plugin-transform-object-super" "^7.12.13" "@babel/plugin-transform-parameters" "^7.13.0" "@babel/plugin-transform-property-literals" "^7.12.13" - "@babel/plugin-transform-regenerator" "^7.12.13" + "@babel/plugin-transform-regenerator" "^7.13.15" "@babel/plugin-transform-reserved-words" "^7.12.13" "@babel/plugin-transform-shorthand-properties" "^7.12.13" "@babel/plugin-transform-spread" "^7.13.0" @@ -902,10 +934,10 @@ "@babel/plugin-transform-unicode-escapes" "^7.12.13" "@babel/plugin-transform-unicode-regex" "^7.12.13" "@babel/preset-modules" "^0.1.4" - "@babel/types" "^7.13.0" - babel-plugin-polyfill-corejs2 "^0.1.4" - babel-plugin-polyfill-corejs3 "^0.1.3" - babel-plugin-polyfill-regenerator "^0.1.2" + "@babel/types" "^7.13.14" + babel-plugin-polyfill-corejs2 "^0.2.0" + babel-plugin-polyfill-corejs3 "^0.2.0" + babel-plugin-polyfill-regenerator "^0.2.0" core-js-compat "^3.9.0" semver "^6.3.0" @@ -920,15 +952,16 @@ "@babel/types" "^7.4.4" esutils "^2.0.2" -"@babel/preset-react@^7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/preset-react/-/preset-react-7.12.13.tgz" - integrity sha512-TYM0V9z6Abb6dj1K7i5NrEhA13oS5ujUYQYDfqIBXYHOc2c2VkFgc+q9kyssIyUfy4/hEwqrgSlJ/Qgv8zJLsA== +"@babel/preset-react@^7.13.13": + version "7.13.13" + resolved "https://registry.yarnpkg.com/@babel/preset-react/-/preset-react-7.13.13.tgz#fa6895a96c50763fe693f9148568458d5a839761" + integrity sha512-gx+tDLIE06sRjKJkVtpZ/t3mzCDOnPG+ggHZG9lffUbX8+wC739x20YQc9V35Do6ZAxaUc/HhVHIiOzz5MvDmA== dependencies: - "@babel/helper-plugin-utils" "^7.12.13" + "@babel/helper-plugin-utils" "^7.13.0" + "@babel/helper-validator-option" "^7.12.17" "@babel/plugin-transform-react-display-name" "^7.12.13" - "@babel/plugin-transform-react-jsx" "^7.12.13" - "@babel/plugin-transform-react-jsx-development" "^7.12.12" + "@babel/plugin-transform-react-jsx" "^7.13.12" + "@babel/plugin-transform-react-jsx-development" "^7.12.17" "@babel/plugin-transform-react-pure-annotations" "^7.12.1" "@babel/preset-typescript@^7.13.0": @@ -1012,6 +1045,15 @@ lodash "^4.17.19" to-fast-properties "^2.0.0" +"@babel/types@^7.13.12", "@babel/types@^7.13.14": + version "7.13.14" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.13.14.tgz#c35a4abb15c7cd45a2746d78ab328e362cbace0d" + integrity sha512-A2aa3QTkWoyqsZZFl56MLUsfmh7O0gN41IPvXAE/++8ojpbz12SszD7JEGYVdn4f9Kt4amIei07swF1h4AqmmQ== + dependencies: + "@babel/helper-validator-identifier" "^7.12.11" + lodash "^4.17.19" + to-fast-properties "^2.0.0" + "@bcoe/v8-coverage@^0.2.3": version "0.2.3" resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz" @@ -1262,10 +1304,10 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@skolplattformen/embedded-api@^2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@skolplattformen/embedded-api/-/embedded-api-2.0.0.tgz#45d12a5d844487f03d1dff96a5b9bd9a4752cff2" - integrity sha512-aZaNRCMV+Z6F7jiwY6aREAbhWtyDUIbvMnoqOIGMd1dbLyQZ2hUS75r67IYL4Kj0a1Jov2cdysrAqg6QsYfLXw== +"@skolplattformen/embedded-api@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@skolplattformen/embedded-api/-/embedded-api-4.0.0.tgz#22ff23b12a111dbc92b20ee2017c78d417cd6e7d" + integrity sha512-leVEr1FXD2knV1K9ZT6bNcL+vCiuO+XpzASJAQOtYfgq869wF4Le5taP8N7jzxHh+Mm2hw7CaMsl5DIbL0YfFg== dependencies: "@types/he" "^1.1.1" camelcase-keys "^6.2.2" @@ -1291,10 +1333,10 @@ lz-string "^1.4.4" pretty-format "^26.6.2" -"@testing-library/jest-dom@^5.11.9": - version "5.11.9" - resolved "https://registry.yarnpkg.com/@testing-library/jest-dom/-/jest-dom-5.11.9.tgz" - integrity sha512-Mn2gnA9d1wStlAIT2NU8J15LNob0YFBVjs2aEQ3j8rsfRQo+lAs7/ui1i2TGaJjapLmuNPLTsrm+nPjmZDwpcQ== +"@testing-library/jest-dom@^5.11.10": + version "5.11.10" + resolved "https://registry.yarnpkg.com/@testing-library/jest-dom/-/jest-dom-5.11.10.tgz#1cd90715023e1627f5ed26ab3b38e6f22d77046c" + integrity sha512-FuKiq5xuk44Fqm0000Z9w0hjOdwZRNzgx7xGGxQYepWFZy+OYUMOT/wPI4nLYXCaVltNVpU1W/qmD88wLWDsqQ== dependencies: "@babel/runtime" "^7.9.2" "@types/testing-library__jest-dom" "^5.9.1" @@ -1305,10 +1347,10 @@ lodash "^4.17.15" redent "^3.0.0" -"@testing-library/react-hooks@^5.1.0": - version "5.1.0" - resolved "https://registry.yarnpkg.com/@testing-library/react-hooks/-/react-hooks-5.1.0.tgz#6014b7536d0e9427a1e73ce1d073c49a6af5fb3b" - integrity sha512-ChRyyA14e0CeVkWGp24v8q/IiWUqH+B8daRx4lGZme4dsudmMNWz+Qo2Q2NzbD2O5rAVXh2hSbS/KTKeqHYhkw== +"@testing-library/react-hooks@^5.1.1": + version "5.1.1" + resolved "https://registry.yarnpkg.com/@testing-library/react-hooks/-/react-hooks-5.1.1.tgz#1fbaae8a4e8a4a7f97b176c23e1e890c41bbbfa5" + integrity sha512-52D2XnpelFDefnWpy/V6z2qGNj8JLIvW5DjYtelMvFXdEyWiykSaI7IXHwFy4ICoqXJDmmwHAiFRiFboub/U5g== dependencies: "@babel/runtime" "^7.12.5" "@types/react" ">=16.9.0" @@ -1317,10 +1359,10 @@ filter-console "^0.1.1" react-error-boundary "^3.1.0" -"@testing-library/react@^11.2.5": - version "11.2.5" - resolved "https://registry.yarnpkg.com/@testing-library/react/-/react-11.2.5.tgz" - integrity sha512-yEx7oIa/UWLe2F2dqK0FtMF9sJWNXD+2PPtp39BvE0Kh9MJ9Kl0HrZAgEuhUJR+Lx8Di6Xz+rKwSdEPY2UV8ZQ== +"@testing-library/react@^11.2.6": + version "11.2.6" + resolved "https://registry.yarnpkg.com/@testing-library/react/-/react-11.2.6.tgz#586a23adc63615985d85be0c903f374dab19200b" + integrity sha512-TXMCg0jT8xmuU8BkKMtp8l7Z50Ykew5WNX8UoIKTaLFwKkP2+1YDhOLA2Ga3wY4x29jyntk7EWfum0kjlYiSjQ== dependencies: "@babel/runtime" "^7.12.5" "@testing-library/dom" "^7.28.1" @@ -1402,7 +1444,7 @@ dependencies: "@types/istanbul-lib-report" "*" -"@types/jest@*", "@types/jest@^26.0.20": +"@types/jest@*": version "26.0.20" resolved "https://registry.yarnpkg.com/@types/jest/-/jest-26.0.20.tgz" integrity sha512-9zi2Y+5USJRxd0FsahERhBwlcvFh6D2GLQnY2FH2BzK8J9s9omvNHIbvABwIluXa0fD8XVKMLTO0aOEuUfACAA== @@ -1410,6 +1452,14 @@ jest-diff "^26.0.0" pretty-format "^26.0.0" +"@types/jest@^26.0.22": + version "26.0.22" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-26.0.22.tgz#8308a1debdf1b807aa47be2838acdcd91e88fbe6" + integrity sha512-eeWwWjlqxvBxc4oQdkueW5OF/gtfSceKk4OnOAGlUSwS/liBRtZppbJuz1YkgbrbfGOoeBHun9fOvXnjNwrSOw== + dependencies: + jest-diff "^26.0.0" + pretty-format "^26.0.0" + "@types/json-schema@^7.0.3": version "7.0.7" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.7.tgz" @@ -1504,13 +1554,13 @@ dependencies: "@types/yargs-parser" "*" -"@typescript-eslint/eslint-plugin@^4.17.0": - version "4.17.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.17.0.tgz#6f856eca4e6a52ce9cf127dfd349096ad936aa2d" - integrity sha512-/fKFDcoHg8oNan39IKFOb5WmV7oWhQe1K6CDaAVfJaNWEhmfqlA24g+u1lqU5bMH7zuNasfMId4LaYWC5ijRLw== +"@typescript-eslint/eslint-plugin@^4.21.0": + version "4.21.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.21.0.tgz#3fce2bfa76d95c00ac4f33dff369cb593aab8878" + integrity sha512-FPUyCPKZbVGexmbCFI3EQHzCZdy2/5f+jv6k2EDljGdXSRc0cKvbndd2nHZkSLqCNOPk0jB6lGzwIkglXcYVsQ== dependencies: - "@typescript-eslint/experimental-utils" "4.17.0" - "@typescript-eslint/scope-manager" "4.17.0" + "@typescript-eslint/experimental-utils" "4.21.0" + "@typescript-eslint/scope-manager" "4.21.0" debug "^4.1.1" functional-red-black-tree "^1.0.1" lodash "^4.17.15" @@ -1518,15 +1568,15 @@ semver "^7.3.2" tsutils "^3.17.1" -"@typescript-eslint/experimental-utils@4.17.0": - version "4.17.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.17.0.tgz#762c44aaa1a6a3c05b6d63a8648fb89b89f84c80" - integrity sha512-ZR2NIUbnIBj+LGqCFGQ9yk2EBQrpVVFOh9/Kd0Lm6gLpSAcCuLLe5lUCibKGCqyH9HPwYC0GIJce2O1i8VYmWA== +"@typescript-eslint/experimental-utils@4.21.0": + version "4.21.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.21.0.tgz#0b0bb7c15d379140a660c003bdbafa71ae9134b6" + integrity sha512-cEbgosW/tUFvKmkg3cU7LBoZhvUs+ZPVM9alb25XvR0dal4qHL3SiUqHNrzoWSxaXA9gsifrYrS1xdDV6w/gIA== dependencies: "@types/json-schema" "^7.0.3" - "@typescript-eslint/scope-manager" "4.17.0" - "@typescript-eslint/types" "4.17.0" - "@typescript-eslint/typescript-estree" "4.17.0" + "@typescript-eslint/scope-manager" "4.21.0" + "@typescript-eslint/types" "4.21.0" + "@typescript-eslint/typescript-estree" "4.21.0" eslint-scope "^5.0.0" eslint-utils "^2.0.0" @@ -1568,6 +1618,14 @@ "@typescript-eslint/types" "4.17.0" "@typescript-eslint/visitor-keys" "4.17.0" +"@typescript-eslint/scope-manager@4.21.0": + version "4.21.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.21.0.tgz#c81b661c4b8af1ec0c010d847a8f9ab76ab95b4d" + integrity sha512-kfOjF0w1Ix7+a5T1knOw00f7uAP9Gx44+OEsNQi0PvvTPLYeXJlsCJ4tYnDj5PQEYfpcgOH5yBlw7K+UEI9Agw== + dependencies: + "@typescript-eslint/types" "4.21.0" + "@typescript-eslint/visitor-keys" "4.21.0" + "@typescript-eslint/types@4.14.2": version "4.14.2" resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.14.2.tgz" @@ -1578,6 +1636,11 @@ resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.17.0.tgz#f57d8fc7f31b348db946498a43050083d25f40ad" integrity sha512-RN5z8qYpJ+kXwnLlyzZkiJwfW2AY458Bf8WqllkondQIcN2ZxQowAToGSd9BlAUZDB5Ea8I6mqL2quGYCLT+2g== +"@typescript-eslint/types@4.21.0": + version "4.21.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.21.0.tgz#abdc3463bda5d31156984fa5bc316789c960edef" + integrity sha512-+OQaupjGVVc8iXbt6M1oZMwyKQNehAfLYJJ3SdvnofK2qcjfor9pEM62rVjBknhowTkh+2HF+/KdRAc/wGBN2w== + "@typescript-eslint/typescript-estree@4.14.2": version "4.14.2" resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.14.2.tgz" @@ -1605,6 +1668,19 @@ semver "^7.3.2" tsutils "^3.17.1" +"@typescript-eslint/typescript-estree@4.21.0": + version "4.21.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.21.0.tgz#3817bd91857beeaeff90f69f1f112ea58d350b0a" + integrity sha512-ZD3M7yLaVGVYLw4nkkoGKumb7Rog7QID9YOWobFDMQKNl+vPxqVIW/uDk+MDeGc+OHcoG2nJ2HphwiPNajKw3w== + dependencies: + "@typescript-eslint/types" "4.21.0" + "@typescript-eslint/visitor-keys" "4.21.0" + debug "^4.1.1" + globby "^11.0.1" + is-glob "^4.0.1" + semver "^7.3.2" + tsutils "^3.17.1" + "@typescript-eslint/visitor-keys@4.14.2": version "4.14.2" resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.14.2.tgz" @@ -1621,6 +1697,14 @@ "@typescript-eslint/types" "4.17.0" eslint-visitor-keys "^2.0.0" +"@typescript-eslint/visitor-keys@4.21.0": + version "4.21.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.21.0.tgz#990a9acdc124331f5863c2cf21c88ba65233cd8d" + integrity sha512-dH22dROWGi5Z6p+Igc8bLVLmwy7vEe8r+8c+raPQU0LxgogPUrRAtRGtvBWmlr9waTu3n+QLt/qrS/hWzk1x5w== + dependencies: + "@typescript-eslint/types" "4.21.0" + eslint-visitor-keys "^2.0.0" + abab@^2.0.3: version "2.0.5" resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.5.tgz" @@ -1762,6 +1846,17 @@ array-includes@^3.1.1, array-includes@^3.1.2: get-intrinsic "^1.0.1" is-string "^1.0.5" +array-includes@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.3.tgz#c7f619b382ad2afaf5326cddfdc0afc61af7690a" + integrity sha512-gcem1KlBU7c9rB+Rq8/3PPKsK2kjqeEBa3bD5kkQo4nYlOHQCJqIJFqBXDEfwaRuYTT4E+FxA9xez7Gf/e3Q7A== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.18.0-next.2" + get-intrinsic "^1.1.1" + is-string "^1.0.5" + array-union@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz" @@ -1781,9 +1876,9 @@ array.prototype.flat@^1.2.3: define-properties "^1.1.3" es-abstract "^1.18.0-next.1" -array.prototype.flatmap@^1.2.3: +array.prototype.flatmap@^1.2.4: version "1.2.4" - resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.2.4.tgz" + resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.2.4.tgz#94cfd47cc1556ec0747d97f7c7738c58122004c9" integrity sha512-r9Z0zYoxqHz60vvQbWEdXIEtCwHF0yxaWfno9qzXeNHvfyl3BZqygmGzb84dsubyaXLH4husF+NFgMSdpZhk2Q== dependencies: call-bind "^1.0.0" @@ -1890,29 +1985,29 @@ babel-plugin-jest-hoist@^26.6.2: "@types/babel__core" "^7.0.0" "@types/babel__traverse" "^7.0.6" -babel-plugin-polyfill-corejs2@^0.1.4: - version "0.1.10" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.1.10.tgz#a2c5c245f56c0cac3dbddbf0726a46b24f0f81d1" - integrity sha512-DO95wD4g0A8KRaHKi0D51NdGXzvpqVLnLu5BTvDlpqUEpTmeEtypgC1xqesORaWmiUOQI14UHKlzNd9iZ2G3ZA== +babel-plugin-polyfill-corejs2@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.2.0.tgz#686775bf9a5aa757e10520903675e3889caeedc4" + integrity sha512-9bNwiR0dS881c5SHnzCmmGlMkJLl0OUZvxrxHo9w/iNoRuqaPjqlvBf4HrovXtQs/au5yKkpcdgfT1cC5PAZwg== dependencies: - "@babel/compat-data" "^7.13.0" - "@babel/helper-define-polyfill-provider" "^0.1.5" + "@babel/compat-data" "^7.13.11" + "@babel/helper-define-polyfill-provider" "^0.2.0" semver "^6.1.1" -babel-plugin-polyfill-corejs3@^0.1.3: - version "0.1.7" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.1.7.tgz#80449d9d6f2274912e05d9e182b54816904befd0" - integrity sha512-u+gbS9bbPhZWEeyy1oR/YaaSpod/KDT07arZHb80aTpl8H5ZBq+uN1nN9/xtX7jQyfLdPfoqI4Rue/MQSWJquw== +babel-plugin-polyfill-corejs3@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.2.0.tgz#f4b4bb7b19329827df36ff56f6e6d367026cb7a2" + integrity sha512-zZyi7p3BCUyzNxLx8KV61zTINkkV65zVkDAFNZmrTCRVhjo1jAS+YLvDJ9Jgd/w2tsAviCwFHReYfxO3Iql8Yg== dependencies: - "@babel/helper-define-polyfill-provider" "^0.1.5" - core-js-compat "^3.8.1" + "@babel/helper-define-polyfill-provider" "^0.2.0" + core-js-compat "^3.9.1" -babel-plugin-polyfill-regenerator@^0.1.2: - version "0.1.6" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.1.6.tgz#0fe06a026fe0faa628ccc8ba3302da0a6ce02f3f" - integrity sha512-OUrYG9iKPKz8NxswXbRAdSwF0GhRdIEMTloQATJi4bDuFqrXaXcCUT/VGNrr8pBcjMh1RxZ7Xt9cytVJTJfvMg== +babel-plugin-polyfill-regenerator@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.2.0.tgz#853f5f5716f4691d98c84f8069c7636ea8da7ab8" + integrity sha512-J7vKbCuD2Xi/eEHxquHN14bXAW9CXtecwuLrOIDJtcZzTaPzV1VdEfoUf9AzcRBMolKUQKM9/GVojeh0hFiqMg== dependencies: - "@babel/helper-define-polyfill-provider" "^0.1.5" + "@babel/helper-define-polyfill-provider" "^0.2.0" babel-preset-current-node-syntax@^1.0.0: version "1.0.1" @@ -2290,7 +2385,7 @@ copy-descriptor@^0.1.0: resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz" integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= -core-js-compat@^3.8.1, core-js-compat@^3.9.0: +core-js-compat@^3.9.0: version "3.9.1" resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.9.1.tgz#4e572acfe90aff69d76d8c37759d21a5c59bb455" integrity sha512-jXAirMQxrkbiiLsCx9bQPJFA6llDadKMpYrBJQJ3/c4/vsPP/fAf29h24tviRlvwUL6AmY5CHLu2GvjuYviQqA== @@ -2298,6 +2393,14 @@ core-js-compat@^3.8.1, core-js-compat@^3.9.0: browserslist "^4.16.3" semver "7.0.0" +core-js-compat@^3.9.1: + version "3.10.1" + resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.10.1.tgz#62183a3a77ceeffcc420d907a3e6fc67d9b27f1c" + integrity sha512-ZHQTdTPkqvw2CeHiZC970NNJcnwzT6YIueDMASKt+p3WbZsLXOcoD392SkcWhkC0wBBHhlfhqGKKsNCQUozYtg== + dependencies: + browserslist "^4.16.3" + semver "7.0.0" + core-js-pure@^3.0.0: version "3.8.3" resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.8.3.tgz" @@ -2638,6 +2741,28 @@ es-abstract@^1.18.0-next.1: string.prototype.trimend "^1.0.3" string.prototype.trimstart "^1.0.3" +es-abstract@^1.18.0-next.2: + version "1.18.0" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.18.0.tgz#ab80b359eecb7ede4c298000390bc5ac3ec7b5a4" + integrity sha512-LJzK7MrQa8TS0ja2w3YNLzUgJCGPdPOV1yVvezjNnS89D+VR08+Szt2mz3YB2Dck/+w5tfIq/RoUAFqJJGM2yw== + dependencies: + call-bind "^1.0.2" + es-to-primitive "^1.2.1" + function-bind "^1.1.1" + get-intrinsic "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.2" + is-callable "^1.2.3" + is-negative-zero "^2.0.1" + is-regex "^1.1.2" + is-string "^1.0.5" + object-inspect "^1.9.0" + object-keys "^1.1.1" + object.assign "^4.1.2" + string.prototype.trimend "^1.0.4" + string.prototype.trimstart "^1.0.4" + unbox-primitive "^1.0.0" + es-to-primitive@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz" @@ -2736,10 +2861,10 @@ eslint-plugin-import@^2.22.1: resolve "^1.17.0" tsconfig-paths "^3.9.0" -eslint-plugin-jest@^24.2.1: - version "24.2.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-24.2.1.tgz#7e84f16a3ca6589b86be9732a93d71367a4ed627" - integrity sha512-s24ve8WUu3DLVidvlSzaqlOpTZre9lTkZTAO+a7X0WMtj8HraWTiTEkW3pbDT1xVxqEHMWSv+Kx7MyqR50nhBw== +eslint-plugin-jest@^24.3.4: + version "24.3.4" + resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-24.3.4.tgz#6d90c3554de0302e879603dd6405474c98849f19" + integrity sha512-3n5oY1+fictanuFkTWPwSlehugBTAgwLnYLFsCllzE3Pl1BwywHl5fL0HFxmMjoQY8xhUDk8uAWc3S4JOHGh3A== dependencies: "@typescript-eslint/experimental-utils" "^4.0.1" @@ -2765,22 +2890,23 @@ eslint-plugin-react-hooks@^4.2.0: resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.2.0.tgz#8c229c268d468956334c943bb45fc860280f5556" integrity sha512-623WEiZJqxR7VdxFCKLI6d6LLpwJkGPYKODnkH3D7WpOG5KM8yWueBd8TLsNAetEJNF5iJmolaAKO3F8yzyVBQ== -eslint-plugin-react@^7.22.0: - version "7.22.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.22.0.tgz#3d1c542d1d3169c45421c1215d9470e341707269" - integrity sha512-p30tuX3VS+NWv9nQot9xIGAHBXR0+xJVaZriEsHoJrASGCJZDJ8JLNM0YqKqI0AKm6Uxaa1VUHoNEibxRCMQHA== +eslint-plugin-react@^7.23.2: + version "7.23.2" + resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.23.2.tgz#2d2291b0f95c03728b55869f01102290e792d494" + integrity sha512-AfjgFQB+nYszudkxRkTFu0UR1zEQig0ArVMPloKhxwlwkzaw/fBiH0QWcBBhZONlXqQC51+nfqFrkn4EzHcGBw== dependencies: - array-includes "^3.1.1" - array.prototype.flatmap "^1.2.3" + array-includes "^3.1.3" + array.prototype.flatmap "^1.2.4" doctrine "^2.1.0" has "^1.0.3" jsx-ast-utils "^2.4.1 || ^3.0.0" - object.entries "^1.1.2" - object.fromentries "^2.0.2" - object.values "^1.1.1" + minimatch "^3.0.4" + object.entries "^1.1.3" + object.fromentries "^2.0.4" + object.values "^1.1.3" prop-types "^15.7.2" - resolve "^1.18.1" - string.prototype.matchall "^4.0.2" + resolve "^2.0.0-next.3" + string.prototype.matchall "^4.0.4" eslint-scope@^5.0.0, eslint-scope@^5.1.1: version "5.1.1" @@ -2807,10 +2933,10 @@ eslint-visitor-keys@^2.0.0: resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz" integrity sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ== -eslint@^7.21.0: - version "7.21.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.21.0.tgz#4ecd5b8c5b44f5dedc9b8a110b01bbfeb15d1c83" - integrity sha512-W2aJbXpMNofUp0ztQaF40fveSsJBjlSCSWpy//gzfTvwC+USs/nceBrKmlJOiM8r1bLwP2EuYkCqArn/6QTIgg== +eslint@^7.23.0: + version "7.23.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.23.0.tgz#8d029d252f6e8cf45894b4bee08f5493f8e94325" + integrity sha512-kqvNVbdkjzpFy0XOszNwjkKzZ+6TcwCQ/h+ozlcIWwaimBBuhlQ4nN6kbiM2L+OjDcznkTJxzYfRFH92sx4a0Q== dependencies: "@babel/code-frame" "7.12.11" "@eslint/eslintrc" "^0.4.0" @@ -2829,7 +2955,7 @@ eslint@^7.21.0: file-entry-cache "^6.0.1" functional-red-black-tree "^1.0.1" glob-parent "^5.0.0" - globals "^12.1.0" + globals "^13.6.0" ignore "^4.0.6" import-fresh "^3.0.0" imurmurhash "^0.1.4" @@ -2837,7 +2963,7 @@ eslint@^7.21.0: js-yaml "^3.13.1" json-stable-stringify-without-jsonify "^1.0.1" levn "^0.4.1" - lodash "^4.17.20" + lodash "^4.17.21" minimatch "^3.0.4" natural-compare "^1.4.0" optionator "^0.9.1" @@ -3177,7 +3303,7 @@ get-caller-file@^2.0.1: resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== -get-intrinsic@^1.0.1, get-intrinsic@^1.0.2, get-intrinsic@^1.1.0: +get-intrinsic@^1.0.1, get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.1.tgz" integrity sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q== @@ -3253,6 +3379,13 @@ globals@^12.1.0: dependencies: type-fest "^0.8.1" +globals@^13.6.0: + version "13.8.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.8.0.tgz#3e20f504810ce87a8d72e55aecf8435b50f4c1b3" + integrity sha512-rHtdA6+PDBIjeEvA91rpqzEvk/k3/i7EeNQiryiWuJH0Hw9cpyJMAt2jtbAwUaRdhD+573X4vWw6IcjKPasi9Q== + dependencies: + type-fest "^0.20.2" + globby@^11.0.1: version "11.0.2" resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.2.tgz" @@ -3298,6 +3431,11 @@ har-validator@~5.1.3: ajv "^6.12.3" har-schema "^2.0.0" +has-bigints@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.1.tgz#64fe6acb020673e3b78db035a5af69aa9d07b113" + integrity sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA== + has-flag@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz" @@ -3313,6 +3451,11 @@ has-symbols@^1.0.1: resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.1.tgz" integrity sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg== +has-symbols@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.2.tgz#165d3070c00309752a1236a479331e3ac56f1423" + integrity sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw== + has-value@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz" @@ -3470,9 +3613,9 @@ inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4: resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== -internal-slot@^1.0.2: +internal-slot@^1.0.3: version "1.0.3" - resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.3.tgz" + resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.3.tgz#7347e307deeea2faac2ac6205d4bc7d34967f59c" integrity sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA== dependencies: get-intrinsic "^1.1.0" @@ -3503,12 +3646,24 @@ is-arrayish@^0.2.1: resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz" integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= +is-bigint@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.1.tgz#6923051dfcbc764278540b9ce0e6b3213aa5ebc2" + integrity sha512-J0ELF4yHFxHy0cmSxZuheDOz2luOdVvqjwmEcj8H/L1JHeuEDSDbeRP+Dk9kFVk5RTFzbucJ2Kb9F7ixY2QaCg== + +is-boolean-object@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.0.tgz#e2aaad3a3a8fca34c28f6eee135b156ed2587ff0" + integrity sha512-a7Uprx8UtD+HWdyYwnD1+ExtTgqQtD2k/1yJgtXP6wnMm8byhkoTZRl+95LLThpzNZJ5aEvi46cdH+ayMFRwmA== + dependencies: + call-bind "^1.0.0" + is-buffer@^1.1.5: version "1.1.6" resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz" integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== -is-callable@^1.1.4, is-callable@^1.2.2: +is-callable@^1.1.4, is-callable@^1.2.2, is-callable@^1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.3.tgz" integrity sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ== @@ -3608,6 +3763,11 @@ is-negative-zero@^2.0.1: resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.1.tgz" integrity sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w== +is-number-object@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.4.tgz#36ac95e741cf18b283fc1ddf5e83da798e3ec197" + integrity sha512-zohwelOAur+5uXtk8O3GPQ1eAcu4ZX3UwxQhUlfFFMNpUd83gXgjbhJh6HmB6LUNV/ieOLQuDwJO3dWJosUeMw== + is-number@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz" @@ -3632,7 +3792,7 @@ is-potential-custom-element-name@^1.0.0: resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.0.tgz" integrity sha1-DFLlS8yjkbssSUsh6GJtczbG45c= -is-regex@^1.1.1: +is-regex@^1.1.1, is-regex@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.2.tgz" integrity sha512-axvdhb5pdhEVThqJzYXwMlVuZwC+FF2DpcOhTS+y/8jVq4trxyPgfcwIxIKiyeuLlSQYKkmUaPQJ8ZE4yNKXDg== @@ -3655,7 +3815,7 @@ is-string@^1.0.5: resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.5.tgz" integrity sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ== -is-symbol@^1.0.2: +is-symbol@^1.0.2, is-symbol@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.3.tgz" integrity sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ== @@ -4354,6 +4514,11 @@ lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20: resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz" integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA== +lodash@^4.17.21: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + loose-envify@^1.1.0, loose-envify@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz" @@ -4669,7 +4834,7 @@ object.assign@^4.1.0, object.assign@^4.1.2: has-symbols "^1.0.1" object-keys "^1.1.1" -object.entries@^1.1.2: +object.entries@^1.1.2, object.entries@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.3.tgz" integrity sha512-ym7h7OZebNS96hn5IJeyUmaWhaSM4SVtAPPfNLQEI2MYWCO2egsITb9nab2+i/Pwibx+R0mtn+ltKJXRSeTMGg== @@ -4679,14 +4844,14 @@ object.entries@^1.1.2: es-abstract "^1.18.0-next.1" has "^1.0.3" -object.fromentries@^2.0.2: - version "2.0.3" - resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.3.tgz" - integrity sha512-IDUSMXs6LOSJBWE++L0lzIbSqHl9KDCfff2x/JSEIDtEUavUnyMYC2ZGay/04Zq4UT8lvd4xNhU4/YHKibAOlw== +object.fromentries@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.4.tgz#26e1ba5c4571c5c6f0890cef4473066456a120b8" + integrity sha512-EsFBshs5RUUpQEY1D4q/m59kMfz4YJvxuNCJcv/jWwOJr34EaVnG11ZrZa0UHB3wnzV1wx8m58T4hQL8IuNXlQ== dependencies: - call-bind "^1.0.0" + call-bind "^1.0.2" define-properties "^1.1.3" - es-abstract "^1.18.0-next.1" + es-abstract "^1.18.0-next.2" has "^1.0.3" object.pick@^1.3.0: @@ -4706,6 +4871,16 @@ object.values@^1.1.1: es-abstract "^1.18.0-next.1" has "^1.0.3" +object.values@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.3.tgz#eaa8b1e17589f02f698db093f7c62ee1699742ee" + integrity sha512-nkF6PfDB9alkOUxpf1HNm/QlkeW3SReqL5WXeBLpEJJnlPSvRaDQpW3gQTksTN3fgJX4hL42RzKyOin6ff3tyw== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.18.0-next.2" + has "^1.0.3" + once@^1.3.0, once@^1.3.1, once@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz" @@ -5035,12 +5210,13 @@ react-is@^17.0.1: resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.1.tgz" integrity sha512-NAnt2iGDXohE5LI7uBnLnqvLQMtzhkiAOLXTmv+qnF9Ky7xAPcX8Up/xWIhxvLVGJvuLiNc4xQLtuqDRzb4fSA== -react-redux@^7.2.2: - version "7.2.2" - resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-7.2.2.tgz" - integrity sha512-8+CQ1EvIVFkYL/vu6Olo7JFLWop1qRUeb46sGtIMDCSpgwPQq8fPLpirIB0iTqFe9XYEFPHssdX8/UwN6pAkEA== +react-redux@^7.2.3: + version "7.2.3" + resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-7.2.3.tgz#4c084618600bb199012687da9e42123cca3f0be9" + integrity sha512-ZhAmQ1lrK+Pyi0ZXNMUZuYxYAZd59wFuVDGUt536kSGdD0ya9Q7BfsE95E3TsFLE3kOSFp5m6G5qbatE+Ic1+w== dependencies: "@babel/runtime" "^7.12.1" + "@types/react-redux" "^7.1.16" hoist-non-react-statics "^3.3.2" loose-envify "^1.4.0" prop-types "^15.7.2" @@ -5158,9 +5334,9 @@ regex-not@^1.0.0, regex-not@^1.0.2: extend-shallow "^3.0.2" safe-regex "^1.1.0" -regexp.prototype.flags@^1.3.0: +regexp.prototype.flags@^1.3.1: version "1.3.1" - resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.3.1.tgz" + resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.3.1.tgz#7ef352ae8d159e758c0eadca6f8fcb4eef07be26" integrity sha512-JiBdRBq91WlY7uRJ0ds7R+dU02i6LKi8r3BuQhNXn+kmeLN+EfHhfjqMRis1zJxnlu88hq/4dx0P2OP3APRTOA== dependencies: call-bind "^1.0.2" @@ -5305,6 +5481,14 @@ resolve@^1.14.2: is-core-module "^2.2.0" path-parse "^1.0.6" +resolve@^2.0.0-next.3: + version "2.0.0-next.3" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-2.0.0-next.3.tgz#d41016293d4a8586a39ca5d9b5f15cbea1f55e46" + integrity sha512-W8LucSynKUIDu9ylraa7ueVZ7hc0uAgJBxVsQSKOXOyle8a93qXhcz+XAXZ8bIq2d6i4Ehddn6Evt+0/UwKk6Q== + dependencies: + is-core-module "^2.2.0" + path-parse "^1.0.6" + ret@~0.1.10: version "0.1.15" resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz" @@ -5459,7 +5643,7 @@ shellwords@^0.1.1: resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz" integrity sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww== -side-channel@^1.0.3, side-channel@^1.0.4: +side-channel@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz" integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== @@ -5667,18 +5851,18 @@ string-width@^4.1.0, string-width@^4.2.0: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.0" -string.prototype.matchall@^4.0.2: - version "4.0.3" - resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.3.tgz" - integrity sha512-OBxYDA2ifZQ2e13cP82dWFMaCV9CGF8GzmN4fljBVw5O5wep0lu4gacm1OL6MjROoUnB8VbkWRThqkV2YFLNxw== +string.prototype.matchall@^4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.4.tgz#608f255e93e072107f5de066f81a2dfb78cf6b29" + integrity sha512-pknFIWVachNcyqRfaQSeu/FUfpvJTe4uskUSZ9Wc1RijsPuzbZ8TyYT8WCNnntCjUEqQ3vUHMAfVj2+wLAisPQ== dependencies: - call-bind "^1.0.0" + call-bind "^1.0.2" define-properties "^1.1.3" - es-abstract "^1.18.0-next.1" + es-abstract "^1.18.0-next.2" has-symbols "^1.0.1" - internal-slot "^1.0.2" - regexp.prototype.flags "^1.3.0" - side-channel "^1.0.3" + internal-slot "^1.0.3" + regexp.prototype.flags "^1.3.1" + side-channel "^1.0.4" string.prototype.trimend@^1.0.3: version "1.0.3" @@ -5688,6 +5872,14 @@ string.prototype.trimend@^1.0.3: call-bind "^1.0.0" define-properties "^1.1.3" +string.prototype.trimend@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz#e75ae90c2942c63504686c18b287b4a0b1a45f80" + integrity sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + string.prototype.trimstart@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.3.tgz" @@ -5696,6 +5888,14 @@ string.prototype.trimstart@^1.0.3: call-bind "^1.0.0" define-properties "^1.1.3" +string.prototype.trimstart@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz#b36399af4ab2999b4c9c648bd7a3fb2bb26feeed" + integrity sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + string_decoder@^1.1.1: version "1.3.0" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" @@ -5940,6 +6140,11 @@ type-fest@^0.11.0: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.11.0.tgz" integrity sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ== +type-fest@^0.20.2: + version "0.20.2" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" + integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== + type-fest@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.6.0.tgz" @@ -5962,6 +6167,16 @@ typescript@^3.9.7: resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.7.tgz" integrity sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw== +unbox-primitive@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.1.tgz#085e215625ec3162574dc8859abee78a59b14471" + integrity sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw== + dependencies: + function-bind "^1.1.1" + has-bigints "^1.0.1" + has-symbols "^1.0.2" + which-boxed-primitive "^1.0.2" + unicode-canonical-property-names-ecmascript@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz" @@ -6132,6 +6347,17 @@ whatwg-url@^8.0.0: tr46 "^2.0.2" webidl-conversions "^6.1.0" +which-boxed-primitive@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" + integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg== + dependencies: + is-bigint "^1.0.1" + is-boolean-object "^1.1.0" + is-number-object "^1.0.4" + is-string "^1.0.5" + is-symbol "^1.0.3" + which-module@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz"