From 275745fd3ae18779fdc1c4061f103d7d065e8b9c Mon Sep 17 00:00:00 2001 From: Alejandro Celaya Date: Thu, 27 Jul 2023 22:23:46 +0200 Subject: [PATCH] Move some modules from src to shlink-web-component --- shlink-web-component/Main.tsx | 4 +- .../common/AsideMenu.scss | 4 +- .../common/AsideMenu.tsx | 0 shlink-web-component/container/index.ts | 21 ++-- .../domains/DomainSelector.tsx | 2 +- .../domains/helpers/DomainDropdown.tsx | 2 +- .../short-urls/EditShortUrl.tsx | 2 +- .../short-urls/UseExistingIfFoundInfoIcon.tsx | 2 +- .../short-urls/helpers/ExportShortUrlsBtn.tsx | 4 +- .../short-urls/helpers/ShortUrlsRow.tsx | 2 +- .../short-urls/helpers/ShortUrlsRowMenu.tsx | 2 +- .../short-urls/helpers/Tags.tsx | 2 +- .../short-urls/helpers/hooks.ts | 2 +- shlink-web-component/tags/TagsTable.tsx | 4 +- shlink-web-component/tags/TagsTableRow.tsx | 4 +- .../tags/helpers/EditTagModal.tsx | 4 +- shlink-web-component/tags/helpers/Tag.tsx | 2 +- .../tags/helpers/TagBullet.tsx | 2 +- .../tags/helpers/TagsSelector.tsx | 2 +- shlink-web-component/tags/reducers/tagEdit.ts | 2 +- shlink-web-component/utils/helpers/hooks.ts | 96 +++++++++++++++++++ .../utils/helpers/query.ts | 0 .../utils/services/ColorGenerator.ts | 4 +- .../utils/services/LocalStorage.ts | 14 +++ .../utils/services/ReportExporter.ts | 30 ++++++ .../utils/services/provideServices.ts | 14 +++ shlink-web-component/visits/DomainVisits.tsx | 2 +- .../visits/NonOrphanVisits.tsx | 2 +- shlink-web-component/visits/OrphanVisits.tsx | 2 +- .../visits/ShortUrlVisits.tsx | 4 +- shlink-web-component/visits/TagVisits.tsx | 6 +- .../visits/TagVisitsHeader.tsx | 2 +- .../visits/charts/LineChartCard.tsx | 2 +- .../visits/helpers/OpenMapModalBtn.tsx | 2 +- shlink-web-component/visits/helpers/hooks.ts | 2 +- src/api/services/ShlinkApiClient.ts | 2 +- src/common/services/ReportExporter.ts | 29 ------ src/common/services/provideServices.ts | 2 - src/utils/helpers/csvjson.ts | 2 +- src/utils/helpers/hooks.ts | 37 +------ src/utils/helpers/qrCodes.ts | 2 +- src/utils/services/provideServices.ts | 2 +- test/common/AsideMenu.test.tsx | 2 +- test/common/services/ReportExporter.test.ts | 2 +- .../helpers/ExportShortUrlsBtn.test.tsx | 2 +- test/tags/helpers/Tag.test.tsx | 2 +- test/tags/reducers/tagEdit.test.ts | 2 +- test/utils/helpers/query.test.ts | 2 +- test/utils/services/ColorGenerator.test.ts | 2 +- .../services/__mocks__/ColorGenerator.mock.ts | 2 +- test/visits/TagVisitsHeader.test.tsx | 2 +- 51 files changed, 212 insertions(+), 133 deletions(-) rename {src => shlink-web-component}/common/AsideMenu.scss (93%) rename {src => shlink-web-component}/common/AsideMenu.tsx (100%) create mode 100644 shlink-web-component/utils/helpers/hooks.ts rename {src => shlink-web-component}/utils/helpers/query.ts (100%) rename {src => shlink-web-component}/utils/services/ColorGenerator.ts (93%) create mode 100644 shlink-web-component/utils/services/LocalStorage.ts create mode 100644 shlink-web-component/utils/services/ReportExporter.ts create mode 100644 shlink-web-component/utils/services/provideServices.ts diff --git a/shlink-web-component/Main.tsx b/shlink-web-component/Main.tsx index 57c5d822..cf20bb30 100644 --- a/shlink-web-component/Main.tsx +++ b/shlink-web-component/Main.tsx @@ -4,10 +4,10 @@ import classNames from 'classnames'; import type { FC } from 'react'; import { useEffect } from 'react'; import { Navigate, Route, Routes, useLocation } from 'react-router-dom'; -import { AsideMenu } from '../src/common/AsideMenu'; import { NotFound } from '../src/common/NotFound'; -import { useSwipeable, useToggle } from '../src/utils/helpers/hooks'; +import { AsideMenu } from './common/AsideMenu'; import { useFeature } from './utils/features'; +import { useSwipeable, useToggle } from './utils/helpers/hooks'; import { useRoutesPrefix } from './utils/routesPrefix'; export const Main = ( diff --git a/src/common/AsideMenu.scss b/shlink-web-component/common/AsideMenu.scss similarity index 93% rename from src/common/AsideMenu.scss rename to shlink-web-component/common/AsideMenu.scss index 4e7e462d..d648607a 100644 --- a/src/common/AsideMenu.scss +++ b/shlink-web-component/common/AsideMenu.scss @@ -1,5 +1,5 @@ -@import '../utils/base'; -@import '../utils/mixins/vertical-align'; +@import '../../src/utils/base'; +@import '../../src/utils/mixins/vertical-align'; .aside-menu { width: $asideMenuWidth; diff --git a/src/common/AsideMenu.tsx b/shlink-web-component/common/AsideMenu.tsx similarity index 100% rename from src/common/AsideMenu.tsx rename to shlink-web-component/common/AsideMenu.tsx diff --git a/shlink-web-component/container/index.ts b/shlink-web-component/container/index.ts index c6456fab..7512d36b 100644 --- a/shlink-web-component/container/index.ts +++ b/shlink-web-component/container/index.ts @@ -1,19 +1,17 @@ import type { IContainer } from 'bottlejs'; import Bottle from 'bottlejs'; import { pick } from 'ramda'; -import { connect as reduxConnect } from 'react-redux/es/exports'; +import { connect as reduxConnect } from 'react-redux'; import { HttpClient } from '../../src/common/services/HttpClient'; import { ImageDownloader } from '../../src/common/services/ImageDownloader'; -import { ReportExporter } from '../../src/common/services/ReportExporter'; import { csvToJson, jsonToCsv } from '../../src/utils/helpers/csvjson'; -import { useTimeoutToggle } from '../../src/utils/helpers/hooks'; -import { ColorGenerator } from '../../src/utils/services/ColorGenerator'; -import { LocalStorage } from '../../src/utils/services/LocalStorage'; import { provideServices as provideDomainsServices } from '../domains/services/provideServices'; import { provideServices as provideMercureServices } from '../mercure/services/provideServices'; import { provideServices as provideOverviewServices } from '../overview/services/provideServices'; import { provideServices as provideShortUrlsServices } from '../short-urls/services/provideServices'; import { provideServices as provideTagsServices } from '../tags/services/provideServices'; +import { provideServices as provideUtilsServices } from '../utils/services/provideServices'; +import { ReportExporter } from '../utils/services/ReportExporter'; import { provideServices as provideVisitsServices } from '../visits/services/provideServices'; import { provideServices as provideWebComponentServices } from './provideServices'; @@ -38,15 +36,16 @@ const connect: ConnectDecorator = (propsFromState: string[] | null, actionServic actionServiceNames.reduce(mapActionService, {}), ); -provideWebComponentServices(bottle, connect); +provideWebComponentServices(bottle); provideShortUrlsServices(bottle, connect); provideTagsServices(bottle, connect); provideVisitsServices(bottle, connect); provideMercureServices(bottle); provideDomainsServices(bottle, connect); provideOverviewServices(bottle, connect); +provideUtilsServices(bottle); -// TODO Check which of these can be moved to shlink-web-component, and which are needed by the app too +// FIXME Check which of these can be moved to shlink-web-component, and which are needed by the app too bottle.constant('window', window); bottle.constant('console', console); bottle.constant('fetch', window.fetch.bind(window)); @@ -55,13 +54,5 @@ bottle.service('HttpClient', HttpClient, 'fetch'); bottle.service('ImageDownloader', ImageDownloader, 'HttpClient', 'window'); bottle.service('ReportExporter', ReportExporter, 'window', 'jsonToCsv'); -bottle.constant('localStorage', window.localStorage); -bottle.service('Storage', LocalStorage, 'localStorage'); -bottle.service('ColorGenerator', ColorGenerator, 'Storage'); - bottle.constant('csvToJson', csvToJson); bottle.constant('jsonToCsv', jsonToCsv); - -bottle.constant('setTimeout', window.setTimeout); -bottle.constant('clearTimeout', window.clearTimeout); -bottle.serviceFactory('useTimeoutToggle', useTimeoutToggle, 'setTimeout', 'clearTimeout'); diff --git a/shlink-web-component/domains/DomainSelector.tsx b/shlink-web-component/domains/DomainSelector.tsx index 5d643ae9..e84104a1 100644 --- a/shlink-web-component/domains/DomainSelector.tsx +++ b/shlink-web-component/domains/DomainSelector.tsx @@ -5,7 +5,7 @@ import { useEffect } from 'react'; import type { InputProps } from 'reactstrap'; import { Button, DropdownItem, Input, InputGroup, UncontrolledTooltip } from 'reactstrap'; import { DropdownBtn } from '../../src/utils/DropdownBtn'; -import { useToggle } from '../../src/utils/helpers/hooks'; +import { useToggle } from '../utils/helpers/hooks'; import type { DomainsList } from './reducers/domainsList'; import './DomainSelector.scss'; diff --git a/shlink-web-component/domains/helpers/DomainDropdown.tsx b/shlink-web-component/domains/helpers/DomainDropdown.tsx index d36b2cbe..0db99ee8 100644 --- a/shlink-web-component/domains/helpers/DomainDropdown.tsx +++ b/shlink-web-component/domains/helpers/DomainDropdown.tsx @@ -3,9 +3,9 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import type { FC } from 'react'; import { Link } from 'react-router-dom'; import { DropdownItem } from 'reactstrap'; -import { useToggle } from '../../../src/utils/helpers/hooks'; import { RowDropdownBtn } from '../../../src/utils/RowDropdownBtn'; import { useFeature } from '../../utils/features'; +import { useToggle } from '../../utils/helpers/hooks'; import { useRoutesPrefix } from '../../utils/routesPrefix'; import { DEFAULT_DOMAIN } from '../../visits/reducers/domainVisits'; import type { Domain } from '../data'; diff --git a/shlink-web-component/short-urls/EditShortUrl.tsx b/shlink-web-component/short-urls/EditShortUrl.tsx index add730d4..8ef5fd66 100644 --- a/shlink-web-component/short-urls/EditShortUrl.tsx +++ b/shlink-web-component/short-urls/EditShortUrl.tsx @@ -7,9 +7,9 @@ import { useLocation, useParams } from 'react-router-dom'; import { Button, Card } from 'reactstrap'; import { ShlinkApiError } from '../../src/api/ShlinkApiError'; import { useGoBack } from '../../src/utils/helpers/hooks'; -import { parseQuery } from '../../src/utils/helpers/query'; import { Message } from '../../src/utils/Message'; import { Result } from '../../src/utils/Result'; +import { parseQuery } from '../utils/helpers/query'; import { useSetting } from '../utils/settings'; import type { ShortUrlIdentifier } from './data'; import { shortUrlDataFromShortUrl, urlDecodeShortCode } from './helpers'; diff --git a/shlink-web-component/short-urls/UseExistingIfFoundInfoIcon.tsx b/shlink-web-component/short-urls/UseExistingIfFoundInfoIcon.tsx index 4ff7e19d..32c8d130 100644 --- a/shlink-web-component/short-urls/UseExistingIfFoundInfoIcon.tsx +++ b/shlink-web-component/short-urls/UseExistingIfFoundInfoIcon.tsx @@ -1,7 +1,7 @@ import { faInfoCircle as infoIcon } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Modal, ModalBody, ModalHeader } from 'reactstrap'; -import { useToggle } from '../../src/utils/helpers/hooks'; +import { useToggle } from '../utils/helpers/hooks'; import './UseExistingIfFoundInfoIcon.scss'; const InfoModal = ({ isOpen, toggle }: { isOpen: boolean; toggle: () => void }) => ( diff --git a/shlink-web-component/short-urls/helpers/ExportShortUrlsBtn.tsx b/shlink-web-component/short-urls/helpers/ExportShortUrlsBtn.tsx index e2d06332..9f5af661 100644 --- a/shlink-web-component/short-urls/helpers/ExportShortUrlsBtn.tsx +++ b/shlink-web-component/short-urls/helpers/ExportShortUrlsBtn.tsx @@ -1,9 +1,9 @@ import type { FC } from 'react'; import { useCallback } from 'react'; -import type { ReportExporter } from '../../../src/common/services/ReportExporter'; import { ExportBtn } from '../../../src/utils/ExportBtn'; -import { useToggle } from '../../../src/utils/helpers/hooks'; import type { ShlinkApiClient } from '../../api-contract'; +import { useToggle } from '../../utils/helpers/hooks'; +import type { ReportExporter } from '../../utils/services/ReportExporter'; import type { ShortUrl } from '../data'; import { useShortUrlsQuery } from './hooks'; diff --git a/shlink-web-component/short-urls/helpers/ShortUrlsRow.tsx b/shlink-web-component/short-urls/helpers/ShortUrlsRow.tsx index 4c9a664c..5ded6acb 100644 --- a/shlink-web-component/short-urls/helpers/ShortUrlsRow.tsx +++ b/shlink-web-component/short-urls/helpers/ShortUrlsRow.tsx @@ -4,7 +4,7 @@ import { ExternalLink } from 'react-external-link'; import { CopyToClipboardIcon } from '../../../src/utils/CopyToClipboardIcon'; import { Time } from '../../../src/utils/dates/Time'; import type { TimeoutToggle } from '../../../src/utils/helpers/hooks'; -import type { ColorGenerator } from '../../../src/utils/services/ColorGenerator'; +import type { ColorGenerator } from '../../utils/services/ColorGenerator'; import { useSetting } from '../../utils/settings'; import type { ShortUrl } from '../data'; import { useShortUrlsQuery } from './hooks'; diff --git a/shlink-web-component/short-urls/helpers/ShortUrlsRowMenu.tsx b/shlink-web-component/short-urls/helpers/ShortUrlsRowMenu.tsx index ce7401c5..33057e3b 100644 --- a/shlink-web-component/short-urls/helpers/ShortUrlsRowMenu.tsx +++ b/shlink-web-component/short-urls/helpers/ShortUrlsRowMenu.tsx @@ -7,8 +7,8 @@ import { import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import type { FC } from 'react'; import { DropdownItem } from 'reactstrap'; -import { useToggle } from '../../../src/utils/helpers/hooks'; import { RowDropdownBtn } from '../../../src/utils/RowDropdownBtn'; +import { useToggle } from '../../utils/helpers/hooks'; import type { ShortUrl, ShortUrlModalProps } from '../data'; import { ShortUrlDetailLink } from './ShortUrlDetailLink'; diff --git a/shlink-web-component/short-urls/helpers/Tags.tsx b/shlink-web-component/short-urls/helpers/Tags.tsx index f724cbcc..b6bd6067 100644 --- a/shlink-web-component/short-urls/helpers/Tags.tsx +++ b/shlink-web-component/short-urls/helpers/Tags.tsx @@ -1,7 +1,7 @@ import { isEmpty } from 'ramda'; import type { FC } from 'react'; -import type { ColorGenerator } from '../../../src/utils/services/ColorGenerator'; import { Tag } from '../../tags/helpers/Tag'; +import type { ColorGenerator } from '../../utils/services/ColorGenerator'; interface TagsProps { tags: string[]; diff --git a/shlink-web-component/short-urls/helpers/hooks.ts b/shlink-web-component/short-urls/helpers/hooks.ts index 9192a6d2..1a6a1879 100644 --- a/shlink-web-component/short-urls/helpers/hooks.ts +++ b/shlink-web-component/short-urls/helpers/hooks.ts @@ -2,10 +2,10 @@ import { isEmpty, pipe } from 'ramda'; import { useMemo } from 'react'; import { useLocation, useNavigate } from 'react-router-dom'; import { orderToString, stringToOrder } from '../../../src/utils/helpers/ordering'; -import { parseQuery, stringifyQuery } from '../../../src/utils/helpers/query'; import type { BooleanString } from '../../../src/utils/utils'; import { parseOptionalBooleanToString } from '../../../src/utils/utils'; import type { TagsFilteringMode } from '../../api-contract'; +import { parseQuery, stringifyQuery } from '../../utils/helpers/query'; import { useRoutesPrefix } from '../../utils/routesPrefix'; import type { ShortUrlsOrder, ShortUrlsOrderableFields } from '../data'; diff --git a/shlink-web-component/tags/TagsTable.tsx b/shlink-web-component/tags/TagsTable.tsx index 891d2a66..30b9ed2a 100644 --- a/shlink-web-component/tags/TagsTable.tsx +++ b/shlink-web-component/tags/TagsTable.tsx @@ -3,10 +3,10 @@ import type { FC } from 'react'; import { useEffect, useRef } from 'react'; import { useLocation } from 'react-router-dom'; import { SimplePaginator } from '../../src/common/SimplePaginator'; -import { useQueryState } from '../../src/utils/helpers/hooks'; -import { parseQuery } from '../../src/utils/helpers/query'; import { SimpleCard } from '../../src/utils/SimpleCard'; import { TableOrderIcon } from '../../src/utils/table/TableOrderIcon'; +import { useQueryState } from '../utils/helpers/hooks'; +import { parseQuery } from '../utils/helpers/query'; import type { TagsListChildrenProps, TagsOrder, TagsOrderableFields } from './data/TagsListChildrenProps'; import type { TagsTableRowProps } from './TagsTableRow'; import './TagsTable.scss'; diff --git a/shlink-web-component/tags/TagsTableRow.tsx b/shlink-web-component/tags/TagsTableRow.tsx index 4dd7a403..080bd381 100644 --- a/shlink-web-component/tags/TagsTableRow.tsx +++ b/shlink-web-component/tags/TagsTableRow.tsx @@ -3,11 +3,11 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import type { FC } from 'react'; import { Link } from 'react-router-dom'; import { DropdownItem } from 'reactstrap'; -import { useToggle } from '../../src/utils/helpers/hooks'; import { prettify } from '../../src/utils/helpers/numbers'; import { RowDropdownBtn } from '../../src/utils/RowDropdownBtn'; -import type { ColorGenerator } from '../../src/utils/services/ColorGenerator'; +import { useToggle } from '../utils/helpers/hooks'; import { useRoutesPrefix } from '../utils/routesPrefix'; +import type { ColorGenerator } from '../utils/services/ColorGenerator'; import type { SimplifiedTag, TagModalProps } from './data'; import { TagBullet } from './helpers/TagBullet'; diff --git a/shlink-web-component/tags/helpers/EditTagModal.tsx b/shlink-web-component/tags/helpers/EditTagModal.tsx index 9fc65de6..9a8818b3 100644 --- a/shlink-web-component/tags/helpers/EditTagModal.tsx +++ b/shlink-web-component/tags/helpers/EditTagModal.tsx @@ -5,10 +5,10 @@ import { useState } from 'react'; import { HexColorPicker } from 'react-colorful'; import { Button, Input, InputGroup, Modal, ModalBody, ModalFooter, ModalHeader, Popover } from 'reactstrap'; import { ShlinkApiError } from '../../../src/api/ShlinkApiError'; -import { useToggle } from '../../../src/utils/helpers/hooks'; import { Result } from '../../../src/utils/Result'; -import type { ColorGenerator } from '../../../src/utils/services/ColorGenerator'; import { handleEventPreventingDefault } from '../../../src/utils/utils'; +import { useToggle } from '../../utils/helpers/hooks'; +import type { ColorGenerator } from '../../utils/services/ColorGenerator'; import type { TagModalProps } from '../data'; import type { EditTag, TagEdition } from '../reducers/tagEdit'; import './EditTagModal.scss'; diff --git a/shlink-web-component/tags/helpers/Tag.tsx b/shlink-web-component/tags/helpers/Tag.tsx index 6acf6bcc..4e9f33f8 100644 --- a/shlink-web-component/tags/helpers/Tag.tsx +++ b/shlink-web-component/tags/helpers/Tag.tsx @@ -1,6 +1,6 @@ import classNames from 'classnames'; import type { FC, MouseEventHandler, PropsWithChildren } from 'react'; -import type { ColorGenerator } from '../../../src/utils/services/ColorGenerator'; +import type { ColorGenerator } from '../../utils/services/ColorGenerator'; import './Tag.scss'; type TagProps = PropsWithChildren<{ diff --git a/shlink-web-component/tags/helpers/TagBullet.tsx b/shlink-web-component/tags/helpers/TagBullet.tsx index 65c1038a..0c303571 100644 --- a/shlink-web-component/tags/helpers/TagBullet.tsx +++ b/shlink-web-component/tags/helpers/TagBullet.tsx @@ -1,4 +1,4 @@ -import type { ColorGenerator } from '../../../src/utils/services/ColorGenerator'; +import type { ColorGenerator } from '../../utils/services/ColorGenerator'; import './TagBullet.scss'; interface TagBulletProps { diff --git a/shlink-web-component/tags/helpers/TagsSelector.tsx b/shlink-web-component/tags/helpers/TagsSelector.tsx index 31993e84..72d74fcc 100644 --- a/shlink-web-component/tags/helpers/TagsSelector.tsx +++ b/shlink-web-component/tags/helpers/TagsSelector.tsx @@ -1,7 +1,7 @@ import { useEffect } from 'react'; import type { SuggestionComponentProps, TagComponentProps } from 'react-tag-autocomplete'; import ReactTags from 'react-tag-autocomplete'; -import type { ColorGenerator } from '../../../src/utils/services/ColorGenerator'; +import type { ColorGenerator } from '../../utils/services/ColorGenerator'; import { useSetting } from '../../utils/settings'; import type { TagsList } from '../reducers/tagsList'; import { Tag } from './Tag'; diff --git a/shlink-web-component/tags/reducers/tagEdit.ts b/shlink-web-component/tags/reducers/tagEdit.ts index 3a6f69c2..4bc2f8ec 100644 --- a/shlink-web-component/tags/reducers/tagEdit.ts +++ b/shlink-web-component/tags/reducers/tagEdit.ts @@ -1,10 +1,10 @@ import type { PayloadAction } from '@reduxjs/toolkit'; import { createAction, createSlice } from '@reduxjs/toolkit'; import { pick } from 'ramda'; -import type { ColorGenerator } from '../../../src/utils/services/ColorGenerator'; import type { ProblemDetailsError, ShlinkApiClient } from '../../api-contract'; import { parseApiError } from '../../api-contract/utils'; import { createAsyncThunk } from '../../utils/redux'; +import type { ColorGenerator } from '../../utils/services/ColorGenerator'; const REDUCER_PREFIX = 'shlink/tagEdit'; diff --git a/shlink-web-component/utils/helpers/hooks.ts b/shlink-web-component/utils/helpers/hooks.ts new file mode 100644 index 00000000..d51cb13a --- /dev/null +++ b/shlink-web-component/utils/helpers/hooks.ts @@ -0,0 +1,96 @@ +import type { DependencyList, EffectCallback } from 'react'; +import { useEffect, useRef, useState } from 'react'; +import { useLocation, useNavigate } from 'react-router-dom'; +import { useSwipeable as useReactSwipeable } from 'react-swipeable'; +import { v4 as uuid } from 'uuid'; +import { parseQuery, stringifyQuery } from './query'; + +const DEFAULT_DELAY = 2000; + +export type TimeoutToggle = (initialValue?: boolean, delay?: number) => [boolean, () => void]; + +export const useTimeoutToggle = ( + setTimeout: (callback: Function, timeout: number) => number, + clearTimeout: (timer: number) => void, +): TimeoutToggle => (initialValue = false, delay = DEFAULT_DELAY) => { + const [flag, setFlag] = useState(initialValue); + const timeout = useRef(undefined); + const callback = () => { + setFlag(!initialValue); + + if (timeout.current) { + clearTimeout(timeout.current); + } + + timeout.current = setTimeout(() => setFlag(initialValue), delay); + }; + + return [flag, callback]; +}; + +type ToggleResult = [boolean, () => void, () => void, () => void]; + +export const useToggle = (initialValue = false): ToggleResult => { + const [flag, setFlag] = useState(initialValue); + return [flag, () => setFlag(!flag), () => setFlag(true), () => setFlag(false)]; +}; + +export const useSwipeable = (showSidebar: () => void, hideSidebar: () => void) => { + const swipeMenuIfNoModalExists = (callback: () => void) => (e: any) => { + const swippedOnVisitsTable = (e.event.composedPath() as HTMLElement[]).some( + ({ classList }) => classList?.contains('visits-table'), + ); + + if (swippedOnVisitsTable || document.querySelector('.modal')) { + return; + } + + callback(); + }; + + return useReactSwipeable({ + delta: 40, + onSwipedLeft: swipeMenuIfNoModalExists(hideSidebar), + onSwipedRight: swipeMenuIfNoModalExists(showSidebar), + }); +}; + +export const useQueryState = (paramName: string, initialState: T): [ T, (newValue: T) => void ] => { + const [value, setValue] = useState(initialState); + const setValueWithLocation = (valueToSet: T) => { + const { location, history } = window; + const query = parseQuery(location.search); + + query[paramName] = valueToSet; + history.pushState(null, '', `${location.pathname}?${stringifyQuery(query)}`); + setValue(valueToSet); + }; + + return [value, setValueWithLocation]; +}; + +export const useEffectExceptFirstTime = (callback: EffectCallback, deps: DependencyList): void => { + const isFirstLoad = useRef(true); + + useEffect(() => { + !isFirstLoad.current && callback(); + isFirstLoad.current = false; + }, deps); +}; + +export const useGoBack = () => { + const navigate = useNavigate(); + return () => navigate(-1); +}; + +export const useParsedQuery = (): T => { + const { search } = useLocation(); + return parseQuery(search); +}; + +export const useDomId = (): string => { + const { current: id } = useRef(`dom-${uuid()}`); + return id; +}; + +export const useElementRef = () => useRef(null); diff --git a/src/utils/helpers/query.ts b/shlink-web-component/utils/helpers/query.ts similarity index 100% rename from src/utils/helpers/query.ts rename to shlink-web-component/utils/helpers/query.ts diff --git a/src/utils/services/ColorGenerator.ts b/shlink-web-component/utils/services/ColorGenerator.ts similarity index 93% rename from src/utils/services/ColorGenerator.ts rename to shlink-web-component/utils/services/ColorGenerator.ts index 789fe122..eab6909e 100644 --- a/src/utils/services/ColorGenerator.ts +++ b/shlink-web-component/utils/services/ColorGenerator.ts @@ -1,6 +1,6 @@ import { isNil } from 'ramda'; -import { rangeOf } from '../utils'; -import type { LocalStorage } from './LocalStorage'; +import type { LocalStorage } from '../../../src/utils/services/LocalStorage'; +import { rangeOf } from '../../../src/utils/utils'; const HEX_COLOR_LENGTH = 6; const HEX_DIGITS = '0123456789ABCDEF'; diff --git a/shlink-web-component/utils/services/LocalStorage.ts b/shlink-web-component/utils/services/LocalStorage.ts new file mode 100644 index 00000000..9c404e07 --- /dev/null +++ b/shlink-web-component/utils/services/LocalStorage.ts @@ -0,0 +1,14 @@ +const PREFIX = 'shlink'; +const buildPath = (path: string) => `${PREFIX}.${path}`; + +export class LocalStorage { + public constructor(private readonly localStorage: Storage) {} + + public readonly get = (key: string): T | undefined => { + const item = this.localStorage.getItem(buildPath(key)); + + return item ? JSON.parse(item) as T : undefined; + }; + + public readonly set = (key: string, value: any) => this.localStorage.setItem(buildPath(key), JSON.stringify(value)); +} diff --git a/shlink-web-component/utils/services/ReportExporter.ts b/shlink-web-component/utils/services/ReportExporter.ts new file mode 100644 index 00000000..fb13676e --- /dev/null +++ b/shlink-web-component/utils/services/ReportExporter.ts @@ -0,0 +1,30 @@ +import type { JsonToCsv } from '../../../src/utils/helpers/csvjson'; +import { saveCsv } from '../../../src/utils/helpers/files'; +import type { ExportableShortUrl } from '../../short-urls/data'; +import type { NormalizedVisit } from '../../visits/types'; + +export class ReportExporter { + public constructor(private readonly window: Window, private readonly jsonToCsv: JsonToCsv) { + } + + public readonly exportVisits = (filename: string, visits: NormalizedVisit[]) => { + if (!visits.length) { + return; + } + + this.exportCsv(filename, visits); + }; + + public readonly exportShortUrls = (shortUrls: ExportableShortUrl[]) => { + if (!shortUrls.length) { + return; + } + + this.exportCsv('short_urls.csv', shortUrls); + }; + + private readonly exportCsv = (filename: string, rows: object[]) => { + const csv = this.jsonToCsv(rows); + saveCsv(this.window, csv, filename); + }; +} diff --git a/shlink-web-component/utils/services/provideServices.ts b/shlink-web-component/utils/services/provideServices.ts new file mode 100644 index 00000000..871e72f1 --- /dev/null +++ b/shlink-web-component/utils/services/provideServices.ts @@ -0,0 +1,14 @@ +import type Bottle from 'bottlejs'; +import { useTimeoutToggle } from '../helpers/hooks'; +import { ColorGenerator } from './ColorGenerator'; +import { LocalStorage } from './LocalStorage'; + +export function provideServices(bottle: Bottle) { + bottle.constant('localStorage', window.localStorage); + bottle.service('Storage', LocalStorage, 'localStorage'); + bottle.service('ColorGenerator', ColorGenerator, 'Storage'); + + bottle.constant('setTimeout', window.setTimeout); + bottle.constant('clearTimeout', window.clearTimeout); + bottle.serviceFactory('useTimeoutToggle', useTimeoutToggle, 'setTimeout', 'clearTimeout'); +} diff --git a/shlink-web-component/visits/DomainVisits.tsx b/shlink-web-component/visits/DomainVisits.tsx index 5ec2027c..871937c6 100644 --- a/shlink-web-component/visits/DomainVisits.tsx +++ b/shlink-web-component/visits/DomainVisits.tsx @@ -1,9 +1,9 @@ import { useParams } from 'react-router-dom'; -import type { ReportExporter } from '../../src/common/services/ReportExporter'; import { useGoBack } from '../../src/utils/helpers/hooks'; import type { ShlinkVisitsParams } from '../api-contract'; import { boundToMercureHub } from '../mercure/helpers/boundToMercureHub'; import { Topics } from '../mercure/helpers/Topics'; +import type { ReportExporter } from '../utils/services/ReportExporter'; import type { DomainVisits as DomainVisitsState, LoadDomainVisits } from './reducers/domainVisits'; import type { NormalizedVisit } from './types'; import { toApiParams } from './types/helpers'; diff --git a/shlink-web-component/visits/NonOrphanVisits.tsx b/shlink-web-component/visits/NonOrphanVisits.tsx index afc31792..1822ced7 100644 --- a/shlink-web-component/visits/NonOrphanVisits.tsx +++ b/shlink-web-component/visits/NonOrphanVisits.tsx @@ -1,7 +1,7 @@ -import type { ReportExporter } from '../../src/common/services/ReportExporter'; import { useGoBack } from '../../src/utils/helpers/hooks'; import { boundToMercureHub } from '../mercure/helpers/boundToMercureHub'; import { Topics } from '../mercure/helpers/Topics'; +import type { ReportExporter } from '../utils/services/ReportExporter'; import type { LoadVisits, VisitsInfo } from './reducers/types'; import type { NormalizedVisit, VisitsParams } from './types'; import { toApiParams } from './types/helpers'; diff --git a/shlink-web-component/visits/OrphanVisits.tsx b/shlink-web-component/visits/OrphanVisits.tsx index b5db855c..ff2dafa1 100644 --- a/shlink-web-component/visits/OrphanVisits.tsx +++ b/shlink-web-component/visits/OrphanVisits.tsx @@ -1,7 +1,7 @@ -import type { ReportExporter } from '../../src/common/services/ReportExporter'; import { useGoBack } from '../../src/utils/helpers/hooks'; import { boundToMercureHub } from '../mercure/helpers/boundToMercureHub'; import { Topics } from '../mercure/helpers/Topics'; +import type { ReportExporter } from '../utils/services/ReportExporter'; import type { LoadOrphanVisits } from './reducers/orphanVisits'; import type { VisitsInfo } from './reducers/types'; import type { NormalizedVisit, VisitsParams } from './types'; diff --git a/shlink-web-component/visits/ShortUrlVisits.tsx b/shlink-web-component/visits/ShortUrlVisits.tsx index 02cc19ae..5dd66980 100644 --- a/shlink-web-component/visits/ShortUrlVisits.tsx +++ b/shlink-web-component/visits/ShortUrlVisits.tsx @@ -1,13 +1,13 @@ import { useEffect } from 'react'; import { useLocation, useParams } from 'react-router-dom'; -import type { ReportExporter } from '../../src/common/services/ReportExporter'; import { useGoBack } from '../../src/utils/helpers/hooks'; -import { parseQuery } from '../../src/utils/helpers/query'; import { boundToMercureHub } from '../mercure/helpers/boundToMercureHub'; import { Topics } from '../mercure/helpers/Topics'; import type { ShortUrlIdentifier } from '../short-urls/data'; import { urlDecodeShortCode } from '../short-urls/helpers'; import type { ShortUrlDetail } from '../short-urls/reducers/shortUrlDetail'; +import { parseQuery } from '../utils/helpers/query'; +import type { ReportExporter } from '../utils/services/ReportExporter'; import type { LoadShortUrlVisits, ShortUrlVisits as ShortUrlVisitsState } from './reducers/shortUrlVisits'; import { ShortUrlVisitsHeader } from './ShortUrlVisitsHeader'; import type { NormalizedVisit, VisitsParams } from './types'; diff --git a/shlink-web-component/visits/TagVisits.tsx b/shlink-web-component/visits/TagVisits.tsx index 0fbd308b..9bfc183d 100644 --- a/shlink-web-component/visits/TagVisits.tsx +++ b/shlink-web-component/visits/TagVisits.tsx @@ -1,10 +1,10 @@ import { useParams } from 'react-router-dom'; -import type { ShlinkVisitsParams } from '../../api/types'; -import type { ReportExporter } from '../../src/common/services/ReportExporter'; import { useGoBack } from '../../src/utils/helpers/hooks'; -import type { ColorGenerator } from '../../src/utils/services/ColorGenerator'; +import type { ShlinkVisitsParams } from '../api-contract'; import { boundToMercureHub } from '../mercure/helpers/boundToMercureHub'; import { Topics } from '../mercure/helpers/Topics'; +import type { ColorGenerator } from '../utils/services/ColorGenerator'; +import type { ReportExporter } from '../utils/services/ReportExporter'; import type { LoadTagVisits, TagVisits as TagVisitsState } from './reducers/tagVisits'; import { TagVisitsHeader } from './TagVisitsHeader'; import type { NormalizedVisit } from './types'; diff --git a/shlink-web-component/visits/TagVisitsHeader.tsx b/shlink-web-component/visits/TagVisitsHeader.tsx index b53bd5e4..341b0bad 100644 --- a/shlink-web-component/visits/TagVisitsHeader.tsx +++ b/shlink-web-component/visits/TagVisitsHeader.tsx @@ -1,5 +1,5 @@ -import type { ColorGenerator } from '../../src/utils/services/ColorGenerator'; import { Tag } from '../tags/helpers/Tag'; +import type { ColorGenerator } from '../utils/services/ColorGenerator'; import type { TagVisits } from './reducers/tagVisits'; import { VisitsHeader } from './VisitsHeader'; import './ShortUrlVisitsHeader.scss'; diff --git a/shlink-web-component/visits/charts/LineChartCard.tsx b/shlink-web-component/visits/charts/LineChartCard.tsx index 0fc05bd3..b09a3206 100644 --- a/shlink-web-component/visits/charts/LineChartCard.tsx +++ b/shlink-web-component/visits/charts/LineChartCard.tsx @@ -25,11 +25,11 @@ import { } from 'reactstrap'; import { pointerOnHover, renderChartLabel } from '../../../src/utils/helpers/charts'; import { STANDARD_DATE_FORMAT } from '../../../src/utils/helpers/date'; -import { useToggle } from '../../../src/utils/helpers/hooks'; import { prettify } from '../../../src/utils/helpers/numbers'; import { HIGHLIGHTED_COLOR, MAIN_COLOR } from '../../../src/utils/theme'; import { ToggleSwitch } from '../../../src/utils/ToggleSwitch'; import { rangeOf } from '../../../src/utils/utils'; +import { useToggle } from '../../utils/helpers/hooks'; import type { NormalizedVisit, Stats } from '../types'; import { fillTheGaps } from '../utils'; import './LineChartCard.scss'; diff --git a/shlink-web-component/visits/helpers/OpenMapModalBtn.tsx b/shlink-web-component/visits/helpers/OpenMapModalBtn.tsx index 5ed1c536..b36a2ce9 100644 --- a/shlink-web-component/visits/helpers/OpenMapModalBtn.tsx +++ b/shlink-web-component/visits/helpers/OpenMapModalBtn.tsx @@ -2,7 +2,7 @@ import { faMapMarkedAlt as mapIcon } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { useState } from 'react'; import { Button, Dropdown, DropdownItem, DropdownMenu, UncontrolledTooltip } from 'reactstrap'; -import { useDomId, useToggle } from '../../../src/utils/helpers/hooks'; +import { useDomId, useToggle } from '../../utils/helpers/hooks'; import type { CityStats } from '../types'; import { MapModal } from './MapModal'; import './OpenMapModalBtn.scss'; diff --git a/shlink-web-component/visits/helpers/hooks.ts b/shlink-web-component/visits/helpers/hooks.ts index 0b465453..05809522 100644 --- a/shlink-web-component/visits/helpers/hooks.ts +++ b/shlink-web-component/visits/helpers/hooks.ts @@ -5,9 +5,9 @@ import { useLocation, useNavigate } from 'react-router-dom'; import { formatIsoDate } from '../../../src/utils/helpers/date'; import type { DateRange } from '../../../src/utils/helpers/dateIntervals'; import { datesToDateRange } from '../../../src/utils/helpers/dateIntervals'; -import { parseQuery, stringifyQuery } from '../../../src/utils/helpers/query'; import type { BooleanString } from '../../../src/utils/utils'; import { parseBooleanToString } from '../../../src/utils/utils'; +import { parseQuery, stringifyQuery } from '../../utils/helpers/query'; import type { OrphanVisitType, VisitsFilter } from '../types'; interface VisitsQuery { diff --git a/src/api/services/ShlinkApiClient.ts b/src/api/services/ShlinkApiClient.ts index 78b3efa8..965e633c 100644 --- a/src/api/services/ShlinkApiClient.ts +++ b/src/api/services/ShlinkApiClient.ts @@ -18,9 +18,9 @@ import type { ShlinkVisitsParams } from '../../../shlink-web-component/api-contract'; import { isRegularNotFound, parseApiError } from '../../../shlink-web-component/api-contract/utils'; import type { ShortUrl, ShortUrlData } from '../../../shlink-web-component/short-urls/data'; +import { stringifyQuery } from '../../../shlink-web-component/utils/helpers/query'; import type { HttpClient } from '../../common/services/HttpClient'; import { orderToString } from '../../utils/helpers/ordering'; -import { stringifyQuery } from '../../utils/helpers/query'; import { replaceAuthorityFromUri } from '../../utils/helpers/uri'; import type { OptionalString } from '../../utils/utils'; diff --git a/src/common/services/ReportExporter.ts b/src/common/services/ReportExporter.ts index f3b81376..e69de29b 100644 --- a/src/common/services/ReportExporter.ts +++ b/src/common/services/ReportExporter.ts @@ -1,29 +0,0 @@ -import type { ExportableShortUrl } from '../../../shlink-web-component/short-urls/data'; -import type { NormalizedVisit } from '../../../shlink-web-component/visits/types'; -import type { JsonToCsv } from '../../utils/helpers/csvjson'; -import { saveCsv } from '../../utils/helpers/files'; - -export class ReportExporter { - public constructor(private readonly window: Window, private readonly jsonToCsv: JsonToCsv) {} - - public readonly exportVisits = (filename: string, visits: NormalizedVisit[]) => { - if (!visits.length) { - return; - } - - this.exportCsv(filename, visits); - }; - - public readonly exportShortUrls = (shortUrls: ExportableShortUrl[]) => { - if (!shortUrls.length) { - return; - } - - this.exportCsv('short_urls.csv', shortUrls); - }; - - private readonly exportCsv = (filename: string, rows: object[]) => { - const csv = this.jsonToCsv(rows); - saveCsv(this.window, csv, filename); - }; -} diff --git a/src/common/services/provideServices.ts b/src/common/services/provideServices.ts index 57e91e10..8e606bb2 100644 --- a/src/common/services/provideServices.ts +++ b/src/common/services/provideServices.ts @@ -10,7 +10,6 @@ import { ScrollToTop } from '../ScrollToTop'; import { ShlinkVersionsContainer } from '../ShlinkVersionsContainer'; import { HttpClient } from './HttpClient'; import { ImageDownloader } from './ImageDownloader'; -import { ReportExporter } from './ReportExporter'; export const provideServices = (bottle: Bottle, connect: ConnectDecorator) => { // Services @@ -20,7 +19,6 @@ export const provideServices = (bottle: Bottle, connect: ConnectDecorator) => { bottle.service('HttpClient', HttpClient, 'fetch'); bottle.service('ImageDownloader', ImageDownloader, 'HttpClient', 'window'); - bottle.service('ReportExporter', ReportExporter, 'window', 'jsonToCsv'); // Components bottle.serviceFactory('ScrollToTop', () => ScrollToTop); diff --git a/src/utils/helpers/csvjson.ts b/src/utils/helpers/csvjson.ts index 83411c51..bf89a1b8 100644 --- a/src/utils/helpers/csvjson.ts +++ b/src/utils/helpers/csvjson.ts @@ -7,7 +7,7 @@ export const csvToJson = (csvContent: string) => new Promise((resolve) = export type CsvToJson = typeof csvToJson; -const jsonParser = new Parser(); // TODO This accepts options if needed +const jsonParser = new Parser(); // This accepts options if needed export const jsonToCsv = (data: T[]): string => jsonParser.parse(data); diff --git a/src/utils/helpers/hooks.ts b/src/utils/helpers/hooks.ts index d51cb13a..2c405800 100644 --- a/src/utils/helpers/hooks.ts +++ b/src/utils/helpers/hooks.ts @@ -1,9 +1,8 @@ import type { DependencyList, EffectCallback } from 'react'; import { useEffect, useRef, useState } from 'react'; import { useLocation, useNavigate } from 'react-router-dom'; -import { useSwipeable as useReactSwipeable } from 'react-swipeable'; import { v4 as uuid } from 'uuid'; -import { parseQuery, stringifyQuery } from './query'; +import { parseQuery } from '../../../shlink-web-component/utils/helpers/query'; const DEFAULT_DELAY = 2000; @@ -35,40 +34,6 @@ export const useToggle = (initialValue = false): ToggleResult => { return [flag, () => setFlag(!flag), () => setFlag(true), () => setFlag(false)]; }; -export const useSwipeable = (showSidebar: () => void, hideSidebar: () => void) => { - const swipeMenuIfNoModalExists = (callback: () => void) => (e: any) => { - const swippedOnVisitsTable = (e.event.composedPath() as HTMLElement[]).some( - ({ classList }) => classList?.contains('visits-table'), - ); - - if (swippedOnVisitsTable || document.querySelector('.modal')) { - return; - } - - callback(); - }; - - return useReactSwipeable({ - delta: 40, - onSwipedLeft: swipeMenuIfNoModalExists(hideSidebar), - onSwipedRight: swipeMenuIfNoModalExists(showSidebar), - }); -}; - -export const useQueryState = (paramName: string, initialState: T): [ T, (newValue: T) => void ] => { - const [value, setValue] = useState(initialState); - const setValueWithLocation = (valueToSet: T) => { - const { location, history } = window; - const query = parseQuery(location.search); - - query[paramName] = valueToSet; - history.pushState(null, '', `${location.pathname}?${stringifyQuery(query)}`); - setValue(valueToSet); - }; - - return [value, setValueWithLocation]; -}; - export const useEffectExceptFirstTime = (callback: EffectCallback, deps: DependencyList): void => { const isFirstLoad = useRef(true); diff --git a/src/utils/helpers/qrCodes.ts b/src/utils/helpers/qrCodes.ts index 2e66d676..356bd54a 100644 --- a/src/utils/helpers/qrCodes.ts +++ b/src/utils/helpers/qrCodes.ts @@ -1,5 +1,5 @@ import { isEmpty } from 'ramda'; -import { stringifyQuery } from './query'; +import { stringifyQuery } from '../../../shlink-web-component/utils/helpers/query'; export type QrCodeFormat = 'svg' | 'png'; diff --git a/src/utils/services/provideServices.ts b/src/utils/services/provideServices.ts index 7a16b11a..b7fa4d03 100644 --- a/src/utils/services/provideServices.ts +++ b/src/utils/services/provideServices.ts @@ -1,7 +1,7 @@ import type Bottle from 'bottlejs'; +import { ColorGenerator } from '../../../shlink-web-component/utils/services/ColorGenerator'; import { csvToJson, jsonToCsv } from '../helpers/csvjson'; import { useTimeoutToggle } from '../helpers/hooks'; -import { ColorGenerator } from './ColorGenerator'; import { LocalStorage } from './LocalStorage'; export const provideServices = (bottle: Bottle) => { diff --git a/test/common/AsideMenu.test.tsx b/test/common/AsideMenu.test.tsx index fac3fe61..9a20b6e2 100644 --- a/test/common/AsideMenu.test.tsx +++ b/test/common/AsideMenu.test.tsx @@ -1,7 +1,7 @@ import { render, screen } from '@testing-library/react'; import { fromPartial } from '@total-typescript/shoehorn'; import { MemoryRouter } from 'react-router'; -import { AsideMenu } from '../../src/common/AsideMenu'; +import { AsideMenu } from '../../shlink-web-component/common/AsideMenu'; describe('', () => { const setUp = () => render( diff --git a/test/common/services/ReportExporter.test.ts b/test/common/services/ReportExporter.test.ts index 6d040e0c..6be3ffeb 100644 --- a/test/common/services/ReportExporter.test.ts +++ b/test/common/services/ReportExporter.test.ts @@ -1,6 +1,6 @@ import type { ExportableShortUrl } from '../../../shlink-web-component/short-urls/data'; +import { ReportExporter } from '../../../shlink-web-component/utils/services/ReportExporter'; import type { NormalizedVisit } from '../../../shlink-web-component/visits/types'; -import { ReportExporter } from '../../../src/common/services/ReportExporter'; import { windowMock } from '../../__mocks__/Window.mock'; describe('ReportExporter', () => { diff --git a/test/short-urls/helpers/ExportShortUrlsBtn.test.tsx b/test/short-urls/helpers/ExportShortUrlsBtn.test.tsx index 8be25676..adf74767 100644 --- a/test/short-urls/helpers/ExportShortUrlsBtn.test.tsx +++ b/test/short-urls/helpers/ExportShortUrlsBtn.test.tsx @@ -3,7 +3,7 @@ import { fromPartial } from '@total-typescript/shoehorn'; import { MemoryRouter } from 'react-router-dom'; import type { ShortUrl } from '../../../shlink-web-component/short-urls/data'; import { ExportShortUrlsBtn as createExportShortUrlsBtn } from '../../../shlink-web-component/short-urls/helpers/ExportShortUrlsBtn'; -import type { ReportExporter } from '../../../src/common/services/ReportExporter'; +import type { ReportExporter } from '../../../shlink-web-component/utils/services/ReportExporter'; import type { NotFoundServer, SelectedServer } from '../../../src/servers/data'; import { renderWithEvents } from '../../__helpers__/setUpTest'; diff --git a/test/tags/helpers/Tag.test.tsx b/test/tags/helpers/Tag.test.tsx index b0d840e7..232aecc1 100644 --- a/test/tags/helpers/Tag.test.tsx +++ b/test/tags/helpers/Tag.test.tsx @@ -2,7 +2,7 @@ import { screen } from '@testing-library/react'; import { fromPartial } from '@total-typescript/shoehorn'; import type { ReactNode } from 'react'; import { Tag } from '../../../shlink-web-component/tags/helpers/Tag'; -import type { ColorGenerator } from '../../../src/utils/services/ColorGenerator'; +import type { ColorGenerator } from '../../../shlink-web-component/utils/services/ColorGenerator'; import { MAIN_COLOR } from '../../../src/utils/theme'; import { renderWithEvents } from '../../__helpers__/setUpTest'; diff --git a/test/tags/reducers/tagEdit.test.ts b/test/tags/reducers/tagEdit.test.ts index 31500d5c..c31c9a78 100644 --- a/test/tags/reducers/tagEdit.test.ts +++ b/test/tags/reducers/tagEdit.test.ts @@ -1,8 +1,8 @@ import { fromPartial } from '@total-typescript/shoehorn'; import { editTag as editTagCreator, tagEdited, tagEditReducerCreator } from '../../../shlink-web-component/tags/reducers/tagEdit'; +import type { ColorGenerator } from '../../../shlink-web-component/utils/services/ColorGenerator'; import type { ShlinkApiClient } from '../../../src/api/services/ShlinkApiClient'; import type { ShlinkState } from '../../../src/container/types'; -import type { ColorGenerator } from '../../../src/utils/services/ColorGenerator'; describe('tagEditReducer', () => { const oldName = 'foo'; diff --git a/test/utils/helpers/query.test.ts b/test/utils/helpers/query.test.ts index 68e1350c..a4fae9d9 100644 --- a/test/utils/helpers/query.test.ts +++ b/test/utils/helpers/query.test.ts @@ -1,4 +1,4 @@ -import { parseQuery, stringifyQuery } from '../../../src/utils/helpers/query'; +import { parseQuery, stringifyQuery } from '../../../shlink-web-component/utils/helpers/query'; describe('query', () => { describe('parseQuery', () => { diff --git a/test/utils/services/ColorGenerator.test.ts b/test/utils/services/ColorGenerator.test.ts index dc0d8a44..c1809448 100644 --- a/test/utils/services/ColorGenerator.test.ts +++ b/test/utils/services/ColorGenerator.test.ts @@ -1,5 +1,5 @@ import { fromPartial } from '@total-typescript/shoehorn'; -import { ColorGenerator } from '../../../src/utils/services/ColorGenerator'; +import { ColorGenerator } from '../../../shlink-web-component/utils/services/ColorGenerator'; import type { LocalStorage } from '../../../src/utils/services/LocalStorage'; import { MAIN_COLOR } from '../../../src/utils/theme'; diff --git a/test/utils/services/__mocks__/ColorGenerator.mock.ts b/test/utils/services/__mocks__/ColorGenerator.mock.ts index d898575d..f8b038c3 100644 --- a/test/utils/services/__mocks__/ColorGenerator.mock.ts +++ b/test/utils/services/__mocks__/ColorGenerator.mock.ts @@ -1,5 +1,5 @@ import { fromPartial } from '@total-typescript/shoehorn'; -import type { ColorGenerator } from '../../../../src/utils/services/ColorGenerator'; +import type { ColorGenerator } from '../../../../shlink-web-component/utils/services/ColorGenerator'; export const colorGeneratorMock = fromPartial({ getColorForKey: vi.fn(() => 'red'), diff --git a/test/visits/TagVisitsHeader.test.tsx b/test/visits/TagVisitsHeader.test.tsx index df4f5a83..680a7cfd 100644 --- a/test/visits/TagVisitsHeader.test.tsx +++ b/test/visits/TagVisitsHeader.test.tsx @@ -1,8 +1,8 @@ import { render, screen } from '@testing-library/react'; import { fromPartial } from '@total-typescript/shoehorn'; +import type { ColorGenerator } from '../../shlink-web-component/utils/services/ColorGenerator'; import type { TagVisits } from '../../shlink-web-component/visits/reducers/tagVisits'; import { TagVisitsHeader } from '../../shlink-web-component/visits/TagVisitsHeader'; -import type { ColorGenerator } from '../../src/utils/services/ColorGenerator'; describe('', () => { const tagVisits = fromPartial({