diff --git a/.env b/.env index ceb8e422..04963936 100644 --- a/.env +++ b/.env @@ -1,2 +1,2 @@ -VITE_API_URL=https://www.omdbapi.com/ -VITE_API_KEY=dbb72d83 +NEXT_PUBLIC_API_URL=https://www.omdbapi.com/ +NEXT_PUBLIC_API_KEY=dbb72d83 diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 826d5682..eb1498a6 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -10,9 +10,10 @@ module.exports = { 'plugin:@typescript-eslint/recommended', 'plugin:import/recommended', 'prettier', + 'next/core-web-vitals' ], - ignorePatterns: ['dist', '.eslintrc.cjs', 'vite.config.ts', 'prettier.config.js', '@typescript-eslint', 'node_modules', 'tailwind.config.js'], - plugins: ['react', 'react-refresh', 'simple-import-sort', 'import', 'prettier'], + ignorePatterns: ['dist', '.eslintrc.cjs', 'prettier.config.js', 'node_modules', 'tailwind.config.js', 'next.config.js', 'environment.d.ts'], + plugins: ['react', 'react-refresh', 'simple-import-sort', 'import', 'prettier', '@typescript-eslint'], parser: '@typescript-eslint/parser', parserOptions: { ecmaFeatures: { @@ -34,14 +35,7 @@ module.exports = { 'no-void': 0, 'no-param-reassign': 0, 'import/no-extraneous-dependencies': 0, - 'import/extensions': [ - 'error', - 'ignorePackages', - { - 'ts': 'always', - 'tsx': 'always' - } - ], + 'import/extensions': 0, 'import/namespace': 0, 'sort-imports': ['error', {ignoreCase: true, ignoreDeclarationSort: true}], 'import/order': [ @@ -60,7 +54,7 @@ module.exports = { position: 'before', }, { - pattern: '@src/**', + pattern: '*', group: 'internal', }, ], @@ -77,6 +71,7 @@ module.exports = { 'import/resolver': { typescript: { alwaysTryTypes: true, + project: './tsconfig.json', }, node: { extensions: ['.js','.jsx','.ts','.tsx'] diff --git a/.github/actions/ci-setup/action.yml b/.github/actions/ci-setup/action.yml deleted file mode 100644 index c72f6e4b..00000000 --- a/.github/actions/ci-setup/action.yml +++ /dev/null @@ -1,21 +0,0 @@ -name: "Setup Continuous Integration" -description: "Cache Dependencies" -runs: - using: "composite" - steps: - - name: Setup Node.js - uses: actions/setup-node@v3 - with: - node-version: ${{ env.NODE_VERSION }} - cache: "npm" - - - name: Cache NPM Dependencies - uses: actions/cache@v3 - id: cache-primes - with: - path: node_modules - key: ${{ runner.os }}-node-${{ hashFiles('package-lock.json') }} - - - name: Install Dependencies - run: npm install - shell: bash diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 00000000..7f92c9e8 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,25 @@ +1. Task: [click](https://github.com/rolling-scopes-school/tasks/tree/master/react/modules/module04) +2. Screenshot: +3. Deploy: [click](https://quiddlee.github.io/Cinemania/) +4. Done 14.11.2023 / deadline 20.11.2023 +5. Score: 100 / 100 + +## Functional requirements 🍿 +- [x] πŸ“₯ Redux is integrated to the app with the help of Redux Toolkit - 25 points +- [x] πŸ” Search is saved in the store - 5 points +- [x] πŸ”’ Items per page is saved in the store - 5 points +- [x] πŸͺŸ View mode is saved in the store - 10 points +- [x] πŸ”ƒ Loading indicators are shown, loading flags are saved in the store, - 10 points +- [x] πŸ“ž When either search or items per page is changed, application makes a new call using RTK Query to fetch the data - 25 points +- [x] πŸ§ͺ Tests had been modified to test the functionality using Redux and RTK Query - 20 points + +## Penalties πŸ‘Ž +- [ ] πŸ˜₯ TypeScript isn't used: -95 points +- [ ] 😱 Usage of any: -20 points per each +- [ ] πŸ™€ Usage of ts-ignore: -20 points per each +- [ ] πŸ§ƒ Direct DOM manipulations inside the React components: -50 points per each +- [ ] πŸͺ React hooks are used to get access to either state, or to the component lifecycle: -70 points +- [ ] πŸ’¨ Presence of code-smells (God-object, chunks of duplicate code), commented code sections: -10 points per each +- [ ] πŸ“š Usage of component libraries, e.g. Material UI, Ant Design: -100 points +- [ ] πŸ“” Test coverage is less than 80%: -30 points +- [ ] πŸ“› Commits after the deadline: -40 points diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml deleted file mode 100644 index 5f406f42..00000000 --- a/.github/workflows/deploy.yml +++ /dev/null @@ -1,29 +0,0 @@ -name: Deploy - -on: [push] - -permissions: - contents: write - -env: - NODE_VERSION: 18.16.0 - -jobs: - deploy: - name: Build And Deploy - runs-on: ubuntu-latest - - steps: - - name: Checkout️ - uses: actions/checkout@v3 - - - name: Setup Continuous integration - uses: ./.github/actions/ci-setup - - - name: Build - run: npm run build - - - name: Deploy - uses: JamesIves/github-pages-deploy-action@v4 - with: - folder: dist diff --git a/.gitignore b/.gitignore index 8c5de10f..ef6c7201 100644 --- a/.gitignore +++ b/.gitignore @@ -1,26 +1,37 @@ -# Logs -logs -*.log +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js +.yarn/install-state.gz + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem +.idea + +# debug npm-debug.log* yarn-debug.log* yarn-error.log* -pnpm-debug.log* -lerna-debug.log* -coverage - -node_modules -dist -dist-ssr -*.local - -# Editor directories and files -.vscode/* -!.vscode/extensions.json -.idea -.DS_Store -*.suo -*.ntvs* -*.njsproj -*.sln -*.sw? -#*.env + +# local env files +#.env + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts diff --git a/README.md b/README.md index 00079868..04806f19 100644 --- a/README.md +++ b/README.md @@ -1 +1 @@ -# react-components +# Cinemania 🍿 diff --git a/app/model/slice.test.tsx b/app/model/slice.test.tsx new file mode 100644 index 00000000..532920cb --- /dev/null +++ b/app/model/slice.test.tsx @@ -0,0 +1,13 @@ +import { describe, expect, it } from 'vitest'; + +import { appReducer, dataFetched, initialState } from './slice'; + +describe('appSlice', () => { + it("should change app's slice dataFetched state", () => { + const state = appReducer(initialState, dataFetched(true)); + + expect(state).toEqual({ + isFetching: true, + }); + }); +}); diff --git a/app/model/slice.ts b/app/model/slice.ts new file mode 100644 index 00000000..96039a36 --- /dev/null +++ b/app/model/slice.ts @@ -0,0 +1,23 @@ +import { createSlice, PayloadAction } from '@reduxjs/toolkit'; + +interface IInitialState { + isFetching: boolean; +} + +export const initialState: IInitialState = { + isFetching: false, +}; + +export const appSlice = createSlice({ + name: 'app', + initialState, + reducers: { + dataFetched: (state, action: PayloadAction) => { + state.isFetching = action.payload; + }, + }, +}); + +export const { dataFetched } = appSlice.actions; + +export const appReducer = appSlice.reducer; diff --git a/src/app/store/store.ts b/app/store/store.ts similarity index 73% rename from src/app/store/store.ts rename to app/store/store.ts index 44493cc8..9dadf5fe 100644 --- a/src/app/store/store.ts +++ b/app/store/store.ts @@ -1,8 +1,9 @@ import { combineReducers, configureStore } from '@reduxjs/toolkit'; -import { movieApi } from '../../entities/movie/api/movieApi.ts'; -import { searchReducer } from '../../features/Search/model/slice.ts'; -import { appReducer } from '../model/slice.ts'; +import { movieApi } from '@entities/movie/api/movieApi'; +import { createWrapper } from 'next-redux-wrapper'; + +import { appReducer } from '../model/slice'; export type AppStore = ReturnType; export type RootState = ReturnType; @@ -11,7 +12,6 @@ export type PreloadState = Partial; const rootReducer = combineReducers({ [movieApi.reducerPath]: movieApi.reducer, - searchReducer, appReducer, }); @@ -22,3 +22,5 @@ export const setupStore = (preloadedState?: PreloadState) => middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(movieApi.middleware), }); + +export const wrapper = createWrapper(() => setupStore()); diff --git a/src/assets/arrow-left.svg b/assets/arrow-left.svg similarity index 100% rename from src/assets/arrow-left.svg rename to assets/arrow-left.svg diff --git a/src/assets/arrow-right.svg b/assets/arrow-right.svg similarity index 100% rename from src/assets/arrow-right.svg rename to assets/arrow-right.svg diff --git a/src/assets/chevron-left.svg b/assets/chevron-left.svg similarity index 100% rename from src/assets/chevron-left.svg rename to assets/chevron-left.svg diff --git a/src/assets/reactJS-logo.png b/assets/reactJS-logo.png similarity index 100% rename from src/assets/reactJS-logo.png rename to assets/reactJS-logo.png diff --git a/src/assets/search.svg b/assets/search.svg similarity index 100% rename from src/assets/search.svg rename to assets/search.svg diff --git a/entities/movie/Movie.test.tsx b/entities/movie/Movie.test.tsx new file mode 100644 index 00000000..b8d148bb --- /dev/null +++ b/entities/movie/Movie.test.tsx @@ -0,0 +1,73 @@ +import { screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; + +import * as useGetMovieList from '@shared/hooks/useGetMovieList'; +import renderWithRouter from '@test/helpers/RenderWithRouter'; +import { mockMovieItem, mockMovies } from '@test/mocks/data'; +import { afterEach, describe, expect, it, vi } from 'vitest'; + +import Movie from './ui/Movie'; + +const mockedUseGetMovieList = vi.spyOn(useGetMovieList, 'default'); + +describe('Movie', () => { + afterEach(() => void vi.clearAllMocks()); + + it('should render the relevant movie data', () => { + renderWithRouter( + , + ); + + const poster = screen.getByTestId('movie-poster'); + const title = screen.getByTestId('movie-title'); + const year = screen.getByTestId('movie-year'); + + const mockPosterPath = mockMovieItem.Poster.slice( + mockMovieItem.Poster.lastIndexOf('/') + 1, + ); + const match = poster.src.match(mockPosterPath); + const renderedPath = match?.at(0); + + expect(poster).toBeInTheDocument(); + expect(title).toBeInTheDocument(); + expect(year).toBeInTheDocument(); + + expect(renderedPath).toBe(mockPosterPath); + expect(title).toHaveTextContent(mockMovieItem.Title); + expect(year).toHaveTextContent(mockMovieItem.Year); + }); + + it('should open a detailed card component when clicking on a card', async () => { + mockedUseGetMovieList.mockReturnValue({ + movieList: mockMovies, + totalResults: mockMovies.length, + }); + + const router = renderWithRouter( + , + ); + + const movie = screen.getByTestId('movie-item'); + await userEvent.click(movie); + + expect(router.push).toHaveBeenCalledWith( + `/${mockMovieItem.imdbID}`, + `/${mockMovieItem.imdbID}`, + { + locale: undefined, + scroll: true, + shallow: undefined, + }, + ); + }); +}); diff --git a/src/entities/movie/api/movieApi.test.tsx b/entities/movie/api/movieApi.test.tsx similarity index 81% rename from src/entities/movie/api/movieApi.test.tsx rename to entities/movie/api/movieApi.test.tsx index 03f9aa5d..f30ba2e7 100644 --- a/src/entities/movie/api/movieApi.test.tsx +++ b/entities/movie/api/movieApi.test.tsx @@ -1,17 +1,21 @@ import { ReactNode } from 'react'; import { renderHook, waitFor } from '@testing-library/react'; -import { Provider } from 'react-redux'; -import { describe, it } from 'vitest'; -import { useGetMovieListQuery, useGetMovieQuery } from './movieApi.ts'; -import { setupStore } from '../../../app/store/store.ts'; +import { + useGetMovieListQuery, + useGetMovieQuery, +} from '@entities/movie/api/movieApi'; import { DEFAULT_PAGE, MOVIES_PER_PAGE, QUERY_FALLBACK, -} from '../../../shared/const/const.ts'; -import { mockMovieDetails, mockMovies } from '../../../test/mocks/data.ts'; +} from '@shared/const/const'; +import { mockMovieDetails, mockMovies } from '@test/mocks/data'; +import { Provider } from 'react-redux'; +import { describe, expect, it } from 'vitest'; + +import { setupStore } from '../../../app/store/store'; function wrapper({ children }: { children: ReactNode }) { const store = setupStore(); diff --git a/src/entities/movie/api/movieApi.ts b/entities/movie/api/movieApi.ts similarity index 63% rename from src/entities/movie/api/movieApi.ts rename to entities/movie/api/movieApi.ts index a3cc9394..22fb3d88 100644 --- a/src/entities/movie/api/movieApi.ts +++ b/entities/movie/api/movieApi.ts @@ -1,11 +1,11 @@ -import { IInitialState } from '../../../features/Search/types/types.ts'; -import rootApi from '../../../shared/api/rootApi.ts'; -import { QUERY_FALLBACK } from '../../../shared/const/const.ts'; import { ApiErrorResponse, ApiMovieListResponse, ApiMovieResponse, -} from '../../../shared/types/types.ts'; +} from '@customTypes/types'; +import { IInitialState } from '@features/Search/types/types'; +import rootApi from '@shared/api/rootApi'; +import { QUERY_FALLBACK } from '@shared/const/const'; interface IMovieListParams { query: IInitialState['query']; @@ -17,13 +17,13 @@ export const movieApi = rootApi.injectEndpoints({ endpoints: (build) => ({ getMovieList: build.query({ query: ({ query, page, moviesPerPage }) => - `?apikey=${import.meta.env.VITE_API_KEY}&s=${ + `?apikey=${process.env.NEXT_PUBLIC_API_KEY}&s=${ query || QUERY_FALLBACK || moviesPerPage }&page=${page}`, }), getMovie: build.query({ - query: (id) => `?apikey=${import.meta.env.VITE_API_KEY}&i=${id}`, + query: (id) => `?apikey=${process.env.NEXT_PUBLIC_API_KEY}&i=${id}`, }), }), }); diff --git a/src/entities/movie/ui/Movie.tsx b/entities/movie/ui/Movie.tsx similarity index 69% rename from src/entities/movie/ui/Movie.tsx rename to entities/movie/ui/Movie.tsx index 983b4773..474e8124 100644 --- a/src/entities/movie/ui/Movie.tsx +++ b/entities/movie/ui/Movie.tsx @@ -1,15 +1,17 @@ import { memo, MouseEvent } from 'react'; -import { useLocation } from 'react-router-dom'; +import Image from 'next/image'; +import colors from 'tailwindcss/colors'; -import ReactLogo from '../../../assets/reactJS-logo.png'; -import { NOT_EXIST } from '../../../shared/const/const.ts'; -import useRadialHover from '../../../shared/hooks/useRadialHover.ts'; -import { Movie as MovieData } from '../../../shared/types/types.ts'; -import LinkWithQuery from '../../../shared/ui/LinkWithQuery.tsx'; +import ReactLogo from '@assets/reactJS-logo.png'; +import { Movie as TMovie } from '@customTypes/types'; +import { NOT_EXIST } from '@shared/const/const'; +import useRadialHover from '@shared/hooks/useRadialHover'; +import LinkWithQuery from '@shared/ui/LinkWithQuery'; +import StarRating from '@shared/ui/StarRating'; interface IMovieProps { - data: MovieData; + data: TMovie; delay: number; onMouseMove: (e: MouseEvent) => void; onMouseOut: () => void; @@ -23,19 +25,13 @@ const Movie = memo(function Movie({ }: IMovieProps) { const { handleMouseOut, handleMouseMove, containerRef } = useRadialHover(); - const { pathname } = useLocation(); - const { Poster, Title, Year, imdbID } = data; const poster = Poster === NOT_EXIST ? ReactLogo : Poster; const animationDelay = `0.${String(delay)}s`; - const isDetailsClose = pathname.slice(1) === ''; return ( - +
  • - {Year} +
  • diff --git a/entities/scroll/context/smoothScroll.tsx b/entities/scroll/context/smoothScroll.tsx new file mode 100644 index 00000000..ddcf00d0 --- /dev/null +++ b/entities/scroll/context/smoothScroll.tsx @@ -0,0 +1,73 @@ +import React, { + createContext, + PropsWithChildren, + RefObject, + useEffect, + useMemo, + useRef, + useState, +} from 'react'; + +import LocomotiveScroll, { InstanceOptions } from 'locomotive-scroll'; + +interface ISmoothScrollProviderProps extends PropsWithChildren { + options: InstanceOptions; +} + +interface ISmoothScrollContext { + scroll: null | LocomotiveScroll; + containerRef: RefObject; +} + +export const SmoothScrollContext = createContext({ + scroll: null, +} as ISmoothScrollContext); + +function SmoothScrollProvider({ + children, + options, +}: ISmoothScrollProviderProps) { + const [scroll, setScroll] = useState(null); + const containerRef = useRef(null); + const value = useMemo(() => ({ scroll, containerRef }), [scroll]); + + useEffect(() => { + let locoScroll: LocomotiveScroll; + let containerObserver: ResizeObserver; + const { current: scrollContainer } = containerRef; + + if (!scroll && scrollContainer) { + (async () => { + try { + const SmoothScroll = (await import('locomotive-scroll')).default; + locoScroll = new SmoothScroll({ + el: scrollContainer, + ...options, + }); + + containerObserver = new ResizeObserver(() => locoScroll.update()); + containerObserver.observe(scrollContainer); + setScroll(locoScroll); + } catch (e) { + // if the error was caught that means, the test environment is used + } + })(); + } + + return () => { + locoScroll?.destroy(); + containerObserver?.disconnect(); + }; + }, [options, scroll]); + + return ( + + {children} + + ); +} + +SmoothScrollContext.displayName = 'SmoothScrollContext'; +SmoothScrollProvider.displayName = 'SmoothScrollProvider'; + +export default SmoothScrollProvider; diff --git a/entities/scroll/hooks/useScroll.ts b/entities/scroll/hooks/useScroll.ts new file mode 100644 index 00000000..101caa5e --- /dev/null +++ b/entities/scroll/hooks/useScroll.ts @@ -0,0 +1,14 @@ +import { useContext } from 'react'; + +import { SmoothScrollContext } from '@entities/scroll/context/smoothScroll'; + +function useScroll() { + const context = useContext(SmoothScrollContext); + + if (context === undefined) + throw new Error('The scroll context is used outside the provider!'); + + return context; +} + +export default useScroll; diff --git a/environment.d.ts b/environment.d.ts new file mode 100644 index 00000000..725bfab6 --- /dev/null +++ b/environment.d.ts @@ -0,0 +1,6 @@ +namespace NodeJS { + interface ProcessEnv { + NEXT_PUBLIC_API_URL: string; + NEXT_PUBLIC_API_KEY: string; + } +} diff --git a/src/features/MovieList/MovieList.test.tsx b/features/MovieList/MovieList.test.tsx similarity index 60% rename from src/features/MovieList/MovieList.test.tsx rename to features/MovieList/MovieList.test.tsx index 6e21904c..592c6034 100644 --- a/src/features/MovieList/MovieList.test.tsx +++ b/features/MovieList/MovieList.test.tsx @@ -1,27 +1,16 @@ -import { RefObject } from 'react'; - import { screen } from '@testing-library/react'; -import LocomotiveScroll from 'locomotive-scroll'; -import { afterAll, beforeAll, describe, expect, it } from 'vitest'; -import MovieList from './MovieList.tsx'; -import Movie from '../../entities/movie/ui/Movie.tsx'; -import * as useGetMovieList from '../../shared/hooks/useGetMovieList.ts'; -import renderWithRouterProvider from '../../test/helpers/renderWithRouterProvider.tsx'; -import { mockMovies } from '../../test/mocks/data.ts'; +import Movie from '@entities/movie/ui/Movie'; +import MovieList from '@features/MovieList/MovieList'; +import * as useGetMovieList from '@shared/hooks/useGetMovieList'; +import renderWithRouter from '@test/helpers/RenderWithRouter'; +import { mockMovies } from '@test/mocks/data'; +import { beforeAll, describe, expect, it, vi } from 'vitest'; const mockedUseGetMovieList = vi.spyOn(useGetMovieList, 'default'); -let scroll: RefObject; describe('MovieList', () => { - beforeAll(() => { - scroll = { current: new LocomotiveScroll() }; - vi.clearAllMocks(); - }); - - afterAll(() => { - scroll.current?.destroy(); - }); + beforeAll(() => void vi.clearAllMocks()); it('should display an empty list message', () => { mockedUseGetMovieList.mockReturnValue({ @@ -29,9 +18,8 @@ describe('MovieList', () => { totalResults: 0, }); - renderWithRouterProvider( + renderWithRouter( ( { totalResults: mockMovies.length, }); - renderWithRouterProvider( + renderWithRouter( ( ReactNode; +} + +function MovieList({ render, children }: IMovieListProps) { + const { listRef, handleClick } = useListClick(); + const { movieList } = useGetMovieList(); + + if (!movieList) return ; + + return ( +
      + {children} + {movieList?.map(render)} +
    + ); +} + +export default MovieList; diff --git a/src/features/MovieList/hooks/useListClick.ts b/features/MovieList/hooks/useListClick.ts similarity index 50% rename from src/features/MovieList/hooks/useListClick.ts rename to features/MovieList/hooks/useListClick.ts index 5d9bb091..77bb4310 100644 --- a/src/features/MovieList/hooks/useListClick.ts +++ b/features/MovieList/hooks/useListClick.ts @@ -1,26 +1,20 @@ -import { MouseEvent, RefObject, useRef } from 'react'; +import { MouseEvent, useRef } from 'react'; -import LocomotiveScroll from 'locomotive-scroll'; -import { useNavigate } from 'react-router-dom'; - -import { - DEFAULT_PAGE, - SCROLL_TOP_DURATION, -} from '../../../shared/const/const.ts'; -import useUrl from '../../../shared/hooks/useUrl.ts'; -import { urlParams } from '../../../shared/types/enums.ts'; +import { urlParams } from '@customTypes/enums'; +import useScroll from '@entities/scroll/hooks/useScroll'; +import { DEFAULT_PAGE, SCROLL_TOP_DURATION } from '@shared/const/const'; +import useUrl from '@shared/hooks/useUrl'; /** * Closes the details section on list click. * - * @param {RefObject} scroll - A reference to the scroll container. Used to scroll to the top of the page * @return obj - An object containing the list reference and the click handler. * @return {RefObject} obj.listRef - A reference to the list element. * @return {(e: MouseEvent) => void} obj.handleClick - A function to handle the click event. * */ -function useListClick(scroll: RefObject) { +function useListClick() { + const { scroll } = useScroll(); const listRef = useRef(null); - const navigate = useNavigate(); const { readUrl } = useUrl(); function handleClick(e: MouseEvent) { @@ -29,8 +23,7 @@ function useListClick(scroll: RefObject) { if (target !== listRef.current || currPage === DEFAULT_PAGE) return; - navigate('/'); - scroll.current?.scrollTo('top', { duration: SCROLL_TOP_DURATION }); + scroll?.scrollTo('top', { duration: SCROLL_TOP_DURATION }); } return { listRef, handleClick }; diff --git a/features/MovieList/ui/MovieListHeader.tsx b/features/MovieList/ui/MovieListHeader.tsx new file mode 100644 index 00000000..4e247fb4 --- /dev/null +++ b/features/MovieList/ui/MovieListHeader.tsx @@ -0,0 +1,41 @@ +import { PropsWithChildren, useCallback } from 'react'; + +import { urlParams } from '@customTypes/enums'; +import { ItemsPerPage } from '@customTypes/types'; +import useScrollTop from '@shared/hooks/useScrollTop'; +import useUrl from '@shared/hooks/useUrl'; +import Tabs from '@shared/ui/Tabs'; + +function MovieListHeader({ children }: PropsWithChildren) { + const { readUrl, setUrl } = useUrl(); + const moviesPerPage = Number(readUrl(urlParams.MOVIES_PER_PAGE)); + + useScrollTop(moviesPerPage); + + const handleMoviesPerPage = useCallback( + (newMoviesPerPage: number) => { + if (newMoviesPerPage !== moviesPerPage) + setUrl(urlParams.MOVIES_PER_PAGE, newMoviesPerPage); + }, + [moviesPerPage, setUrl], + ); + + return ( +
    + + handler={handleMoviesPerPage} + activeValue={moviesPerPage}> + value={3}>03 movies + value={5}>05 movies + value={10}>10 movies + + {children} +
    + ); +} + +export default MovieListHeader; diff --git a/src/features/MovieList/ui/MovieNotFound.tsx b/features/MovieList/ui/MovieNotFound.tsx similarity index 86% rename from src/features/MovieList/ui/MovieNotFound.tsx rename to features/MovieList/ui/MovieNotFound.tsx index 4894f95d..f4e001a2 100644 --- a/src/features/MovieList/ui/MovieNotFound.tsx +++ b/features/MovieList/ui/MovieNotFound.tsx @@ -1,4 +1,4 @@ -import Modal from '../../../shared/ui/Modal.tsx'; +import Modal from '@shared/ui/Modal'; function MovieNotFound() { return ( diff --git a/src/features/MovieList/ui/PageNum.tsx b/features/MovieList/ui/PageNum.tsx similarity index 74% rename from src/features/MovieList/ui/PageNum.tsx rename to features/MovieList/ui/PageNum.tsx index e1885762..7b97787f 100644 --- a/src/features/MovieList/ui/PageNum.tsx +++ b/features/MovieList/ui/PageNum.tsx @@ -1,18 +1,16 @@ import { useEffect, useRef } from 'react'; -import useAnime from '../../../shared/hooks/useAnime.ts'; -import useAppSelector from '../../../shared/hooks/useAppSelector.ts'; -import useGetMovieList from '../../../shared/hooks/useGetMovieList.ts'; -import useUrl from '../../../shared/hooks/useUrl.ts'; -import selectMoviesPerPage from '../../../shared/lib/selectors/selectMoviesPerPage.ts'; -import { urlParams } from '../../../shared/types/enums.ts'; +import { urlParams } from '@customTypes/enums'; +import useAnime from '@shared/hooks/useAnime'; +import useGetMovieList from '@shared/hooks/useGetMovieList'; +import useUrl from '@shared/hooks/useUrl'; function PageNum() { const { readUrl } = useUrl(); const { totalResults } = useGetMovieList(); - const moviesPerPage = useAppSelector(selectMoviesPerPage); const prevMaxPage = useRef(0); + const moviesPerPage = Number(readUrl(urlParams.MOVIES_PER_PAGE)); const currPage = Number(readUrl(urlParams.PAGE)); const maxPage = Math.ceil(totalResults / moviesPerPage); diff --git a/src/features/Pagination/Pagination.test.tsx b/features/Pagination/Pagination.test.tsx similarity index 52% rename from src/features/Pagination/Pagination.test.tsx rename to features/Pagination/Pagination.test.tsx index 1dea88d9..1293e204 100644 --- a/src/features/Pagination/Pagination.test.tsx +++ b/features/Pagination/Pagination.test.tsx @@ -1,33 +1,20 @@ -import { RefObject } from 'react'; - import { screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; -import LocomotiveScroll from 'locomotive-scroll'; -import { afterAll, afterEach, beforeAll, describe, expect, it } from 'vitest'; -import Pagination from './Pagination.tsx'; -import * as useGetMovieList from '../../shared/hooks/useGetMovieList.ts'; -import * as useUrl from '../../shared/hooks/useUrl.ts'; -import renderWithRouterProvider from '../../test/helpers/renderWithRouterProvider.tsx'; -import { mockMovies } from '../../test/mocks/data.ts'; +import Pagination from '@features/Pagination/Pagination'; +import renderWithRouterProvider from '@test/helpers/renderWithRouterProvider'; +import { mockMovies } from '@test/mocks/data'; +import { afterEach, describe, expect, it, vi } from 'vitest'; + +import * as useGetMovieList from '../../shared/hooks/useGetMovieList'; +import * as useUrl from '../../shared/hooks/useUrl'; const mockedUseUrl = vi.spyOn(useUrl, 'default'); const mockedUseGetMovieList = vi.spyOn(useGetMovieList, 'default'); const totalResults = 40; -let scroll: RefObject; describe('Pagination', () => { - afterEach(() => { - vi.clearAllMocks(); - }); - - beforeAll(() => { - scroll = { current: new LocomotiveScroll() }; - }); - - afterAll(() => { - scroll.current?.destroy(); - }); + afterEach(() => void vi.clearAllMocks()); it('should update URL query parameter when page changes', async () => { mockedUseGetMovieList.mockReturnValue({ @@ -35,7 +22,7 @@ describe('Pagination', () => { totalResults, }); - renderWithRouterProvider(); + renderWithRouterProvider(); const [button] = screen.getAllByTestId('pagination'); diff --git a/src/features/Pagination/Pagination.tsx b/features/Pagination/Pagination.tsx similarity index 59% rename from src/features/Pagination/Pagination.tsx rename to features/Pagination/Pagination.tsx index 78f50c3b..2bd7ab78 100644 --- a/src/features/Pagination/Pagination.tsx +++ b/features/Pagination/Pagination.tsx @@ -1,24 +1,16 @@ -import { RefObject } from 'react'; +import arrowLeft from '@assets/arrow-left.svg'; +import arrowRight from '@assets/arrow-right.svg'; +import usePagination from '@features/Pagination/hooks/usePagination'; +import Button from '@features/Pagination/ui/Button'; -import LocomotiveScroll from 'locomotive-scroll'; - -import usePagination from './hooks/usePagination.ts'; -import Button from './ui/Button.tsx'; -import arrowLeft from '../../assets/arrow-left.svg'; -import arrowRight from '../../assets/arrow-right.svg'; - -interface IPaginationProps { - scroll: RefObject; -} - -function Pagination({ scroll }: IPaginationProps) { +function Pagination() { const { handleNextPage, handlePrevPage, isPrevDisabled, isNextDisabled, noPages, - } = usePagination(scroll); + } = usePagination(); if (noPages) return null; diff --git a/features/Pagination/hooks/usePagination.ts b/features/Pagination/hooks/usePagination.ts new file mode 100644 index 00000000..d2246454 --- /dev/null +++ b/features/Pagination/hooks/usePagination.ts @@ -0,0 +1,40 @@ +import { useCallback } from 'react'; + +import { urlParams } from '@customTypes/enums'; +import { DEFAULT_PAGE, MOVIES_PER_PAGE } from '@shared/const/const'; +import useAppSelector from '@shared/hooks/useAppSelector'; +import useGetMovieList from '@shared/hooks/useGetMovieList'; +import useScrollTop from '@shared/hooks/useScrollTop'; +import useUrl from '@shared/hooks/useUrl'; +import selectIsFetching from '@shared/lib/selectors/selectIsFetching'; + +function usePagination() { + const { setUrl, readUrl } = useUrl(); + const isFetching = useAppSelector(selectIsFetching); + const { totalResults } = useGetMovieList(); + + const currPage = Number(readUrl(urlParams.PAGE)); + const isPrevDisabled = currPage === DEFAULT_PAGE || isFetching; + const isNextDisabled = isFetching; + const noPages = totalResults <= MOVIES_PER_PAGE; + + useScrollTop(currPage, currPage); + + const handleNextPage = useCallback(() => { + setUrl(urlParams.PAGE, currPage + 1); + }, [setUrl, currPage]); + + const handlePrevPage = useCallback(() => { + setUrl(urlParams.PAGE, currPage - 1); + }, [currPage, setUrl]); + + return { + handleNextPage, + handlePrevPage, + isPrevDisabled, + isNextDisabled, + noPages, + }; +} + +export default usePagination; diff --git a/src/features/Pagination/ui/Button.tsx b/features/Pagination/ui/Button.tsx similarity index 87% rename from src/features/Pagination/ui/Button.tsx rename to features/Pagination/ui/Button.tsx index 889219e8..ccf99515 100644 --- a/src/features/Pagination/ui/Button.tsx +++ b/features/Pagination/ui/Button.tsx @@ -1,5 +1,7 @@ import { ButtonHTMLAttributes, memo } from 'react'; +import Image from 'next/image'; + interface IButtonProps extends ButtonHTMLAttributes { position: 'left' | 'right'; children: string; @@ -21,9 +23,11 @@ const Button = memo(function Button({ const arrowDirectionSecondSnooze = isLeftPosition ? 'translate-x-14' : '-translate-x-14'; + const ariaLabel = isLeftPosition ? 'Pagination left' : 'Pagination right'; return ( diff --git a/features/Search/const/const.ts b/features/Search/const/const.ts new file mode 100644 index 00000000..ab6d52be --- /dev/null +++ b/features/Search/const/const.ts @@ -0,0 +1,2 @@ +export const ENTER_KEY = 'Enter'; +export const ESCAPE_KEY = 'Escape'; diff --git a/src/features/Search/types/types.ts b/features/Search/types/types.ts similarity index 93% rename from src/features/Search/types/types.ts rename to features/Search/types/types.ts index ab119490..363c2f2f 100644 --- a/src/features/Search/types/types.ts +++ b/features/Search/types/types.ts @@ -1,4 +1,4 @@ -import { MovieList } from '../../../shared/types/types.ts'; +import { MovieList } from '../../../shared/types/types'; export enum SearchActions { QUERY_UPDATED = 'search/queryUpdated', diff --git a/index.html b/index.html deleted file mode 100644 index db6fadc9..00000000 --- a/index.html +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - - - Cinemania | Dive into Movie Wonderland - - -
    - - - diff --git a/next.config.js b/next.config.js new file mode 100644 index 00000000..1df68f2e --- /dev/null +++ b/next.config.js @@ -0,0 +1,14 @@ +/** @type {import('next').NextConfig} */ +const nextConfig = { + reactStrictMode: true, + images: { + remotePatterns: [ + { + protocol: 'https', + hostname: 'm.media-amazon.com', + }, + ], + }, +}; + +module.exports = nextConfig; diff --git a/package-lock.json b/package-lock.json index 0309aaaa..544d8e26 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,63 +1,62 @@ { "name": "cinemania", - "version": "0.0.0", + "version": "0.1.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "cinemania", - "version": "0.0.0", + "version": "0.1.0", "dependencies": { "@reduxjs/toolkit": "^1.9.7", "animejs": "^3.2.1", "clsx": "^2.0.0", "locomotive-scroll": "^4.1.4", - "react": "^18.2.0", - "react-dom": "^18.2.0", + "next": "14.0.3", + "next-redux-wrapper": "^8.1.0", + "react": "^18", + "react-dom": "^18", "react-redux": "^8.1.3", - "react-router-dom": "^6.18.0", "redux": "^4.2.1", - "tailwind-merge": "^2.0.0" + "tailwind-merge": "^2.0.0", + "use-view-transitions": "^1.0.16" }, "devDependencies": { - "@edge-runtime/vm": "^3.1.7", "@testing-library/dom": "^9.3.3", "@testing-library/jest-dom": "^6.1.4", "@testing-library/react": "^14.1.2", "@testing-library/user-event": "^14.5.1", - "@types/animejs": "^3.1.11", - "@types/deep-equal": "^1.0.4", - "@types/locomotive-scroll": "^4.1.2", - "@types/react": "^18.2.15", - "@types/react-dom": "^18.2.7", - "@types/react-redux": "^7.1.30", - "@typescript-eslint/eslint-plugin": "^6.0.0", - "@typescript-eslint/parser": "^6.0.0", - "@vitejs/plugin-react": "^4.0.3", + "@types/animejs": "^3.1.12", + "@types/locomotive-scroll": "^4.1.3", + "@types/node": "^20", + "@types/react": "^18", + "@types/react-dom": "^18", + "@vitejs/plugin-react": "^4.2.0", "@vitest/coverage-v8": "^0.34.6", - "autoprefixer": "^10.4.16", - "eslint": "^8.50.0", + "autoprefixer": "^10.0.1", + "eslint": "^8", "eslint-config-airbnb": "^19.0.4", "eslint-config-airbnb-base": "^15.0.0", "eslint-config-airbnb-typescript": "^17.1.0", + "eslint-config-next": "14.0.3", "eslint-config-prettier": "^9.0.0", "eslint-import-resolver-typescript": "^3.6.1", - "eslint-plugin-import": "^2.28.1", - "eslint-plugin-jsx-a11y": "^6.7.1", - "eslint-plugin-prettier": "^5.0.0", + "eslint-plugin-import": "^2.29.0", + "eslint-plugin-jsx-a11y": "^6.8.0", + "eslint-plugin-prettier": "^5.0.1", "eslint-plugin-react": "^7.33.2", "eslint-plugin-react-hooks": "^4.6.0", - "eslint-plugin-react-refresh": "^0.4.3", + "eslint-plugin-react-refresh": "^0.4.4", "eslint-plugin-simple-import-sort": "^10.0.0", + "happy-dom": "^12.10.3", "husky": "^8.0.3", - "lint-staged": "^15.0.2", - "msw": "^2.0.4", - "postcss": "^8.4.30", - "prettier": "^3.0.3", - "prettier-plugin-tailwindcss": "^0.5.4", - "tailwindcss": "^3.3.3", - "typescript": "^5.2.2", - "vite": "^4.4.9", + "lint-staged": "^15.1.0", + "msw": "^2.0.8", + "postcss": "^8", + "prettier": "^3.1.0", + "prettier-plugin-tailwindcss": "^0.5.7", + "tailwindcss": "^3.3.0", + "typescript": "^5", "vitest": "^0.34.6" } }, @@ -102,43 +101,114 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.22.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", - "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.4.tgz", + "integrity": "sha512-r1IONyb6Ia+jYR2vvIDhdWdlTGhqbBoFqLTQidzZ4kepUFH15ejXvFHxCVbtl7BOXIudsIubf4E81xeA3h3IXA==", "dev": true, "dependencies": { - "@babel/highlight": "^7.22.13", + "@babel/highlight": "^7.23.4", "chalk": "^2.4.2" }, "engines": { "node": ">=6.9.0" } }, + "node_modules/@babel/code-frame/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/code-frame/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/code-frame/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/code-frame/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/@babel/code-frame/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@babel/code-frame/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/code-frame/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/@babel/compat-data": { - "version": "7.23.2", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.2.tgz", - "integrity": "sha512-0S9TQMmDHlqAZ2ITT95irXKfxN9bncq8ZCoJhun3nHL/lLUxd2NKBJYoNGWH7S0hz6fRQwWlAWn/ILM0C70KZQ==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.3.tgz", + "integrity": "sha512-BmR4bWbDIoFJmJ9z2cZ8Gmm2MXgEDgjdWgpKmKWUt54UGFJdlj31ECtbaDvCG/qVdG3AQ1SfpZEs01lUFbzLOQ==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.23.2", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.2.tgz", - "integrity": "sha512-n7s51eWdaWZ3vGT2tD4T7J6eJs3QoBXydv7vkUM06Bf1cbVD2Kc2UrkzhiQwobfV7NwOnQXYL7UBJ5VPU+RGoQ==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.3.tgz", + "integrity": "sha512-Jg+msLuNuCJDyBvFv5+OKOUjWMZgd85bKjbICd3zWrKAo+bJ49HJufi7CQE0q0uR8NGyO6xkCACScNqyjHSZew==", "dev": true, "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.22.13", - "@babel/generator": "^7.23.0", + "@babel/generator": "^7.23.3", "@babel/helper-compilation-targets": "^7.22.15", - "@babel/helper-module-transforms": "^7.23.0", + "@babel/helper-module-transforms": "^7.23.3", "@babel/helpers": "^7.23.2", - "@babel/parser": "^7.23.0", + "@babel/parser": "^7.23.3", "@babel/template": "^7.22.15", - "@babel/traverse": "^7.23.2", - "@babel/types": "^7.23.0", + "@babel/traverse": "^7.23.3", + "@babel/types": "^7.23.3", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -163,12 +233,12 @@ } }, "node_modules/@babel/generator": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz", - "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==", + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.4.tgz", + "integrity": "sha512-esuS49Cga3HcThFNebGhlgsrVLkvhqvYDTzgjfFFlHJcIfLe5jFmRRfCQ1KuBfc4Jrtn3ndLgKWAKjBE+IraYQ==", "dev": true, "dependencies": { - "@babel/types": "^7.23.0", + "@babel/types": "^7.23.4", "@jridgewell/gen-mapping": "^0.3.2", "@jridgewell/trace-mapping": "^0.3.17", "jsesc": "^2.5.1" @@ -249,9 +319,9 @@ } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.0.tgz", - "integrity": "sha512-WhDWw1tdrlT0gMgUJSlX0IQvoO1eN279zrAUbVB+KpV2c3Tylz8+GnKOLllCS6Z/iZQEyVYxhZVUdPTqs2YYPw==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz", + "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==", "dev": true, "dependencies": { "@babel/helper-environment-visitor": "^7.22.20", @@ -301,9 +371,9 @@ } }, "node_modules/@babel/helper-string-parser": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", - "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz", + "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==", "dev": true, "engines": { "node": ">=6.9.0" @@ -328,23 +398,23 @@ } }, "node_modules/@babel/helpers": { - "version": "7.23.2", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.2.tgz", - "integrity": "sha512-lzchcp8SjTSVe/fPmLwtWVBFC7+Tbn8LGHDVfDp9JGxpAY5opSaEFgt8UQvrnECWOTdji2mOWMz1rOhkHscmGQ==", + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.4.tgz", + "integrity": "sha512-HfcMizYz10cr3h29VqyfGL6ZWIjTwWfvYBMsBVGwpcbhNGe3wQ1ZXZRPzZoAHhd9OqHadHqjQ89iVKINXnbzuw==", "dev": true, "dependencies": { "@babel/template": "^7.22.15", - "@babel/traverse": "^7.23.2", - "@babel/types": "^7.23.0" + "@babel/traverse": "^7.23.4", + "@babel/types": "^7.23.4" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", - "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", + "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", "dev": true, "dependencies": { "@babel/helper-validator-identifier": "^7.22.20", @@ -355,10 +425,81 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/highlight/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/highlight/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/@babel/highlight/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@babel/highlight/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/@babel/parser": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz", - "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==", + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.4.tgz", + "integrity": "sha512-vf3Xna6UEprW+7t6EtOmFpHNAuxw3xqPZghy+brsnusscJRW5BMUzzHZc5ICjULee81WeUV2jjakG09MDglJXQ==", "dev": true, "bin": { "parser": "bin/babel-parser.js" @@ -368,9 +509,9 @@ } }, "node_modules/@babel/plugin-transform-react-jsx-self": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.22.5.tgz", - "integrity": "sha512-nTh2ogNUtxbiSbxaT4Ds6aXnXEipHweN9YRgOX/oNXdf0cCrGn/+2LozFa3lnPV5D90MkjhgckCPBrsoSc1a7g==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.23.3.tgz", + "integrity": "sha512-qXRvbeKDSfwnlJnanVRp0SfuWE5DQhwQr5xtLBzp56Wabyo+4CMosF6Kfp+eOD/4FYpql64XVJ2W0pVLlJZxOQ==", "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.22.5" @@ -383,9 +524,9 @@ } }, "node_modules/@babel/plugin-transform-react-jsx-source": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.22.5.tgz", - "integrity": "sha512-yIiRO6yobeEIaI0RTbIr8iAK9FcBHLtZq0S89ZPjDLQXBA4xvghaKqI0etp/tF3htTM0sazJKKLz9oEiGRtu7w==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.23.3.tgz", + "integrity": "sha512-91RS0MDnAWDNvGC6Wio5XYkyWI39FMFO+JK9+4AlgaTH+yWwVTsw7/sn6LK0lH7c5F+TFkpv/3LfCJ1Ydwof/g==", "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.22.5" @@ -398,9 +539,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.23.2", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.2.tgz", - "integrity": "sha512-mM8eg4yl5D6i3lu2QKPuPH4FArvJ8KhTofbE7jwMUv9KX5mBvwPAqnV3MlyBNqdp9RyRKP6Yck8TrfYrPvX3bg==", + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.4.tgz", + "integrity": "sha512-2Yv65nlWnWlSpe3fXEyX5i7fx5kIKo4Qbcj+hMO0odwaneFjfXw5fdum+4yL20O0QiaHpia0cYQ9xpNMqrBwHg==", "dependencies": { "regenerator-runtime": "^0.14.0" }, @@ -423,19 +564,19 @@ } }, "node_modules/@babel/traverse": { - "version": "7.23.2", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz", - "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==", + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.4.tgz", + "integrity": "sha512-IYM8wSUwunWTB6tFC2dkKZhxbIjHoWemdK+3f8/wq8aKhbUscxD5MX72ubd90fxvFknaLPeGw5ycU84V1obHJg==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.22.13", - "@babel/generator": "^7.23.0", + "@babel/code-frame": "^7.23.4", + "@babel/generator": "^7.23.4", "@babel/helper-environment-visitor": "^7.22.20", "@babel/helper-function-name": "^7.23.0", "@babel/helper-hoist-variables": "^7.22.5", "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.23.0", - "@babel/types": "^7.23.0", + "@babel/parser": "^7.23.4", + "@babel/types": "^7.23.4", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -444,12 +585,12 @@ } }, "node_modules/@babel/types": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", - "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.4.tgz", + "integrity": "sha512-7uIFwVYpoplT5jp/kVv6EF93VaJ8H+Yn5IczYiaAi98ajzjfoZfslet/e0sLh+wVBjb2qqIut1b0S26VSafsSQ==", "dev": true, "dependencies": { - "@babel/helper-string-parser": "^7.22.5", + "@babel/helper-string-parser": "^7.23.4", "@babel/helper-validator-identifier": "^7.22.20", "to-fast-properties": "^2.0.0" }, @@ -490,31 +631,10 @@ "statuses": "^2.0.1" } }, - "node_modules/@edge-runtime/primitives": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/@edge-runtime/primitives/-/primitives-4.0.5.tgz", - "integrity": "sha512-t7QiN5d/KpXgCvIfSt6Nm9Hj3WVdNgc5CpOD73jasY+9EvTI7Ngdj5cXvjcHrPcmYWJZMySPgeEeoL/1N/Llag==", - "dev": true, - "engines": { - "node": ">=16" - } - }, - "node_modules/@edge-runtime/vm": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/@edge-runtime/vm/-/vm-3.1.7.tgz", - "integrity": "sha512-hUMFbDQ/nZN+1TLMi6iMO1QFz9RSV8yGG8S42WFPFma1d7VSNE0eMdJUmwjmtav22/iQkzHMmu6oTSfAvRGS8g==", - "dev": true, - "dependencies": { - "@edge-runtime/primitives": "4.0.5" - }, - "engines": { - "node": ">=16" - } - }, "node_modules/@esbuild/android-arm": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz", - "integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==", + "version": "0.19.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.7.tgz", + "integrity": "sha512-YGSPnndkcLo4PmVl2tKatEn+0mlVMr3yEpOOT0BeMria87PhvoJb5dg5f5Ft9fbCVgtAz4pWMzZVgSEGpDAlww==", "cpu": [ "arm" ], @@ -528,9 +648,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz", - "integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==", + "version": "0.19.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.7.tgz", + "integrity": "sha512-YEDcw5IT7hW3sFKZBkCAQaOCJQLONVcD4bOyTXMZz5fr66pTHnAet46XAtbXAkJRfIn2YVhdC6R9g4xa27jQ1w==", "cpu": [ "arm64" ], @@ -544,9 +664,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz", - "integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==", + "version": "0.19.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.7.tgz", + "integrity": "sha512-jhINx8DEjz68cChFvM72YzrqfwJuFbfvSxZAk4bebpngGfNNRm+zRl4rtT9oAX6N9b6gBcFaJHFew5Blf6CvUw==", "cpu": [ "x64" ], @@ -560,9 +680,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz", - "integrity": "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==", + "version": "0.19.7", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.7.tgz", + "integrity": "sha512-dr81gbmWN//3ZnBIm6YNCl4p3pjnabg1/ZVOgz2fJoUO1a3mq9WQ/1iuEluMs7mCL+Zwv7AY5e3g1hjXqQZ9Iw==", "cpu": [ "arm64" ], @@ -576,9 +696,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz", - "integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==", + "version": "0.19.7", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.7.tgz", + "integrity": "sha512-Lc0q5HouGlzQEwLkgEKnWcSazqr9l9OdV2HhVasWJzLKeOt0PLhHaUHuzb8s/UIya38DJDoUm74GToZ6Wc7NGQ==", "cpu": [ "x64" ], @@ -592,9 +712,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz", - "integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==", + "version": "0.19.7", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.7.tgz", + "integrity": "sha512-+y2YsUr0CxDFF7GWiegWjGtTUF6gac2zFasfFkRJPkMAuMy9O7+2EH550VlqVdpEEchWMynkdhC9ZjtnMiHImQ==", "cpu": [ "arm64" ], @@ -608,9 +728,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz", - "integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==", + "version": "0.19.7", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.7.tgz", + "integrity": "sha512-CdXOxIbIzPJmJhrpmJTLx+o35NoiKBIgOvmvT+jeSadYiWJn0vFKsl+0bSG/5lwjNHoIDEyMYc/GAPR9jxusTA==", "cpu": [ "x64" ], @@ -624,9 +744,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz", - "integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==", + "version": "0.19.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.7.tgz", + "integrity": "sha512-Y+SCmWxsJOdQtjcBxoacn/pGW9HDZpwsoof0ttL+2vGcHokFlfqV666JpfLCSP2xLxFpF1lj7T3Ox3sr95YXww==", "cpu": [ "arm" ], @@ -640,9 +760,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz", - "integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==", + "version": "0.19.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.7.tgz", + "integrity": "sha512-inHqdOVCkUhHNvuQPT1oCB7cWz9qQ/Cz46xmVe0b7UXcuIJU3166aqSunsqkgSGMtUCWOZw3+KMwI6otINuC9g==", "cpu": [ "arm64" ], @@ -656,9 +776,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz", - "integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==", + "version": "0.19.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.7.tgz", + "integrity": "sha512-2BbiL7nLS5ZO96bxTQkdO0euGZIUQEUXMTrqLxKUmk/Y5pmrWU84f+CMJpM8+EHaBPfFSPnomEaQiG/+Gmh61g==", "cpu": [ "ia32" ], @@ -672,9 +792,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz", - "integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==", + "version": "0.19.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.7.tgz", + "integrity": "sha512-BVFQla72KXv3yyTFCQXF7MORvpTo4uTA8FVFgmwVrqbB/4DsBFWilUm1i2Oq6zN36DOZKSVUTb16jbjedhfSHw==", "cpu": [ "loong64" ], @@ -688,9 +808,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz", - "integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==", + "version": "0.19.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.7.tgz", + "integrity": "sha512-DzAYckIaK+pS31Q/rGpvUKu7M+5/t+jI+cdleDgUwbU7KdG2eC3SUbZHlo6Q4P1CfVKZ1lUERRFP8+q0ob9i2w==", "cpu": [ "mips64el" ], @@ -704,9 +824,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz", - "integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==", + "version": "0.19.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.7.tgz", + "integrity": "sha512-JQ1p0SmUteNdUaaiRtyS59GkkfTW0Edo+e0O2sihnY4FoZLz5glpWUQEKMSzMhA430ctkylkS7+vn8ziuhUugQ==", "cpu": [ "ppc64" ], @@ -720,9 +840,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz", - "integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==", + "version": "0.19.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.7.tgz", + "integrity": "sha512-xGwVJ7eGhkprY/nB7L7MXysHduqjpzUl40+XoYDGC4UPLbnG+gsyS1wQPJ9lFPcxYAaDXbdRXd1ACs9AE9lxuw==", "cpu": [ "riscv64" ], @@ -736,9 +856,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz", - "integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==", + "version": "0.19.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.7.tgz", + "integrity": "sha512-U8Rhki5PVU0L0nvk+E8FjkV8r4Lh4hVEb9duR6Zl21eIEYEwXz8RScj4LZWA2i3V70V4UHVgiqMpszXvG0Yqhg==", "cpu": [ "s390x" ], @@ -752,9 +872,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz", - "integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==", + "version": "0.19.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.7.tgz", + "integrity": "sha512-ZYZopyLhm4mcoZXjFt25itRlocKlcazDVkB4AhioiL9hOWhDldU9n38g62fhOI4Pth6vp+Mrd5rFKxD0/S+7aQ==", "cpu": [ "x64" ], @@ -768,9 +888,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz", - "integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==", + "version": "0.19.7", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.7.tgz", + "integrity": "sha512-/yfjlsYmT1O3cum3J6cmGG16Fd5tqKMcg5D+sBYLaOQExheAJhqr8xOAEIuLo8JYkevmjM5zFD9rVs3VBcsjtQ==", "cpu": [ "x64" ], @@ -784,9 +904,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz", - "integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==", + "version": "0.19.7", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.7.tgz", + "integrity": "sha512-MYDFyV0EW1cTP46IgUJ38OnEY5TaXxjoDmwiTXPjezahQgZd+j3T55Ht8/Q9YXBM0+T9HJygrSRGV5QNF/YVDQ==", "cpu": [ "x64" ], @@ -800,9 +920,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz", - "integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==", + "version": "0.19.7", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.7.tgz", + "integrity": "sha512-JcPvgzf2NN/y6X3UUSqP6jSS06V0DZAV/8q0PjsZyGSXsIGcG110XsdmuWiHM+pno7/mJF6fjH5/vhUz/vA9fw==", "cpu": [ "x64" ], @@ -816,9 +936,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz", - "integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==", + "version": "0.19.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.7.tgz", + "integrity": "sha512-ZA0KSYti5w5toax5FpmfcAgu3ZNJxYSRm0AW/Dao5up0YV1hDVof1NvwLomjEN+3/GMtaWDI+CIyJOMTRSTdMw==", "cpu": [ "arm64" ], @@ -832,9 +952,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz", - "integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==", + "version": "0.19.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.7.tgz", + "integrity": "sha512-CTOnijBKc5Jpk6/W9hQMMvJnsSYRYgveN6O75DTACCY18RA2nqka8dTZR+x/JqXCRiKk84+5+bRKXUSbbwsS0A==", "cpu": [ "ia32" ], @@ -848,9 +968,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz", - "integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==", + "version": "0.19.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.7.tgz", + "integrity": "sha512-gRaP2sk6hc98N734luX4VpF318l3w+ofrtTu9j5L8EQXF+FzQKV6alCOHMVoJJHvVK/mGbwBXfOL1HETQu9IGQ==", "cpu": [ "x64" ], @@ -888,9 +1008,9 @@ } }, "node_modules/@eslint/eslintrc": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.2.tgz", - "integrity": "sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.3.tgz", + "integrity": "sha512-yZzuIG+jnVu6hNSzFEN07e8BxF3uAzYtQb6uDkaYZLo6oYZDCq454c5kB8zxnzfCYyP4MIuyBn10L0DqwujTmA==", "dev": true, "dependencies": { "ajv": "^6.12.4", @@ -938,9 +1058,9 @@ } }, "node_modules/@eslint/js": { - "version": "8.52.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.52.0.tgz", - "integrity": "sha512-mjZVbpaeMZludF2fsWLD0Z9gCref1Tk4i9+wddjRvpUNqqcndPkBD09N/Mapey0b3jaXbLm2kICwFv2E64QinA==", + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.54.0.tgz", + "integrity": "sha512-ut5V+D+fOoWPgGGNj83GGjnntO39xDy6DWxO0wb7Jp3DcMX0TfIqdzHF85VTQkerdyGmuuMD9AKAo5KiNlf/AQ==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -1058,9 +1178,9 @@ } }, "node_modules/@mswjs/interceptors": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@mswjs/interceptors/-/interceptors-0.25.10.tgz", - "integrity": "sha512-5/HOSUmD/GgR8pV4ID7QbpXJZ9HP5x1hItdwT+SFeWfYzg9l/81zrggV9mDWD3w97AiU+0gfrpZHy2LJUFlFSg==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@mswjs/interceptors/-/interceptors-0.25.12.tgz", + "integrity": "sha512-a+zyoR01cPQeukSmaDEkE6aMwSjjfcT5ILzsyxmctEeCePnc2DMOd0X8Fn9bytq1IsAfMxJf/lu2aTfdivDbRg==", "dev": true, "dependencies": { "@open-draft/deferred-promise": "^2.2.0", @@ -1074,248 +1194,448 @@ "node": ">=18" } }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "node_modules/@next/env": { + "version": "14.0.3", + "resolved": "https://registry.npmjs.org/@next/env/-/env-14.0.3.tgz", + "integrity": "sha512-7xRqh9nMvP5xrW4/+L0jgRRX+HoNRGnfJpD+5Wq6/13j3dsdzxO3BCXn7D3hMqsDb+vjZnJq+vI7+EtgrYZTeA==" + }, + "node_modules/@next/eslint-plugin-next": { + "version": "14.0.3", + "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-14.0.3.tgz", + "integrity": "sha512-j4K0n+DcmQYCVnSAM+UByTVfIHnYQy2ODozfQP+4RdwtRDfobrIvKq1K4Exb2koJ79HSSa7s6B2SA8T/1YR3RA==", "dev": true, "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" + "glob": "7.1.7" } }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, + "node_modules/@next/swc-darwin-arm64": { + "version": "14.0.3", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.0.3.tgz", + "integrity": "sha512-64JbSvi3nbbcEtyitNn2LEDS/hcleAFpHdykpcnrstITFlzFgB/bW0ER5/SJJwUPj+ZPY+z3e+1jAfcczRLVGw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">= 8" + "node": ">= 10" } }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, + "node_modules/@next/swc-darwin-x64": { + "version": "14.0.3", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.0.3.tgz", + "integrity": "sha512-RkTf+KbAD0SgYdVn1XzqE/+sIxYGB7NLMZRn9I4Z24afrhUpVJx6L8hsRnIwxz3ERE2NFURNliPjJ2QNfnWicQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">= 8" + "node": ">= 10" } }, - "node_modules/@open-draft/deferred-promise": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@open-draft/deferred-promise/-/deferred-promise-2.2.0.tgz", - "integrity": "sha512-CecwLWx3rhxVQF6V4bAgPS5t+So2sTbPgAzafKkVizyi7tlwpcFpdFqq+wqF2OwNBmqFuu6tOyouTuxgpMfzmA==", - "dev": true - }, - "node_modules/@open-draft/logger": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@open-draft/logger/-/logger-0.3.0.tgz", - "integrity": "sha512-X2g45fzhxH238HKO4xbSr7+wBS8Fvw6ixhTDuvLd5mqh6bJJCFAPwU9mPDxbcrRtfxv4u5IHCEH77BmxvXmmxQ==", - "dev": true, - "dependencies": { - "is-node-process": "^1.2.0", - "outvariant": "^1.4.0" + "node_modules/@next/swc-linux-arm64-gnu": { + "version": "14.0.3", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.0.3.tgz", + "integrity": "sha512-3tBWGgz7M9RKLO6sPWC6c4pAw4geujSwQ7q7Si4d6bo0l6cLs4tmO+lnSwFp1Tm3lxwfMk0SgkJT7EdwYSJvcg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" } }, - "node_modules/@open-draft/until": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@open-draft/until/-/until-2.1.0.tgz", - "integrity": "sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg==", - "dev": true - }, - "node_modules/@pkgr/utils": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/@pkgr/utils/-/utils-2.4.2.tgz", - "integrity": "sha512-POgTXhjrTfbTV63DiFXav4lBHiICLKKwDeaKn9Nphwj7WH6m0hMMCaJkMyRWjgtPFyRKRVoMXXjczsTQRDEhYw==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.3", - "fast-glob": "^3.3.0", - "is-glob": "^4.0.3", - "open": "^9.1.0", - "picocolors": "^1.0.0", - "tslib": "^2.6.0" - }, + "node_modules/@next/swc-linux-arm64-musl": { + "version": "14.0.3", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.0.3.tgz", + "integrity": "sha512-v0v8Kb8j8T23jvVUWZeA2D8+izWspeyeDGNaT2/mTHWp7+37fiNfL8bmBWiOmeumXkacM/AB0XOUQvEbncSnHA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "^12.20.0 || ^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/unts" + "node": ">= 10" } }, - "node_modules/@reduxjs/toolkit": { - "version": "1.9.7", - "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-1.9.7.tgz", - "integrity": "sha512-t7v8ZPxhhKgOKtU+uyJT13lu4vL7az5aFi4IdoDs/eS548edn2M8Ik9h8fxgvMjGoAUVFSt6ZC1P5cWmQ014QQ==", - "dependencies": { - "immer": "^9.0.21", - "redux": "^4.2.1", - "redux-thunk": "^2.4.2", - "reselect": "^4.1.8" - }, - "peerDependencies": { - "react": "^16.9.0 || ^17.0.0 || ^18", - "react-redux": "^7.2.1 || ^8.0.2" - }, - "peerDependenciesMeta": { - "react": { - "optional": true - }, - "react-redux": { - "optional": true - } + "node_modules/@next/swc-linux-x64-gnu": { + "version": "14.0.3", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.0.3.tgz", + "integrity": "sha512-VM1aE1tJKLBwMGtyBR21yy+STfl0MapMQnNrXkxeyLs0GFv/kZqXS5Jw/TQ3TSUnbv0QPDf/X8sDXuMtSgG6eg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" } }, - "node_modules/@remix-run/router": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.11.0.tgz", - "integrity": "sha512-BHdhcWgeiudl91HvVa2wxqZjSHbheSgIiDvxrF1VjFzBzpTtuDPkOdOi3Iqvc08kXtFkLjhbS+ML9aM8mJS+wQ==", + "node_modules/@next/swc-linux-x64-musl": { + "version": "14.0.3", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.0.3.tgz", + "integrity": "sha512-64EnmKy18MYFL5CzLaSuUn561hbO1Gk16jM/KHznYP3iCIfF9e3yULtHaMy0D8zbHfxset9LTOv6cuYKJgcOxg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=14.0.0" + "node": ">= 10" } }, - "node_modules/@sinclair/typebox": { - "version": "0.27.8", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", - "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", - "dev": true + "node_modules/@next/swc-win32-arm64-msvc": { + "version": "14.0.3", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.0.3.tgz", + "integrity": "sha512-WRDp8QrmsL1bbGtsh5GqQ/KWulmrnMBgbnb+59qNTW1kVi1nG/2ndZLkcbs2GX7NpFLlToLRMWSQXmPzQm4tog==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } }, - "node_modules/@testing-library/dom": { - "version": "9.3.3", - "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-9.3.3.tgz", - "integrity": "sha512-fB0R+fa3AUqbLHWyxXa2kGVtf1Fe1ZZFr0Zp6AIbIAzXb2mKbEXl+PCQNUOaq5lbTab5tfctfXRNsWXxa2f7Aw==", + "node_modules/@next/swc-win32-ia32-msvc": { + "version": "14.0.3", + "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.0.3.tgz", + "integrity": "sha512-EKffQeqCrj+t6qFFhIFTRoqb2QwX1mU7iTOvMyLbYw3QtqTw9sMwjykyiMlZlrfm2a4fA84+/aeW+PMg1MjuTg==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-x64-msvc": { + "version": "14.0.3", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.0.3.tgz", + "integrity": "sha512-ERhKPSJ1vQrPiwrs15Pjz/rvDHZmkmvbf/BjPN/UCOI++ODftT0GtasDPi0j+y6PPJi5HsXw+dpRaXUaw4vjuQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.10.4", - "@babel/runtime": "^7.12.5", - "@types/aria-query": "^5.0.1", - "aria-query": "5.1.3", - "chalk": "^4.1.0", - "dom-accessibility-api": "^0.5.9", - "lz-string": "^1.5.0", - "pretty-format": "^27.0.2" + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" }, "engines": { - "node": ">=14" + "node": ">= 8" } }, - "node_modules/@testing-library/dom/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "dev": true, "dependencies": { - "color-convert": "^2.0.1" + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": ">= 8" } }, - "node_modules/@testing-library/dom/node_modules/aria-query": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz", - "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==", + "node_modules/@open-draft/deferred-promise": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@open-draft/deferred-promise/-/deferred-promise-2.2.0.tgz", + "integrity": "sha512-CecwLWx3rhxVQF6V4bAgPS5t+So2sTbPgAzafKkVizyi7tlwpcFpdFqq+wqF2OwNBmqFuu6tOyouTuxgpMfzmA==", + "dev": true + }, + "node_modules/@open-draft/logger": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@open-draft/logger/-/logger-0.3.0.tgz", + "integrity": "sha512-X2g45fzhxH238HKO4xbSr7+wBS8Fvw6ixhTDuvLd5mqh6bJJCFAPwU9mPDxbcrRtfxv4u5IHCEH77BmxvXmmxQ==", "dev": true, "dependencies": { - "deep-equal": "^2.0.5" + "is-node-process": "^1.2.0", + "outvariant": "^1.4.0" } }, - "node_modules/@testing-library/dom/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/@open-draft/until": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@open-draft/until/-/until-2.1.0.tgz", + "integrity": "sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg==", + "dev": true + }, + "node_modules/@pkgr/utils": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@pkgr/utils/-/utils-2.4.2.tgz", + "integrity": "sha512-POgTXhjrTfbTV63DiFXav4lBHiICLKKwDeaKn9Nphwj7WH6m0hMMCaJkMyRWjgtPFyRKRVoMXXjczsTQRDEhYw==", "dev": true, "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "cross-spawn": "^7.0.3", + "fast-glob": "^3.3.0", + "is-glob": "^4.0.3", + "open": "^9.1.0", + "picocolors": "^1.0.0", + "tslib": "^2.6.0" }, "engines": { - "node": ">=10" + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "url": "https://opencollective.com/unts" } }, - "node_modules/@testing-library/dom/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, + "node_modules/@reduxjs/toolkit": { + "version": "1.9.7", + "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-1.9.7.tgz", + "integrity": "sha512-t7v8ZPxhhKgOKtU+uyJT13lu4vL7az5aFi4IdoDs/eS548edn2M8Ik9h8fxgvMjGoAUVFSt6ZC1P5cWmQ014QQ==", "dependencies": { - "color-name": "~1.1.4" + "immer": "^9.0.21", + "redux": "^4.2.1", + "redux-thunk": "^2.4.2", + "reselect": "^4.1.8" }, - "engines": { - "node": ">=7.0.0" + "peerDependencies": { + "react": "^16.9.0 || ^17.0.0 || ^18", + "react-redux": "^7.2.1 || ^8.0.2" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-redux": { + "optional": true + } } }, - "node_modules/@testing-library/dom/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.5.1.tgz", + "integrity": "sha512-YaN43wTyEBaMqLDYeze+gQ4ZrW5RbTEGtT5o1GVDkhpdNcsLTnLRcLccvwy3E9wiDKWg9RIhuoy3JQKDRBfaZA==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] }, - "node_modules/@testing-library/dom/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.5.1.tgz", + "integrity": "sha512-n1bX+LCGlQVuPlCofO0zOKe1b2XkFozAVRoczT+yxWZPGnkEAKTTYVOGZz8N4sKuBnKMxDbfhUsB1uwYdup/sw==", + "cpu": [ + "arm64" + ], "dev": true, - "engines": { - "node": ">=8" - } + "optional": true, + "os": [ + "android" + ] }, - "node_modules/@testing-library/dom/node_modules/pretty-format": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", - "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.5.1.tgz", + "integrity": "sha512-QqJBumdvfBqBBmyGHlKxje+iowZwrHna7pokj/Go3dV1PJekSKfmjKrjKQ/e6ESTGhkfPNLq3VXdYLAc+UtAQw==", + "cpu": [ + "arm64" + ], "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } + "optional": true, + "os": [ + "darwin" + ] }, - "node_modules/@testing-library/dom/node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.5.1.tgz", + "integrity": "sha512-RrkDNkR/P5AEQSPkxQPmd2ri8WTjSl0RYmuFOiEABkEY/FSg0a4riihWQGKDJ4LnV9gigWZlTMx2DtFGzUrYQw==", + "cpu": [ + "x64" + ], "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } + "optional": true, + "os": [ + "darwin" + ] }, - "node_modules/@testing-library/dom/node_modules/react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.5.1.tgz", + "integrity": "sha512-ZFPxvUZmE+fkB/8D9y/SWl/XaDzNSaxd1TJUSE27XAKlRpQ2VNce/86bGd9mEUgL3qrvjJ9XTGwoX0BrJkYK/A==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.5.1.tgz", + "integrity": "sha512-FEuAjzVIld5WVhu+M2OewLmjmbXWd3q7Zcx+Rwy4QObQCqfblriDMMS7p7+pwgjZoo9BLkP3wa9uglQXzsB9ww==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.5.1.tgz", + "integrity": "sha512-f5Gs8WQixqGRtI0Iq/cMqvFYmgFzMinuJO24KRfnv7Ohi/HQclwrBCYkzQu1XfLEEt3DZyvveq9HWo4bLJf1Lw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.5.1.tgz", + "integrity": "sha512-CWPkPGrFfN2vj3mw+S7A/4ZaU3rTV7AkXUr08W9lNP+UzOvKLVf34tWCqrKrfwQ0NTk5GFqUr2XGpeR2p6R4gw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.5.1.tgz", + "integrity": "sha512-ZRETMFA0uVukUC9u31Ed1nx++29073goCxZtmZARwk5aF/ltuENaeTtRVsSQzFlzdd4J6L3qUm+EW8cbGt0CKQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.5.1.tgz", + "integrity": "sha512-ihqfNJNb2XtoZMSCPeoo0cYMgU04ksyFIoOw5S0JUVbOhafLot+KD82vpKXOurE2+9o/awrqIxku9MRR9hozHQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.5.1.tgz", + "integrity": "sha512-zK9MRpC8946lQ9ypFn4gLpdwr5a01aQ/odiIJeL9EbgZDMgbZjjT/XzTqJvDfTmnE1kHdbG20sAeNlpc91/wbg==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.5.1.tgz", + "integrity": "sha512-5I3Nz4Sb9TYOtkRwlH0ow+BhMH2vnh38tZ4J4mggE48M/YyJyp/0sPSxhw1UeS1+oBgQ8q7maFtSeKpeRJu41Q==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rushstack/eslint-patch": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.6.0.tgz", + "integrity": "sha512-2/U3GXA6YiPYQDLGwtGlnNgKYBSwCFIHf8Y9LUY5VATHdtbLlU0Y1R3QoBnT0aB4qv/BEiVVsj7LJXoQCgJ2vA==", "dev": true }, - "node_modules/@testing-library/dom/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true + }, + "node_modules/@swc/helpers": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.2.tgz", + "integrity": "sha512-E4KcWTpoLHqwPHLxidpOqQbcrZVgi0rsmmZXUle1jXmJfuIf/UWpczUJ7MZZ5tlxytgJXyp0w4PGkkeLiuIdZw==", + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@testing-library/dom": { + "version": "9.3.3", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-9.3.3.tgz", + "integrity": "sha512-fB0R+fa3AUqbLHWyxXa2kGVtf1Fe1ZZFr0Zp6AIbIAzXb2mKbEXl+PCQNUOaq5lbTab5tfctfXRNsWXxa2f7Aw==", "dev": true, "dependencies": { - "has-flag": "^4.0.0" + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^5.0.1", + "aria-query": "5.1.3", + "chalk": "^4.1.0", + "dom-accessibility-api": "^0.5.9", + "lz-string": "^1.5.0", + "pretty-format": "^27.0.2" }, "engines": { - "node": ">=8" + "node": ">=14" } }, "node_modules/@testing-library/jest-dom": { @@ -1359,21 +1679,6 @@ } } }, - "node_modules/@testing-library/jest-dom/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, "node_modules/@testing-library/jest-dom/node_modules/chalk": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", @@ -1387,45 +1692,6 @@ "node": ">=8" } }, - "node_modules/@testing-library/jest-dom/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@testing-library/jest-dom/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/@testing-library/jest-dom/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@testing-library/jest-dom/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/@testing-library/react": { "version": "14.1.2", "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-14.1.2.tgz", @@ -1457,33 +1723,22 @@ "@testing-library/dom": ">=7.21.4" } }, - "node_modules/@tootallnate/once": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", - "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", - "dev": true, - "optional": true, - "peer": true, - "engines": { - "node": ">= 10" - } - }, "node_modules/@types/animejs": { - "version": "3.1.11", - "resolved": "https://registry.npmjs.org/@types/animejs/-/animejs-3.1.11.tgz", - "integrity": "sha512-BIVx60G/eflyqdeKBL4+gZ3L+A0afeo11wo6FpX66bpSUQuI6roei5gYbFaGjbzawOo6hrUVPoDSfS6lwsgn8A==", + "version": "3.1.12", + "resolved": "https://registry.npmjs.org/@types/animejs/-/animejs-3.1.12.tgz", + "integrity": "sha512-fpdH+ZtlO0kqjTOqRaBdsEmvpRNOayI8k4EVkEtitL5l6wducDOXk0rgQgfZqWf/ZX9DzXrHf257S5i9xTcISQ==", "dev": true }, "node_modules/@types/aria-query": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.3.tgz", - "integrity": "sha512-0Z6Tr7wjKJIk4OUEjVUQMtyunLDy339vcMaj38Kpj6jM2OE1p3S4kXExKZ7a3uXQAPCoy3sbrP1wibDKaf39oA==", + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", + "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", "dev": true }, "node_modules/@types/babel__core": { - "version": "7.20.3", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.3.tgz", - "integrity": "sha512-54fjTSeSHwfan8AyHWrKbfBWiEUrNTZsUwPTDSNaaP1QDQIZbeNUg3a59E9D+375MzUw/x1vx2/0F5LBz+AeYA==", + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", "dev": true, "dependencies": { "@babel/parser": "^7.20.7", @@ -1494,18 +1749,18 @@ } }, "node_modules/@types/babel__generator": { - "version": "7.6.6", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.6.tgz", - "integrity": "sha512-66BXMKb/sUWbMdBNdMvajU7i/44RkrA3z/Yt1c7R5xejt8qh84iU54yUWCtm0QwGJlDcf/gg4zd/x4mpLAlb/w==", + "version": "7.6.7", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.7.tgz", + "integrity": "sha512-6Sfsq+EaaLrw4RmdFWE9Onp63TOUue71AWb4Gpa6JxzgTYtimbM086WnYTy2U67AofR++QKCo08ZP6pwx8YFHQ==", "dev": true, "dependencies": { "@babel/types": "^7.0.0" } }, "node_modules/@types/babel__template": { - "version": "7.4.3", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.3.tgz", - "integrity": "sha512-ciwyCLeuRfxboZ4isgdNZi/tkt06m8Tw6uGbBSBgWrnnZGNXiEyM27xc/PjXGQLqlZ6ylbgHMnm7ccF9tCkOeQ==", + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", "dev": true, "dependencies": { "@babel/parser": "^7.1.0", @@ -1513,24 +1768,24 @@ } }, "node_modules/@types/babel__traverse": { - "version": "7.20.3", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.3.tgz", - "integrity": "sha512-Lsh766rGEFbaxMIDH7Qa+Yha8cMVI3qAK6CHt3OR0YfxOIn5Z54iHiyDRycHrBqeIiqGa20Kpsv1cavfBKkRSw==", + "version": "7.20.4", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.4.tgz", + "integrity": "sha512-mSM/iKUk5fDDrEV/e83qY+Cr3I1+Q3qqTuEn++HAWYjEa1+NxZr6CNrcJGf2ZTnq4HoFGC3zaTPZTobCzCFukA==", "dev": true, "dependencies": { "@babel/types": "^7.20.7" } }, "node_modules/@types/chai": { - "version": "4.3.9", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.9.tgz", - "integrity": "sha512-69TtiDzu0bcmKQv3yg1Zx409/Kd7r0b5F1PfpYJfSHzLGtB53547V4u+9iqKYsTu/O2ai6KTb0TInNpvuQ3qmg==", + "version": "4.3.11", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.11.tgz", + "integrity": "sha512-qQR1dr2rGIHYlJulmr8Ioq3De0Le9E4MJ5AiaeAETJJpndT1uUNHsGFK3L/UIu+rbkQSdj8J/w2bCsBZc/Y5fQ==", "dev": true }, "node_modules/@types/chai-subset": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/@types/chai-subset/-/chai-subset-1.3.4.tgz", - "integrity": "sha512-CCWNXrJYSUIojZ1149ksLl3AN9cmZ5djf+yUoVVV+NuYrtydItQVlL2ZDqyC6M6O9LWRnVf8yYDxbXHO2TfQZg==", + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/chai-subset/-/chai-subset-1.3.5.tgz", + "integrity": "sha512-c2mPnw+xHtXDoHmdtcCXGwyLMiauiAyxWMzhGpqHC4nqI/Y5G2XhTampslK2rb59kpcuHon03UH8W6iYUzw88A==", "dev": true, "dependencies": { "@types/chai": "*" @@ -1542,12 +1797,6 @@ "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==", "dev": true }, - "node_modules/@types/deep-equal": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@types/deep-equal/-/deep-equal-1.0.4.tgz", - "integrity": "sha512-tqdiS4otQP4KmY0PR3u6KbZ5EWvhNdUoS/jc93UuK23C220lOZ/9TvjfxdPcKvqwwDVtmtSCrnr0p/2dirAxkA==", - "dev": true - }, "node_modules/@types/hoist-non-react-statics": { "version": "3.3.5", "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.5.tgz", @@ -1570,10 +1819,11 @@ "dev": true }, "node_modules/@types/json-schema": { - "version": "7.0.14", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.14.tgz", - "integrity": "sha512-U3PUjAudAdJBeC2pgN8uTIKgxrb4nlDF3SF0++EldXQvQBGkpFZMSnwQiIoDU77tv45VgNkl/L4ouD+rEomujw==", - "dev": true + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "peer": true }, "node_modules/@types/json5": { "version": "0.0.29", @@ -1582,29 +1832,29 @@ "dev": true }, "node_modules/@types/locomotive-scroll": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/@types/locomotive-scroll/-/locomotive-scroll-4.1.2.tgz", - "integrity": "sha512-K4/YWVuLf+xW5lXPue8RdWAm96dVPlyn8ISqxGdK9QflLFy82cDsvpyHJchcKtfp+qNV9OZ11nq56T5oa8jogA==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/@types/locomotive-scroll/-/locomotive-scroll-4.1.3.tgz", + "integrity": "sha512-mo8BIiFA2OOyB/Mmv0U0WL9AjBisUdUi0AMeA6hcMODEFLZvwk0UUPM+yKzMnwfpYxC/LKNiZKXO7LQp+08mMg==", "dev": true }, "node_modules/@types/node": { - "version": "20.8.10", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.10.tgz", - "integrity": "sha512-TlgT8JntpcbmKUFzjhsyhGfP2fsiz1Mv56im6enJ905xG1DAYesxJaeSbGqQmAw8OWPdhyJGhGSQGKRNJ45u9w==", + "version": "20.9.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.9.4.tgz", + "integrity": "sha512-wmyg8HUhcn6ACjsn8oKYjkN/zUzQeNtMy44weTJSM6p4MMzEOuKbA3OjJ267uPCOW7Xex9dyrNTful8XTQYoDA==", "dev": true, "dependencies": { "undici-types": "~5.26.4" } }, "node_modules/@types/prop-types": { - "version": "15.7.9", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.9.tgz", - "integrity": "sha512-n1yyPsugYNSmHgxDFjicaI2+gCNjsBck8UX9kuofAKlc0h1bL+20oSF72KeNaW2DUlesbEVCFgyV2dPGTiY42g==" + "version": "15.7.11", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.11.tgz", + "integrity": "sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng==" }, "node_modules/@types/react": { - "version": "18.2.33", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.33.tgz", - "integrity": "sha512-v+I7S+hu3PIBoVkKGpSYYpiBT1ijqEzWpzQD62/jm4K74hPpSP7FF9BnKG6+fg2+62weJYkkBWDJlZt5JO/9hg==", + "version": "18.2.38", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.38.tgz", + "integrity": "sha512-cBBXHzuPtQK6wNthuVMV6IjHAFkdl/FOPFIlkd81/Cd1+IqkHu/A+w4g43kaQQoYHik/ruaQBDL72HyCy1vuMw==", "dependencies": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -1612,36 +1862,25 @@ } }, "node_modules/@types/react-dom": { - "version": "18.2.14", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.14.tgz", - "integrity": "sha512-V835xgdSVmyQmI1KLV2BEIUgqEuinxp9O4G6g3FqO/SqLac049E53aysv0oEFD2kHfejeKU+ZqL2bcFWj9gLAQ==", + "version": "18.2.17", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.17.tgz", + "integrity": "sha512-rvrT/M7Df5eykWFxn6MYt5Pem/Dbyc1N8Y0S9Mrkw2WFCRiqUgw9P7ul2NpwsXCSM1DVdENzdG9J5SreqfAIWg==", "devOptional": true, "dependencies": { "@types/react": "*" } }, - "node_modules/@types/react-redux": { - "version": "7.1.30", - "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.30.tgz", - "integrity": "sha512-i2kqM6YaUwFKduamV6QM/uHbb0eCP8f8ZQ/0yWf+BsAVVsZPRYJ9eeGWZ3uxLfWwwA0SrPRMTPTqsPFkY3HZdA==", - "dev": true, - "dependencies": { - "@types/hoist-non-react-statics": "^3.3.0", - "@types/react": "*", - "hoist-non-react-statics": "^3.3.0", - "redux": "^4.0.0" - } - }, "node_modules/@types/scheduler": { - "version": "0.16.5", - "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.5.tgz", - "integrity": "sha512-s/FPdYRmZR8SjLWGMCuax7r3qCWQw9QKHzXVukAuuIJkXkDRwp+Pu5LMIVFi0Fxbav35WURicYr8u1QsoybnQw==" + "version": "0.16.8", + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.8.tgz", + "integrity": "sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==" }, "node_modules/@types/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-MMzuxN3GdFwskAnb6fz0orFvhfqi752yjaXylr0Rp4oDg5H0Zn1IuyRhDVvYOwAXoJirx2xuS16I3WjxnAIHiQ==", - "dev": true + "version": "7.5.6", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.6.tgz", + "integrity": "sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A==", + "dev": true, + "peer": true }, "node_modules/@types/statuses": { "version": "2.0.4", @@ -1655,16 +1894,17 @@ "integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.9.0.tgz", - "integrity": "sha512-lgX7F0azQwRPB7t7WAyeHWVfW1YJ9NIgd9mvGhfQpRY56X6AVf8mwM8Wol+0z4liE7XX3QOt8MN1rUKCfSjRIA==", + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.12.0.tgz", + "integrity": "sha512-XOpZ3IyJUIV1b15M7HVOpgQxPPF7lGXgsfcEIu3yDxFPaf/xZKt7s9QO/pbk7vpWQyVulpJbu4E5LwpZiQo4kA==", "dev": true, + "peer": true, "dependencies": { "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.9.0", - "@typescript-eslint/type-utils": "6.9.0", - "@typescript-eslint/utils": "6.9.0", - "@typescript-eslint/visitor-keys": "6.9.0", + "@typescript-eslint/scope-manager": "6.12.0", + "@typescript-eslint/type-utils": "6.12.0", + "@typescript-eslint/utils": "6.12.0", + "@typescript-eslint/visitor-keys": "6.12.0", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.2.4", @@ -1690,15 +1930,15 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.9.0.tgz", - "integrity": "sha512-GZmjMh4AJ/5gaH4XF2eXA8tMnHWP+Pm1mjQR2QN4Iz+j/zO04b9TOvJYOX2sCNIQHtRStKTxRY1FX7LhpJT4Gw==", + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.12.0.tgz", + "integrity": "sha512-s8/jNFPKPNRmXEnNXfuo1gemBdVmpQsK1pcu+QIvuNJuhFzGrpD7WjOcvDc/+uEdfzSYpNu7U/+MmbScjoQ6vg==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "6.9.0", - "@typescript-eslint/types": "6.9.0", - "@typescript-eslint/typescript-estree": "6.9.0", - "@typescript-eslint/visitor-keys": "6.9.0", + "@typescript-eslint/scope-manager": "6.12.0", + "@typescript-eslint/types": "6.12.0", + "@typescript-eslint/typescript-estree": "6.12.0", + "@typescript-eslint/visitor-keys": "6.12.0", "debug": "^4.3.4" }, "engines": { @@ -1718,13 +1958,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.9.0.tgz", - "integrity": "sha512-1R8A9Mc39n4pCCz9o79qRO31HGNDvC7UhPhv26TovDsWPBDx+Sg3rOZdCELIA3ZmNoWAuxaMOT7aWtGRSYkQxw==", + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.12.0.tgz", + "integrity": "sha512-5gUvjg+XdSj8pcetdL9eXJzQNTl3RD7LgUiYTl8Aabdi8hFkaGSYnaS6BLc0BGNaDH+tVzVwmKtWvu0jLgWVbw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.9.0", - "@typescript-eslint/visitor-keys": "6.9.0" + "@typescript-eslint/types": "6.12.0", + "@typescript-eslint/visitor-keys": "6.12.0" }, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -1735,13 +1975,14 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.9.0.tgz", - "integrity": "sha512-XXeahmfbpuhVbhSOROIzJ+b13krFmgtc4GlEuu1WBT+RpyGPIA4Y/eGnXzjbDj5gZLzpAXO/sj+IF/x2GtTMjQ==", + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.12.0.tgz", + "integrity": "sha512-WWmRXxhm1X8Wlquj+MhsAG4dU/Blvf1xDgGaYCzfvStP2NwPQh6KBvCDbiOEvaE0filhranjIlK/2fSTVwtBng==", "dev": true, + "peer": true, "dependencies": { - "@typescript-eslint/typescript-estree": "6.9.0", - "@typescript-eslint/utils": "6.9.0", + "@typescript-eslint/typescript-estree": "6.12.0", + "@typescript-eslint/utils": "6.12.0", "debug": "^4.3.4", "ts-api-utils": "^1.0.1" }, @@ -1762,9 +2003,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.9.0.tgz", - "integrity": "sha512-+KB0lbkpxBkBSiVCuQvduqMJy+I1FyDbdwSpM3IoBS7APl4Bu15lStPjgBIdykdRqQNYqYNMa8Kuidax6phaEw==", + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.12.0.tgz", + "integrity": "sha512-MA16p/+WxM5JG/F3RTpRIcuOghWO30//VEOvzubM8zuOOBYXsP+IfjoCXXiIfy2Ta8FRh9+IO9QLlaFQUU+10Q==", "dev": true, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -1775,13 +2016,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.9.0.tgz", - "integrity": "sha512-NJM2BnJFZBEAbCfBP00zONKXvMqihZCrmwCaik0UhLr0vAgb6oguXxLX1k00oQyD+vZZ+CJn3kocvv2yxm4awQ==", + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.12.0.tgz", + "integrity": "sha512-vw9E2P9+3UUWzhgjyyVczLWxZ3GuQNT7QpnIY3o5OMeLO/c8oHljGc8ZpryBMIyympiAAaKgw9e5Hl9dCWFOYw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.9.0", - "@typescript-eslint/visitor-keys": "6.9.0", + "@typescript-eslint/types": "6.12.0", + "@typescript-eslint/visitor-keys": "6.12.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -1802,17 +2043,18 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.9.0.tgz", - "integrity": "sha512-5Wf+Jsqya7WcCO8me504FBigeQKVLAMPmUzYgDbWchINNh1KJbxCgVya3EQ2MjvJMVeXl3pofRmprqX6mfQkjQ==", + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.12.0.tgz", + "integrity": "sha512-LywPm8h3tGEbgfyjYnu3dauZ0U7R60m+miXgKcZS8c7QALO9uWJdvNoP+duKTk2XMWc7/Q3d/QiCuLN9X6SWyQ==", "dev": true, + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.12", "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.9.0", - "@typescript-eslint/types": "6.9.0", - "@typescript-eslint/typescript-estree": "6.9.0", + "@typescript-eslint/scope-manager": "6.12.0", + "@typescript-eslint/types": "6.12.0", + "@typescript-eslint/typescript-estree": "6.12.0", "semver": "^7.5.4" }, "engines": { @@ -1827,12 +2069,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.9.0.tgz", - "integrity": "sha512-dGtAfqjV6RFOtIP8I0B4ZTBRrlTT8NHHlZZSchQx3qReaoDeXhYM++M4So2AgFK9ZB0emRPA6JI1HkafzA2Ibg==", + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.12.0.tgz", + "integrity": "sha512-rg3BizTZHF1k3ipn8gfrzDXXSFKyOEB5zxYXInQ6z0hUvmQlhaZQzK+YmHmNViMA9HzW5Q9+bPPt90bU6GQwyw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.9.0", + "@typescript-eslint/types": "6.12.0", "eslint-visitor-keys": "^3.4.1" }, "engines": { @@ -1850,22 +2092,22 @@ "dev": true }, "node_modules/@vitejs/plugin-react": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.1.0.tgz", - "integrity": "sha512-rM0SqazU9iqPUraQ2JlIvReeaxOoRj6n+PzB1C0cBzIbd8qP336nC39/R9yPi3wVcah7E7j/kdU1uCUqMEU4OQ==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.2.0.tgz", + "integrity": "sha512-+MHTH/e6H12kRp5HUkzOGqPMksezRMmW+TNzlh/QXfI8rRf6l2Z2yH/v12no1UvTwhZgEDMuQ7g7rrfMseU6FQ==", "dev": true, "dependencies": { - "@babel/core": "^7.22.20", - "@babel/plugin-transform-react-jsx-self": "^7.22.5", - "@babel/plugin-transform-react-jsx-source": "^7.22.5", - "@types/babel__core": "^7.20.2", + "@babel/core": "^7.23.3", + "@babel/plugin-transform-react-jsx-self": "^7.23.3", + "@babel/plugin-transform-react-jsx-source": "^7.23.3", + "@types/babel__core": "^7.20.4", "react-refresh": "^0.14.0" }, "engines": { "node": "^14.18.0 || >=16.0.0" }, "peerDependencies": { - "vite": "^4.2.0" + "vite": "^4.2.0 || ^5.0.0" } }, "node_modules/@vitest/coverage-v8": { @@ -1962,6 +2204,38 @@ "url": "https://opencollective.com/vitest" } }, + "node_modules/@vitest/snapshot/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@vitest/snapshot/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@vitest/snapshot/node_modules/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "dev": true + }, "node_modules/@vitest/spy": { "version": "0.34.6", "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-0.34.6.tgz", @@ -1984,17 +2258,41 @@ "loupe": "^2.3.6", "pretty-format": "^29.5.0" }, - "funding": { - "url": "https://opencollective.com/vitest" + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@vitest/utils/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/abab": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", - "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", - "dev": true, - "optional": true, - "peer": true + "node_modules/@vitest/utils/node_modules/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "dev": true }, "node_modules/acorn": { "version": "8.11.2", @@ -2026,20 +2324,6 @@ "node": ">=0.4.0" } }, - "node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" - } - }, "node_modules/ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -2062,15 +2346,27 @@ "integrity": "sha512-sWno3ugFryK5nhiDm/2BKeFCpZv7vzerWUcUPyAZLDhMek3+S/p418ldZJbJXo5ZUOpfm2kP2XRO4NJcULMy9A==" }, "node_modules/ansi-escapes": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-5.0.0.tgz", - "integrity": "sha512-5GFMVX8HqE/TB+FuBJGuO5XG0WrsA6ptUqoODaT/n9mmUaZFkqnBueB4leqGBCmrUHnCnC4PCZTCd0E7QQ83bA==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", "dev": true, "dependencies": { - "type-fest": "^1.0.2" + "type-fest": "^0.21.3" }, "engines": { - "node": ">=12" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-escapes/node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "engines": { + "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -2086,15 +2382,18 @@ } }, "node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "dependencies": { - "color-convert": "^1.9.0" + "color-convert": "^2.0.1" }, "engines": { - "node": ">=4" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, "node_modules/any-promise": { @@ -2129,12 +2428,12 @@ "dev": true }, "node_modules/aria-query": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", - "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz", + "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==", "dev": true, "dependencies": { - "dequal": "^2.0.3" + "deep-equal": "^2.0.5" } }, "node_modules/array-buffer-byte-length": { @@ -2277,9 +2576,9 @@ } }, "node_modules/ast-types-flow": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz", - "integrity": "sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag==", + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.8.tgz", + "integrity": "sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==", "dev": true }, "node_modules/asynciterator.prototype": { @@ -2291,14 +2590,6 @@ "has-symbols": "^1.0.3" } }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "dev": true, - "optional": true, - "peer": true - }, "node_modules/autoprefixer": { "version": "10.4.16", "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.16.tgz", @@ -2349,9 +2640,9 @@ } }, "node_modules/axe-core": { - "version": "4.8.2", - "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.8.2.tgz", - "integrity": "sha512-/dlp0fxyM3R8YW7MFzaHWXrf4zzbr0vaYb23VBFCl83R7nWNPg/yaQw2Dc8jzCMmDVLhSdzH8MjrsuIUuvX+6g==", + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.7.0.tgz", + "integrity": "sha512-M0JtH+hlOL5pLQwHOLNYZaXuhqmvS8oExsqB1SBYgA4Dk7u/xx+YdGHXaK5pyUfed5mYXdlYiphWq3G8cRi5JQ==", "dev": true, "engines": { "node": ">=4" @@ -2398,9 +2689,9 @@ "integrity": "sha512-gbIqZ/eslnUFC1tjEvtz0sgx+xTK20wDnYMIA27VA04R7w6xxXQPZDbibjA9DTWZRA2CXtwHykkVzlCaAJAZig==" }, "node_modules/big-integer": { - "version": "1.6.51", - "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz", - "integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==", + "version": "1.6.52", + "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.52.tgz", + "integrity": "sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==", "dev": true, "engines": { "node": ">=0.6" @@ -2536,6 +2827,17 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "dependencies": { + "streamsearch": "^1.1.0" + }, + "engines": { + "node": ">=10.16.0" + } + }, "node_modules/cac": { "version": "6.7.14", "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", @@ -2578,10 +2880,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001557", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001557.tgz", - "integrity": "sha512-91oR7hLNUP3gG6MLU+n96em322a8Xzes8wWdBKhLgUoiJsAF5irZnxSUCbc+qUZXNnPCfUwLOi9ZCZpkvjQajw==", - "dev": true, + "version": "1.0.30001564", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001564.tgz", + "integrity": "sha512-DqAOf+rhof+6GVx1y+xzbFPeOumfQnhYzVnZD6LAXijR77yPtm9mfOcqOnT3mpnJiZVT+kwLAFnRlZcIz+c6bg==", "funding": [ { "type": "opencollective", @@ -2616,17 +2917,19 @@ } }, "node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": ">=4" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, "node_modules/chardet": { @@ -2687,18 +2990,15 @@ } }, "node_modules/cli-cursor": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-4.0.0.tgz", - "integrity": "sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", "dev": true, "dependencies": { - "restore-cursor": "^4.0.0" + "restore-cursor": "^3.1.0" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=8" } }, "node_modules/cli-spinners": { @@ -2729,89 +3029,76 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/cli-width": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", - "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", - "dev": true, - "engines": { - "node": ">= 10" - } - }, - "node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "node_modules/cli-truncate/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, "engines": { "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, - "node_modules/cliui/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/cli-truncate/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", "dev": true, "dependencies": { - "color-convert": "^2.0.1" + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" }, "engines": { - "node": ">=8" + "node": ">=12" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/cliui/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/cli-truncate/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", "dev": true, "dependencies": { - "color-name": "~1.1.4" + "ansi-regex": "^6.0.1" }, "engines": { - "node": ">=7.0.0" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "node_modules/cliui/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/cliui/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/cliui/node_modules/is-fullwidth-code-point": { + "node_modules/cli-width": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", + "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", "dev": true, "engines": { - "node": ">=8" + "node": ">= 10" } }, - "node_modules/cliui/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "node_modules/client-only": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", + "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==" + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", "dev": true, "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" }, "engines": { - "node": ">=8" + "node": ">=12" } }, "node_modules/cliui/node_modules/wrap-ansi": { @@ -2849,18 +3136,21 @@ } }, "node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, "dependencies": { - "color-name": "1.1.3" + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" } }, "node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, "node_modules/colorette": { @@ -2869,27 +3159,13 @@ "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", "dev": true }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, "node_modules/commander": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", - "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", "dev": true, "engines": { - "node": ">=16" + "node": ">= 6" } }, "node_modules/concat-map": { @@ -2951,46 +3227,16 @@ "node": ">=4" } }, - "node_modules/cssstyle": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-3.0.0.tgz", - "integrity": "sha512-N4u2ABATi3Qplzf0hWbVCdjenim8F3ojEXpBDF5hBpjzW182MjNGLqfmQ0SkSPeQ+V86ZXgeH8aXj6kayd4jgg==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "rrweb-cssom": "^0.6.0" - }, - "engines": { - "node": ">=14" - } - }, "node_modules/csstype": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", - "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==" - }, - "node_modules/damerau-levenshtein": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", - "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", - "dev": true - }, - "node_modules/data-urls": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-4.0.0.tgz", - "integrity": "sha512-/mMTei/JXPqvFqQtfyTowxmJVwr2PVAeCcDxyFf6LhoOu/09TX2OX3kb2wzi4DMXcfj4OItwDOnhl5oziPnT6g==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "abab": "^2.0.6", - "whatwg-mimetype": "^3.0.0", - "whatwg-url": "^12.0.0" - }, - "engines": { - "node": ">=14" - } + "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==" + }, + "node_modules/damerau-levenshtein": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", + "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", + "dev": true }, "node_modules/debug": { "version": "4.3.4", @@ -3009,14 +3255,6 @@ } } }, - "node_modules/decimal.js": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", - "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==", - "dev": true, - "optional": true, - "peer": true - }, "node_modules/deep-eql": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", @@ -3101,56 +3339,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/default-browser/node_modules/execa": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-7.2.0.tgz", - "integrity": "sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.1", - "human-signals": "^4.3.0", - "is-stream": "^3.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^5.1.0", - "onetime": "^6.0.0", - "signal-exit": "^3.0.7", - "strip-final-newline": "^3.0.0" - }, - "engines": { - "node": "^14.18.0 || ^16.14.0 || >=18.0.0" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/default-browser/node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/default-browser/node_modules/human-signals": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-4.3.1.tgz", - "integrity": "sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==", - "dev": true, - "engines": { - "node": ">=14.18.0" - } - }, - "node_modules/default-browser/node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, "node_modules/defaults": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", @@ -3206,17 +3394,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "dev": true, - "optional": true, - "peer": true, - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/dequal": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", @@ -3277,20 +3454,6 @@ "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", "dev": true }, - "node_modules/domexception": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz", - "integrity": "sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "webidl-conversions": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, "node_modules/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", @@ -3298,9 +3461,9 @@ "dev": true }, "node_modules/electron-to-chromium": { - "version": "1.4.569", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.569.tgz", - "integrity": "sha512-LsrJjZ0IbVy12ApW3gpYpcmHS3iRxH4bkKOW98y1/D+3cvDUWGcbzbsFinfUS8knpcZk/PG/2p/RnkMCYN7PVg==", + "version": "1.4.592", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.592.tgz", + "integrity": "sha512-D3NOkROIlF+d5ixnz7pAf3Lu/AuWpd6AYgI9O67GQXMXTcCP1gJQRotOq35eQy5Sb4hez33XH1YdTtILA7Udww==", "dev": true }, "node_modules/emoji-regex": { @@ -3327,8 +3490,6 @@ "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", "dev": true, - "optional": true, - "peer": true, "engines": { "node": ">=0.12" }, @@ -3472,9 +3633,9 @@ } }, "node_modules/esbuild": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz", - "integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==", + "version": "0.19.7", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.7.tgz", + "integrity": "sha512-6brbTZVqxhqgbpqBR5MzErImcpA0SQdoKOkcWK/U30HtQxnokIpG3TX2r0IJqbFUzqLjhU/zC1S5ndgakObVCQ==", "dev": true, "hasInstallScript": true, "bin": { @@ -3484,28 +3645,28 @@ "node": ">=12" }, "optionalDependencies": { - "@esbuild/android-arm": "0.18.20", - "@esbuild/android-arm64": "0.18.20", - "@esbuild/android-x64": "0.18.20", - "@esbuild/darwin-arm64": "0.18.20", - "@esbuild/darwin-x64": "0.18.20", - "@esbuild/freebsd-arm64": "0.18.20", - "@esbuild/freebsd-x64": "0.18.20", - "@esbuild/linux-arm": "0.18.20", - "@esbuild/linux-arm64": "0.18.20", - "@esbuild/linux-ia32": "0.18.20", - "@esbuild/linux-loong64": "0.18.20", - "@esbuild/linux-mips64el": "0.18.20", - "@esbuild/linux-ppc64": "0.18.20", - "@esbuild/linux-riscv64": "0.18.20", - "@esbuild/linux-s390x": "0.18.20", - "@esbuild/linux-x64": "0.18.20", - "@esbuild/netbsd-x64": "0.18.20", - "@esbuild/openbsd-x64": "0.18.20", - "@esbuild/sunos-x64": "0.18.20", - "@esbuild/win32-arm64": "0.18.20", - "@esbuild/win32-ia32": "0.18.20", - "@esbuild/win32-x64": "0.18.20" + "@esbuild/android-arm": "0.19.7", + "@esbuild/android-arm64": "0.19.7", + "@esbuild/android-x64": "0.19.7", + "@esbuild/darwin-arm64": "0.19.7", + "@esbuild/darwin-x64": "0.19.7", + "@esbuild/freebsd-arm64": "0.19.7", + "@esbuild/freebsd-x64": "0.19.7", + "@esbuild/linux-arm": "0.19.7", + "@esbuild/linux-arm64": "0.19.7", + "@esbuild/linux-ia32": "0.19.7", + "@esbuild/linux-loong64": "0.19.7", + "@esbuild/linux-mips64el": "0.19.7", + "@esbuild/linux-ppc64": "0.19.7", + "@esbuild/linux-riscv64": "0.19.7", + "@esbuild/linux-s390x": "0.19.7", + "@esbuild/linux-x64": "0.19.7", + "@esbuild/netbsd-x64": "0.19.7", + "@esbuild/openbsd-x64": "0.19.7", + "@esbuild/sunos-x64": "0.19.7", + "@esbuild/win32-arm64": "0.19.7", + "@esbuild/win32-ia32": "0.19.7", + "@esbuild/win32-x64": "0.19.7" } }, "node_modules/escalade": { @@ -3518,24 +3679,27 @@ } }, "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true, "engines": { - "node": ">=0.8.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/eslint": { - "version": "8.52.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.52.0.tgz", - "integrity": "sha512-zh/JHnaixqHZsolRB/w9/02akBk9EPrOs9JwcTP2ek7yL5bVvXuRariiaAjjoJ5DvuwQ1WAE/HsMz+w17YgBCg==", + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.54.0.tgz", + "integrity": "sha512-NY0DfAkM8BIZDVl6PgSa1ttZbx3xHgJzSNJKYcQglem6CppHyMhRIQkBVSSMaSRnLhig3jsDbEzOjwCVt4AmmA==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.2", - "@eslint/js": "8.52.0", + "@eslint/eslintrc": "^2.1.3", + "@eslint/js": "8.54.0", "@humanwhocodes/config-array": "^0.11.13", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", @@ -3645,6 +3809,32 @@ "eslint-plugin-import": "^2.25.3" } }, + "node_modules/eslint-config-next": { + "version": "14.0.3", + "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-14.0.3.tgz", + "integrity": "sha512-IKPhpLdpSUyKofmsXUfrvBC49JMUTdeaD8ZIH4v9Vk0sC1X6URTuTJCLtA0Vwuj7V/CQh0oISuSTvNn5//Buew==", + "dev": true, + "dependencies": { + "@next/eslint-plugin-next": "14.0.3", + "@rushstack/eslint-patch": "^1.3.3", + "@typescript-eslint/parser": "^5.4.2 || ^6.0.0", + "eslint-import-resolver-node": "^0.3.6", + "eslint-import-resolver-typescript": "^3.5.2", + "eslint-plugin-import": "^2.28.1", + "eslint-plugin-jsx-a11y": "^6.7.1", + "eslint-plugin-react": "^7.33.2", + "eslint-plugin-react-hooks": "^4.5.0 || 5.0.0-canary-7118f5dd7-20230705" + }, + "peerDependencies": { + "eslint": "^7.23.0 || ^8.0.0", + "typescript": ">=3.3.1" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, "node_modules/eslint-config-prettier": { "version": "9.0.0", "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.0.0.tgz", @@ -3790,27 +3980,27 @@ } }, "node_modules/eslint-plugin-jsx-a11y": { - "version": "6.7.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.7.1.tgz", - "integrity": "sha512-63Bog4iIethyo8smBklORknVjB0T2dwB8Mr/hIC+fBS0uyHdYYpzM/Ed+YC8VxTjlXHEWFOdmgwcDn1U2L9VCA==", + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.8.0.tgz", + "integrity": "sha512-Hdh937BS3KdwwbBaKd5+PLCOmYY6U4f2h9Z2ktwtNKvIdIEu137rjYbcb9ApSbVJfWxANNuiKTD/9tOKjK9qOA==", "dev": true, "dependencies": { - "@babel/runtime": "^7.20.7", - "aria-query": "^5.1.3", - "array-includes": "^3.1.6", - "array.prototype.flatmap": "^1.3.1", - "ast-types-flow": "^0.0.7", - "axe-core": "^4.6.2", - "axobject-query": "^3.1.1", + "@babel/runtime": "^7.23.2", + "aria-query": "^5.3.0", + "array-includes": "^3.1.7", + "array.prototype.flatmap": "^1.3.2", + "ast-types-flow": "^0.0.8", + "axe-core": "=4.7.0", + "axobject-query": "^3.2.1", "damerau-levenshtein": "^1.0.8", "emoji-regex": "^9.2.2", - "has": "^1.0.3", - "jsx-ast-utils": "^3.3.3", - "language-tags": "=1.0.5", + "es-iterator-helpers": "^1.0.15", + "hasown": "^2.0.0", + "jsx-ast-utils": "^3.3.5", + "language-tags": "^1.0.9", "minimatch": "^3.1.2", - "object.entries": "^1.1.6", - "object.fromentries": "^2.0.6", - "semver": "^6.3.0" + "object.entries": "^1.1.7", + "object.fromentries": "^2.0.7" }, "engines": { "node": ">=4.0" @@ -3819,13 +4009,13 @@ "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" } }, - "node_modules/eslint-plugin-jsx-a11y/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "node_modules/eslint-plugin-jsx-a11y/node_modules/aria-query": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", + "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", "dev": true, - "bin": { - "semver": "bin/semver.js" + "dependencies": { + "dequal": "^2.0.3" } }, "node_modules/eslint-plugin-prettier": { @@ -3983,67 +4173,6 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/eslint/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/eslint/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/eslint/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/eslint/node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/eslint/node_modules/globals": { "version": "13.23.0", "resolved": "https://registry.npmjs.org/globals/-/globals-13.23.0.tgz", @@ -4059,27 +4188,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eslint/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/eslint/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/eslint/node_modules/type-fest": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", @@ -4158,28 +4266,55 @@ "dev": true }, "node_modules/execa": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", - "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-7.2.0.tgz", + "integrity": "sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA==", "dev": true, "dependencies": { "cross-spawn": "^7.0.3", - "get-stream": "^8.0.1", - "human-signals": "^5.0.0", + "get-stream": "^6.0.1", + "human-signals": "^4.3.0", "is-stream": "^3.0.0", "merge-stream": "^2.0.0", "npm-run-path": "^5.1.0", "onetime": "^6.0.0", - "signal-exit": "^4.1.0", + "signal-exit": "^3.0.7", "strip-final-newline": "^3.0.0" }, "engines": { - "node": ">=16.17" + "node": "^14.18.0 || ^16.14.0 || >=18.0.0" }, "funding": { "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, + "node_modules/execa/node_modules/mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/execa/node_modules/onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "dev": true, + "dependencies": { + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/external-editor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", @@ -4219,9 +4354,9 @@ "dev": true }, "node_modules/fast-glob": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", - "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", "dev": true, "dependencies": { "@nodelib/fs.stat": "^2.0.2", @@ -4282,6 +4417,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/figures/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, "node_modules/file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -4323,9 +4467,9 @@ } }, "node_modules/flat-cache": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.1.1.tgz", - "integrity": "sha512-/qM2b3LUIaIgviBQovTLvijfyOQXPtSRnRK26ksj2J7rzPIecePUIpJsZ4T02Qg+xiAEKIs5K8dsHEd+VaKa/Q==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", "dev": true, "dependencies": { "flatted": "^3.2.9", @@ -4333,7 +4477,7 @@ "rimraf": "^3.0.2" }, "engines": { - "node": ">=12.0.0" + "node": "^10.12.0 || >=12.0.0" } }, "node_modules/flatted": { @@ -4344,27 +4488,11 @@ }, "node_modules/for-each": { "version": "0.3.3", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", - "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", - "dev": true, - "dependencies": { - "is-callable": "^1.1.3" - } - }, - "node_modules/form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", "dev": true, - "optional": true, - "peer": true, "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" + "is-callable": "^1.1.3" } }, "node_modules/fraction.js": { @@ -4479,12 +4607,12 @@ } }, "node_modules/get-stream": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", - "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", "dev": true, "engines": { - "node": ">=16" + "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -4519,15 +4647,15 @@ } }, "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "version": "7.1.7", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", + "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", "dev": true, "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", - "minimatch": "^3.1.1", + "minimatch": "^3.0.4", "once": "^1.3.0", "path-is-absolute": "^1.0.0" }, @@ -4550,6 +4678,11 @@ "node": ">=10.13.0" } }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==" + }, "node_modules/globals": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", @@ -4609,8 +4742,7 @@ "node_modules/graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" }, "node_modules/graphemer": { "version": "1.4.0", @@ -4632,8 +4764,6 @@ "resolved": "https://registry.npmjs.org/happy-dom/-/happy-dom-12.10.3.tgz", "integrity": "sha512-JzUXOh0wdNGY54oKng5hliuBkq/+aT1V3YpTM+lrN/GoLQTANZsMaIvmHiHe612rauHvPJnDZkZ+5GZR++1Abg==", "dev": true, - "optional": true, - "peer": true, "dependencies": { "css.escape": "^1.5.1", "entities": "^4.5.0", @@ -4643,15 +4773,6 @@ "whatwg-mimetype": "^3.0.0" } }, - "node_modules/has": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.4.tgz", - "integrity": "sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==", - "dev": true, - "engines": { - "node": ">= 0.4.0" - } - }, "node_modules/has-bigints": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", @@ -4662,12 +4783,12 @@ } }, "node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, "engines": { - "node": ">=4" + "node": ">=8" } }, "node_modules/has-property-descriptors": { @@ -4747,19 +4868,10 @@ "react-is": "^16.7.0" } }, - "node_modules/html-encoding-sniffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz", - "integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "whatwg-encoding": "^2.0.0" - }, - "engines": { - "node": ">=12" - } + "node_modules/hoist-non-react-statics/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, "node_modules/html-escaper": { "version": "2.0.2", @@ -4767,44 +4879,13 @@ "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", "dev": true }, - "node_modules/http-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", - "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "@tootallnate/once": "2", - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/human-signals": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", - "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-4.3.1.tgz", + "integrity": "sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==", "dev": true, "engines": { - "node": ">=16.17.0" + "node": ">=14.18.0" } }, "node_modules/husky": { @@ -4827,8 +4908,6 @@ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", "dev": true, - "optional": true, - "peer": true, "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" }, @@ -4857,9 +4936,9 @@ ] }, "node_modules/ignore": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", - "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz", + "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==", "dev": true, "engines": { "node": ">= 4" @@ -4869,203 +4948,19 @@ "version": "9.0.21", "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.21.tgz", "integrity": "sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/immer" - } - }, - "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dev": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "node_modules/inquirer": { - "version": "8.2.6", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.6.tgz", - "integrity": "sha512-M1WuAmb7pn9zdFRtQYk26ZBoY043Sse0wVDdk4Bppr+JOXyQYybdtvK+l9wUibhtjdjvtoiNy8tk+EgsYIUqKg==", - "dev": true, - "dependencies": { - "ansi-escapes": "^4.2.1", - "chalk": "^4.1.1", - "cli-cursor": "^3.1.0", - "cli-width": "^3.0.0", - "external-editor": "^3.0.3", - "figures": "^3.0.0", - "lodash": "^4.17.21", - "mute-stream": "0.0.8", - "ora": "^5.4.1", - "run-async": "^2.4.0", - "rxjs": "^7.5.5", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0", - "through": "^2.3.6", - "wrap-ansi": "^6.0.1" - }, - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/inquirer/node_modules/ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "dev": true, - "dependencies": { - "type-fest": "^0.21.3" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/inquirer/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/inquirer/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/inquirer/node_modules/cli-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", - "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", - "dev": true, - "dependencies": { - "restore-cursor": "^3.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/inquirer/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/inquirer/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/inquirer/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/inquirer/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/inquirer/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/inquirer/node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true, - "engines": { - "node": ">=6" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" } }, - "node_modules/inquirer/node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", "dev": true, "dependencies": { - "mimic-fn": "^2.1.0" + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" }, "engines": { "node": ">=6" @@ -5074,75 +4969,64 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/inquirer/node_modules/restore-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", - "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", "dev": true, - "dependencies": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" - }, "engines": { - "node": ">=8" + "node": ">=0.8.19" } }, - "node_modules/inquirer/node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, - "node_modules/inquirer/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, "engines": { "node": ">=8" } }, - "node_modules/inquirer/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", "dev": true, "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" + "once": "^1.3.0", + "wrappy": "1" } }, - "node_modules/inquirer/node_modules/type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true }, - "node_modules/inquirer/node_modules/wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "node_modules/inquirer": { + "version": "8.2.6", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.6.tgz", + "integrity": "sha512-M1WuAmb7pn9zdFRtQYk26ZBoY043Sse0wVDdk4Bppr+JOXyQYybdtvK+l9wUibhtjdjvtoiNy8tk+EgsYIUqKg==", "dev": true, "dependencies": { - "ansi-styles": "^4.0.0", + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.1", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.21", + "mute-stream": "0.0.8", + "ora": "^5.4.1", + "run-async": "^2.4.0", + "rxjs": "^7.5.5", "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" + "strip-ansi": "^6.0.0", + "through": "^2.3.6", + "wrap-ansi": "^6.0.1" }, "engines": { - "node": ">=8" + "node": ">=12.0.0" } }, "node_modules/internal-slot": { @@ -5320,15 +5204,12 @@ } }, "node_modules/is-fullwidth-code-point": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", - "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true, "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=8" } }, "node_modules/is-generator-function": { @@ -5445,14 +5326,6 @@ "node": ">=8" } }, - "node_modules/is-potential-custom-element-name": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", - "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", - "dev": true, - "optional": true, - "peer": true - }, "node_modules/is-regex": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", @@ -5633,9 +5506,9 @@ "dev": true }, "node_modules/istanbul-lib-coverage": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.1.tgz", - "integrity": "sha512-opCrKqbthmq3SKZ10mFMQG9dk3fTa3quaOLD35kJa5ejwZHd9xAr+kLuziiZz2cG32s4lMZxNdmdcEQnTDP4+g==", + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", "dev": true, "engines": { "node": ">=8" @@ -5655,27 +5528,6 @@ "node": ">=10" } }, - "node_modules/istanbul-lib-report/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-report/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/istanbul-lib-source-maps": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", @@ -5717,9 +5569,9 @@ } }, "node_modules/jiti": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.20.0.tgz", - "integrity": "sha512-3TV69ZbrvV6U5DfQimop50jE9Dl6J8O1ja1dvBbMba/sZ3YBEQqJ2VZRoQPVnhlzjNtU1vaXRZVrVjU4qtm8yA==", + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.0.tgz", + "integrity": "sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==", "dev": true, "bin": { "jiti": "bin/jiti.js" @@ -5751,50 +5603,6 @@ "js-yaml": "bin/js-yaml.js" } }, - "node_modules/jsdom": { - "version": "22.1.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-22.1.0.tgz", - "integrity": "sha512-/9AVW7xNbsBv6GfWho4TTNjEo9fe6Zhf9O7s0Fhhr3u+awPwAJMKwAMXnkk5vBxflqLW9hTHX/0cs+P3gW+cQw==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "abab": "^2.0.6", - "cssstyle": "^3.0.0", - "data-urls": "^4.0.0", - "decimal.js": "^10.4.3", - "domexception": "^4.0.0", - "form-data": "^4.0.0", - "html-encoding-sniffer": "^3.0.0", - "http-proxy-agent": "^5.0.0", - "https-proxy-agent": "^5.0.1", - "is-potential-custom-element-name": "^1.0.1", - "nwsapi": "^2.2.4", - "parse5": "^7.1.2", - "rrweb-cssom": "^0.6.0", - "saxes": "^6.0.0", - "symbol-tree": "^3.2.4", - "tough-cookie": "^4.1.2", - "w3c-xmlserializer": "^4.0.0", - "webidl-conversions": "^7.0.0", - "whatwg-encoding": "^2.0.0", - "whatwg-mimetype": "^3.0.0", - "whatwg-url": "^12.0.1", - "ws": "^8.13.0", - "xml-name-validator": "^4.0.0" - }, - "engines": { - "node": ">=16" - }, - "peerDependencies": { - "canvas": "^2.5.0" - }, - "peerDependenciesMeta": { - "canvas": { - "optional": true - } - } - }, "node_modules/jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", @@ -5874,12 +5682,15 @@ "dev": true }, "node_modules/language-tags": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.5.tgz", - "integrity": "sha512-qJhlO9cGXi6hBGKoxEG/sKZDAHD5Hnu9Hs4WbOY3pCWXDhw0N8x1NenNzm2EnNLkLkk7J2SdxAkDSbb6ftT+UQ==", + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.9.tgz", + "integrity": "sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==", "dev": true, "dependencies": { - "language-subtag-registry": "~0.3.2" + "language-subtag-registry": "^0.3.20" + }, + "engines": { + "node": ">=0.10" } }, "node_modules/lethargy": { @@ -5909,49 +5720,141 @@ "node": ">=10" } }, - "node_modules/lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true - }, - "node_modules/lint-staged": { - "version": "15.0.2", - "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.0.2.tgz", - "integrity": "sha512-vnEy7pFTHyVuDmCAIFKR5QDO8XLVlPFQQyujQ/STOxe40ICWqJ6knS2wSJ/ffX/Lw0rz83luRDh+ET7toN+rOw==", + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "node_modules/lint-staged": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.1.0.tgz", + "integrity": "sha512-ZPKXWHVlL7uwVpy8OZ7YQjYDAuO5X4kMh0XgZvPNxLcCCngd0PO5jKQyy3+s4TL2EnHoIXIzP1422f/l3nZKMw==", + "dev": true, + "dependencies": { + "chalk": "5.3.0", + "commander": "11.1.0", + "debug": "4.3.4", + "execa": "8.0.1", + "lilconfig": "2.1.0", + "listr2": "7.0.2", + "micromatch": "4.0.5", + "pidtree": "0.6.0", + "string-argv": "0.3.2", + "yaml": "2.3.4" + }, + "bin": { + "lint-staged": "bin/lint-staged.js" + }, + "engines": { + "node": ">=18.12.0" + }, + "funding": { + "url": "https://opencollective.com/lint-staged" + } + }, + "node_modules/lint-staged/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "dev": true, + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/lint-staged/node_modules/commander": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", + "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", + "dev": true, + "engines": { + "node": ">=16" + } + }, + "node_modules/lint-staged/node_modules/execa": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", + "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^8.0.1", + "human-signals": "^5.0.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^3.0.0" + }, + "engines": { + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/lint-staged/node_modules/get-stream": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", + "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", + "dev": true, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lint-staged/node_modules/human-signals": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", + "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", + "dev": true, + "engines": { + "node": ">=16.17.0" + } + }, + "node_modules/lint-staged/node_modules/mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lint-staged/node_modules/onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", "dev": true, "dependencies": { - "chalk": "5.3.0", - "commander": "11.1.0", - "debug": "4.3.4", - "execa": "8.0.1", - "lilconfig": "2.1.0", - "listr2": "7.0.2", - "micromatch": "4.0.5", - "pidtree": "0.6.0", - "string-argv": "0.3.2", - "yaml": "2.3.3" - }, - "bin": { - "lint-staged": "bin/lint-staged.js" + "mimic-fn": "^4.0.0" }, "engines": { - "node": ">=18.12.0" + "node": ">=12" }, "funding": { - "url": "https://opencollective.com/lint-staged" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/lint-staged/node_modules/chalk": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", - "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "node_modules/lint-staged/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", "dev": true, "engines": { - "node": "^12.17.0 || ^14.13 || >=16.0.0" + "node": ">=14" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/listr2": { @@ -5971,6 +5874,79 @@ "node": ">=16.0.0" } }, + "node_modules/listr2/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/listr2/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/listr2/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/listr2/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/listr2/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/local-pkg": { "version": "0.4.3", "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.4.3.tgz", @@ -6036,87 +6012,87 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/log-symbols/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/log-update": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-5.0.1.tgz", + "integrity": "sha512-5UtUDQ/6edw4ofyljDNcOVJQ4c7OjDro4h3y8e1GQL5iYElYclVHJ3zeWchylvMaKnDbDilC8irOVyexnA/Slw==", "dev": true, "dependencies": { - "color-convert": "^2.0.1" + "ansi-escapes": "^5.0.0", + "cli-cursor": "^4.0.0", + "slice-ansi": "^5.0.0", + "strip-ansi": "^7.0.1", + "wrap-ansi": "^8.0.1" }, "engines": { - "node": ">=8" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/log-symbols/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/log-update/node_modules/ansi-escapes": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-5.0.0.tgz", + "integrity": "sha512-5GFMVX8HqE/TB+FuBJGuO5XG0WrsA6ptUqoODaT/n9mmUaZFkqnBueB4leqGBCmrUHnCnC4PCZTCd0E7QQ83bA==", "dev": true, "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "type-fest": "^1.0.2" }, "engines": { - "node": ">=10" + "node": ">=12" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/log-symbols/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/log-update/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, "engines": { - "node": ">=7.0.0" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, - "node_modules/log-symbols/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/log-symbols/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/log-update/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", "dev": true, "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/log-symbols/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/log-update/node_modules/cli-cursor": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-4.0.0.tgz", + "integrity": "sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==", "dev": true, "dependencies": { - "has-flag": "^4.0.0" + "restore-cursor": "^4.0.0" }, "engines": { - "node": ">=8" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/log-update": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/log-update/-/log-update-5.0.1.tgz", - "integrity": "sha512-5UtUDQ/6edw4ofyljDNcOVJQ4c7OjDro4h3y8e1GQL5iYElYclVHJ3zeWchylvMaKnDbDilC8irOVyexnA/Slw==", + "node_modules/log-update/node_modules/restore-cursor": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-4.0.0.tgz", + "integrity": "sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==", "dev": true, "dependencies": { - "ansi-escapes": "^5.0.0", - "cli-cursor": "^4.0.0", - "slice-ansi": "^5.0.0", - "strip-ansi": "^7.0.1", - "wrap-ansi": "^8.0.1" + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" }, "engines": { "node": "^12.20.0 || ^14.13.1 || >=16.0.0" @@ -6125,16 +6101,21 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/log-update/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "node_modules/log-update/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", "dev": true, + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, "engines": { "node": ">=12" }, "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/log-update/node_modules/strip-ansi": { @@ -6152,6 +6133,35 @@ "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, + "node_modules/log-update/node_modules/type-fest": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", + "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -6229,57 +6239,29 @@ "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", "dev": true, "engines": { - "node": ">= 8" - } - }, - "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dev": true, - "dependencies": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true, - "optional": true, - "peer": true, - "engines": { - "node": ">= 0.6" + "node": ">= 8" } }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", "dev": true, - "optional": true, - "peer": true, "dependencies": { - "mime-db": "1.52.0" + "braces": "^3.0.2", + "picomatch": "^2.3.1" }, "engines": { - "node": ">= 0.6" + "node": ">=8.6" } }, "node_modules/mimic-fn": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", - "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", "dev": true, "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=6" } }, "node_modules/min-indent": { @@ -6331,9 +6313,9 @@ "dev": true }, "node_modules/msw": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/msw/-/msw-2.0.4.tgz", - "integrity": "sha512-mYDt0cFUYHofXwLSRl5bbPQ7Tl0GmbH+GWE0HdxwzTHMUh5YCWs1n5FvHmVrNIJSylB9ZIKEjq1BK9MfKgEpgg==", + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/msw/-/msw-2.0.8.tgz", + "integrity": "sha512-/5nQCotVka62lvubQ3tMfUS3TukyeBwvWyvAthcXvDlXGhkA/85HlEwZyFlJ3ZsPW45Ty+ao0S4oFvuM12R/kA==", "dev": true, "hasInstallScript": true, "dependencies": { @@ -6341,7 +6323,7 @@ "@bundled-es-modules/js-levenshtein": "^2.0.1", "@bundled-es-modules/statuses": "^1.0.1", "@mswjs/cookies": "^1.1.0", - "@mswjs/interceptors": "^0.25.10", + "@mswjs/interceptors": "^0.25.11", "@open-draft/until": "^2.1.0", "@types/cookie": "^0.4.1", "@types/js-levenshtein": "^1.1.1", @@ -6353,7 +6335,6 @@ "inquirer": "^8.2.0", "is-node-process": "^1.2.0", "js-levenshtein": "^1.1.6", - "node-fetch": "^2.6.7", "outvariant": "^1.4.0", "path-to-regexp": "^6.2.0", "strict-event-emitter": "^0.5.0", @@ -6379,88 +6360,6 @@ } } }, - "node_modules/msw/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/msw/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/msw/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/msw/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/msw/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/msw/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/msw/node_modules/type-fest": { - "version": "2.19.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", - "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", - "dev": true, - "engines": { - "node": ">=12.20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/mute-stream": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", @@ -6479,10 +6378,9 @@ } }, "node_modules/nanoid": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", - "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", - "dev": true, + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", "funding": [ { "type": "github", @@ -6502,46 +6400,59 @@ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, - "node_modules/node-fetch": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", - "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", - "dev": true, + "node_modules/next": { + "version": "14.0.3", + "resolved": "https://registry.npmjs.org/next/-/next-14.0.3.tgz", + "integrity": "sha512-AbYdRNfImBr3XGtvnwOxq8ekVCwbFTv/UJoLwmaX89nk9i051AEY4/HAWzU0YpaTDw8IofUpmuIlvzWF13jxIw==", "dependencies": { - "whatwg-url": "^5.0.0" + "@next/env": "14.0.3", + "@swc/helpers": "0.5.2", + "busboy": "1.6.0", + "caniuse-lite": "^1.0.30001406", + "postcss": "8.4.31", + "styled-jsx": "5.1.1", + "watchpack": "2.4.0" + }, + "bin": { + "next": "dist/bin/next" }, "engines": { - "node": "4.x || >=6.0.0" + "node": ">=18.17.0" + }, + "optionalDependencies": { + "@next/swc-darwin-arm64": "14.0.3", + "@next/swc-darwin-x64": "14.0.3", + "@next/swc-linux-arm64-gnu": "14.0.3", + "@next/swc-linux-arm64-musl": "14.0.3", + "@next/swc-linux-x64-gnu": "14.0.3", + "@next/swc-linux-x64-musl": "14.0.3", + "@next/swc-win32-arm64-msvc": "14.0.3", + "@next/swc-win32-ia32-msvc": "14.0.3", + "@next/swc-win32-x64-msvc": "14.0.3" }, "peerDependencies": { - "encoding": "^0.1.0" + "@opentelemetry/api": "^1.1.0", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "sass": "^1.3.0" }, "peerDependenciesMeta": { - "encoding": { + "@opentelemetry/api": { + "optional": true + }, + "sass": { "optional": true } } }, - "node_modules/node-fetch/node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", - "dev": true - }, - "node_modules/node-fetch/node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", - "dev": true - }, - "node_modules/node-fetch/node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "dev": true, - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" + "node_modules/next-redux-wrapper": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/next-redux-wrapper/-/next-redux-wrapper-8.1.0.tgz", + "integrity": "sha512-2hIau0hcI6uQszOtrvAFqgc0NkZegKYhBB7ZAKiG3jk7zfuQb4E7OV9jfxViqqojh3SEHdnFfPkN9KErttUKuw==", + "peerDependencies": { + "next": ">=9", + "react": "*", + "react-redux": "*" } }, "node_modules/node-releases": { @@ -6595,14 +6506,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/nwsapi": { - "version": "2.2.7", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.7.tgz", - "integrity": "sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ==", - "dev": true, - "optional": true, - "peer": true - }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -6755,15 +6658,15 @@ } }, "node_modules/onetime": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", - "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", "dev": true, "dependencies": { - "mimic-fn": "^4.0.0" + "mimic-fn": "^2.1.0" }, "engines": { - "node": ">=12" + "node": ">=6" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -6815,141 +6718,16 @@ "cli-cursor": "^3.1.0", "cli-spinners": "^2.5.0", "is-interactive": "^1.0.0", - "is-unicode-supported": "^0.1.0", - "log-symbols": "^4.1.0", - "strip-ansi": "^6.0.0", - "wcwidth": "^1.0.1" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ora/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/ora/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/ora/node_modules/cli-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", - "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", - "dev": true, - "dependencies": { - "restore-cursor": "^3.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/ora/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/ora/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/ora/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/ora/node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/ora/node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ora/node_modules/restore-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", - "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", - "dev": true, - "dependencies": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/ora/node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, - "node_modules/ora/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" }, "engines": { - "node": ">=8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/os-tmpdir": { @@ -7009,20 +6787,6 @@ "node": ">=6" } }, - "node_modules/parse5": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", - "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "entities": "^4.4.0" - }, - "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" - } - }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -7089,8 +6853,7 @@ "node_modules/picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" }, "node_modules/picomatch": { "version": "2.3.1", @@ -7149,7 +6912,6 @@ "version": "8.4.31", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", - "dev": true, "funding": [ { "type": "opencollective", @@ -7210,21 +6972,27 @@ } }, "node_modules/postcss-load-config": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.1.tgz", - "integrity": "sha512-vEJIc8RdiBRu3oRAI0ymerOn+7rPuMvRXslTvZUKZonDHFIczxztIyJ1urxM1x9JXEikvpWWTUUqal5j/8QgvA==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz", + "integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==", "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "dependencies": { - "lilconfig": "^2.0.5", - "yaml": "^2.1.1" + "lilconfig": "^3.0.0", + "yaml": "^2.3.4" }, "engines": { "node": ">= 14" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, "peerDependencies": { "postcss": ">=8.0.9", "ts-node": ">=9.0.0" @@ -7238,6 +7006,15 @@ } } }, + "node_modules/postcss-load-config/node_modules/lilconfig": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.0.0.tgz", + "integrity": "sha512-K2U4W2Ff5ibV7j7ydLr+zLAkIg5JJ4lPn1Ltsdt+Tz/IjQ8buJ55pZAxoP34lqIiwtF9iAvtLv3JGv7CAyAg+g==", + "dev": true, + "engines": { + "node": ">=14" + } + }, "node_modules/postcss-nested": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.1.tgz", @@ -7286,9 +7063,9 @@ } }, "node_modules/prettier": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.3.tgz", - "integrity": "sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.1.0.tgz", + "integrity": "sha512-TQLvXjq5IAibjh8EpBIkNKxO749UEWABoiIZehEPiY4GNpVdhaFKqSTu+QrlU6D2dPAfubRmtJTi4K4YkQ5eXw==", "dev": true, "bin": { "prettier": "bin/prettier.cjs" @@ -7313,9 +7090,9 @@ } }, "node_modules/prettier-plugin-tailwindcss": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/prettier-plugin-tailwindcss/-/prettier-plugin-tailwindcss-0.5.6.tgz", - "integrity": "sha512-2Xgb+GQlkPAUCFi3sV+NOYcSI5XgduvDBL2Zt/hwJudeKXkyvRS65c38SB0yb9UB40+1rL83I6m0RtlOQ8eHdg==", + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/prettier-plugin-tailwindcss/-/prettier-plugin-tailwindcss-0.5.7.tgz", + "integrity": "sha512-4v6uESAgwCni6YF6DwJlRaDjg9Z+al5zM4JfngcazMy4WEf/XkPS5TEQjbD+DZ5iNuG6RrKQLa/HuX2SYzC3kQ==", "dev": true, "engines": { "node": ">=14.21.3" @@ -7385,17 +7162,17 @@ } }, "node_modules/pretty-format": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", - "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", "dev": true, "dependencies": { - "@jest/schemas": "^29.6.3", + "ansi-regex": "^5.0.1", "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" + "react-is": "^17.0.1" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, "node_modules/pretty-format/node_modules/ansi-styles": { @@ -7410,12 +7187,6 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/pretty-format/node_modules/react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", - "dev": true - }, "node_modules/prop-types": { "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", @@ -7427,31 +7198,21 @@ "react-is": "^16.13.1" } }, - "node_modules/psl": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", - "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", - "dev": true, - "optional": true, - "peer": true + "node_modules/prop-types/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "dev": true }, "node_modules/punycode": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", - "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true, "engines": { "node": ">=6" } }, - "node_modules/querystringify": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", - "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", - "dev": true, - "optional": true, - "peer": true - }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -7496,9 +7257,10 @@ } }, "node_modules/react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true }, "node_modules/react-redux": { "version": "8.1.3", @@ -7552,36 +7314,6 @@ "node": ">=0.10.0" } }, - "node_modules/react-router": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.18.0.tgz", - "integrity": "sha512-vk2y7Dsy8wI02eRRaRmOs9g2o+aE72YCx5q9VasT1N9v+lrdB79tIqrjMfByHiY5+6aYkH2rUa5X839nwWGPDg==", - "dependencies": { - "@remix-run/router": "1.11.0" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "react": ">=16.8" - } - }, - "node_modules/react-router-dom": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.18.0.tgz", - "integrity": "sha512-Ubrue4+Ercc/BoDkFQfc6og5zRQ4A8YxSO3Knsne+eRbZ+IepAsK249XBH/XaFuOYOYr3L3r13CXTLvYt5JDjw==", - "dependencies": { - "@remix-run/router": "1.11.0", - "react-router": "6.18.0" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "react": ">=16.8", - "react-dom": ">=16.8" - } - }, "node_modules/read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", @@ -7697,14 +7429,6 @@ "node": ">=0.10.0" } }, - "node_modules/requires-port": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", - "dev": true, - "optional": true, - "peer": true - }, "node_modules/reselect": { "version": "4.1.8", "resolved": "https://registry.npmjs.org/reselect/-/reselect-4.1.8.tgz", @@ -7746,51 +7470,18 @@ } }, "node_modules/restore-cursor": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-4.0.0.tgz", - "integrity": "sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", "dev": true, "dependencies": { "onetime": "^5.1.0", "signal-exit": "^3.0.2" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/restore-cursor/node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/restore-cursor/node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=8" } }, - "node_modules/restore-cursor/node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, "node_modules/reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", @@ -7823,29 +7514,33 @@ } }, "node_modules/rollup": { - "version": "3.29.4", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz", - "integrity": "sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==", + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.5.1.tgz", + "integrity": "sha512-0EQribZoPKpb5z1NW/QYm3XSR//Xr8BeEXU49Lc/mQmpmVVG5jPUVrpc2iptup/0WMrY9mzas0fxH+TjYvG2CA==", "dev": true, "bin": { "rollup": "dist/bin/rollup" }, "engines": { - "node": ">=14.18.0", + "node": ">=18.0.0", "npm": ">=8.0.0" }, "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.5.1", + "@rollup/rollup-android-arm64": "4.5.1", + "@rollup/rollup-darwin-arm64": "4.5.1", + "@rollup/rollup-darwin-x64": "4.5.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.5.1", + "@rollup/rollup-linux-arm64-gnu": "4.5.1", + "@rollup/rollup-linux-arm64-musl": "4.5.1", + "@rollup/rollup-linux-x64-gnu": "4.5.1", + "@rollup/rollup-linux-x64-musl": "4.5.1", + "@rollup/rollup-win32-arm64-msvc": "4.5.1", + "@rollup/rollup-win32-ia32-msvc": "4.5.1", + "@rollup/rollup-win32-x64-msvc": "4.5.1", "fsevents": "~2.3.2" } }, - "node_modules/rrweb-cssom": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz", - "integrity": "sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==", - "dev": true, - "optional": true, - "peer": true - }, "node_modules/run-applescript": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-5.0.0.tgz", @@ -7884,18 +7579,6 @@ "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, - "node_modules/run-applescript/node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/run-applescript/node_modules/human-signals": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", @@ -7917,15 +7600,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/run-applescript/node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/run-applescript/node_modules/npm-run-path": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", @@ -7938,27 +7612,6 @@ "node": ">=8" } }, - "node_modules/run-applescript/node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/run-applescript/node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, "node_modules/run-applescript/node_modules/strip-final-newline": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", @@ -8067,20 +7720,6 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true }, - "node_modules/saxes": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", - "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "xmlchars": "^2.2.0" - }, - "engines": { - "node": ">=v12.22.7" - } - }, "node_modules/scheduler": { "version": "0.23.0", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", @@ -8193,16 +7832,10 @@ "dev": true }, "node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true }, "node_modules/slash": { "version": "3.0.0", @@ -8241,6 +7874,18 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/slice-ansi/node_modules/is-fullwidth-code-point": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", + "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/smoothscroll-polyfill": { "version": "0.4.4", "resolved": "https://registry.npmjs.org/smoothscroll-polyfill/-/smoothscroll-polyfill-0.4.4.tgz", @@ -8259,7 +7904,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -8280,9 +7924,9 @@ } }, "node_modules/std-env": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.4.3.tgz", - "integrity": "sha512-f9aPhy8fYBuMN+sNfakZV18U39PbalgjXG3lLB9WkaYTxijru61wb57V9wxxNthXM5Sd88ETBWi29qLAsHO52Q==", + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.5.0.tgz", + "integrity": "sha512-JGUEaALvL0Mf6JCfYnJOTcobY+Nc7sG/TemDRBqCA0wEr4DER7zDchaaixTlmOxAjG1uRJmX82EQcxwTQTkqVA==", "dev": true }, "node_modules/stop-iteration-iterator": { @@ -8297,74 +7941,58 @@ "node": ">= 0.4" } }, + "node_modules/streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/strict-event-emitter": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/strict-event-emitter/-/strict-event-emitter-0.5.1.tgz", "integrity": "sha512-vMgjE/GGEPEFnhFub6pa4FmJBRBVOLpIII2hvCZ8Kzb7K0hlHo7mQv6xYrBvCL2LtAIBwFUK8wvuJgTVSQ5MFQ==", "dev": true }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dev": true, - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "node_modules/string-argv": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz", - "integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==", - "dev": true, - "engines": { - "node": ">=0.6.19" - } - }, - "node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dev": true, - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.2.0" } }, - "node_modules/string-width/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "node_modules/string-argv": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz", + "integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==", "dev": true, "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" + "node": ">=0.6.19" } }, - "node_modules/string-width/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "dependencies": { - "ansi-regex": "^6.0.1" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" }, "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" + "node": ">=8" } }, + "node_modules/string-width/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, "node_modules/string.prototype.matchall": { "version": "4.0.10", "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.10.tgz", @@ -8499,6 +8127,28 @@ "url": "https://github.com/sponsors/antfu" } }, + "node_modules/styled-jsx": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.1.tgz", + "integrity": "sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==", + "dependencies": { + "client-only": "0.0.1" + }, + "engines": { + "node": ">= 12.0.0" + }, + "peerDependencies": { + "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "babel-plugin-macros": { + "optional": true + } + } + }, "node_modules/sucrase": { "version": "3.34.0", "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.34.0.tgz", @@ -8521,15 +8171,6 @@ "node": ">=8" } }, - "node_modules/sucrase/node_modules/commander": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", - "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, "node_modules/sucrase/node_modules/glob": { "version": "7.1.6", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", @@ -8551,15 +8192,15 @@ } }, "node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "dependencies": { - "has-flag": "^3.0.0" + "has-flag": "^4.0.0" }, "engines": { - "node": ">=4" + "node": ">=8" } }, "node_modules/supports-preserve-symlinks-flag": { @@ -8574,14 +8215,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/symbol-tree": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", - "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", - "dev": true, - "optional": true, - "peer": true - }, "node_modules/synckit": { "version": "0.8.5", "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.5.tgz", @@ -8777,37 +8410,6 @@ "node": ">=8.0" } }, - "node_modules/tough-cookie": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz", - "integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "psl": "^1.1.33", - "punycode": "^2.1.1", - "universalify": "^0.2.0", - "url-parse": "^1.5.3" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/tr46": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-4.1.1.tgz", - "integrity": "sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "punycode": "^2.3.0" - }, - "engines": { - "node": ">=14" - } - }, "node_modules/ts-api-utils": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.3.tgz", @@ -8853,8 +8455,7 @@ "node_modules/tslib": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", - "dev": true + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" }, "node_modules/type-check": { "version": "0.4.0", @@ -8878,12 +8479,12 @@ } }, "node_modules/type-fest": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", - "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", "dev": true, "engines": { - "node": ">=10" + "node": ">=12.20" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -8968,9 +8569,9 @@ } }, "node_modules/ufo": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.3.1.tgz", - "integrity": "sha512-uY/99gMLIOlJPwATcMVYfqDSxUR9//AUcgZMzwfSTJPDKzA1S8mX4VLqa+fiAtveraQUBCz4FFcwVZBGbwBXIw==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.3.2.tgz", + "integrity": "sha512-o+ORpgGwaYQXgqGDwd+hkS4PuZ3QnmqMMxRuajK/a38L6fTpcE5GPIfrf+L/KemFzfUpeUQc1rRS1iDBozvnFA==", "dev": true }, "node_modules/unbox-primitive": { @@ -8994,17 +8595,6 @@ "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", "dev": true }, - "node_modules/universalify": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", - "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", - "dev": true, - "optional": true, - "peer": true, - "engines": { - "node": ">= 4.0.0" - } - }, "node_modules/untildify": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", @@ -9053,18 +8643,6 @@ "punycode": "^2.1.0" } }, - "node_modules/url-parse": { - "version": "1.5.10", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", - "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "querystringify": "^2.1.1", - "requires-port": "^1.0.0" - } - }, "node_modules/use-sync-external-store": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", @@ -9073,6 +8651,15 @@ "react": "^16.8.0 || ^17.0.0 || ^18.0.0" } }, + "node_modules/use-view-transitions": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/use-view-transitions/-/use-view-transitions-1.0.16.tgz", + "integrity": "sha512-6suGH0QsKUCLXQqs9uRV6gL4TxNS3eTRT/uPpYQRZ7rh7sJw0ULm+8ZAJfUsaWRSKumKC4Yg6763do9m1MXI+w==", + "peerDependencies": { + "react": "^18.2.0", + "react-dom": "^18.2.0" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -9080,9 +8667,9 @@ "dev": true }, "node_modules/v8-to-istanbul": { - "version": "9.1.3", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.1.3.tgz", - "integrity": "sha512-9lDD+EVI2fjFsMWXc6dy5JJzBsVTcQ2fVkfBvncZ6xJWG9wtBhOldG+mHkSL0+V1K/xgZz0JDO5UT5hFwHUghg==", + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.2.0.tgz", + "integrity": "sha512-/EH/sDgxU2eGxajKdwLCDmQ4FWq+kpi3uCmBGpw1xJtnAxEjlD8j8PEiGWpCIMIs3ciNAgH0d3TTJiUkYzyZjA==", "dev": true, "dependencies": { "@jridgewell/trace-mapping": "^0.3.12", @@ -9105,29 +8692,29 @@ } }, "node_modules/vite": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.0.tgz", - "integrity": "sha512-ulr8rNLA6rkyFAlVWw2q5YJ91v098AFQ2R0PRFwPzREXOUJQPtFUG0t+/ZikhaOCDqFoDhN6/v8Sq0o4araFAw==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.0.2.tgz", + "integrity": "sha512-6CCq1CAJCNM1ya2ZZA7+jS2KgnhbzvxakmlIjN24cF/PXhRMzpM/z8QgsVJA/Dm5fWUWnVEsmtBoMhmerPxT0g==", "dev": true, "dependencies": { - "esbuild": "^0.18.10", - "postcss": "^8.4.27", - "rollup": "^3.27.1" + "esbuild": "^0.19.3", + "postcss": "^8.4.31", + "rollup": "^4.2.0" }, "bin": { "vite": "bin/vite.js" }, "engines": { - "node": "^14.18.0 || >=16.0.0" + "node": "^18.0.0 || >=20.0.0" }, "funding": { "url": "https://github.com/vitejs/vite?sponsor=1" }, "optionalDependencies": { - "fsevents": "~2.3.2" + "fsevents": "~2.3.3" }, "peerDependencies": { - "@types/node": ">= 14", + "@types/node": "^18.0.0 || >=20.0.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", @@ -9259,18 +8846,16 @@ } } }, - "node_modules/w3c-xmlserializer": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz", - "integrity": "sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==", - "dev": true, - "optional": true, - "peer": true, + "node_modules/watchpack": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", + "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", "dependencies": { - "xml-name-validator": "^4.0.0" + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" }, "engines": { - "node": ">=14" + "node": ">=10.13.0" } }, "node_modules/wcwidth": { @@ -9287,8 +8872,6 @@ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", "dev": true, - "optional": true, - "peer": true, "engines": { "node": ">=12" } @@ -9298,8 +8881,6 @@ "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz", "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==", "dev": true, - "optional": true, - "peer": true, "dependencies": { "iconv-lite": "0.6.3" }, @@ -9312,27 +8893,10 @@ "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz", "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==", "dev": true, - "optional": true, - "peer": true, "engines": { "node": ">=12" } }, - "node_modules/whatwg-url": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-12.0.1.tgz", - "integrity": "sha512-Ed/LrqB8EPlGxjS+TrsXcpUond1mhccS3pchLhzSgPCnTimUCKj3IZE75pAs5m6heB2U2TMerKFUXheyHY+VDQ==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "tr46": "^4.1.1", - "webidl-conversions": "^7.0.0" - }, - "engines": { - "node": ">=14" - } - }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -9441,59 +9005,17 @@ } }, "node_modules/wrap-ansi": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", "dev": true, "dependencies": { - "ansi-regex": "^6.0.1" + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" }, "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" + "node": ">=8" } }, "node_modules/wrappy": { @@ -9502,48 +9024,6 @@ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "dev": true }, - "node_modules/ws": { - "version": "8.14.2", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.14.2.tgz", - "integrity": "sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g==", - "dev": true, - "optional": true, - "peer": true, - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/xml-name-validator": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", - "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==", - "dev": true, - "optional": true, - "peer": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/xmlchars": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", - "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", - "dev": true, - "optional": true, - "peer": true - }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", @@ -9560,9 +9040,9 @@ "dev": true }, "node_modules/yaml": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.3.tgz", - "integrity": "sha512-zw0VAJxgeZ6+++/su5AFoqBbZbrEakwu+X0M5HmcwUiBL7AzcuPKjj5we4xfQLp78LkEMpD0cOnUhmgOVy3KdQ==", + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.4.tgz", + "integrity": "sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==", "dev": true, "engines": { "node": ">= 14" @@ -9595,35 +9075,6 @@ "node": ">=12" } }, - "node_modules/yargs/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/yargs/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/yargs/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", diff --git a/package.json b/package.json index 220fd1ca..1318b917 100644 --- a/package.json +++ b/package.json @@ -1,15 +1,14 @@ { "name": "cinemania", + "version": "0.1.0", "private": true, - "version": "0.0.0", - "type": "module", "scripts": { - "dev": "vite --host", - "build": "tsc && vite build", - "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0", - "preview": "vite preview", + "dev": "next dev --turbo", + "build": "next build", + "start": "next start", + "lint": "next lint", "type-check": "tsc --noEmit", - "format": "prettier --write \"src/**/*.{ts,tsx,css}\"", + "format": "prettier --write \"./**/*.{ts,tsx,css}\"", "prepare": "husky install", "precommit": "npx lint-staged && npm run type-check", "test": "vitest", @@ -22,52 +21,51 @@ "animejs": "^3.2.1", "clsx": "^2.0.0", "locomotive-scroll": "^4.1.4", - "react": "^18.2.0", - "react-dom": "^18.2.0", + "next": "14.0.3", + "next-redux-wrapper": "^8.1.0", + "react": "^18", + "react-dom": "^18", "react-redux": "^8.1.3", - "react-router-dom": "^6.18.0", "redux": "^4.2.1", - "tailwind-merge": "^2.0.0" + "tailwind-merge": "^2.0.0", + "use-view-transitions": "^1.0.16" }, "devDependencies": { - "@edge-runtime/vm": "^3.1.7", "@testing-library/dom": "^9.3.3", "@testing-library/jest-dom": "^6.1.4", "@testing-library/react": "^14.1.2", "@testing-library/user-event": "^14.5.1", - "@types/animejs": "^3.1.11", - "@types/deep-equal": "^1.0.4", - "@types/locomotive-scroll": "^4.1.2", - "@types/react": "^18.2.15", - "@types/react-dom": "^18.2.7", - "@types/react-redux": "^7.1.30", - "@typescript-eslint/eslint-plugin": "^6.0.0", - "@typescript-eslint/parser": "^6.0.0", - "@vitejs/plugin-react": "^4.0.3", + "@types/animejs": "^3.1.12", + "@types/locomotive-scroll": "^4.1.3", + "@types/node": "^20", + "@types/react": "^18", + "@types/react-dom": "^18", + "@vitejs/plugin-react": "^4.2.0", "@vitest/coverage-v8": "^0.34.6", - "autoprefixer": "^10.4.16", - "eslint": "^8.50.0", + "autoprefixer": "^10.0.1", + "eslint": "^8", "eslint-config-airbnb": "^19.0.4", "eslint-config-airbnb-base": "^15.0.0", "eslint-config-airbnb-typescript": "^17.1.0", + "eslint-config-next": "14.0.3", "eslint-config-prettier": "^9.0.0", "eslint-import-resolver-typescript": "^3.6.1", - "eslint-plugin-import": "^2.28.1", - "eslint-plugin-jsx-a11y": "^6.7.1", - "eslint-plugin-prettier": "^5.0.0", + "eslint-plugin-import": "^2.29.0", + "eslint-plugin-jsx-a11y": "^6.8.0", + "eslint-plugin-prettier": "^5.0.1", "eslint-plugin-react": "^7.33.2", "eslint-plugin-react-hooks": "^4.6.0", - "eslint-plugin-react-refresh": "^0.4.3", + "eslint-plugin-react-refresh": "^0.4.4", "eslint-plugin-simple-import-sort": "^10.0.0", + "happy-dom": "^12.10.3", "husky": "^8.0.3", - "lint-staged": "^15.0.2", - "msw": "^2.0.4", - "postcss": "^8.4.30", - "prettier": "^3.0.3", - "prettier-plugin-tailwindcss": "^0.5.4", - "tailwindcss": "^3.3.3", - "typescript": "^5.2.2", - "vite": "^4.4.9", + "lint-staged": "^15.1.0", + "msw": "^2.0.8", + "postcss": "^8", + "prettier": "^3.1.0", + "prettier-plugin-tailwindcss": "^0.5.7", + "tailwindcss": "^3.3.0", + "typescript": "^5", "vitest": "^0.34.6" } } diff --git a/src/pages/NotFound/NotFound.tsx b/pages/404.tsx similarity index 57% rename from src/pages/NotFound/NotFound.tsx rename to pages/404.tsx index 4fefb5ce..90334adc 100644 --- a/src/pages/NotFound/NotFound.tsx +++ b/pages/404.tsx @@ -1,13 +1,11 @@ -import LinkWithQuery from '../../shared/ui/LinkWithQuery.tsx'; -import Modal from '../../shared/ui/Modal.tsx'; -import GradientBackground from '../AppLayout/ui/GradientBackground.tsx'; +import LinkWithQuery from '@shared/ui/LinkWithQuery'; +import Modal from '@shared/ui/Modal'; -function NotFound() { +function Custom404() { return (
    -

    Page not found β›” @@ -15,7 +13,7 @@ function NotFound() {

    We're sorry, the page you are looking for does not exist

    - + Go back @@ -23,4 +21,4 @@ function NotFound() { ); } -export default NotFound; +export default Custom404; diff --git a/pages/[id]/index.tsx b/pages/[id]/index.tsx new file mode 100644 index 00000000..644f3264 --- /dev/null +++ b/pages/[id]/index.tsx @@ -0,0 +1,26 @@ +import { movieApi } from '@entities/movie/api/movieApi'; +import { getRunningQueriesThunk } from '@shared/api/rootApi'; +import MovieDetails from '@widgets/MovieDetails/MovieDetails'; +import { GetServerSidePropsContext } from 'next'; + +import { wrapper } from '../../app/store/store'; + +export const getServerSideProps = wrapper.getServerSideProps( + (store) => + async ({ params }: GetServerSidePropsContext) => { + const id = params?.id; + + if (id) { + store.dispatch(movieApi.endpoints.getMovie.initiate(id as string)); + await Promise.all(store.dispatch(getRunningQueriesThunk())); + } + + return { props: {} }; + }, +); + +function Details() { + return ; +} + +export default Details; diff --git a/pages/_app.tsx b/pages/_app.tsx new file mode 100644 index 00000000..47737a21 --- /dev/null +++ b/pages/_app.tsx @@ -0,0 +1,43 @@ +import type { AppProps } from 'next/app'; +import { useRouter } from 'next/router'; +import { useNextRouterViewTransitions } from 'use-view-transitions/next'; + +import { UseNextRouterViewTransitionsProps } from '@customTypes/interfaces'; +import SmoothScrollProvider from '@entities/scroll/context/smoothScroll'; +import ErrorBoundary from '@shared/ui/ErrorBoundary'; +import FallbackUi from '@shared/ui/FallbackUi'; +import AppLayout from '@widgets/AppLayout/AppLayout'; +import { Provider } from 'react-redux'; + +import { wrapper } from '../app/store/store'; + +import '@styles/globals.css'; + +function App({ Component, ...rest }: AppProps) { + const { store, props } = wrapper.useWrappedStore(rest); + const { pageProps } = props; + const router = useRouter(); + useNextRouterViewTransitions(router as UseNextRouterViewTransitionsProps); + + return ( + }> + + + + + + + + + ); +} + +export default App; diff --git a/pages/_document.tsx b/pages/_document.tsx new file mode 100644 index 00000000..9d1b5ee4 --- /dev/null +++ b/pages/_document.tsx @@ -0,0 +1,13 @@ +import { Head, Html, Main, NextScript } from 'next/document'; + +export default function Document() { + return ( + + + +
    + + + + ); +} diff --git a/pages/index.tsx b/pages/index.tsx new file mode 100644 index 00000000..d5c8105b --- /dev/null +++ b/pages/index.tsx @@ -0,0 +1,35 @@ +import { movieApi } from '@entities/movie/api/movieApi'; +import { getRunningQueriesThunk } from '@shared/api/rootApi'; +import { + DEFAULT_PAGE, + MOVIES_PER_PAGE, + QUERY_FALLBACK, +} from '@shared/const/const'; +import { GetServerSidePropsContext } from 'next'; + +import { wrapper } from '../app/store/store'; + +export const getServerSideProps = wrapper.getServerSideProps( + (store) => + async ({ + query: { page, search, moviesPerPage }, + }: GetServerSidePropsContext) => { + store.dispatch( + movieApi.endpoints.getMovieList.initiate({ + query: (search as string) || QUERY_FALLBACK, + page: (page as string) || String(DEFAULT_PAGE), + moviesPerPage: Number(moviesPerPage) || MOVIES_PER_PAGE, + }), + ); + + await Promise.all(store.dispatch(getRunningQueriesThunk())); + + return { props: {} }; + }, +); + +function Index() { + return null; +} + +export default Index; diff --git a/postcss.config.js b/postcss.config.js index 2aa7205d..33ad091d 100644 --- a/postcss.config.js +++ b/postcss.config.js @@ -1,6 +1,6 @@ -export default { +module.exports = { plugins: { tailwindcss: {}, autoprefixer: {}, }, -}; +} diff --git a/public/.gitkeep b/public/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/src/shared/api/baseQuery.ts b/shared/api/baseQuery.ts similarity index 73% rename from src/shared/api/baseQuery.ts rename to shared/api/baseQuery.ts index c28942c3..89fa3cfa 100644 --- a/src/shared/api/baseQuery.ts +++ b/shared/api/baseQuery.ts @@ -1,7 +1,7 @@ import { fetchBaseQuery } from '@reduxjs/toolkit/dist/query/react'; const baseQuery = fetchBaseQuery({ - baseUrl: `${import.meta.env.VITE_API_URL}`, + baseUrl: `${process.env.NEXT_PUBLIC_API_URL}`, }); export default baseQuery; diff --git a/shared/api/rootApi.ts b/shared/api/rootApi.ts new file mode 100644 index 00000000..7c21b59a --- /dev/null +++ b/shared/api/rootApi.ts @@ -0,0 +1,23 @@ +import { createApi } from '@reduxjs/toolkit/query/react'; + +import { HYDRATE } from 'next-redux-wrapper'; + +import baseQuery from './baseQuery'; + +const rootApi = createApi({ + reducerPath: 'rootApi', + baseQuery, + extractRehydrationInfo(action, { reducerPath }) { + if (action.type === HYDRATE) { + return action.payload[reducerPath]; + } + return undefined; + }, + endpoints: () => ({}), +}); + +export const { + util: { getRunningQueriesThunk }, +} = rootApi; + +export default rootApi; diff --git a/src/shared/const/const.ts b/shared/const/const.ts similarity index 78% rename from src/shared/const/const.ts rename to shared/const/const.ts index 96f6c510..f2f26356 100644 --- a/src/shared/const/const.ts +++ b/shared/const/const.ts @@ -1,8 +1,7 @@ -import { urlParams } from '../types/enums.ts'; +import { urlParams } from '../types/enums'; export const QUERY_FALLBACK = 'all'; export const NOT_EXIST = 'N/A'; -export const LOCAL_STORAGE_SEARCH_QUERY = 'search-query'; export const DEFAULT_PAGE = 1; export const MOVIES_PER_PAGE = 10; export const APP_TITLE = 'Cinemania | Dive into Movie Wonderland'; @@ -10,4 +9,5 @@ export const SCROLL_TOP_DURATION = 300; export const QUERY_PARAMS_INIT = { [urlParams.PAGE]: String(DEFAULT_PAGE), [urlParams.MOVIES_PER_PAGE]: String(MOVIES_PER_PAGE), + [urlParams.SEARCH]: QUERY_FALLBACK, }; diff --git a/src/shared/hooks/useAnime.ts b/shared/hooks/useAnime.ts similarity index 82% rename from src/shared/hooks/useAnime.ts rename to shared/hooks/useAnime.ts index 9ee074fb..592a7233 100644 --- a/src/shared/hooks/useAnime.ts +++ b/shared/hooks/useAnime.ts @@ -2,12 +2,10 @@ import { DependencyList, useEffect, useRef } from 'react'; -import { AnimeInstance } from 'animejs'; -import anime from 'animejs/lib/anime.es.js'; - -import reduceAnimeTargets from '../lib/helpers/reduceAnimeTargets.ts'; -import { IParams } from '../types/interfaces.ts'; -import { AnimeTarget } from '../types/types.ts'; +import { IParams } from '@customTypes/interfaces'; +import { AnimeTarget } from '@customTypes/types'; +import reduceAnimeTargets from '@shared/lib/helpers/reduceAnimeTargets'; +import anime, { AnimeInstance } from 'animejs'; /** * Applies anime.js animation to the element using the specified parameters and dependencies. diff --git a/src/shared/hooks/useAnimeTimeline.ts b/shared/hooks/useAnimeTimeline.ts similarity index 83% rename from src/shared/hooks/useAnimeTimeline.ts rename to shared/hooks/useAnimeTimeline.ts index fa548327..97035473 100644 --- a/src/shared/hooks/useAnimeTimeline.ts +++ b/shared/hooks/useAnimeTimeline.ts @@ -2,12 +2,10 @@ import { DependencyList, useEffect, useRef } from 'react'; -import { AnimeTimelineInstance } from 'animejs'; -import anime from 'animejs/lib/anime.es'; - -import reduceAnimeTargets from '../lib/helpers/reduceAnimeTargets.ts'; -import { IParams } from '../types/interfaces.ts'; -import { AnimeTarget } from '../types/types.ts'; +import { IParams } from '@customTypes/interfaces'; +import { AnimeTarget } from '@customTypes/types'; +import reduceAnimeTargets from '@shared/lib/helpers/reduceAnimeTargets'; +import anime, { AnimeTimelineInstance } from 'animejs'; interface IOptions { set?: { targets: AnimeTarget; values: { [key: string]: number } }[]; diff --git a/src/shared/hooks/useAppDispatch.ts b/shared/hooks/useAppDispatch.ts similarity index 70% rename from src/shared/hooks/useAppDispatch.ts rename to shared/hooks/useAppDispatch.ts index 7cd45114..5864b46c 100644 --- a/src/shared/hooks/useAppDispatch.ts +++ b/shared/hooks/useAppDispatch.ts @@ -1,6 +1,6 @@ import { useDispatch } from 'react-redux'; -import { AppDispatch } from '../../app/store/store.ts'; +import { AppDispatch } from '../../app/store/store'; const useAppDispatch = () => useDispatch(); export default useAppDispatch; diff --git a/src/shared/hooks/useAppSelector.ts b/shared/hooks/useAppSelector.ts similarity index 75% rename from src/shared/hooks/useAppSelector.ts rename to shared/hooks/useAppSelector.ts index a96e5db5..c3701118 100644 --- a/src/shared/hooks/useAppSelector.ts +++ b/shared/hooks/useAppSelector.ts @@ -1,6 +1,6 @@ import { TypedUseSelectorHook, useSelector } from 'react-redux'; -import { RootState } from '../../app/store/store.ts'; +import { RootState } from '../../app/store/store'; const useAppSelector: TypedUseSelectorHook = useSelector; export default useAppSelector; diff --git a/src/shared/hooks/useDispatchIsFetching.ts b/shared/hooks/useDispatchIsFetching.ts similarity index 71% rename from src/shared/hooks/useDispatchIsFetching.ts rename to shared/hooks/useDispatchIsFetching.ts index a904c19e..42d2848a 100644 --- a/src/shared/hooks/useDispatchIsFetching.ts +++ b/shared/hooks/useDispatchIsFetching.ts @@ -1,7 +1,7 @@ import { useEffect } from 'react'; -import useAppDispatch from './useAppDispatch.ts'; -import { dataFetchedMainPage } from '../../app/model/slice.ts'; +import useAppDispatch from './useAppDispatch'; +import { dataFetched } from '../../app/model/slice'; /** * Dispatches the `dataFetched` action with the given `isFetching` value. @@ -12,7 +12,7 @@ import { dataFetchedMainPage } from '../../app/model/slice.ts'; function useDispatchIsFetching(isFetching: boolean) { const dispatch = useAppDispatch(); useEffect(() => { - dispatch(dataFetchedMainPage(isFetching)); + dispatch(dataFetched(isFetching)); }, [dispatch, isFetching]); } diff --git a/src/shared/hooks/useDocumentTitle.ts b/shared/hooks/useDocumentTitle.ts similarity index 89% rename from src/shared/hooks/useDocumentTitle.ts rename to shared/hooks/useDocumentTitle.ts index 866ee06f..e25d0120 100644 --- a/src/shared/hooks/useDocumentTitle.ts +++ b/shared/hooks/useDocumentTitle.ts @@ -1,6 +1,6 @@ import { useEffect } from 'react'; -import { APP_TITLE } from '../const/const.ts'; +import { APP_TITLE } from '../const/const'; /** * Updates the document title when a new title is provided. diff --git a/shared/hooks/useGetMovie.ts b/shared/hooks/useGetMovie.ts new file mode 100644 index 00000000..af51dfaf --- /dev/null +++ b/shared/hooks/useGetMovie.ts @@ -0,0 +1,26 @@ +import { useRouter } from 'next/router'; + +import { useGetMovieQuery } from '@entities/movie/api/movieApi'; +import useDispatchIsFetching from '@shared/hooks/useDispatchIsFetching'; + +/** + * Retrieves movie data using the useGetMovieQuery hook and dispatches the isFetching state to the useDispatchIsFetching function. + * + * @returns {Object} obj - An object containing the movie data. + * @returns {ApiMovieResponse} obj.movie - The movie data. + */ +function useGetMovie() { + const { query } = useRouter(); + const id = (query?.id as string) ?? '1'; + const { data: movie, isLoading, isFetching } = useGetMovieQuery(id); + + useDispatchIsFetching(isLoading || isFetching); + + if (movie && 'Error' in movie) { + return null; + } + + return movie; +} + +export default useGetMovie; diff --git a/shared/hooks/useGetMovieList.test.tsx b/shared/hooks/useGetMovieList.test.tsx new file mode 100644 index 00000000..84569985 --- /dev/null +++ b/shared/hooks/useGetMovieList.test.tsx @@ -0,0 +1,38 @@ +import { ReactNode } from 'react'; + +import { renderHook, waitFor } from '@testing-library/react'; +import { RouterContext } from 'next/dist/shared/lib/router-context.shared-runtime'; + +import useGetMovieList from '@shared/hooks/useGetMovieList'; +import createMockRouter from '@test/helpers/createMockRouter'; +import { Provider } from 'react-redux'; +import { describe, expect, it } from 'vitest'; + +import { setupStore } from '../../app/store/store'; + +function wrapper({ children }: { children: ReactNode }) { + const store = setupStore(); + return ( + + {children} + + ); +} + +describe('useGetMovieList', () => { + it('should return movie list', async () => { + const { result } = renderHook(() => useGetMovieList(), { wrapper }); + + expect(result.current).toMatchObject({ + movieList: undefined, + totalResults: 0, + }); + + await waitFor(() => { + expect(result.current).toMatchObject({ + movieList: undefined, + totalResults: 0, + }); + }); + }); +}); diff --git a/shared/hooks/useGetMovieList.ts b/shared/hooks/useGetMovieList.ts new file mode 100644 index 00000000..f74cf84f --- /dev/null +++ b/shared/hooks/useGetMovieList.ts @@ -0,0 +1,35 @@ +import { urlParams } from '@customTypes/enums'; +import { MovieList } from '@customTypes/types'; +import { useGetMovieListQuery } from '@entities/movie/api/movieApi'; +import useDispatchIsFetching from '@shared/hooks/useDispatchIsFetching'; +import useUrl from '@shared/hooks/useUrl'; + +/** + * Retrieves a list of movies using the `useGetMovieListQuery` hook. + * + * @returns The list of movies fetched using the `useGetMovieListQuery` hook. + */ +function useGetMovieList() { + const { readUrl } = useUrl(); + + const page = readUrl(urlParams.PAGE); + const query = readUrl(urlParams.SEARCH); + const moviesPerPage = Number(readUrl(urlParams.MOVIES_PER_PAGE)); + + const { data, isLoading, isFetching } = useGetMovieListQuery({ + page, + query, + moviesPerPage, + }); + + const movieList = data?.Search?.slice(0, moviesPerPage) as + | MovieList + | undefined; + const totalResults = Number.parseInt(data?.totalResults ?? '0', 10); + + useDispatchIsFetching(isLoading || isFetching); + + return { movieList, totalResults }; +} + +export default useGetMovieList; diff --git a/src/shared/hooks/useKey.ts b/shared/hooks/useKey.ts similarity index 100% rename from src/shared/hooks/useKey.ts rename to shared/hooks/useKey.ts diff --git a/src/shared/hooks/useLocalStorageState.ts b/shared/hooks/useLocalStorageState.ts similarity index 78% rename from src/shared/hooks/useLocalStorageState.ts rename to shared/hooks/useLocalStorageState.ts index ad85956f..039bdc40 100644 --- a/src/shared/hooks/useLocalStorageState.ts +++ b/shared/hooks/useLocalStorageState.ts @@ -8,10 +8,12 @@ import { Dispatch, SetStateAction, useEffect, useState } from 'react'; * @return {[string, Dispatch>]} - An array containing the state value and a function to update the state. */ function useLocalStorageState(initialState: string, key: string) { - const storedValue = localStorage.getItem(key); - const init = storedValue || initialState; + const [value, setValue] = useState(initialState); - const [value, setValue] = useState(init); + useEffect(() => { + const storedValue = localStorage.getItem(key); + if (storedValue) setValue(storedValue); + }, [key]); useEffect(() => { localStorage.setItem(key, value); diff --git a/shared/hooks/useQueryParams.ts b/shared/hooks/useQueryParams.ts new file mode 100644 index 00000000..9bb31cda --- /dev/null +++ b/shared/hooks/useQueryParams.ts @@ -0,0 +1,35 @@ +import { useCallback } from 'react'; + +import { useRouter } from 'next/router'; + +function useQueryParams() { + const router = useRouter(); + + const setQuery = useCallback( + (key: string, value: number | string) => + router.push({ + ...router, + query: { + ...router.query, + [key]: String(value), + }, + }), + [router], + ); + + const deleteQuery = useCallback( + (param: string) => { + const query = { ...router.query }; + delete query[param]; + router.push({ + pathname: router.pathname, + query, + }); + }, + [router], + ); + + return { setQuery, deleteQuery }; +} + +export default useQueryParams; diff --git a/src/shared/hooks/useRadialHover.ts b/shared/hooks/useRadialHover.ts similarity index 99% rename from src/shared/hooks/useRadialHover.ts rename to shared/hooks/useRadialHover.ts index f8b85572..ad2548ef 100644 --- a/src/shared/hooks/useRadialHover.ts +++ b/shared/hooks/useRadialHover.ts @@ -1,6 +1,6 @@ import { MouseEvent, useRef } from 'react'; -import createRadialHover from '../lib/helpers/animateRadialHover.ts'; +import createRadialHover from '../lib/helpers/animateRadialHover'; /** * Attaches radial hover effect to a container element. diff --git a/src/shared/hooks/useScrollTop.ts b/shared/hooks/useScrollTop.ts similarity index 50% rename from src/shared/hooks/useScrollTop.ts rename to shared/hooks/useScrollTop.ts index 53340975..9f393c11 100644 --- a/src/shared/hooks/useScrollTop.ts +++ b/shared/hooks/useScrollTop.ts @@ -1,29 +1,25 @@ /* eslint-disable react-hooks/exhaustive-deps */ -import { DependencyList, RefObject, useEffect, useRef } from 'react'; +import { DependencyList, useEffect, useRef } from 'react'; -import LocomotiveScroll from 'locomotive-scroll'; +import useScroll from '@entities/scroll/hooks/useScroll'; -import { SCROLL_TOP_DURATION } from '../const/const.ts'; +import { SCROLL_TOP_DURATION } from '../const/const'; /** * Update scroll position to top when `currValue` changes. * * @param {unknown} currValue - The current value. - * @param {RefObject | undefined} scroll - The scroll reference. * @param {...DependencyList} deps - Additional dependencies. * @return {void} */ -function useScrollTop( - currValue: unknown, - scroll: RefObject | undefined, - ...deps: DependencyList -) { +function useScrollTop(currValue: unknown, ...deps: DependencyList) { + const { scroll } = useScroll(); const prevValueRef = useRef(currValue); useEffect(() => { if (prevValueRef.current !== currValue) { prevValueRef.current = currValue; - scroll?.current?.scrollTo?.('top', { duration: SCROLL_TOP_DURATION }); + scroll?.scrollTo?.('top', { duration: SCROLL_TOP_DURATION }); } }, [currValue, scroll, ...deps]); } diff --git a/src/shared/hooks/useTabs.ts b/shared/hooks/useTabs.ts similarity index 96% rename from src/shared/hooks/useTabs.ts rename to shared/hooks/useTabs.ts index c3f2587c..d7a260af 100644 --- a/src/shared/hooks/useTabs.ts +++ b/shared/hooks/useTabs.ts @@ -1,6 +1,6 @@ import { useEffect, useRef, useState } from 'react'; -import { itemsPerPage } from '../types/enums.ts'; +import { itemsPerPage } from '../types/enums'; /** * Sets the position of a slider tab based on the active value and number of tabs. diff --git a/src/shared/hooks/useTooltip.ts b/shared/hooks/useTooltip.ts similarity index 82% rename from src/shared/hooks/useTooltip.ts rename to shared/hooks/useTooltip.ts index 8d674e0f..63d4f17f 100644 --- a/src/shared/hooks/useTooltip.ts +++ b/shared/hooks/useTooltip.ts @@ -1,9 +1,8 @@ -import { RefObject, useCallback, useEffect, useRef } from 'react'; +import { useCallback, useEffect, useRef } from 'react'; -import LocomotiveScroll from 'locomotive-scroll'; - -import useAnime from './useAnime.ts'; -import getElementMouseCoord from '../lib/helpers/getElementMouseCoord.ts'; +import useScroll from '@entities/scroll/hooks/useScroll'; +import useAnime from '@shared/hooks/useAnime'; +import getElementMouseCoord from '@shared/lib/helpers/getElementMouseCoord'; const ELEMENT_POSITION_OFFSET = 120; @@ -11,14 +10,14 @@ const ELEMENT_POSITION_OFFSET = 120; * Floating tooltip bubble following the mouse. * The tooltip is displayed when the element is hovered and follows the mouse movement. * - * @param {RefObject} scroll - The reference to the LocomotiveScroll instance. Used to hide the tooltip on scroll * @return {Object} obj - An object containing the tooltip reference, hideTooltip function, and showTooltip function. * @return {HTMLDivElement} obj.tooltipRef - The ref with the tooltip element. * @return {() => void} obj.hideTooltip - Function that is used to hide the tooltip. For example on mouseLeave event. * @return {() => void} obj.showTooltip - Function that is used to show the tooltip. For example on mouseEnter event. */ -function useTooltip(scroll: RefObject) { +function useTooltip() { const tooltipRef = useRef(null); + const { scroll } = useScroll(); const { animation: showTooltipAnimation } = useAnime({ targets: tooltipRef, @@ -58,7 +57,7 @@ function useTooltip(scroll: RefObject) { }, [hideTooltipAnimation]); useEffect(() => { - scroll.current?.on?.('scroll', () => { + scroll?.on?.('scroll', () => { const isVisible = tooltipRef.current && getComputedStyle(tooltipRef.current).opacity === '1'; diff --git a/shared/hooks/useUrl.ts b/shared/hooks/useUrl.ts new file mode 100644 index 00000000..ca8be956 --- /dev/null +++ b/shared/hooks/useUrl.ts @@ -0,0 +1,59 @@ +import { useCallback } from 'react'; + +import { useRouter } from 'next/router'; + +import { UrlParams } from '@customTypes/types'; +import { QUERY_PARAMS_INIT } from '@shared/const/const'; +import useQueryParams from '@shared/hooks/useQueryParams'; + +type SetUrl = { + (query: UrlParams, value: string | number): void; + (multipleQueriesAndValues: Partial>): void; // used for multiple queries at once (to avoid multiple renders and to update history only once for proper history navigation) +}; + +type ReadUrl = (query: UrlParams) => string; + +/** + * Returns an object with two methods, `readUrl` and `setUrl`, that can be used to read and set URL parameters. + * + * @return obj + * @return {ReadUrl} obj.readUrl - A function that takes a query parameter and returns its value from the URL. + * @return {SetUrl} obj.setUrl - A function that takes a query parameter and its value and sets it in the URL. + */ +function useUrl() { + const router = useRouter(); + const { setQuery, deleteQuery } = useQueryParams(); + + const readUrl: ReadUrl = useCallback( + (queryKey: UrlParams) => + (router.query[queryKey as keyof typeof router] as string) ?? + QUERY_PARAMS_INIT[queryKey], + [router], + ); + + const setUrl: SetUrl = useCallback( + ( + query: UrlParams | Partial>, + value?: string | number, + ) => { + if (typeof query === 'object') { + Object.entries(query).forEach(([queryKey, queryValue]) => { + if (queryValue === '') { + deleteQuery(queryKey); + return; + } + void setQuery(queryKey, queryValue); + }); + } + + if (typeof query !== 'object' && value) { + void setQuery(query, value); + } + }, + [deleteQuery, setQuery], + ); + + return { readUrl, setUrl }; +} + +export default useUrl; diff --git a/src/shared/lib/helpers/addLeadingZero.ts b/shared/lib/helpers/addLeadingZero.ts similarity index 100% rename from src/shared/lib/helpers/addLeadingZero.ts rename to shared/lib/helpers/addLeadingZero.ts diff --git a/shared/lib/helpers/animateRadialHover.test.tsx b/shared/lib/helpers/animateRadialHover.test.tsx new file mode 100644 index 00000000..b5149afe --- /dev/null +++ b/shared/lib/helpers/animateRadialHover.test.tsx @@ -0,0 +1,11 @@ +import createRadialHover from '@shared/lib/helpers/animateRadialHover'; +import { describe, expect, it } from 'vitest'; + +describe('animateRadialHover', () => { + it('should create radial hover', async () => { + const [animateRadialHover, cleanUp] = createRadialHover(); + + expect(animateRadialHover).toBeDefined(); + expect(cleanUp).toBeDefined(); + }); +}); diff --git a/src/shared/lib/helpers/animateRadialHover.ts b/shared/lib/helpers/animateRadialHover.ts similarity index 85% rename from src/shared/lib/helpers/animateRadialHover.ts rename to shared/lib/helpers/animateRadialHover.ts index 4f0bfceb..a9439393 100644 --- a/src/shared/lib/helpers/animateRadialHover.ts +++ b/shared/lib/helpers/animateRadialHover.ts @@ -1,10 +1,13 @@ -import { MouseEvent } from 'react'; +import { MouseEvent as ReactMouseEvent } from 'react'; import colors from 'tailwindcss/colors'; -import getElementMouseCoord from './getElementMouseCoord.ts'; +import getElementMouseCoord from './getElementMouseCoord'; -type AnimationFn = (elem: HTMLElement, evt: MouseEvent) => void; +type AnimationFn = ( + elem: HTMLElement, + evt: MouseEvent | ReactMouseEvent, +) => void; type CleanUpFn = (elem: HTMLElement) => void; @@ -41,7 +44,10 @@ function animate( } } -function animateRadialHover(elem: HTMLElement, e: MouseEvent) { +function animateRadialHover( + elem: HTMLElement, + e: MouseEvent | ReactMouseEvent, +) { const { posX, posY } = getElementMouseCoord(elem, e); const startTimeStamp = performance.now(); pointerX = posX; diff --git a/src/shared/lib/helpers/cn.ts b/shared/lib/helpers/cn.ts similarity index 100% rename from src/shared/lib/helpers/cn.ts rename to shared/lib/helpers/cn.ts diff --git a/src/shared/lib/helpers/convertSecsToHrsAndMins.ts b/shared/lib/helpers/convertSecsToHrsAndMins.ts similarity index 91% rename from src/shared/lib/helpers/convertSecsToHrsAndMins.ts rename to shared/lib/helpers/convertSecsToHrsAndMins.ts index 1dd4959c..14136178 100644 --- a/src/shared/lib/helpers/convertSecsToHrsAndMins.ts +++ b/shared/lib/helpers/convertSecsToHrsAndMins.ts @@ -1,4 +1,4 @@ -import { ApiMovieResponse } from '../../types/types.ts'; +import { ApiMovieResponse } from '../../types/types'; /** * Converts the given runtime from seconds to hours and minutes format. diff --git a/shared/lib/helpers/getElementMouseCoord.test.ts b/shared/lib/helpers/getElementMouseCoord.test.ts new file mode 100644 index 00000000..812b11f6 --- /dev/null +++ b/shared/lib/helpers/getElementMouseCoord.test.ts @@ -0,0 +1,33 @@ +import getElementMouseCoord from '@shared/lib/helpers/getElementMouseCoord'; +import { describe, expect, it } from 'vitest'; + +const mockElem = document.createElement('div'); + +describe('getElementMouseCoord', () => { + it('should return mouse coordinates in the document', async () => { + const { posX, posY } = getElementMouseCoord( + mockElem, + new MouseEvent('mousemove', { clientX: 50, clientY: 150 }), + ); + + expect(posX).toBeDefined(); + expect(posY).toBeDefined(); + }); + + it('should properly calculate mouse coordinates in the document', async () => { + const mockCoords = { clientX: 999, clientY: 999 }; + + const { posX, posY } = getElementMouseCoord( + mockElem, + new MouseEvent('mousemove', { clientX: 999, clientY: 999 }), + ); + + const elemBCR = mockElem.getBoundingClientRect(); + + const testPosX = mockCoords.clientX - elemBCR.x; + const testPosY = mockCoords.clientY - elemBCR.y; + + expect(posX).toBe(testPosX); + expect(posY).toBe(testPosY); + }); +}); diff --git a/src/shared/lib/helpers/getElementMouseCoord.ts b/shared/lib/helpers/getElementMouseCoord.ts similarity index 100% rename from src/shared/lib/helpers/getElementMouseCoord.ts rename to shared/lib/helpers/getElementMouseCoord.ts diff --git a/src/shared/lib/helpers/reduceAnimeTargets.ts b/shared/lib/helpers/reduceAnimeTargets.ts similarity index 91% rename from src/shared/lib/helpers/reduceAnimeTargets.ts rename to shared/lib/helpers/reduceAnimeTargets.ts index a575e971..69b98795 100644 --- a/src/shared/lib/helpers/reduceAnimeTargets.ts +++ b/shared/lib/helpers/reduceAnimeTargets.ts @@ -1,7 +1,7 @@ import { RefObject } from 'react'; -import { IParams } from '../../types/interfaces.ts'; -import { AnimeTarget } from '../../types/types.ts'; +import { IParams } from '../../types/interfaces'; +import { AnimeTarget } from '../../types/types'; /** * Reduces the list of Anime.js targets based on the provided parameters. diff --git a/shared/lib/selectors/selectIsFetching.ts b/shared/lib/selectors/selectIsFetching.ts new file mode 100644 index 00000000..cb5e3c7f --- /dev/null +++ b/shared/lib/selectors/selectIsFetching.ts @@ -0,0 +1,10 @@ +import { createSelector } from '@reduxjs/toolkit'; + +import { RootState } from '../../../app/store/store'; + +const selectIsFetching = createSelector( + (state: RootState) => state.appReducer.isFetching, + (isFetching) => isFetching, +); + +export default selectIsFetching; diff --git a/src/shared/types/enums.ts b/shared/types/enums.ts similarity index 89% rename from src/shared/types/enums.ts rename to shared/types/enums.ts index 5573a79a..487abed4 100644 --- a/src/shared/types/enums.ts +++ b/shared/types/enums.ts @@ -7,4 +7,5 @@ export const itemsPerPage = { export const urlParams = { PAGE: 'page', MOVIES_PER_PAGE: 'movies-per-page', + SEARCH: 'search', } as const; diff --git a/src/shared/types/interfaces.ts b/shared/types/interfaces.ts similarity index 50% rename from src/shared/types/interfaces.ts rename to shared/types/interfaces.ts index 5bff7e29..2133b19b 100644 --- a/src/shared/types/interfaces.ts +++ b/shared/types/interfaces.ts @@ -2,7 +2,7 @@ import { ReactNode } from 'react'; import { AnimeParams } from 'animejs'; -import { AnimeTarget } from './types.ts'; +import { AnimeTarget } from './types'; export interface IChildren { children: ReactNode; @@ -11,3 +11,10 @@ export interface IChildren { export interface IParams extends Omit { targets?: AnimeTarget; } + +export interface UseNextRouterViewTransitionsProps { + events: { + on: (event: string, handler: () => void) => void; + off: (event: string, handler: () => void) => void; + }; +} diff --git a/src/shared/types/types.ts b/shared/types/types.ts similarity index 95% rename from src/shared/types/types.ts rename to shared/types/types.ts index 02352571..c25eca0b 100644 --- a/src/shared/types/types.ts +++ b/shared/types/types.ts @@ -1,6 +1,6 @@ import { RefObject } from 'react'; -import { itemsPerPage, urlParams } from './enums.ts'; +import { itemsPerPage, urlParams } from './enums'; export type Movie = Readonly<{ Poster: string; diff --git a/src/shared/ui/Button.tsx b/shared/ui/Button.tsx similarity index 77% rename from src/shared/ui/Button.tsx rename to shared/ui/Button.tsx index fe381f6e..21b54b05 100644 --- a/src/shared/ui/Button.tsx +++ b/shared/ui/Button.tsx @@ -1,9 +1,9 @@ import { ButtonHTMLAttributes, memo } from 'react'; -import useAppSelector from '../hooks/useAppSelector.ts'; -import cn from '../lib/helpers/cn.ts'; -import selectIsFetchingDetails from '../lib/selectors/selectIsFetchingDetails.ts'; -import selectIsFetchingMain from '../lib/selectors/selectIsFetchingMain.ts'; +import selectIsFetching from '@shared/lib/selectors/selectIsFetching'; + +import useAppSelector from '../hooks/useAppSelector'; +import cn from '../lib/helpers/cn'; const buttonTypes = { filled: @@ -25,10 +25,8 @@ const Button = memo(function Button({ disabled, ...props }: IButtonProps) { - const isFetchingMain = useAppSelector(selectIsFetchingMain); - const isFetchingDetails = useAppSelector(selectIsFetchingDetails); + const isFetching = useAppSelector(selectIsFetching); - const isFetching = isFetchingDetails || isFetchingMain; const isDisabled = disabled || isFetching; return ( diff --git a/src/shared/ui/ErrorBoundary.tsx b/shared/ui/ErrorBoundary.tsx similarity index 92% rename from src/shared/ui/ErrorBoundary.tsx rename to shared/ui/ErrorBoundary.tsx index e6993999..d3c767b3 100644 --- a/src/shared/ui/ErrorBoundary.tsx +++ b/shared/ui/ErrorBoundary.tsx @@ -1,6 +1,6 @@ import { Component, ReactNode } from 'react'; -import { IChildren } from '../types/interfaces.ts'; +import { IChildren } from '../types/interfaces'; interface IErrorBoundaryState { hasError?: boolean; diff --git a/src/shared/ui/FallbackUi.tsx b/shared/ui/FallbackUi.tsx similarity index 83% rename from src/shared/ui/FallbackUi.tsx rename to shared/ui/FallbackUi.tsx index c0f35f69..7ee97cd2 100644 --- a/src/shared/ui/FallbackUi.tsx +++ b/shared/ui/FallbackUi.tsx @@ -1,7 +1,8 @@ import { PropsWithChildren } from 'react'; -import LinkWithQuery from './LinkWithQuery.tsx'; -import Modal from './Modal.tsx'; +import Modal from '@shared/ui/Modal'; + +import LinkWithQuery from './LinkWithQuery'; function FallbackUi({ children }: PropsWithChildren) { return ( @@ -18,7 +19,7 @@ function FallbackUi({ children }: PropsWithChildren) {

    If you faced any issues, please contact our support team

    cinemania-help@gmail.com

    - Go back + Go back
    diff --git a/shared/ui/LinkWithQuery.tsx b/shared/ui/LinkWithQuery.tsx new file mode 100644 index 00000000..74a044cd --- /dev/null +++ b/shared/ui/LinkWithQuery.tsx @@ -0,0 +1,34 @@ +import { ReactNode } from 'react'; + +import Link from 'next/link'; +import { useRouter } from 'next/router'; + +interface ILinkWithQueryProps { + children: ReactNode; + href: string; + className?: string; +} + +function LinkWithQuery({ + children, + className = '', + href, + ...props +}: ILinkWithQueryProps) { + const router = useRouter(); + const { id, ...query } = router.query; + + return ( + + {children} + + ); +} + +export default LinkWithQuery; diff --git a/src/shared/ui/Modal.tsx b/shared/ui/Modal.tsx similarity index 54% rename from src/shared/ui/Modal.tsx rename to shared/ui/Modal.tsx index 5c487828..f95dbd55 100644 --- a/src/shared/ui/Modal.tsx +++ b/shared/ui/Modal.tsx @@ -1,5 +1,5 @@ -import useRadialHover from '../hooks/useRadialHover.ts'; -import { IChildren } from '../types/interfaces.ts'; +import useRadialHover from '../hooks/useRadialHover'; +import { IChildren } from '../types/interfaces'; interface IModalProps extends IChildren { className?: string; @@ -13,7 +13,12 @@ function Modal({ className = '', children }: IModalProps) { } = useRadialHover(); return ( -
    +
    void; + isFull?: boolean; + onHoverIn?: () => void; + onHoverOut?: () => void; + color?: string; + size?: number; +} + +function Star({ + onRate, + isFull, + onHoverIn, + onHoverOut, + color, + size, +}: IStartProps) { + const starStyle = { + display: 'block', + width: `${size}px`, + height: `${size}px`, + cursor: 'pointer', + }; + + return ( + + ); +} + +/** + * @param maxRating {number} + * @param color {string} + * @param size {number} + * @param className {string} + * @param messages {string[]} + * @param defaultRating {number} + * @returns {JSX.Element} + * @description Configurable rating component 🌟 + */ +export default function StarRating({ + maxRating = 5, + color = '#fcc419', + size = 48, + className = '', + defaultRating = 0, +}: IStarRatingProps) { + return ( +
    +
    + {Array.from({ length: maxRating }, (_, i) => ( + + ))} +
    +
    + ); +} diff --git a/src/shared/ui/Tabs.tsx b/shared/ui/Tabs.tsx similarity index 92% rename from src/shared/ui/Tabs.tsx rename to shared/ui/Tabs.tsx index 2718831b..dbe60737 100644 --- a/src/shared/ui/Tabs.tsx +++ b/shared/ui/Tabs.tsx @@ -1,4 +1,5 @@ import { + ButtonHTMLAttributes, createContext, memo, MouseEvent, @@ -8,9 +9,9 @@ import { useMemo, } from 'react'; -import Button from './Button.tsx'; -import useAnime from '../hooks/useAnime.ts'; -import useTabs from '../hooks/useTabs.ts'; +import useAnime from '@shared/hooks/useAnime'; +import useTabs from '@shared/hooks/useTabs'; +import Button from '@shared/ui/Button'; interface IOptionProps { children: string; @@ -25,7 +26,7 @@ interface ISelectProps { interface ISelectContext { activeValue: IOptionProps['value']; - handleSetValue: (e: MouseEvent) => void; + handleSetValue: ButtonHTMLAttributes['onClick']; } const SelectContext = createContext(null); diff --git a/shared/ui/ThrowError.tsx b/shared/ui/ThrowError.tsx new file mode 100644 index 00000000..d3ac447a --- /dev/null +++ b/shared/ui/ThrowError.tsx @@ -0,0 +1,19 @@ +import { useState } from 'react'; + +import Button from '@shared/ui/Button'; + +function ThrowError() { + const [isError, setIsError] = useState(false); + + if (isError) { + throw new Error('Test Error'); + } + + return ( + + ); +} + +export default ThrowError; diff --git a/shared/ui/Tooltip.tsx b/shared/ui/Tooltip.tsx new file mode 100644 index 00000000..7d3759d5 --- /dev/null +++ b/shared/ui/Tooltip.tsx @@ -0,0 +1,27 @@ +import { PropsWithChildren, RefObject } from 'react'; + +import { Quicksand } from 'next/font/google'; + +interface ITooltipProps extends PropsWithChildren { + innerRef: RefObject; +} + +const quickSand = Quicksand({ + subsets: ['latin'], + weight: '700', +}); + +function Tooltip({ innerRef, children }: ITooltipProps) { + return ( +
    + {children} +
    + ); +} + +export default Tooltip; diff --git a/src/app/App.tsx b/src/app/App.tsx deleted file mode 100644 index 62024a0a..00000000 --- a/src/app/App.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import { RouterProvider } from 'react-router-dom'; - -import router from './router.tsx'; -import ErrorBoundary from '../shared/ui/ErrorBoundary.tsx'; -import FallbackUi from '../shared/ui/FallbackUi.tsx'; - -function App() { - return ( - }> - - - ); -} - -export default App; diff --git a/src/app/model/slice.test.tsx b/src/app/model/slice.test.tsx deleted file mode 100644 index 917340e0..00000000 --- a/src/app/model/slice.test.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import { describe, expect, it } from 'vitest'; - -import { - appReducer, - dataFetchedDetailsPage, - dataFetchedMainPage, - initialState, - moviesPerPageUpdated, -} from './slice.ts'; - -describe('appSlice', () => { - it("should change app's slice dataFetchedDetailsPage state", () => { - const state = appReducer(initialState, dataFetchedDetailsPage(true)); - - expect(state).toEqual({ - ...initialState, - isFetchingDetailsPage: true, - }); - }); - - it("should change app's slice dataFetchedMainPage state", () => { - const state = appReducer(initialState, dataFetchedMainPage(true)); - - expect(state).toEqual({ - ...initialState, - isFetchingMainPage: true, - }); - }); - - it("should change app's slice moviesPerPage state", () => { - const state = appReducer(initialState, moviesPerPageUpdated(99)); - - expect(state).toEqual({ - ...initialState, - moviesPerPage: 99, - }); - }); -}); diff --git a/src/app/model/slice.ts b/src/app/model/slice.ts deleted file mode 100644 index 892ffcc7..00000000 --- a/src/app/model/slice.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { createSlice, PayloadAction } from '@reduxjs/toolkit'; - -import { MOVIES_PER_PAGE } from '../../shared/const/const.ts'; - -interface IInitialState { - isFetchingMainPage: boolean; - isFetchingDetailsPage: boolean; - moviesPerPage: number; -} - -export const initialState: IInitialState = { - isFetchingMainPage: false, - isFetchingDetailsPage: false, - moviesPerPage: MOVIES_PER_PAGE, -}; - -export const appSlice = createSlice({ - name: 'app', - initialState, - reducers: { - dataFetchedMainPage: (state, action: PayloadAction) => { - state.isFetchingMainPage = action.payload; - }, - - dataFetchedDetailsPage: (state, action: PayloadAction) => { - state.isFetchingDetailsPage = action.payload; - }, - - moviesPerPageUpdated: (state, action: PayloadAction) => { - state.moviesPerPage = action.payload; - }, - }, -}); - -export const { - dataFetchedMainPage, - dataFetchedDetailsPage, - moviesPerPageUpdated, -} = appSlice.actions; - -export const appReducer = appSlice.reducer; diff --git a/src/app/router.tsx b/src/app/router.tsx deleted file mode 100644 index 1aedbce6..00000000 --- a/src/app/router.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import { createHashRouter, RouteObject } from 'react-router-dom'; - -import AppLayout from '../pages/AppLayout/AppLayout.tsx'; -import NotFound from '../pages/NotFound/NotFound.tsx'; - -export const ROUTES: RouteObject[] = [ - { - path: '/', - element: , - errorElement: , - children: [ - { - path: ':movieId', - lazy: () => import('../widgets/MovieDetails/MovieDetails.tsx'), - }, - ], - }, -]; - -const router = createHashRouter(ROUTES); - -export default router; diff --git a/src/entities/movie/Movie.test.tsx b/src/entities/movie/Movie.test.tsx deleted file mode 100644 index d4136cf6..00000000 --- a/src/entities/movie/Movie.test.tsx +++ /dev/null @@ -1,68 +0,0 @@ -import { screen } from '@testing-library/react'; -import userEvent from '@testing-library/user-event'; -import { afterEach, describe, expect, it } from 'vitest'; - -import * as movieApi from './api/movieApi.ts'; -import Movie from './ui/Movie.tsx'; -import * as useGetMovieList from '../../shared/hooks/useGetMovieList.ts'; -import renderWithRouter from '../../test/helpers/RenderWithRouter.tsx'; -import renderWithRouterProvider from '../../test/helpers/renderWithRouterProvider.tsx'; -import { mockMovieItem, mockMovies } from '../../test/mocks/data.ts'; - -const mockedUseGetMovieList = vi.spyOn(useGetMovieList, 'default'); -const mockedUseGetMovieQuery = vi.spyOn(movieApi, 'useGetMovieQuery'); - -describe('Movie', () => { - afterEach(() => { - vi.clearAllMocks(); - }); - - it('should render the relevant movie data', () => { - renderWithRouter( - , - ); - - const poster = screen.getByTestId('movie-poster'); - const title = screen.getByTestId('movie-title'); - const year = screen.getByTestId('movie-year'); - - expect(poster).toBeInTheDocument(); - expect(title).toBeInTheDocument(); - expect(year).toBeInTheDocument(); - - expect(poster).toHaveAttribute('src', mockMovieItem.Poster); - expect(title).toHaveTextContent(mockMovieItem.Title); - expect(year).toHaveTextContent(mockMovieItem.Year); - }); - - it('should open a detailed card component when clicking on a card', async () => { - mockedUseGetMovieList.mockReturnValue({ - movieList: mockMovies, - totalResults: mockMovies.length, - }); - - renderWithRouterProvider(); - - expect(screen.queryByTestId('details-section')).toBeNull(); - - const [movie] = screen.getAllByTestId('movie-item'); - await userEvent.click(movie); - - const detailsSection = await screen.findByTestId('details-section'); - expect(detailsSection).toBeInTheDocument(); - }); - - it('should triggers an additional API call to fetch detailed information when clicking on the card', async () => { - renderWithRouterProvider(); - - const [movie] = screen.getAllByTestId('movie-item'); - await userEvent.click(movie); - - expect(mockedUseGetMovieQuery).toHaveBeenCalled(); - }); -}); diff --git a/src/entities/movie/api/apiMovie-v1.ts b/src/entities/movie/api/apiMovie-v1.ts deleted file mode 100644 index 2e2dc0e8..00000000 --- a/src/entities/movie/api/apiMovie-v1.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { DEFAULT_PAGE, QUERY_FALLBACK } from '../../../shared/const/const.ts'; -import { - ApiErrorResponse, - ApiMovieListResponse, - ApiMovieResponse, -} from '../../../shared/types/types.ts'; - -export async function getMovieList( - query: string, - page: number = DEFAULT_PAGE, -): Promise { - const response = await fetch( - `${import.meta.env.VITE_API_URL}?apikey=${import.meta.env.VITE_API_KEY}&s=${ - query || QUERY_FALLBACK - }&page=${page}`, - ); - - if (!response.ok) throw new Error('Something went wrong fetching movies!'); - - const data = (await response.json()) as - | ApiMovieListResponse - | ApiErrorResponse; - - if (data.Response === 'False') throw new Error(data.Error); - - return data; -} - -export async function getMovie(id: string) { - const response = await fetch( - `${import.meta.env.VITE_API_URL}?apikey=${ - import.meta.env.VITE_API_KEY - }&i=${id}`, - ); - - if (!response.ok) throw new Error('Something went wrong fetching movies!'); - - const data = (await response.json()) as ApiMovieResponse | ApiErrorResponse; - - if (data.Response === 'False') throw new Error(data.Error); - - return data; -} diff --git a/src/entities/movie/loader.ts b/src/entities/movie/loader.ts deleted file mode 100644 index 59075ee8..00000000 --- a/src/entities/movie/loader.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { Params } from 'react-router-dom'; - -import { getMovie } from './api/apiMovie-v1.ts'; - -interface ILoaderParams { - params: Params; -} - -async function loader({ params }: ILoaderParams) { - const { movieId } = params; - if (movieId) return getMovie(movieId); - return null; -} - -export default loader; diff --git a/src/features/MovieList/MovieList.tsx b/src/features/MovieList/MovieList.tsx deleted file mode 100644 index d8f104bc..00000000 --- a/src/features/MovieList/MovieList.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import { PropsWithChildren, ReactNode, RefObject } from 'react'; - -import LocomotiveScroll from 'locomotive-scroll'; - -import useListClick from './hooks/useListClick.ts'; -import MovieNotFound from './ui/MovieNotFound.tsx'; -import useGetMovieList from '../../shared/hooks/useGetMovieList.ts'; -import { Movie } from '../../shared/types/types.ts'; - -interface IMovieListProps extends PropsWithChildren { - scroll: RefObject; - render: (movie: Movie, i: number) => ReactNode; -} - -function MovieList({ scroll, render, children }: IMovieListProps) { - const { listRef, handleClick } = useListClick(scroll); - const { movieList } = useGetMovieList(); - - if (!movieList) return ; - - return ( -
      - {children} - {movieList?.map(render)} -
    - ); -} - -export default MovieList; diff --git a/src/features/MovieList/ui/MovieListHeader.tsx b/src/features/MovieList/ui/MovieListHeader.tsx deleted file mode 100644 index 061e5a38..00000000 --- a/src/features/MovieList/ui/MovieListHeader.tsx +++ /dev/null @@ -1,50 +0,0 @@ -import { PropsWithChildren, RefObject, useCallback } from 'react'; - -import LocomotiveScroll from 'locomotive-scroll'; - -import { moviesPerPageUpdated } from '../../../app/model/slice.ts'; -import useAppDispatch from '../../../shared/hooks/useAppDispatch.ts'; -import useAppSelector from '../../../shared/hooks/useAppSelector.ts'; -import useScrollTop from '../../../shared/hooks/useScrollTop.ts'; -import selectMoviesPerPage from '../../../shared/lib/selectors/selectMoviesPerPage.ts'; -import { ItemsPerPage } from '../../../shared/types/types.ts'; -import Tabs from '../../../shared/ui/Tabs.tsx'; - -interface IMovieListHeader extends PropsWithChildren { - scroll: RefObject; -} - -function MovieListHeader({ children, scroll }: IMovieListHeader) { - const dispatch = useAppDispatch(); - const moviesPerPage = useAppSelector(selectMoviesPerPage); - - useScrollTop(moviesPerPage, scroll); - - const handleMoviesPerPage = useCallback( - (newMoviesPerPage: number) => { - if (newMoviesPerPage === moviesPerPage) return; - - dispatch(moviesPerPageUpdated(newMoviesPerPage)); - }, - [dispatch, moviesPerPage], - ); - - return ( -
    - - handler={handleMoviesPerPage} - activeValue={moviesPerPage}> - value={3}>03 movies - value={5}>05 movies - value={10}>10 movies - - {children} -
    - ); -} - -export default MovieListHeader; diff --git a/src/features/Pagination/hooks/usePagination.ts b/src/features/Pagination/hooks/usePagination.ts deleted file mode 100644 index 1133ce83..00000000 --- a/src/features/Pagination/hooks/usePagination.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { RefObject, useCallback } from 'react'; - -import LocomotiveScroll from 'locomotive-scroll'; - -import { DEFAULT_PAGE, MOVIES_PER_PAGE } from '../../../shared/const/const.ts'; -import useAppSelector from '../../../shared/hooks/useAppSelector.ts'; -import useGetMovieList from '../../../shared/hooks/useGetMovieList.ts'; -import useScrollTop from '../../../shared/hooks/useScrollTop.ts'; -import useUrl from '../../../shared/hooks/useUrl.ts'; -import selectIsFetchingDetails from '../../../shared/lib/selectors/selectIsFetchingDetails.ts'; -import selectIsFetchingMain from '../../../shared/lib/selectors/selectIsFetchingMain.ts'; -import { urlParams } from '../../../shared/types/enums.ts'; - -function usePagination(scroll: RefObject) { - const { setUrl, readUrl } = useUrl(); - const isFetchingMain = useAppSelector(selectIsFetchingMain); - const isFetchingDetails = useAppSelector(selectIsFetchingDetails); - const { totalResults } = useGetMovieList(); - - const isFetching = isFetchingDetails || isFetchingMain; - const currPage = Number(readUrl(urlParams.PAGE)); - const isPrevDisabled = currPage === DEFAULT_PAGE || isFetching; - const isNextDisabled = isFetching; - const noPages = totalResults <= MOVIES_PER_PAGE; - - useScrollTop(currPage, scroll, undefined, currPage); - - const handleNextPage = useCallback(() => { - setUrl(urlParams.PAGE, currPage + 1); - }, [setUrl, currPage]); - - const handlePrevPage = useCallback(() => { - setUrl(urlParams.PAGE, currPage - 1); - }, [currPage, setUrl]); - - return { - handleNextPage, - handlePrevPage, - isPrevDisabled, - isNextDisabled, - noPages, - }; -} - -export default usePagination; diff --git a/src/features/Search/Search.test.tsx b/src/features/Search/Search.test.tsx deleted file mode 100644 index 53d99dd3..00000000 --- a/src/features/Search/Search.test.tsx +++ /dev/null @@ -1,47 +0,0 @@ -import { RefObject } from 'react'; - -import { screen } from '@testing-library/react'; -import userEvent from '@testing-library/user-event'; -import LocomotiveScroll from 'locomotive-scroll'; -import { afterAll, afterEach, beforeAll, expect } from 'vitest'; - -import Search from './Search.tsx'; -import { SEARCH_TEST_VALUE } from '../../test/const/const.ts'; -import renderWithRouterProvider from '../../test/helpers/renderWithRouterProvider.tsx'; - -let scroll: RefObject; - -const mockedSetItem = vi.spyOn(localStorage, 'setItem'); -const mockedGetItem = vi.spyOn(localStorage, 'getItem'); - -describe('Search', () => { - afterEach(() => { - vi.clearAllMocks(); - }); - - beforeAll(() => { - scroll = { current: new LocomotiveScroll() }; - }); - - afterAll(() => { - scroll.current?.destroy(); - }); - - it('should save the entered value to the local storage when clicking on the search button', async () => { - renderWithRouterProvider(); - - await userEvent.click(screen.getByRole('button')); - - expect(mockedSetItem).toHaveBeenCalled(); - }); - - it('should retrieves the value from the local storage upon mounting', async () => { - renderWithRouterProvider(); - - await userEvent.type(screen.getByTestId('search-input'), SEARCH_TEST_VALUE); - await userEvent.click(screen.getByRole('button')); - - expect(mockedGetItem).toHaveBeenCalled(); - expect(screen.getByTestId('search-input')).toHaveValue(SEARCH_TEST_VALUE); - }); -}); diff --git a/src/features/Search/const/const.ts b/src/features/Search/const/const.ts deleted file mode 100644 index 33318e3d..00000000 --- a/src/features/Search/const/const.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { MovieList } from '../../../shared/types/types.ts'; - -export const NO_MOVIES: MovieList = []; -export const NO_RESULTS = 0; -export const ENTER_KEY = 'Enter'; -export const ESCAPE_KEY = 'Escape'; diff --git a/src/features/Search/context/SearchProvider.tsx b/src/features/Search/context/SearchProvider.tsx deleted file mode 100644 index a6e70142..00000000 --- a/src/features/Search/context/SearchProvider.tsx +++ /dev/null @@ -1,129 +0,0 @@ -import { - createContext, - useCallback, - useEffect, - useMemo, - useReducer, -} from 'react'; - -import { getMovieList } from '../../../entities/movie/api/apiMovie-v1.ts'; -import { - DEFAULT_PAGE, - LOCAL_STORAGE_SEARCH_QUERY, -} from '../../../shared/const/const.ts'; -import useUrl from '../../../shared/hooks/useUrl.ts'; -import { urlParams } from '../../../shared/types/enums.ts'; -import { IChildren } from '../../../shared/types/interfaces.ts'; -import { MovieList } from '../../../shared/types/types.ts'; -import { NO_MOVIES, NO_RESULTS } from '../const/const.ts'; -import { - Action, - IInitialState, - ISearchContext, - SearchActions, -} from '../types/types.ts'; - -const initialState: IInitialState = { - query: '', - movies: null, - totalResults: 0, - isLoading: false, -}; - -export const SearchContext = createContext({ - query: '', -} as ISearchContext); - -function reducer(state: IInitialState, action: Action): IInitialState { - switch (action.type) { - case SearchActions.QUERY_UPDATED: - return { ...state, query: action.payload }; - - case SearchActions.MOVIES_LOADED: - return { - ...state, - movies: action.payload.movies, - totalResults: action.payload.totalResults, - isLoading: false, - }; - - case SearchActions.LOADING: - return { ...state, isLoading: true }; - - default: - throw new Error('The action does not exist!'); - } -} - -function SearchProvider({ children }: IChildren) { - const [{ query, movies, totalResults, isLoading }, dispatch] = useReducer( - reducer, - initialState, - ); - const { readUrl, setUrl } = useUrl(); - - const updateQuery = useCallback((newQuery: string) => { - dispatch({ type: SearchActions.QUERY_UPDATED, payload: newQuery }); - }, []); - - const updateMovies = useCallback( - (newMovies: MovieList, newTotalResults: number) => { - dispatch({ - type: SearchActions.MOVIES_LOADED, - payload: { - movies: newMovies, - totalResults: newTotalResults, - }, - }); - }, - [], - ); - - const fetchMovies = useCallback( - async (searchQuery: string, page?: number) => { - localStorage.setItem(LOCAL_STORAGE_SEARCH_QUERY, searchQuery); - - try { - dispatch({ type: SearchActions.LOADING }); - const res = await getMovieList(searchQuery, page); - updateMovies(res.Search, Number(res.totalResults)); - updateQuery(searchQuery); - } catch (e) { - updateMovies(NO_MOVIES, NO_RESULTS); - } - }, - [updateMovies, updateQuery], - ); - - useEffect(() => { - const storedQuery = localStorage.getItem(LOCAL_STORAGE_SEARCH_QUERY); - const urlPage = Number(readUrl(urlParams.PAGE)); - const page = urlPage || DEFAULT_PAGE; - - if (!urlPage) setUrl(urlParams.PAGE, String(page)); - - if (storedQuery === null) return; - - void fetchMovies(storedQuery, page); - }, [fetchMovies, readUrl, setUrl]); - - const providerValue = useMemo( - () => ({ - query, - movies, - totalResults, - isLoading, - updateQuery, - fetchMovies, - }), - [fetchMovies, isLoading, movies, query, totalResults, updateQuery], - ); - - return ( - - {children} - - ); -} - -export default SearchProvider; diff --git a/src/features/Search/hooks/useSearch.ts b/src/features/Search/hooks/useSearch.ts deleted file mode 100644 index 52ba0eaa..00000000 --- a/src/features/Search/hooks/useSearch.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { useContext } from 'react'; - -import { SearchContext } from '../context/SearchProvider.tsx'; - -function useSearch() { - const context = useContext(SearchContext); - - if (context === undefined) - throw new Error('SearchContext is used outside the SearchProvider!'); - - return context; -} - -export default useSearch; diff --git a/src/features/Search/model/slice.test.ts b/src/features/Search/model/slice.test.ts deleted file mode 100644 index da03f488..00000000 --- a/src/features/Search/model/slice.test.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { describe, expect, it } from 'vitest'; - -import { initialState, queryUpdated, searchReducer } from './slice.ts'; - -describe('searchSlice', () => { - it("should change search's slice query state", () => { - const state = searchReducer(initialState, queryUpdated('test')); - - expect(state).toEqual({ query: 'test' }); - }); -}); diff --git a/src/features/Search/model/slice.ts b/src/features/Search/model/slice.ts deleted file mode 100644 index 5bbf6519..00000000 --- a/src/features/Search/model/slice.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { createSlice, PayloadAction } from '@reduxjs/toolkit'; - -import { LOCAL_STORAGE_SEARCH_QUERY } from '../../../shared/const/const.ts'; - -interface IInitialState { - query: string; -} - -export const initialState: IInitialState = { - query: localStorage.getItem(LOCAL_STORAGE_SEARCH_QUERY) ?? '', -}; - -export const searchSlice = createSlice({ - name: 'search', - initialState, - reducers: { - queryUpdated: (state, action: PayloadAction) => { - state.query = action.payload; - }, - }, -}); - -export const { queryUpdated } = searchSlice.actions; - -export const searchReducer = searchSlice.reducer; diff --git a/src/main.tsx b/src/main.tsx deleted file mode 100644 index a7a0763f..00000000 --- a/src/main.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import React from 'react'; - -import ReactDOM from 'react-dom/client'; -import { Provider } from 'react-redux'; - -import './index.css'; -import App from './app/App.tsx'; -import { setupStore } from './app/store/store.ts'; - -const store = setupStore(); - -ReactDOM.createRoot(document.getElementById('root')!).render( - - - - - , -); diff --git a/src/pages/AppLayout/AppLayout.tsx b/src/pages/AppLayout/AppLayout.tsx deleted file mode 100644 index 10fc563d..00000000 --- a/src/pages/AppLayout/AppLayout.tsx +++ /dev/null @@ -1,62 +0,0 @@ -import { Outlet } from 'react-router-dom'; - -import GradientBackground from './ui/GradientBackground.tsx'; -import Movie from '../../entities/movie/ui/Movie.tsx'; -import MovieList from '../../features/MovieList/MovieList.tsx'; -import MovieListHeader from '../../features/MovieList/ui/MovieListHeader.tsx'; -import PageNum from '../../features/MovieList/ui/PageNum.tsx'; -import Pagination from '../../features/Pagination/Pagination.tsx'; -import Search from '../../features/Search/Search.tsx'; -import useScroll from '../../shared/hooks/useScroll.ts'; -import useTooltip from '../../shared/hooks/useTooltip.ts'; -import Tooltip from '../../shared/ui/Tooltip.tsx'; -import Header from '../../widgets/Header/Header.tsx'; -import Logo from '../../widgets/Header/ui/Logo.tsx'; -import TotalResults from '../../widgets/Header/ui/TotalResults.tsx'; -import Loader from '../../widgets/Loader/Loader.tsx'; -import Main from '../../widgets/Main/Main.tsx'; - -function AppLayout() { - const { containerRef, scrollRef } = useScroll(); - const { tooltipRef, hideTooltip, showTooltip } = useTooltip(scrollRef); - - return ( -
    -
    - Click for details - - -
    - - - -
    -
    - ( - - )}> - - - - - -
    - -
    -
    - ); -} - -export default AppLayout; diff --git a/src/pages/AppLayout/ui/GradientBackground.tsx b/src/pages/AppLayout/ui/GradientBackground.tsx deleted file mode 100644 index ff858679..00000000 --- a/src/pages/AppLayout/ui/GradientBackground.tsx +++ /dev/null @@ -1,13 +0,0 @@ -function GradientBackground() { - return ( -
    -
    -
    -
    -
    -
    -
    - ); -} - -export default GradientBackground; diff --git a/src/shared/api/rootApi.ts b/src/shared/api/rootApi.ts deleted file mode 100644 index ad89ec35..00000000 --- a/src/shared/api/rootApi.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { createApi } from '@reduxjs/toolkit/query/react'; - -import baseQuery from './baseQuery.ts'; - -const rootApi = createApi({ - reducerPath: 'rootApi', - baseQuery, - endpoints: () => ({}), -}); - -export default rootApi; diff --git a/src/shared/hooks/useGetMovie.ts b/src/shared/hooks/useGetMovie.ts deleted file mode 100644 index 1d7c59ed..00000000 --- a/src/shared/hooks/useGetMovie.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { useEffect } from 'react'; - -import { useLocation } from 'react-router-dom'; - -import useAppDispatch from './useAppDispatch.ts'; -import { dataFetchedDetailsPage } from '../../app/model/slice.ts'; -import { useGetMovieQuery } from '../../entities/movie/api/movieApi.ts'; - -/** - * Retrieves movie data using the useGetMovieQuery hook and dispatches the isFetching state to the useDispatchIsFetching function. - * - * @returns {Object} obj - An object containing the movie data. - * @returns {ApiMovieResponse} obj.movie - The movie data. - */ -function useGetMovie() { - const { pathname } = useLocation(); - - const id = pathname.slice(1); - const { data: movie, isLoading, isFetching } = useGetMovieQuery(id); - const dispatch = useAppDispatch(); - - useEffect(() => { - dispatch(dataFetchedDetailsPage(isFetching || isLoading)); - }, [dispatch, isFetching, isLoading]); - - if (movie && 'Error' in movie) throw new Error(movie.Error); - - return movie; -} - -export default useGetMovie; diff --git a/src/shared/hooks/useGetMovieList.ts b/src/shared/hooks/useGetMovieList.ts deleted file mode 100644 index cafa148a..00000000 --- a/src/shared/hooks/useGetMovieList.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { useEffect } from 'react'; - -import useAppDispatch from './useAppDispatch.ts'; -import useAppSelector from './useAppSelector.ts'; -import useUrl from './useUrl.ts'; -import { dataFetchedDetailsPage } from '../../app/model/slice.ts'; -import { useGetMovieListQuery } from '../../entities/movie/api/movieApi.ts'; -import selectMoviesPerPage from '../lib/selectors/selectMoviesPerPage.ts'; -import selectSearchQuery from '../lib/selectors/selectSearchQuery.ts'; -import { urlParams } from '../types/enums.ts'; -import { MovieList } from '../types/types.ts'; - -/** - * Retrieves a list of movies using the `useGetMovieListQuery` hook. - * - * @returns The list of movies fetched using the `useGetMovieListQuery` hook. - */ -function useGetMovieList() { - const { readUrl } = useUrl(); - - const query = useAppSelector(selectSearchQuery); - const moviesPerPage = useAppSelector(selectMoviesPerPage); - const dispatch = useAppDispatch(); - const page = readUrl(urlParams.PAGE); - - const { data, isLoading, isFetching } = useGetMovieListQuery({ - page, - query, - moviesPerPage, - }); - - const movieList = data?.Search?.slice(0, moviesPerPage) as - | MovieList - | undefined; - const totalResults = Number.parseInt(data?.totalResults ?? '0', 10); - - useEffect(() => { - dispatch(dataFetchedDetailsPage(isFetching || isLoading)); - }, [dispatch, isFetching, isLoading]); - - return { movieList, totalResults }; -} - -export default useGetMovieList; diff --git a/src/shared/hooks/useScroll.ts b/src/shared/hooks/useScroll.ts deleted file mode 100644 index 5baf5d85..00000000 --- a/src/shared/hooks/useScroll.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { RefObject, useEffect, useRef } from 'react'; - -import LocomotiveScroll from 'locomotive-scroll'; - -/** - * Hook for using Locomotive Scroll. - * - * @template TContainer - The type of the container element. - * @returns obj - An object containing `containerRef` and `scrollRef` as React Ref Objects. - * @returns obj.containerRef {TContainer} - ref with the container element that scroll is attached to. - * @returns obj.scrollRef {LocomotiveScroll} - ref with the locomotive scroll instance. - */ -function useScroll() { - const containerRef = useRef(null); - const scrollRef = useRef(); - const observerRef = useRef(); - - useEffect(() => { - if (containerRef.current && LocomotiveScroll) { - containerRef.current.setAttribute('data-Scroll-container', 'true'); - - try { - scrollRef.current = new LocomotiveScroll({ - el: containerRef.current, - smooth: true, - smartphone: { - smooth: true, - }, - touchMultiplier: 6, - lerp: 0.2, - multiplier: 1.6, - }); - } catch (e) { - // if the error is caught that means the test environment is used - observerRef.current?.disconnect?.(); - } - - observerRef.current = new ResizeObserver( - () => scrollRef.current?.update(), - ); - observerRef.current.observe(containerRef.current); - } - - return () => { - scrollRef.current?.destroy(); - observerRef.current?.disconnect(); - }; - }, [containerRef]); - - return { containerRef, scrollRef } as { - containerRef: RefObject; - scrollRef: RefObject; - }; -} - -export default useScroll; diff --git a/src/shared/hooks/useUrl.ts b/src/shared/hooks/useUrl.ts deleted file mode 100644 index 7d123d7c..00000000 --- a/src/shared/hooks/useUrl.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { useCallback } from 'react'; - -import { useSearchParams } from 'react-router-dom'; - -import { QUERY_PARAMS_INIT } from '../const/const.ts'; -import { UrlParams } from '../types/types.ts'; - -type SetUrl = { - (query: UrlParams, value: string | number): void; - (multipleQueriesAndValues: Record): void; // used for multiple queries at once (to avoid multiple renders and to update history only once for proper history navigation) -}; - -type ReadUrl = (query: UrlParams) => string; - -/** - * Returns an object with two methods, `readUrl` and `setUrl`, that can be used to read and set URL parameters. - * - * @return obj - * @return {ReadUrl} obj.readUrl - A function that takes a query parameter and returns its value from the URL. - * @return {SetUrl} obj.setUrl - A function that takes a query parameter and its value and sets it in the URL. - */ -function useUrl() { - const [searchParams, setSearchParams] = useSearchParams(QUERY_PARAMS_INIT); - - const readUrl: ReadUrl = useCallback( - (query: UrlParams) => searchParams.get(query) as string, - [searchParams], - ); - - const setUrl: SetUrl = useCallback( - ( - query: UrlParams | Record, - value?: string | number, - ) => { - if (typeof query === 'object') { - Object.entries(query).forEach(([queryKey, queryValue]) => - searchParams.set(queryKey, String(queryValue)), - ); - } - - if (typeof query !== 'object' && value) { - searchParams.set(query, String(value)); - } - - setSearchParams(searchParams); - }, - [searchParams, setSearchParams], - ); - - return { readUrl, setUrl }; -} - -export default useUrl; diff --git a/src/shared/lib/selectors/selectIsFetchingDetails.ts b/src/shared/lib/selectors/selectIsFetchingDetails.ts deleted file mode 100644 index d74f9c0a..00000000 --- a/src/shared/lib/selectors/selectIsFetchingDetails.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { createSelector } from '@reduxjs/toolkit'; - -import { RootState } from '../../../app/store/store.ts'; - -const selectIsFetchingMainPage = createSelector( - (state: RootState) => state.appReducer.isFetchingDetailsPage, - (isFetching) => isFetching, -); - -export default selectIsFetchingMainPage; diff --git a/src/shared/lib/selectors/selectIsFetchingMain.ts b/src/shared/lib/selectors/selectIsFetchingMain.ts deleted file mode 100644 index 28f8ce53..00000000 --- a/src/shared/lib/selectors/selectIsFetchingMain.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { createSelector } from '@reduxjs/toolkit'; - -import { RootState } from '../../../app/store/store.ts'; - -const selectIsFetchingMain = createSelector( - (state: RootState) => state.appReducer.isFetchingMainPage, - (isFetching) => isFetching, -); - -export default selectIsFetchingMain; diff --git a/src/shared/lib/selectors/selectMoviesPerPage.ts b/src/shared/lib/selectors/selectMoviesPerPage.ts deleted file mode 100644 index 2c1d5103..00000000 --- a/src/shared/lib/selectors/selectMoviesPerPage.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { createSelector } from '@reduxjs/toolkit'; - -import { RootState } from '../../../app/store/store.ts'; - -const selectIsFetching = createSelector( - (state: RootState) => state.appReducer.moviesPerPage, - (moviesPerPage) => moviesPerPage, -); - -export default selectIsFetching; diff --git a/src/shared/lib/selectors/selectSearchQuery.ts b/src/shared/lib/selectors/selectSearchQuery.ts deleted file mode 100644 index abf0d282..00000000 --- a/src/shared/lib/selectors/selectSearchQuery.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { createSelector } from '@reduxjs/toolkit'; - -import { RootState } from '../../../app/store/store.ts'; - -const selectSearchQuery = createSelector( - (state: RootState) => state.searchReducer.query, - (query) => query, -); - -export default selectSearchQuery; diff --git a/src/shared/ui/LinkWithQuery.tsx b/src/shared/ui/LinkWithQuery.tsx deleted file mode 100644 index 1838eacf..00000000 --- a/src/shared/ui/LinkWithQuery.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import { ReactNode } from 'react'; - -import { - Link, - useLocation, - unstable_useViewTransitionState as useViewTransitionState, -} from 'react-router-dom'; - -interface ILinkWithQueryProps { - children: ReactNode; - to: string; - className?: string; - viewTransition?: boolean; -} - -function LinkWithQuery({ - children, - className = '', - to, - viewTransition = true, - ...props -}: ILinkWithQueryProps) { - const { search } = useLocation(); - useViewTransitionState(to + search); - - return ( - - {children} - - ); -} - -export default LinkWithQuery; diff --git a/src/shared/ui/Tooltip.tsx b/src/shared/ui/Tooltip.tsx deleted file mode 100644 index b7caa027..00000000 --- a/src/shared/ui/Tooltip.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import { ReactNode, RefObject } from 'react'; - -import { createPortal } from 'react-dom'; - -interface ITooltipProps { - innerRef: RefObject; - children: ReactNode; -} - -function Tooltip({ innerRef, children }: ITooltipProps) { - return createPortal( -
    - {children} -
    , - document.body, - ); -} - -export default Tooltip; diff --git a/src/test/helpers/RenderWithRouter.tsx b/src/test/helpers/RenderWithRouter.tsx deleted file mode 100644 index 99c3927f..00000000 --- a/src/test/helpers/RenderWithRouter.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import { ReactNode } from 'react'; - -import { render } from '@testing-library/react'; -import { createMemoryRouter, RouterProvider } from 'react-router-dom'; - -import { ROUTES } from '../../app/router.tsx'; - -function RenderWithRouter( - element?: ReactNode | null, - initialEntries?: string[], - initialIndex?: number, -) { - const routes = element ? [{ path: '/', element }] : ROUTES; - - const router = createMemoryRouter(routes, { - initialEntries, - initialIndex, - }); - render(); -} - -export default RenderWithRouter; diff --git a/src/test/helpers/renderWithRouterProvider.tsx b/src/test/helpers/renderWithRouterProvider.tsx deleted file mode 100644 index ee00f2df..00000000 --- a/src/test/helpers/renderWithRouterProvider.tsx +++ /dev/null @@ -1,45 +0,0 @@ -import { ReactElement } from 'react'; - -import { setupListeners } from '@reduxjs/toolkit/query'; -import { render } from '@testing-library/react'; -import { Provider } from 'react-redux'; -import { createMemoryRouter, RouterProvider } from 'react-router-dom'; - -import { ROUTES } from '../../app/router.tsx'; -import { AppStore, PreloadState, setupStore } from '../../app/store/store.ts'; - -interface IOptions { - preloadedState?: PreloadState; - store?: AppStore; - initialEntries?: string[]; - initialIndex?: number; -} - -function renderWithRouterProvider( - ui?: ReactElement | null, - { - preloadedState, - store = setupStore(preloadedState), - initialEntries, - initialIndex, - }: IOptions = {}, -) { - setupListeners(store.dispatch); - - const routes = ui ? [{ path: '/', element: ui }] : ROUTES; - const router = createMemoryRouter(routes, { - initialEntries, - initialIndex, - }); - - return { - store, - ...render( - - - , - ), - }; -} - -export default renderWithRouterProvider; diff --git a/src/test/setup.ts b/src/test/setup.ts deleted file mode 100644 index 2b88423d..00000000 --- a/src/test/setup.ts +++ /dev/null @@ -1,14 +0,0 @@ -import * as matchers from '@testing-library/jest-dom/matchers'; -import { beforeAll } from 'vitest'; - -import server from './mocks/server.ts'; - -expect.extend(matchers); - -beforeAll(() => - server.listen({ - onUnhandledRequest: 'error', - }), -); -afterEach(() => server.resetHandlers()); -afterAll(() => server.close()); diff --git a/src/vite-env.d.ts b/src/vite-env.d.ts deleted file mode 100644 index f230acea..00000000 --- a/src/vite-env.d.ts +++ /dev/null @@ -1,10 +0,0 @@ -/// - -interface ImportMetaEnv { - readonly VITE_API_URL: string; - readonly VITE_API_KEY: string; -} - -interface ImportMeta { - readonly env: ImportMetaEnv; -} diff --git a/src/widgets/Header/const/const.ts b/src/widgets/Header/const/const.ts deleted file mode 100644 index d491c445..00000000 --- a/src/widgets/Header/const/const.ts +++ /dev/null @@ -1,3 +0,0 @@ -export const APP_TITLE = 'cinemania'; -export const LOGO_LETTERS = [...APP_TITLE.split('')]; -export const LOGO_ANIMATION_OFFSET = 0.02; diff --git a/src/widgets/Loader/hooks/useLoader.ts b/src/widgets/Loader/hooks/useLoader.ts deleted file mode 100644 index f230ccad..00000000 --- a/src/widgets/Loader/hooks/useLoader.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { RefObject, useEffect } from 'react'; - -import LocomotiveScroll from 'locomotive-scroll'; - -import useAppSelector from '../../../shared/hooks/useAppSelector.ts'; -import selectIsFetchingDetails from '../../../shared/lib/selectors/selectIsFetchingDetails.ts'; -import selectIsFetchingMain from '../../../shared/lib/selectors/selectIsFetchingMain.ts'; - -/** - * A custom hook that checks if the loader or the search is currently loading. - * - * @param {RefObject} scrollRef - The reference to the scroll component. - * @return {boolean} isLoading - A boolean indicating if the loader is loading. - */ -function useLoader(scrollRef: RefObject) { - const isFetchingMain = useAppSelector(selectIsFetchingMain); - const isFetchingDetails = useAppSelector(selectIsFetchingDetails); - - const isFetching = isFetchingDetails || isFetchingMain; - - useEffect(() => { - const scroll = scrollRef.current; - scroll?.stop(); - return () => void scroll?.start(); - }, [scrollRef]); - - return isFetching; -} - -export default useLoader; diff --git a/src/widgets/MovieDetails/MovieDetails.tsx b/src/widgets/MovieDetails/MovieDetails.tsx deleted file mode 100644 index 7ed01b7c..00000000 --- a/src/widgets/MovieDetails/MovieDetails.tsx +++ /dev/null @@ -1,82 +0,0 @@ -import { isRouteErrorResponse, useRouteError } from 'react-router-dom'; - -import Actors from './ui/Actors.tsx'; -import BackButton from './ui/BackButton.tsx'; -import Description from './ui/Description.tsx'; -import Director from './ui/Director.tsx'; -import Genre from './ui/Genre.tsx'; -import Poster from './ui/Poster.tsx'; -import Rating from './ui/Rating.tsx'; -import Runtime from './ui/Runtime.tsx'; -import Title from './ui/Title.tsx'; -import ReactLogo from '../../assets/reactJS-logo.png'; -import { NOT_EXIST } from '../../shared/const/const.ts'; -import useDocumentTitle from '../../shared/hooks/useDocumentTitle.ts'; -import useGetMovie from '../../shared/hooks/useGetMovie.ts'; -import convertSecsToHrsAndMins from '../../shared/lib/helpers/convertSecsToHrsAndMins.ts'; -import FallbackUi from '../../shared/ui/FallbackUi.tsx'; - -export function Component() { - const movie = useGetMovie(); - useDocumentTitle(`Cinemania | ${movie?.Title}`); - - if (!movie) return null; - - const { - Poster: poster, - Title: title, - Runtime: runtime, - Genre: genre, - Plot: plot, - Year: year, - imdbRating, - imdbVotes, - Director: director, - Actors: actors, - } = movie; - - const time = convertSecsToHrsAndMins(runtime); - const description = `${plot.slice(0, 150)}...`; - const safePoster = poster === NOT_EXIST ? ReactLogo : poster; - - return ( -
    -
    - -
    - - {title} - - {genre} - - {description} - {director} - {actors} -
    -
    -
    - ); -} - -Component.displayName = 'MovieDetails'; - -export function ErrorBoundary() { - const error = useRouteError(); - - const errorMessage = isRouteErrorResponse(error) ? ( -

    - {error.status} {error.statusText} -

    - ) : ( -

    {(error as Error).message}

    - ); - - return {errorMessage}; -} - -ErrorBoundary.displayName = 'MovieDetailsErrorBoundary'; diff --git a/src/index.css b/styles/globals.css similarity index 100% rename from src/index.css rename to styles/globals.css diff --git a/tailwind.config.js b/tailwind.config.ts similarity index 73% rename from tailwind.config.js rename to tailwind.config.ts index 6997cea6..7f5b4fe7 100644 --- a/tailwind.config.js +++ b/tailwind.config.ts @@ -1,6 +1,15 @@ -/** @type {import('tailwindcss').Config} */ -export default { - content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'], +import type { Config } from 'tailwindcss'; + +const config: Config = { + content: [ + './pages/**/*.{js,ts,jsx,tsx,mdx}', + './app/**/*.{js,ts,jsx,tsx,mdx}', + './entities/**/*.{js,ts,jsx,tsx,mdx}', + './features/**/*.{js,ts,jsx,tsx,mdx}', + './pages-layer/**/*.{js,ts,jsx,tsx,mdx}', + './shared/**/*.{js,ts,jsx,tsx,mdx}', + './widgets/**/*.{js,ts,jsx,tsx,mdx}', + ], theme: { extend: { transitionTimingFunction: { @@ -16,10 +25,10 @@ export default { keyframes: { 'fade-in': { '0%': { - opacity: 0, + opacity: '0', }, '100%': { - opacity: 1, + opacity: '1', }, }, 'movie-fade-in': { @@ -33,17 +42,17 @@ export default { 'pagination-fade-in': { '0%': { scale: '0.3', - opacity: 0, + opacity: '0', }, '100%': { scale: '1', - opacity: 1, + opacity: '1', }, }, float: { '0%': { translate3d: '0', - rotate: 0, + rotate: '0', }, '20%': { transform: 'translate3d(-50px, 15px, 0)', @@ -56,13 +65,13 @@ export default { }, '60%': { rotate: '10deg', - scale: 1.2, + scale: '1.2', transform: 'translate3d(30px, 20px, 0)', }, '100%': { translate3d: '0', - rotate: 0, - scale: 1, + rotate: '0', + scale: '1', }, }, }, @@ -77,10 +86,7 @@ export default { float: 'float 16s ease-in-out infinite', }, }, - fontFamily: { - sans: 'Poppins, monospace, sans-serif', - quicksand: 'Quicksand, sans-serif', - }, }, plugins: [], }; +export default config; diff --git a/src/test/const/const.ts b/test/const/const.ts similarity index 100% rename from src/test/const/const.ts rename to test/const/const.ts diff --git a/test/helpers/RenderWithRouter.tsx b/test/helpers/RenderWithRouter.tsx new file mode 100644 index 00000000..9ac20d5b --- /dev/null +++ b/test/helpers/RenderWithRouter.tsx @@ -0,0 +1,22 @@ +import { ReactNode } from 'react'; + +import { render } from '@testing-library/react'; +import { RouterContext } from 'next/dist/shared/lib/router-context.shared-runtime'; +import { NextRouter } from 'next/router'; + +import createMockRouter from '@test/helpers/createMockRouter'; + +function renderWithRouter( + ui?: ReactNode | null, + router: Partial = {}, +) { + const mockRouter = createMockRouter(router); + + render( + {ui}, + ); + + return mockRouter; +} + +export default renderWithRouter; diff --git a/test/helpers/createMockRouter.ts b/test/helpers/createMockRouter.ts new file mode 100644 index 00000000..51ff414e --- /dev/null +++ b/test/helpers/createMockRouter.ts @@ -0,0 +1,34 @@ +import { NextRouter } from 'next/router'; + +import { vi } from 'vitest'; + +function createMockRouter(router: Partial): NextRouter { + return { + basePath: '', + pathname: '/', + route: '/', + query: {}, + asPath: '/', + forward: vi.fn(), + back: vi.fn(), + beforePopState: vi.fn(), + prefetch: vi.fn(), + push: vi.fn(), + reload: vi.fn(), + replace: vi.fn(), + events: { + on: vi.fn(), + off: vi.fn(), + emit: vi.fn(), + }, + isFallback: false, + isLocaleDomain: false, + isReady: true, + defaultLocale: 'en', + domainLocales: [], + isPreview: false, + ...router, + }; +} + +export default createMockRouter; diff --git a/src/test/helpers/createMockSearchContext.ts b/test/helpers/createMockSearchContext.ts similarity index 61% rename from src/test/helpers/createMockSearchContext.ts rename to test/helpers/createMockSearchContext.ts index 2e90ba9f..d29d0203 100644 --- a/src/test/helpers/createMockSearchContext.ts +++ b/test/helpers/createMockSearchContext.ts @@ -1,6 +1,7 @@ -import { ISearchContext } from '../../features/Search/types/types.ts'; -import { MovieList as TMovieList } from '../../shared/types/types.ts'; -import { mockMovies } from '../mocks/data.ts'; +import { MovieList as TMovieList } from '@customTypes/types'; +import { ISearchContext } from '@features/Search/types/types'; +import { mockMovies } from '@test/mocks/data'; +import { vi } from 'vitest'; function createMockSearchContext( movieData: TMovieList | null = mockMovies, diff --git a/src/test/helpers/renderWithProvider.tsx b/test/helpers/renderWithProvider.tsx similarity index 80% rename from src/test/helpers/renderWithProvider.tsx rename to test/helpers/renderWithProvider.tsx index 3f406844..4092b98e 100644 --- a/src/test/helpers/renderWithProvider.tsx +++ b/test/helpers/renderWithProvider.tsx @@ -2,14 +2,11 @@ import { PropsWithChildren, ReactElement } from 'react'; import { setupListeners } from '@reduxjs/toolkit/query'; import { render } from '@testing-library/react'; -import { Provider } from 'react-redux'; -import { AppStore, PreloadState, setupStore } from '../../app/store/store.ts'; +import IOptions from '@test/types/interfaces'; +import { Provider } from 'react-redux'; -interface IOptions { - preloadedState?: PreloadState; - store?: AppStore; -} +import { setupStore } from '../../app/store/store'; function renderWithProvider( ui: ReactElement, diff --git a/test/helpers/renderWithRouterProvider.tsx b/test/helpers/renderWithRouterProvider.tsx new file mode 100644 index 00000000..de9124a8 --- /dev/null +++ b/test/helpers/renderWithRouterProvider.tsx @@ -0,0 +1,39 @@ +import { ReactNode } from 'react'; + +import { setupListeners } from '@reduxjs/toolkit/query'; +import { render } from '@testing-library/react'; +import { RouterContext } from 'next/dist/shared/lib/router-context.shared-runtime'; +import { NextRouter } from 'next/router'; + +import createMockRouter from '@test/helpers/createMockRouter'; +import IOptions from '@test/types/interfaces'; +import { Provider } from 'react-redux'; + +import { setupStore } from '../../app/store/store'; + +function renderWithRouter( + ui?: ReactNode | null, + router: Partial = {}, + { + preloadedState = {}, + store = setupStore(preloadedState), + ...renderOptions + }: IOptions = {}, +) { + const mockRouter = createMockRouter(router); + + setupListeners(store.dispatch); + + return { + store, + router: mockRouter, + ...render( + + {ui} + , + { ...renderOptions }, + ), + }; +} + +export default renderWithRouter; diff --git a/src/test/mocks/data.ts b/test/mocks/data.ts similarity index 83% rename from src/test/mocks/data.ts rename to test/mocks/data.ts index 9eaf7c88..592ebeb8 100644 --- a/src/test/mocks/data.ts +++ b/test/mocks/data.ts @@ -1,14 +1,14 @@ -import { NOT_EXIST } from '../../shared/const/const.ts'; +import { NOT_EXIST } from '../../shared/const/const'; import { ApiMovieResponse, MovieList as TMovieList, -} from '../../shared/types/types.ts'; +} from '../../shared/types/types'; export const mockMovieItem = { Year: '2023', imdbID: 'tt1016150', Title: 'test', - Poster: 'test', + Poster: '/test', Type: 'test', }; @@ -17,70 +17,70 @@ export const mockMovies: TMovieList = [ Year: '2023', imdbID: 'tt1016150', Title: 'test', - Poster: 'test', + Poster: '/test', Type: 'test', }, { Year: '2023', imdbID: crypto.randomUUID(), Title: 'test', - Poster: 'test', + Poster: '/test', Type: 'test', }, { Year: '2023', imdbID: crypto.randomUUID(), Title: 'test', - Poster: 'test', + Poster: '/test', Type: 'test', }, { Year: '2023', imdbID: crypto.randomUUID(), Title: 'test', - Poster: 'test', + Poster: '/test', Type: 'test', }, { Year: '2023', imdbID: crypto.randomUUID(), Title: 'test', - Poster: 'test', + Poster: '/test', Type: 'test', }, { Year: '2023', imdbID: crypto.randomUUID(), Title: 'test', - Poster: 'test', + Poster: '/test', Type: 'test', }, { Year: '2023', imdbID: crypto.randomUUID(), Title: 'test', - Poster: 'test', + Poster: '/test', Type: 'test', }, { Year: '2023', imdbID: crypto.randomUUID(), Title: 'test', - Poster: 'test', + Poster: '/test', Type: 'test', }, { Year: '2023', imdbID: crypto.randomUUID(), Title: 'test', - Poster: 'test', + Poster: '/test', Type: 'test', }, { Year: '2023', imdbID: crypto.randomUUID(), Title: 'test', - Poster: 'test', + Poster: '/test', Type: 'test', }, ]; @@ -88,7 +88,7 @@ export const mockMovies: TMovieList = [ export const mockMovieDetails: ApiMovieResponse = { Year: '2023', Type: 'test', - Poster: 'test', + Poster: '/test', Title: 'test', imdbID: 'test', Response: 'True', diff --git a/src/test/mocks/handlers.ts b/test/mocks/handlers.ts similarity index 62% rename from src/test/mocks/handlers.ts rename to test/mocks/handlers.ts index ced21af9..e6cfd601 100644 --- a/src/test/mocks/handlers.ts +++ b/test/mocks/handlers.ts @@ -1,14 +1,15 @@ +import { loadEnvConfig } from '@next/env'; + import { delay, http, HttpResponse } from 'msw'; -import { - mockMovieDetails, - mockMovieDetailsNoPoster, - mockMovies, -} from './data.ts'; -import { NO_POSTER_QUERY_TEST_CASE } from '../const/const.ts'; +import { mockMovieDetails, mockMovieDetailsNoPoster, mockMovies } from './data'; +import { NO_POSTER_QUERY_TEST_CASE } from '../const/const'; + +const projectDir = process.cwd(); +loadEnvConfig(projectDir); const handlers = [ - http.get(`${import.meta.env.VITE_API_URL}`, async ({ request }) => { + http.get(`${process.env.NEXT_PUBLIC_API_URL}`, async ({ request }) => { await delay(); const url = new URL(request.url); diff --git a/src/test/mocks/server.ts b/test/mocks/server.ts similarity index 73% rename from src/test/mocks/server.ts rename to test/mocks/server.ts index e4026f9d..8f041004 100644 --- a/src/test/mocks/server.ts +++ b/test/mocks/server.ts @@ -1,6 +1,6 @@ import { setupServer } from 'msw/node'; -import handlers from './handlers.ts'; +import handlers from './handlers'; const server = setupServer(...handlers); diff --git a/test/setup.ts b/test/setup.ts new file mode 100644 index 00000000..99044251 --- /dev/null +++ b/test/setup.ts @@ -0,0 +1,18 @@ +import '@testing-library/jest-dom'; + +import { loadEnvConfig } from '@next/env'; + +import { afterAll, afterEach, beforeAll } from 'vitest'; + +import server from './mocks/server'; + +const projectDir = process.cwd(); +loadEnvConfig(projectDir); + +beforeAll(() => + server.listen({ + onUnhandledRequest: 'error', + }), +); +afterEach(() => server.resetHandlers()); +afterAll(() => server.close()); diff --git a/test/types/interfaces.ts b/test/types/interfaces.ts new file mode 100644 index 00000000..a74396c0 --- /dev/null +++ b/test/types/interfaces.ts @@ -0,0 +1,8 @@ +import { AppStore, PreloadState } from '../../app/store/store'; + +interface IOptions { + preloadedState?: PreloadState; + store?: AppStore; +} + +export default IOptions; diff --git a/tsconfig.json b/tsconfig.json index c372cd42..a1b12178 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,26 +1,61 @@ { "compilerOptions": { - "target": "ESNext", - "useDefineForClassFields": true, - "lib": ["ESNext", "DOM", "DOM.Iterable"], - "module": "ESNext", + "target": "es5", + "lib": [ + "dom", + "dom.iterable", + "esnext" + ], + "allowJs": true, "skipLibCheck": true, - - /* Bundler mode */ + "strict": true, + "noEmit": true, + "esModuleInterop": true, + "module": "esnext", "moduleResolution": "bundler", - "allowImportingTsExtensions": true, "resolveJsonModule": true, "isolatedModules": true, - "noEmit": true, - "jsx": "react-jsx", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "noFallthroughCasesInSwitch": true, - "types": ["vitest/globals", "@testing-library/jest-dom"] + "jsx": "preserve", + "incremental": true, + "paths": { + "@features/*": [ + "./features/*" + ], + "@entities/*": [ + "./entities/*" + ], + "@shared/*": [ + "./shared/*" + ], + "@widgets/*": [ + "./widgets/*" + ], + "@customTypes/*": [ + "./shared/types/*" + ], + "@styles/*": [ + "./styles/*" + ], + "@assets/*": [ + "./assets/*" + ], + "@test/*": [ + "./test/*" + ] + }, + "plugins": [ + { + "name": "next" + } + ] }, - "include": ["src"], - "references": [{ "path": "./tsconfig.node.json" }] + "include": [ + "next-env.d.ts", + "**/*.ts", + "**/*.tsx", + ".next/types/**/*.ts" + ], + "exclude": [ + "node_modules" + ] } diff --git a/tsconfig.node.json b/tsconfig.node.json deleted file mode 100644 index 42872c59..00000000 --- a/tsconfig.node.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "compilerOptions": { - "composite": true, - "skipLibCheck": true, - "module": "ESNext", - "moduleResolution": "bundler", - "allowSyntheticDefaultImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/vite.config.ts b/vite.config.ts deleted file mode 100644 index 3aaf49dd..00000000 --- a/vite.config.ts +++ /dev/null @@ -1,16 +0,0 @@ -/// -/// - -import { defineConfig } from 'vite'; -import react from '@vitejs/plugin-react'; - -export default defineConfig({ - plugins: [react()], - test: { - globals: true, - environment: 'happy-dom', - setupFiles: './src/test/setup.ts', - css: false, - }, - base: './', -}); diff --git a/vitest.config.ts b/vitest.config.ts new file mode 100644 index 00000000..5fec753e --- /dev/null +++ b/vitest.config.ts @@ -0,0 +1,30 @@ +import react from '@vitejs/plugin-react'; +import { defineConfig } from 'vitest/config'; + +import { resolve } from 'path'; + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react()], + test: { + globals: true, + environment: 'happy-dom', + setupFiles: ['./test/setup.ts'], + css: false, + }, + resolve: { + alias: [ + { find: '@features', replacement: resolve(__dirname, './features') }, + { find: '@entities', replacement: resolve(__dirname, './entities') }, + { find: '@shared', replacement: resolve(__dirname, './shared') }, + { find: '@widgets', replacement: resolve(__dirname, './widgets') }, + { + find: '@customTypes', + replacement: resolve(__dirname, './shared/types'), + }, + { find: '@styles', replacement: resolve(__dirname, './styles') }, + { find: '@assets', replacement: resolve(__dirname, './assets') }, + { find: '@test', replacement: resolve(__dirname, './test') }, + ], + }, +}); diff --git a/src/pages/AppLayout/AppLayout.test.tsx b/widgets/AppLayout/AppLayout.test.tsx similarity index 62% rename from src/pages/AppLayout/AppLayout.test.tsx rename to widgets/AppLayout/AppLayout.test.tsx index 44d3fcd4..524f9cb0 100644 --- a/src/pages/AppLayout/AppLayout.test.tsx +++ b/widgets/AppLayout/AppLayout.test.tsx @@ -1,8 +1,10 @@ import { screen } from '@testing-library/react'; -import { describe, it } from 'vitest'; -import renderWithRouter from '../../test/helpers/RenderWithRouter.tsx'; -import Logo from '../../widgets/Header/ui/Logo.tsx'; +import renderWithRouter from '@test/helpers/RenderWithRouter'; +import Logo from '@widgets/Header/ui/Logo'; +import { describe, expect, it } from 'vitest'; + +import Custom404 from '../../pages/404'; describe('App', () => { it('should render the logo', () => { @@ -12,7 +14,7 @@ describe('App', () => { }); it('should display 404 page when navigating to an invalid route', () => { - renderWithRouter(null, ['test/not-found']); + renderWithRouter(); expect(screen.getByTestId('not-found')).toBeInTheDocument(); }); diff --git a/widgets/AppLayout/AppLayout.tsx b/widgets/AppLayout/AppLayout.tsx new file mode 100644 index 00000000..6f4873e4 --- /dev/null +++ b/widgets/AppLayout/AppLayout.tsx @@ -0,0 +1,78 @@ +import { PropsWithChildren } from 'react'; + +import { Poppins } from 'next/font/google'; +import Head from 'next/head'; + +import Movie from '@entities/movie/ui/Movie'; +import useScroll from '@entities/scroll/hooks/useScroll'; +import MovieList from '@features/MovieList/MovieList'; +import MovieListHeader from '@features/MovieList/ui/MovieListHeader'; +import PageNum from '@features/MovieList/ui/PageNum'; +import Pagination from '@features/Pagination/Pagination'; +import Search from '@features/Search/Search'; +import { APP_TITLE } from '@shared/const/const'; +import useTooltip from '@shared/hooks/useTooltip'; +import ThrowError from '@shared/ui/ThrowError'; +import Tooltip from '@shared/ui/Tooltip'; +import GradientBackground from '@widgets/AppLayout/ui/GradientBackground'; +import Header from '@widgets/Header/Header'; +import Logo from '@widgets/Header/ui/Logo'; +import TotalResults from '@widgets/Header/ui/TotalResults'; +import Loader from '@widgets/Loader/Loader'; +import Main from '@widgets/Main/Main'; + +const poppins = Poppins({ + subsets: ['latin'], + weight: '500', +}); + +function AppLayout({ children }: PropsWithChildren) { + const { containerRef } = useScroll(); + const { tooltipRef, showTooltip, hideTooltip } = useTooltip(); + + return ( + <> + + {APP_TITLE} + + + Click for details +
    +
    + + +
    + + + + +
    +
    + ( + + )}> + + + + + {children} +
    + +
    +
    + + ); +} + +export default AppLayout; diff --git a/widgets/AppLayout/ui/GradientBackground.tsx b/widgets/AppLayout/ui/GradientBackground.tsx new file mode 100644 index 00000000..e2570ff3 --- /dev/null +++ b/widgets/AppLayout/ui/GradientBackground.tsx @@ -0,0 +1,13 @@ +function GradientBackground() { + return ( +
    +
    +
    +
    +
    +
    +
    + ); +} + +export default GradientBackground; diff --git a/src/widgets/Header/Header.tsx b/widgets/Header/Header.tsx similarity index 88% rename from src/widgets/Header/Header.tsx rename to widgets/Header/Header.tsx index d355d6c6..a3756ef5 100644 --- a/src/widgets/Header/Header.tsx +++ b/widgets/Header/Header.tsx @@ -1,4 +1,4 @@ -import { IChildren } from '../../shared/types/interfaces.ts'; +import { IChildren } from '@customTypes/interfaces'; function Header({ children }: IChildren) { return ( diff --git a/src/widgets/Header/ui/Logo.tsx b/widgets/Header/ui/Logo.tsx similarity index 99% rename from src/widgets/Header/ui/Logo.tsx rename to widgets/Header/ui/Logo.tsx index 43188e49..2708fcaa 100644 --- a/src/widgets/Header/ui/Logo.tsx +++ b/widgets/Header/ui/Logo.tsx @@ -1,8 +1,7 @@ import { useEffect, useRef } from 'react'; -import anime from 'animejs/lib/anime.es'; - -import LinkWithQuery from '../../../shared/ui/LinkWithQuery.tsx'; +import LinkWithQuery from '@shared/ui/LinkWithQuery'; +import anime from 'animejs'; function Logo() { const popCornRef = useRef(null); @@ -210,8 +209,8 @@ function Logo() { }, []); return ( - -

    + +

    ; -} - -function Loader({ scroll }: ILoaderProps) { - const isFetching = useLoader(scroll); +function Loader() { + const isLoading = useLoader(); - if (!isFetching) return null; + if (!isLoading) return null; return createPortal(
    { + const handleStart = () => setLoading(true); + const handleComplete = () => setLoading(false); + + router.events.on('routeChangeStart', handleStart); + router.events.on('routeChangeComplete', handleComplete); + router.events.on('routeChangeError', handleComplete); + + return () => { + router.events.off('routeChangeStart', handleStart); + router.events.off('routeChangeComplete', handleComplete); + router.events.off('routeChangeError', handleComplete); + }; + }, [router.asPath, router.events]); + + useEffect(() => { + scroll?.stop(); + return () => void scroll?.start(); + }, [scroll]); + + return isLoading; +} + +export default useLoader; diff --git a/src/widgets/Main/Main.tsx b/widgets/Main/Main.tsx similarity index 100% rename from src/widgets/Main/Main.tsx rename to widgets/Main/Main.tsx diff --git a/src/widgets/MovieDetails/MovieDetails.test.tsx b/widgets/MovieDetails/MovieDetails.test.tsx similarity index 67% rename from src/widgets/MovieDetails/MovieDetails.test.tsx rename to widgets/MovieDetails/MovieDetails.test.tsx index fdd46eef..397b7006 100644 --- a/src/widgets/MovieDetails/MovieDetails.test.tsx +++ b/widgets/MovieDetails/MovieDetails.test.tsx @@ -1,19 +1,17 @@ import { screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; + +import reactLogo from '@assets/reactJS-logo.png'; +import { movieApi } from '@entities/movie/api/movieApi'; +import * as useGetMovie from '@shared/hooks/useGetMovie'; +import convertSecsToHrsAndMins from '@shared/lib/helpers/convertSecsToHrsAndMins'; +import { NO_POSTER_QUERY_TEST_CASE } from '@test/const/const'; +import renderWithRouter from '@test/helpers/RenderWithRouter'; +import { mockMovieDetails, mockMovieDetailsNoPoster } from '@test/mocks/data'; +import MovieDetails from '@widgets/MovieDetails/MovieDetails'; import { afterEach, describe, expect, it, vi } from 'vitest'; -import * as MovieDetails from './MovieDetails.tsx'; -import { setupStore } from '../../app/store/store.ts'; -import reactLogo from '../../assets/reactJS-logo.png'; -import { movieApi } from '../../entities/movie/api/movieApi.ts'; -import * as useGetMovie from '../../shared/hooks/useGetMovie.ts'; -import convertSecsToHrsAndMins from '../../shared/lib/helpers/convertSecsToHrsAndMins.ts'; -import renderWithRouter from '../../test/helpers/RenderWithRouter.tsx'; -import renderWithRouterProvider from '../../test/helpers/renderWithRouterProvider.tsx'; -import { - mockMovieDetails, - mockMovieDetailsNoPoster, -} from '../../test/mocks/data.ts'; +import { setupStore } from '../../app/store/store'; const runtimeHours = convertSecsToHrsAndMins(mockMovieDetails.Runtime); const descriptionSliced = `${mockMovieDetails.Plot.slice(0, 150)}...`; @@ -29,24 +27,16 @@ describe('Movie details', () => { it('should render the details section', async () => { mockedUseGetMovie.mockReturnValue(mockMovieDetails); - renderWithRouter(); + renderWithRouter(); const detailsSection = await screen.findByTestId('details-section'); expect(detailsSection).toBeInTheDocument(); }); - it('should display the loader while fetching data', async () => { - renderWithRouterProvider(); - - const loader = await screen.findByTestId('loader'); - - expect(loader).toBeDefined(); - }); - it('should properly calculate and edit the runtime', async () => { mockedUseGetMovie.mockReturnValue(mockMovieDetails); - renderWithRouter(); + renderWithRouter(); const runtime = await screen.findByTestId('details-runtime'); expect(runtime).toHaveTextContent(runtimeHours); @@ -55,7 +45,7 @@ describe('Movie details', () => { it('should properly slice the description', async () => { mockedUseGetMovie.mockReturnValue(mockMovieDetails); - renderWithRouter(); + renderWithRouter(); const description = await screen.findByTestId('details-description'); expect(description).toHaveTextContent(descriptionSliced); @@ -64,17 +54,23 @@ describe('Movie details', () => { it('should handle no poster case', async () => { mockedUseGetMovie.mockReturnValue(mockMovieDetailsNoPoster); - renderWithRouter(); + renderWithRouter(, { basePath: NO_POSTER_QUERY_TEST_CASE }); + + const poster = + await screen.findByTestId('details-poster'); - const poster = await screen.findByTestId('details-poster'); + const reactLogoPath = (reactLogo as unknown as string).slice( + (reactLogo as unknown as string).lastIndexOf('/') + 1, + ); + const match = poster.src.match(reactLogoPath); - expect(poster).toHaveAttribute('src', reactLogo); + expect(match?.at(0)).toBe(reactLogoPath); }); it('should correctly display the details data', async () => { mockedUseGetMovie.mockReturnValue(mockMovieDetails); - renderWithRouter(); + renderWithRouter(); const [poster, title, runtime, genre, rating, descr, director, cast] = await Promise.all([ @@ -97,7 +93,6 @@ describe('Movie details', () => { expect(director).toBeInTheDocument(); expect(cast).toBeInTheDocument(); - expect(poster).toHaveAttribute('src', mockMovieDetails.Poster); expect(title).toHaveTextContent(mockMovieDetails.Title); expect(runtime).toHaveTextContent(runtimeHours); expect(genre).toHaveTextContent(mockMovieDetails.Genre); @@ -109,7 +104,8 @@ describe('Movie details', () => { it('should hide the component on close button click', async () => { mockedUseGetMovie.mockReturnValue(mockMovieDetails); - renderWithRouterProvider(null, { initialEntries: ['/test'] }); + + const router = renderWithRouter(); const [closeButton, detailsSection] = await Promise.all([ screen.findByTestId('details-close'), @@ -121,10 +117,6 @@ describe('Movie details', () => { await userEvent.click(closeButton); - const closeButtonAfterClose = screen.queryByTestId('details-close'); - const detailsSectionAfterClose = screen.queryByTestId('details-section'); - - expect(closeButtonAfterClose).toBeNull(); - expect(detailsSectionAfterClose).toBeNull(); + expect(router.push).toHaveBeenCalled(); }); }); diff --git a/widgets/MovieDetails/MovieDetails.tsx b/widgets/MovieDetails/MovieDetails.tsx new file mode 100644 index 00000000..d78c5748 --- /dev/null +++ b/widgets/MovieDetails/MovieDetails.tsx @@ -0,0 +1,65 @@ +import ReactLogo from '@assets/reactJS-logo.png'; +import { NOT_EXIST } from '@shared/const/const'; +import useDocumentTitle from '@shared/hooks/useDocumentTitle'; +import useGetMovie from '@shared/hooks/useGetMovie'; +import convertSecsToHrsAndMins from '@shared/lib/helpers/convertSecsToHrsAndMins'; +import Actors from '@widgets/MovieDetails/ui/Actors'; +import BackButton from '@widgets/MovieDetails/ui/BackButton'; +import Description from '@widgets/MovieDetails/ui/Description'; +import Director from '@widgets/MovieDetails/ui/Director'; +import Genre from '@widgets/MovieDetails/ui/Genre'; +import Poster from '@widgets/MovieDetails/ui/Poster'; +import Rating from '@widgets/MovieDetails/ui/Rating'; +import Runtime from '@widgets/MovieDetails/ui/Runtime'; +import Title from '@widgets/MovieDetails/ui/Title'; + +import Custom404 from '../../pages/404'; + +function MovieDetails() { + const movie = useGetMovie(); + useDocumentTitle(`Cinemania | ${movie?.Title}`); + + if (!movie) return ; + + const { + Poster: poster, + Title: title, + Runtime: runtime, + Genre: genre, + Plot: plot, + Year: year, + imdbRating, + imdbVotes, + Director: director, + Actors: actors, + } = movie; + + const time = convertSecsToHrsAndMins(runtime); + const description = `${plot.slice(0, 150)}...`; + const safePoster = poster === NOT_EXIST ? ReactLogo : poster; + + return ( +
    +
    + +
    + + {title} + + {genre} + + {description} + {director} + {actors} +
    +
    +
    + ); +} + +export default MovieDetails; diff --git a/src/widgets/MovieDetails/ui/Actors.tsx b/widgets/MovieDetails/ui/Actors.tsx similarity index 100% rename from src/widgets/MovieDetails/ui/Actors.tsx rename to widgets/MovieDetails/ui/Actors.tsx diff --git a/src/widgets/MovieDetails/ui/BackButton.tsx b/widgets/MovieDetails/ui/BackButton.tsx similarity index 73% rename from src/widgets/MovieDetails/ui/BackButton.tsx rename to widgets/MovieDetails/ui/BackButton.tsx index e862fd61..35067a98 100644 --- a/src/widgets/MovieDetails/ui/BackButton.tsx +++ b/widgets/MovieDetails/ui/BackButton.tsx @@ -1,18 +1,26 @@ import { memo } from 'react'; -import chevronLeft from '../../../assets/chevron-left.svg'; -import LinkWithQuery from '../../../shared/ui/LinkWithQuery.tsx'; +import Image from 'next/image'; + +import chevronLeft from '@assets/chevron-left.svg'; +import LinkWithQuery from '@shared/ui/LinkWithQuery'; const BackButton = memo(function BackButton() { return ( - +
    - -