diff --git a/shlink-web-component/ShlinkWebComponent.tsx b/shlink-web-component/ShlinkWebComponent.tsx index 3cf5d3a0..cb377c3c 100644 --- a/shlink-web-component/ShlinkWebComponent.tsx +++ b/shlink-web-component/ShlinkWebComponent.tsx @@ -3,9 +3,9 @@ import type Bottle from 'bottlejs'; import type { FC, ReactNode } from 'react'; import { useEffect, useRef, useState } from 'react'; import { Provider } from 'react-redux'; -import type { SemVer } from '../src/utils/helpers/version'; import type { ShlinkApiClient } from './api-contract'; import { FeaturesProvider, useFeatures } from './utils/features'; +import type { SemVer } from './utils/helpers/version'; import { RoutesPrefixProvider } from './utils/routesPrefix'; import type { Settings } from './utils/settings'; import { SettingsProvider } from './utils/settings'; diff --git a/shlink-web-component/api-contract/types.ts b/shlink-web-component/api-contract/types.ts index a370f617..7381c3e1 100644 --- a/shlink-web-component/api-contract/types.ts +++ b/shlink-web-component/api-contract/types.ts @@ -1,5 +1,4 @@ import type { Order } from '../../src/utils/helpers/ordering'; -import type { OptionalString } from '../../src/utils/utils'; import type { ShortUrl, ShortUrlMeta } from '../short-urls/data'; import type { Visit } from '../visits/types'; @@ -70,7 +69,7 @@ export interface ShlinkVisitsOverview { } export interface ShlinkVisitsParams { - domain?: OptionalString; + domain?: string | null; page?: number; itemsPerPage?: number; startDate?: string; @@ -98,12 +97,12 @@ export interface ShlinkEditDomainRedirects extends Partial void; } -const Nr: FC<{ fallback: OptionalString }> = ({ fallback }) => ( +const Nr: FC<{ fallback?: string | null }> = ({ fallback }) => ( {!fallback && No redirect} {fallback && <>{fallback} (as fallback)} diff --git a/shlink-web-component/domains/ManageDomains.tsx b/shlink-web-component/domains/ManageDomains.tsx index 77bf4c8b..1cd68352 100644 --- a/shlink-web-component/domains/ManageDomains.tsx +++ b/shlink-web-component/domains/ManageDomains.tsx @@ -1,10 +1,10 @@ import type { FC } from 'react'; import { useEffect } from 'react'; -import { ShlinkApiError } from '../../src/api/ShlinkApiError'; import { Message } from '../../src/utils/Message'; import { Result } from '../../src/utils/Result'; import { SearchField } from '../../src/utils/SearchField'; import { SimpleCard } from '../../src/utils/SimpleCard'; +import { ShlinkApiError } from '../common/ShlinkApiError'; import { DomainRow } from './DomainRow'; import type { EditDomainRedirects } from './reducers/domainRedirects'; import type { DomainsList } from './reducers/domainsList'; diff --git a/shlink-web-component/domains/helpers/DomainStatusIcon.tsx b/shlink-web-component/domains/helpers/DomainStatusIcon.tsx index 838aba4c..9d7c071c 100644 --- a/shlink-web-component/domains/helpers/DomainStatusIcon.tsx +++ b/shlink-web-component/domains/helpers/DomainStatusIcon.tsx @@ -8,8 +8,8 @@ import type { FC } from 'react'; import { useEffect, useState } from 'react'; import { ExternalLink } from 'react-external-link'; import { UncontrolledTooltip } from 'reactstrap'; -import { useElementRef } from '../../../src/utils/helpers/hooks'; -import type { MediaMatcher } from '../../../src/utils/types'; +import { useElementRef } from '../../utils/helpers/hooks'; +import type { MediaMatcher } from '../../utils/types'; import type { DomainStatus } from '../data'; interface DomainStatusIconProps { diff --git a/shlink-web-component/domains/helpers/EditDomainRedirectsModal.tsx b/shlink-web-component/domains/helpers/EditDomainRedirectsModal.tsx index 99fc74eb..acf1ddf4 100644 --- a/shlink-web-component/domains/helpers/EditDomainRedirectsModal.tsx +++ b/shlink-web-component/domains/helpers/EditDomainRedirectsModal.tsx @@ -1,11 +1,11 @@ import type { FC } from 'react'; import { useState } from 'react'; import { Button, Modal, ModalBody, ModalFooter, ModalHeader } from 'reactstrap'; -import type { ShlinkDomain } from '../../../api/types'; import type { InputFormGroupProps } from '../../../src/utils/forms/InputFormGroup'; import { InputFormGroup } from '../../../src/utils/forms/InputFormGroup'; -import { InfoTooltip } from '../../../src/utils/InfoTooltip'; -import { handleEventPreventingDefault, nonEmptyValueOrNull } from '../../../src/utils/utils'; +import type { ShlinkDomain } from '../../api-contract'; +import { InfoTooltip } from '../../utils/components/InfoTooltip'; +import { handleEventPreventingDefault, nonEmptyValueOrNull } from '../../utils/helpers'; import type { EditDomainRedirects } from '../reducers/domainRedirects'; interface EditDomainRedirectsModalProps { diff --git a/shlink-web-component/overview/Overview.tsx b/shlink-web-component/overview/Overview.tsx index 4d769f2a..c51d48fb 100644 --- a/shlink-web-component/overview/Overview.tsx +++ b/shlink-web-component/overview/Overview.tsx @@ -2,7 +2,6 @@ import type { FC } from 'react'; import { useEffect } from 'react'; import { Link, useNavigate } from 'react-router-dom'; import { Card, CardBody, CardHeader, Row } from 'reactstrap'; -import { prettify } from '../../src/utils/helpers/numbers'; import type { ShlinkShortUrlsListParams } from '../api-contract'; import { boundToMercureHub } from '../mercure/helpers/boundToMercureHub'; import { Topics } from '../mercure/helpers/Topics'; @@ -11,6 +10,7 @@ import type { ShortUrlsList as ShortUrlsListState } from '../short-urls/reducers import { ITEMS_IN_OVERVIEW_PAGE } from '../short-urls/reducers/shortUrlsList'; import type { ShortUrlsTableType } from '../short-urls/ShortUrlsTable'; import type { TagsList } from '../tags/reducers/tagsList'; +import { prettify } from '../utils/helpers/numbers'; import { useRoutesPrefix } from '../utils/routesPrefix'; import { useSetting } from '../utils/settings'; import type { VisitsOverview } from '../visits/reducers/visitsOverview'; diff --git a/shlink-web-component/overview/helpers/HighlightCard.tsx b/shlink-web-component/overview/helpers/HighlightCard.tsx index b4a7d45f..a5d391c0 100644 --- a/shlink-web-component/overview/helpers/HighlightCard.tsx +++ b/shlink-web-component/overview/helpers/HighlightCard.tsx @@ -3,7 +3,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import type { FC, PropsWithChildren, ReactNode } from 'react'; import { Link } from 'react-router-dom'; import { Card, CardText, CardTitle, UncontrolledTooltip } from 'reactstrap'; -import { useElementRef } from '../../../src/utils/helpers/hooks'; +import { useElementRef } from '../../utils/helpers/hooks'; import './HighlightCard.scss'; export type HighlightCardProps = PropsWithChildren<{ diff --git a/shlink-web-component/overview/helpers/VisitsHighlightCard.tsx b/shlink-web-component/overview/helpers/VisitsHighlightCard.tsx index 761c45f0..1617eb2e 100644 --- a/shlink-web-component/overview/helpers/VisitsHighlightCard.tsx +++ b/shlink-web-component/overview/helpers/VisitsHighlightCard.tsx @@ -1,5 +1,5 @@ import type { FC } from 'react'; -import { prettify } from '../../../src/utils/helpers/numbers'; +import { prettify } from '../../utils/helpers/numbers'; import type { PartialVisitsSummary } from '../../visits/reducers/visitsOverview'; import type { HighlightCardProps } from './HighlightCard'; import { HighlightCard } from './HighlightCard'; diff --git a/shlink-web-component/short-urls/EditShortUrl.tsx b/shlink-web-component/short-urls/EditShortUrl.tsx index 8ef5fd66..d8271cd9 100644 --- a/shlink-web-component/short-urls/EditShortUrl.tsx +++ b/shlink-web-component/short-urls/EditShortUrl.tsx @@ -5,10 +5,10 @@ import { useEffect, useMemo } from 'react'; import { ExternalLink } from 'react-external-link'; 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 { Message } from '../../src/utils/Message'; import { Result } from '../../src/utils/Result'; +import { ShlinkApiError } from '../common/ShlinkApiError'; +import { useGoBack } from '../utils/helpers/hooks'; import { parseQuery } from '../utils/helpers/query'; import { useSetting } from '../utils/settings'; import type { ShortUrlIdentifier } from './data'; diff --git a/shlink-web-component/short-urls/Paginator.tsx b/shlink-web-component/short-urls/Paginator.tsx index 0604d4e4..f2488585 100644 --- a/shlink-web-component/short-urls/Paginator.tsx +++ b/shlink-web-component/short-urls/Paginator.tsx @@ -1,14 +1,14 @@ import { Link } from 'react-router-dom'; import { Pagination, PaginationItem, PaginationLink } from 'reactstrap'; +import type { ShlinkPaginator } from '../api-contract'; import type { - NumberOrEllipsis } from '../../src/utils/helpers/pagination'; + NumberOrEllipsis } from '../utils/helpers/pagination'; import { keyForPage, pageIsEllipsis, prettifyPageNumber, progressivePagination, -} from '../../src/utils/helpers/pagination'; -import type { ShlinkPaginator } from '../api-contract'; +} from '../utils/helpers/pagination'; import { useRoutesPrefix } from '../utils/routesPrefix'; interface PaginatorProps { diff --git a/shlink-web-component/short-urls/ShortUrlForm.tsx b/shlink-web-component/short-urls/ShortUrlForm.tsx index 02c46f34..ef64347c 100644 --- a/shlink-web-component/short-urls/ShortUrlForm.tsx +++ b/shlink-web-component/short-urls/ShortUrlForm.tsx @@ -14,10 +14,10 @@ import { DateTimeInput } from '../../src/utils/dates/DateTimeInput'; import { formatIsoDate } from '../../src/utils/helpers/date'; import { IconInput } from '../../src/utils/IconInput'; import { SimpleCard } from '../../src/utils/SimpleCard'; -import { handleEventPreventingDefault, hasValue } from '../../src/utils/utils'; import type { DomainSelectorProps } from '../domains/DomainSelector'; import type { TagsSelectorProps } from '../tags/helpers/TagsSelector'; import { useFeature } from '../utils/features'; +import { handleEventPreventingDefault, hasValue } from '../utils/helpers'; import type { DeviceLongUrls, ShortUrlData } from './data'; import { ShortUrlFormCheckboxGroup } from './helpers/ShortUrlFormCheckboxGroup'; import { UseExistingIfFoundInfoIcon } from './UseExistingIfFoundInfoIcon'; diff --git a/shlink-web-component/short-urls/ShortUrlsList.tsx b/shlink-web-component/short-urls/ShortUrlsList.tsx index a373f930..e4052a21 100644 --- a/shlink-web-component/short-urls/ShortUrlsList.tsx +++ b/shlink-web-component/short-urls/ShortUrlsList.tsx @@ -5,12 +5,12 @@ import { Card } from 'reactstrap'; import { DEFAULT_SHORT_URLS_ORDERING } from '../../src/settings/reducers/settings'; import type { OrderDir } from '../../src/utils/helpers/ordering'; import { determineOrderDir } from '../../src/utils/helpers/ordering'; -import { TableOrderIcon } from '../../src/utils/table/TableOrderIcon'; import type { ShlinkShortUrlsListParams, ShlinkShortUrlsOrder } from '../api-contract'; import { boundToMercureHub } from '../mercure/helpers/boundToMercureHub'; import { Topics } from '../mercure/helpers/Topics'; import { useFeature } from '../utils/features'; import { useSettings } from '../utils/settings'; +import { TableOrderIcon } from '../utils/table/TableOrderIcon'; import type { ShortUrlsOrder, ShortUrlsOrderableFields } from './data'; import { useShortUrlsQuery } from './helpers/hooks'; import { Paginator } from './Paginator'; diff --git a/shlink-web-component/short-urls/data/index.ts b/shlink-web-component/short-urls/data/index.ts index ec1b14b7..f1654a07 100644 --- a/shlink-web-component/short-urls/data/index.ts +++ b/shlink-web-component/short-urls/data/index.ts @@ -1,6 +1,6 @@ -import type { ShlinkVisitsSummary } from '../../../api/types'; import type { Order } from '../../../src/utils/helpers/ordering'; -import type { Nullable, OptionalString } from '../../../src/utils/utils'; +import type { ShlinkVisitsSummary } from '../../api-contract'; +import type { Nullable, OptionalString } from '../../utils/helpers'; export interface DeviceLongUrls { android?: OptionalString; diff --git a/shlink-web-component/short-urls/helpers/CreateShortUrlResult.tsx b/shlink-web-component/short-urls/helpers/CreateShortUrlResult.tsx index 0261f04a..4518bf61 100644 --- a/shlink-web-component/short-urls/helpers/CreateShortUrlResult.tsx +++ b/shlink-web-component/short-urls/helpers/CreateShortUrlResult.tsx @@ -4,9 +4,9 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { useEffect } from 'react'; import CopyToClipboard from 'react-copy-to-clipboard'; import { Tooltip } from 'reactstrap'; -import { ShlinkApiError } from '../../../src/api/ShlinkApiError'; -import type { TimeoutToggle } from '../../../src/utils/helpers/hooks'; import { Result } from '../../../src/utils/Result'; +import { ShlinkApiError } from '../../common/ShlinkApiError'; +import type { TimeoutToggle } from '../../utils/helpers/hooks'; import type { ShortUrlCreation } from '../reducers/shortUrlCreation'; import './CreateShortUrlResult.scss'; diff --git a/shlink-web-component/short-urls/helpers/DeleteShortUrlModal.tsx b/shlink-web-component/short-urls/helpers/DeleteShortUrlModal.tsx index 7771450c..8e9ee720 100644 --- a/shlink-web-component/short-urls/helpers/DeleteShortUrlModal.tsx +++ b/shlink-web-component/short-urls/helpers/DeleteShortUrlModal.tsx @@ -1,10 +1,10 @@ import { pipe } from 'ramda'; import { useEffect, useState } from 'react'; import { Modal, ModalBody, ModalFooter, ModalHeader } from 'reactstrap'; -import { ShlinkApiError } from '../../../src/api/ShlinkApiError'; import { Result } from '../../../src/utils/Result'; -import { handleEventPreventingDefault } from '../../../src/utils/utils'; import { isInvalidDeletionError } from '../../api-contract/utils'; +import { ShlinkApiError } from '../../common/ShlinkApiError'; +import { handleEventPreventingDefault } from '../../utils/helpers'; import type { ShortUrlIdentifier, ShortUrlModalProps } from '../data'; import type { ShortUrlDeletion } from '../reducers/shortUrlDeletion'; diff --git a/shlink-web-component/short-urls/helpers/ExportShortUrlsBtn.tsx b/shlink-web-component/short-urls/helpers/ExportShortUrlsBtn.tsx index 9f5af661..7f5193c1 100644 --- a/shlink-web-component/short-urls/helpers/ExportShortUrlsBtn.tsx +++ b/shlink-web-component/short-urls/helpers/ExportShortUrlsBtn.tsx @@ -1,7 +1,7 @@ import type { FC } from 'react'; import { useCallback } from 'react'; -import { ExportBtn } from '../../../src/utils/ExportBtn'; import type { ShlinkApiClient } from '../../api-contract'; +import { ExportBtn } from '../../utils/components/ExportBtn'; import { useToggle } from '../../utils/helpers/hooks'; import type { ReportExporter } from '../../utils/services/ReportExporter'; import type { ShortUrl } from '../data'; diff --git a/shlink-web-component/short-urls/helpers/QrCodeModal.tsx b/shlink-web-component/short-urls/helpers/QrCodeModal.tsx index 9c825bc1..82dc3ab6 100644 --- a/shlink-web-component/short-urls/helpers/QrCodeModal.tsx +++ b/shlink-web-component/short-urls/helpers/QrCodeModal.tsx @@ -3,10 +3,10 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { useMemo, useState } from 'react'; import { ExternalLink } from 'react-external-link'; import { Button, FormGroup, Modal, ModalBody, ModalHeader, Row } from 'reactstrap'; -import type { ImageDownloader } from '../../../src/common/services/ImageDownloader'; -import { CopyToClipboardIcon } from '../../../src/utils/CopyToClipboardIcon'; -import type { QrCodeFormat, QrErrorCorrection } from '../../../src/utils/helpers/qrCodes'; -import { buildQrCodeUrl } from '../../../src/utils/helpers/qrCodes'; +import { CopyToClipboardIcon } from '../../utils/components/CopyToClipboardIcon'; +import type { QrCodeFormat, QrErrorCorrection } from '../../utils/helpers/qrCodes'; +import { buildQrCodeUrl } from '../../utils/helpers/qrCodes'; +import type { ImageDownloader } from '../../utils/services/ImageDownloader'; import type { ShortUrlModalProps } from '../data'; import { QrErrorCorrectionDropdown } from './qr-codes/QrErrorCorrectionDropdown'; import { QrFormatDropdown } from './qr-codes/QrFormatDropdown'; diff --git a/shlink-web-component/short-urls/helpers/ShortUrlFormCheckboxGroup.tsx b/shlink-web-component/short-urls/helpers/ShortUrlFormCheckboxGroup.tsx index 54f16b2a..cb3b6e86 100644 --- a/shlink-web-component/short-urls/helpers/ShortUrlFormCheckboxGroup.tsx +++ b/shlink-web-component/short-urls/helpers/ShortUrlFormCheckboxGroup.tsx @@ -1,6 +1,6 @@ import type { ChangeEvent, FC, PropsWithChildren } from 'react'; import { Checkbox } from '../../../src/utils/Checkbox'; -import { InfoTooltip } from '../../../src/utils/InfoTooltip'; +import { InfoTooltip } from '../../utils/components/InfoTooltip'; type ShortUrlFormCheckboxGroupProps = PropsWithChildren<{ checked?: boolean; diff --git a/shlink-web-component/short-urls/helpers/ShortUrlStatus.tsx b/shlink-web-component/short-urls/helpers/ShortUrlStatus.tsx index 817bf30e..f7a88230 100644 --- a/shlink-web-component/short-urls/helpers/ShortUrlStatus.tsx +++ b/shlink-web-component/short-urls/helpers/ShortUrlStatus.tsx @@ -5,7 +5,7 @@ import { isBefore } from 'date-fns'; import type { FC, ReactNode } from 'react'; import { UncontrolledTooltip } from 'reactstrap'; import { formatHumanFriendly, now, parseISO } from '../../../src/utils/helpers/date'; -import { useElementRef } from '../../../src/utils/helpers/hooks'; +import { useElementRef } from '../../utils/helpers/hooks'; import type { ShortUrl } from '../data'; interface ShortUrlStatusProps { diff --git a/shlink-web-component/short-urls/helpers/ShortUrlVisitsCount.tsx b/shlink-web-component/short-urls/helpers/ShortUrlVisitsCount.tsx index 985992c7..1d672356 100644 --- a/shlink-web-component/short-urls/helpers/ShortUrlVisitsCount.tsx +++ b/shlink-web-component/short-urls/helpers/ShortUrlVisitsCount.tsx @@ -3,8 +3,8 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import classNames from 'classnames'; import { UncontrolledTooltip } from 'reactstrap'; import { formatHumanFriendly, parseISO } from '../../../src/utils/helpers/date'; -import { useElementRef } from '../../../src/utils/helpers/hooks'; -import { prettify } from '../../../src/utils/helpers/numbers'; +import { useElementRef } from '../../utils/helpers/hooks'; +import { prettify } from '../../utils/helpers/numbers'; import type { ShortUrl } from '../data'; import { ShortUrlDetailLink } from './ShortUrlDetailLink'; import './ShortUrlVisitsCount.scss'; diff --git a/shlink-web-component/short-urls/helpers/ShortUrlsFilterDropdown.tsx b/shlink-web-component/short-urls/helpers/ShortUrlsFilterDropdown.tsx index c8664cbe..2a2b7d8c 100644 --- a/shlink-web-component/short-urls/helpers/ShortUrlsFilterDropdown.tsx +++ b/shlink-web-component/short-urls/helpers/ShortUrlsFilterDropdown.tsx @@ -1,6 +1,6 @@ import { DropdownItem } from 'reactstrap'; import { DropdownBtn } from '../../../src/utils/DropdownBtn'; -import { hasValue } from '../../../src/utils/utils'; +import { hasValue } from '../../utils/helpers'; import type { ShortUrlsFilter } from '../data'; interface ShortUrlsFilterDropdownProps { diff --git a/shlink-web-component/short-urls/helpers/ShortUrlsRow.tsx b/shlink-web-component/short-urls/helpers/ShortUrlsRow.tsx index 5ded6acb..56cd8b71 100644 --- a/shlink-web-component/short-urls/helpers/ShortUrlsRow.tsx +++ b/shlink-web-component/short-urls/helpers/ShortUrlsRow.tsx @@ -1,9 +1,9 @@ import type { FC } from 'react'; import { useEffect, useRef } from 'react'; 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 { CopyToClipboardIcon } from '../../utils/components/CopyToClipboardIcon'; import type { ColorGenerator } from '../../utils/services/ColorGenerator'; import { useSetting } from '../../utils/settings'; import type { ShortUrl } from '../data'; diff --git a/shlink-web-component/short-urls/helpers/hooks.ts b/shlink-web-component/short-urls/helpers/hooks.ts index 1a6a1879..00f4078d 100644 --- a/shlink-web-component/short-urls/helpers/hooks.ts +++ b/shlink-web-component/short-urls/helpers/hooks.ts @@ -2,9 +2,9 @@ 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 type { BooleanString } from '../../../src/utils/utils'; -import { parseOptionalBooleanToString } from '../../../src/utils/utils'; import type { TagsFilteringMode } from '../../api-contract'; +import type { BooleanString } from '../../utils/helpers'; +import { parseOptionalBooleanToString } from '../../utils/helpers'; import { parseQuery, stringifyQuery } from '../../utils/helpers/query'; import { useRoutesPrefix } from '../../utils/routesPrefix'; import type { ShortUrlsOrder, ShortUrlsOrderableFields } from '../data'; diff --git a/shlink-web-component/short-urls/helpers/index.ts b/shlink-web-component/short-urls/helpers/index.ts index 2c1821c5..97d332be 100644 --- a/shlink-web-component/short-urls/helpers/index.ts +++ b/shlink-web-component/short-urls/helpers/index.ts @@ -1,5 +1,5 @@ import { isNil } from 'ramda'; -import type { OptionalString } from '../../../src/utils/utils'; +import type { OptionalString } from '../../utils/helpers'; import type { ShortUrlCreationSettings } from '../../utils/settings'; import { DEFAULT_DOMAIN } from '../../visits/reducers/domainVisits'; import type { ShortUrl, ShortUrlData } from '../data'; diff --git a/shlink-web-component/short-urls/helpers/qr-codes/QrErrorCorrectionDropdown.tsx b/shlink-web-component/short-urls/helpers/qr-codes/QrErrorCorrectionDropdown.tsx index d7d7ded2..0eb73d9a 100644 --- a/shlink-web-component/short-urls/helpers/qr-codes/QrErrorCorrectionDropdown.tsx +++ b/shlink-web-component/short-urls/helpers/qr-codes/QrErrorCorrectionDropdown.tsx @@ -1,7 +1,7 @@ import type { FC } from 'react'; import { DropdownItem } from 'reactstrap'; import { DropdownBtn } from '../../../../src/utils/DropdownBtn'; -import type { QrErrorCorrection } from '../../../../src/utils/helpers/qrCodes'; +import type { QrErrorCorrection } from '../../../utils/helpers/qrCodes'; interface QrErrorCorrectionDropdownProps { errorCorrection: QrErrorCorrection; diff --git a/shlink-web-component/short-urls/helpers/qr-codes/QrFormatDropdown.tsx b/shlink-web-component/short-urls/helpers/qr-codes/QrFormatDropdown.tsx index a005b061..526940dc 100644 --- a/shlink-web-component/short-urls/helpers/qr-codes/QrFormatDropdown.tsx +++ b/shlink-web-component/short-urls/helpers/qr-codes/QrFormatDropdown.tsx @@ -1,7 +1,7 @@ import type { FC } from 'react'; import { DropdownItem } from 'reactstrap'; import { DropdownBtn } from '../../../../src/utils/DropdownBtn'; -import type { QrCodeFormat } from '../../../../src/utils/helpers/qrCodes'; +import type { QrCodeFormat } from '../../../utils/helpers/qrCodes'; interface QrFormatDropdownProps { format: QrCodeFormat; diff --git a/shlink-web-component/tags/TagsList.tsx b/shlink-web-component/tags/TagsList.tsx index 916ca9a0..4e7c5bc1 100644 --- a/shlink-web-component/tags/TagsList.tsx +++ b/shlink-web-component/tags/TagsList.tsx @@ -2,12 +2,12 @@ import { pipe } from 'ramda'; import type { FC } from 'react'; import { useEffect, useState } from 'react'; import { Row } from 'reactstrap'; -import { ShlinkApiError } from '../../src/api/ShlinkApiError'; import { determineOrderDir, sortList } from '../../src/utils/helpers/ordering'; import { Message } from '../../src/utils/Message'; import { OrderingDropdown } from '../../src/utils/OrderingDropdown'; import { Result } from '../../src/utils/Result'; import { SearchField } from '../../src/utils/SearchField'; +import { ShlinkApiError } from '../common/ShlinkApiError'; import { boundToMercureHub } from '../mercure/helpers/boundToMercureHub'; import { Topics } from '../mercure/helpers/Topics'; import { useSettings } from '../utils/settings'; diff --git a/shlink-web-component/tags/TagsTable.tsx b/shlink-web-component/tags/TagsTable.tsx index 30b9ed2a..30d33a7a 100644 --- a/shlink-web-component/tags/TagsTable.tsx +++ b/shlink-web-component/tags/TagsTable.tsx @@ -2,11 +2,11 @@ import { splitEvery } from 'ramda'; import type { FC } from 'react'; import { useEffect, useRef } from 'react'; import { useLocation } from 'react-router-dom'; -import { SimplePaginator } from '../../src/common/SimplePaginator'; import { SimpleCard } from '../../src/utils/SimpleCard'; -import { TableOrderIcon } from '../../src/utils/table/TableOrderIcon'; +import { SimplePaginator } from '../utils/components/SimplePaginator'; import { useQueryState } from '../utils/helpers/hooks'; import { parseQuery } from '../utils/helpers/query'; +import { TableOrderIcon } from '../utils/table/TableOrderIcon'; 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 080bd381..5c84ea7b 100644 --- a/shlink-web-component/tags/TagsTableRow.tsx +++ b/shlink-web-component/tags/TagsTableRow.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 { prettify } from '../../src/utils/helpers/numbers'; import { RowDropdownBtn } from '../../src/utils/RowDropdownBtn'; import { useToggle } from '../utils/helpers/hooks'; +import { prettify } from '../utils/helpers/numbers'; import { useRoutesPrefix } from '../utils/routesPrefix'; import type { ColorGenerator } from '../utils/services/ColorGenerator'; import type { SimplifiedTag, TagModalProps } from './data'; diff --git a/shlink-web-component/tags/helpers/DeleteTagConfirmModal.tsx b/shlink-web-component/tags/helpers/DeleteTagConfirmModal.tsx index c16462e2..58f56d65 100644 --- a/shlink-web-component/tags/helpers/DeleteTagConfirmModal.tsx +++ b/shlink-web-component/tags/helpers/DeleteTagConfirmModal.tsx @@ -1,6 +1,6 @@ import { Button, Modal, ModalBody, ModalFooter, ModalHeader } from 'reactstrap'; -import { ShlinkApiError } from '../../../src/api/ShlinkApiError'; import { Result } from '../../../src/utils/Result'; +import { ShlinkApiError } from '../../common/ShlinkApiError'; import type { TagModalProps } from '../data'; import type { TagDeletion } from '../reducers/tagDelete'; diff --git a/shlink-web-component/tags/helpers/EditTagModal.tsx b/shlink-web-component/tags/helpers/EditTagModal.tsx index 9a8818b3..2279e473 100644 --- a/shlink-web-component/tags/helpers/EditTagModal.tsx +++ b/shlink-web-component/tags/helpers/EditTagModal.tsx @@ -4,9 +4,9 @@ import { pipe } from 'ramda'; 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 { Result } from '../../../src/utils/Result'; -import { handleEventPreventingDefault } from '../../../src/utils/utils'; +import { ShlinkApiError } from '../../common/ShlinkApiError'; +import { handleEventPreventingDefault } from '../../utils/helpers'; import { useToggle } from '../../utils/helpers/hooks'; import type { ColorGenerator } from '../../utils/services/ColorGenerator'; import type { TagModalProps } from '../data'; diff --git a/src/utils/CopyToClipboardIcon.scss b/shlink-web-component/utils/components/CopyToClipboardIcon.scss similarity index 100% rename from src/utils/CopyToClipboardIcon.scss rename to shlink-web-component/utils/components/CopyToClipboardIcon.scss diff --git a/src/utils/CopyToClipboardIcon.tsx b/shlink-web-component/utils/components/CopyToClipboardIcon.tsx similarity index 100% rename from src/utils/CopyToClipboardIcon.tsx rename to shlink-web-component/utils/components/CopyToClipboardIcon.tsx diff --git a/src/utils/ExportBtn.tsx b/shlink-web-component/utils/components/ExportBtn.tsx similarity index 93% rename from src/utils/ExportBtn.tsx rename to shlink-web-component/utils/components/ExportBtn.tsx index feee65d9..dd8b9d1d 100644 --- a/src/utils/ExportBtn.tsx +++ b/shlink-web-component/utils/components/ExportBtn.tsx @@ -3,7 +3,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import type { FC } from 'react'; import type { ButtonProps } from 'reactstrap'; import { Button } from 'reactstrap'; -import { prettify } from './helpers/numbers'; +import { prettify } from '../helpers/numbers'; type ExportBtnProps = Omit & { amount?: number; diff --git a/src/utils/InfoTooltip.tsx b/shlink-web-component/utils/components/InfoTooltip.tsx similarity index 93% rename from src/utils/InfoTooltip.tsx rename to shlink-web-component/utils/components/InfoTooltip.tsx index 4fb281d5..44994e3a 100644 --- a/src/utils/InfoTooltip.tsx +++ b/shlink-web-component/utils/components/InfoTooltip.tsx @@ -3,7 +3,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import type { Placement } from '@popperjs/core'; import type { FC, PropsWithChildren } from 'react'; import { UncontrolledTooltip } from 'reactstrap'; -import { useElementRef } from './helpers/hooks'; +import { useElementRef } from '../helpers/hooks'; export type InfoTooltipProps = PropsWithChildren<{ className?: string; diff --git a/src/utils/PaginationDropdown.tsx b/shlink-web-component/utils/components/PaginationDropdown.tsx similarity index 100% rename from src/utils/PaginationDropdown.tsx rename to shlink-web-component/utils/components/PaginationDropdown.tsx diff --git a/src/common/SimplePaginator.scss b/shlink-web-component/utils/components/SimplePaginator.scss similarity index 100% rename from src/common/SimplePaginator.scss rename to shlink-web-component/utils/components/SimplePaginator.scss diff --git a/src/common/SimplePaginator.tsx b/shlink-web-component/utils/components/SimplePaginator.tsx similarity index 93% rename from src/common/SimplePaginator.tsx rename to shlink-web-component/utils/components/SimplePaginator.tsx index 9271bdaa..1a2ae15c 100644 --- a/src/common/SimplePaginator.tsx +++ b/shlink-web-component/utils/components/SimplePaginator.tsx @@ -1,14 +1,13 @@ import classNames from 'classnames'; import type { FC } from 'react'; import { Pagination, PaginationItem, PaginationLink } from 'reactstrap'; -import type { - NumberOrEllipsis } from '../utils/helpers/pagination'; +import type { NumberOrEllipsis } from '../helpers/pagination'; import { keyForPage, pageIsEllipsis, prettifyPageNumber, progressivePagination, -} from '../utils/helpers/pagination'; +} from '../helpers/pagination'; import './SimplePaginator.scss'; interface SimplePaginatorProps { diff --git a/shlink-web-component/utils/features.ts b/shlink-web-component/utils/features.ts index f616c753..baf83d10 100644 --- a/shlink-web-component/utils/features.ts +++ b/shlink-web-component/utils/features.ts @@ -1,6 +1,6 @@ import { createContext, useContext, useMemo } from 'react'; -import type { SemVer } from '../../src/utils/helpers/version'; -import { versionMatch } from '../../src/utils/helpers/version'; +import type { SemVer } from './helpers/version'; +import { versionMatch } from './helpers/version'; const supportedFeatures = { domainVisits: '3.1.0', diff --git a/src/utils/helpers/charts.ts b/shlink-web-component/utils/helpers/charts.ts similarity index 100% rename from src/utils/helpers/charts.ts rename to shlink-web-component/utils/helpers/charts.ts diff --git a/shlink-web-component/utils/helpers/files.ts b/shlink-web-component/utils/helpers/files.ts new file mode 100644 index 00000000..dde8bfea --- /dev/null +++ b/shlink-web-component/utils/helpers/files.ts @@ -0,0 +1,17 @@ +export const saveUrl = ({ document }: Window, url: string, filename: string) => { + const link = document.createElement('a'); + + link.setAttribute('href', url); + link.setAttribute('download', filename); + link.style.visibility = 'hidden'; + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); +}; + +export const saveCsv = (window: Window, csv: string, filename: string) => { + const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' }); + const url = URL.createObjectURL(blob); + + saveUrl(window, url, filename); +}; diff --git a/shlink-web-component/utils/helpers/index.ts b/shlink-web-component/utils/helpers/index.ts new file mode 100644 index 00000000..0e1f829b --- /dev/null +++ b/shlink-web-component/utils/helpers/index.ts @@ -0,0 +1,32 @@ +import { isEmpty, isNil, pipe, range } from 'ramda'; +import type { SyntheticEvent } from 'react'; + +type Optional = T | null | undefined; + +export type OptionalString = Optional; + +export const handleEventPreventingDefault = (handler: () => T) => pipe( + (e: SyntheticEvent) => e.preventDefault(), + handler, +); + +export const rangeOf = (size: number, mappingFn: (value: number) => T, startAt = 1): T[] => + range(startAt, size + 1).map(mappingFn); + +export type Empty = null | undefined | '' | never[]; + +export const hasValue = (value: T | Empty): value is T => !isNil(value) && !isEmpty(value); + +export type Nullable = { + [P in keyof T]: T[P] | null +}; + +export const nonEmptyValueOrNull = (value: T): T | null => (isEmpty(value) ? null : value); + +export type BooleanString = 'true' | 'false'; + +export const parseBooleanToString = (value: boolean): BooleanString => (value ? 'true' : 'false'); + +export const parseOptionalBooleanToString = (value?: boolean): BooleanString | undefined => ( + value === undefined ? undefined : parseBooleanToString(value) +); diff --git a/shlink-web-component/utils/helpers/json.ts b/shlink-web-component/utils/helpers/json.ts new file mode 100644 index 00000000..c4ceb988 --- /dev/null +++ b/shlink-web-component/utils/helpers/json.ts @@ -0,0 +1,7 @@ +import { Parser } from '@json2csv/plainjs'; + +const jsonParser = new Parser(); // This accepts options if needed + +export const jsonToCsv = (data: T[]): string => jsonParser.parse(data); + +export type JsonToCsv = typeof jsonToCsv; diff --git a/src/utils/helpers/numbers.ts b/shlink-web-component/utils/helpers/numbers.ts similarity index 100% rename from src/utils/helpers/numbers.ts rename to shlink-web-component/utils/helpers/numbers.ts diff --git a/src/utils/helpers/pagination.ts b/shlink-web-component/utils/helpers/pagination.ts similarity index 100% rename from src/utils/helpers/pagination.ts rename to shlink-web-component/utils/helpers/pagination.ts diff --git a/src/utils/helpers/qrCodes.ts b/shlink-web-component/utils/helpers/qrCodes.ts similarity index 87% rename from src/utils/helpers/qrCodes.ts rename to shlink-web-component/utils/helpers/qrCodes.ts index 356bd54a..2e66d676 100644 --- a/src/utils/helpers/qrCodes.ts +++ b/shlink-web-component/utils/helpers/qrCodes.ts @@ -1,5 +1,5 @@ import { isEmpty } from 'ramda'; -import { stringifyQuery } from '../../../shlink-web-component/utils/helpers/query'; +import { stringifyQuery } from './query'; export type QrCodeFormat = 'svg' | 'png'; diff --git a/shlink-web-component/utils/helpers/version.ts b/shlink-web-component/utils/helpers/version.ts new file mode 100644 index 00000000..3505cbc5 --- /dev/null +++ b/shlink-web-component/utils/helpers/version.ts @@ -0,0 +1,21 @@ +import { compare } from 'compare-versions'; + +type SemVerPatternFragment = `${bigint | '*'}`; + +type SemVerPattern = SemVerPatternFragment +| `${SemVerPatternFragment}.${SemVerPatternFragment}` +| `${SemVerPatternFragment}.${SemVerPatternFragment}.${SemVerPatternFragment}`; + +type Versions = { + maxVersion?: SemVerPattern; + minVersion?: SemVerPattern; +}; + +export type SemVer = `${bigint}.${bigint}.${bigint}` | 'latest'; + +export const versionMatch = (versionToMatch: SemVer, { maxVersion, minVersion }: Versions): boolean => { + const matchesMinVersion = !minVersion || compare(versionToMatch, minVersion, '>='); + const matchesMaxVersion = !maxVersion || compare(versionToMatch, maxVersion, '<='); + + return matchesMaxVersion && matchesMinVersion; +}; diff --git a/shlink-web-component/utils/services/ColorGenerator.ts b/shlink-web-component/utils/services/ColorGenerator.ts index eab6909e..3bc8a0ac 100644 --- a/shlink-web-component/utils/services/ColorGenerator.ts +++ b/shlink-web-component/utils/services/ColorGenerator.ts @@ -1,6 +1,6 @@ import { isNil } from 'ramda'; -import type { LocalStorage } from '../../../src/utils/services/LocalStorage'; -import { rangeOf } from '../../../src/utils/utils'; +import { rangeOf } from '../helpers'; +import type { LocalStorage } from './LocalStorage'; const HEX_COLOR_LENGTH = 6; const HEX_DIGITS = '0123456789ABCDEF'; diff --git a/shlink-web-component/utils/services/ImageDownloader.ts b/shlink-web-component/utils/services/ImageDownloader.ts new file mode 100644 index 00000000..a64d9837 --- /dev/null +++ b/shlink-web-component/utils/services/ImageDownloader.ts @@ -0,0 +1,13 @@ +import { saveUrl } from '../helpers/files'; +import type { Fetch } from '../types'; + +export class ImageDownloader { + public constructor(private readonly fetch: Fetch, private readonly window: Window) {} + + public async saveImage(imgUrl: string, filename: string): Promise { + const data = await this.fetch(imgUrl).then((resp) => resp.blob()); + const url = URL.createObjectURL(data); + + saveUrl(this.window, url, filename); + } +} diff --git a/shlink-web-component/utils/services/ReportExporter.ts b/shlink-web-component/utils/services/ReportExporter.ts index fb13676e..f6d96fb2 100644 --- a/shlink-web-component/utils/services/ReportExporter.ts +++ b/shlink-web-component/utils/services/ReportExporter.ts @@ -1,7 +1,7 @@ -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'; +import { saveCsv } from '../helpers/files'; +import type { JsonToCsv } from '../helpers/json'; export class ReportExporter { public constructor(private readonly window: Window, private readonly jsonToCsv: JsonToCsv) { diff --git a/shlink-web-component/utils/services/provideServices.ts b/shlink-web-component/utils/services/provideServices.ts index 871e72f1..dc35a3dc 100644 --- a/shlink-web-component/utils/services/provideServices.ts +++ b/shlink-web-component/utils/services/provideServices.ts @@ -1,13 +1,23 @@ import type Bottle from 'bottlejs'; import { useTimeoutToggle } from '../helpers/hooks'; +import { jsonToCsv } from '../helpers/json'; import { ColorGenerator } from './ColorGenerator'; +import { ImageDownloader } from './ImageDownloader'; import { LocalStorage } from './LocalStorage'; +import { ReportExporter } from './ReportExporter'; export function provideServices(bottle: Bottle) { + bottle.constant('window', window); + bottle.constant('fetch', window.fetch.bind(window)); + bottle.service('ImageDownloader', ImageDownloader, 'fetch', 'window'); + bottle.constant('localStorage', window.localStorage); bottle.service('Storage', LocalStorage, 'localStorage'); bottle.service('ColorGenerator', ColorGenerator, 'Storage'); + bottle.constant('jsonToCsv', jsonToCsv); + bottle.service('ReportExporter', ReportExporter, 'window', 'jsonToCsv'); + bottle.constant('setTimeout', window.setTimeout); bottle.constant('clearTimeout', window.clearTimeout); bottle.serviceFactory('useTimeoutToggle', useTimeoutToggle, 'setTimeout', 'clearTimeout'); diff --git a/src/utils/table/TableOrderIcon.tsx b/shlink-web-component/utils/table/TableOrderIcon.tsx similarity index 90% rename from src/utils/table/TableOrderIcon.tsx rename to shlink-web-component/utils/table/TableOrderIcon.tsx index 4c8d8fae..b4d617ec 100644 --- a/src/utils/table/TableOrderIcon.tsx +++ b/shlink-web-component/utils/table/TableOrderIcon.tsx @@ -1,6 +1,6 @@ import { faCaretDown as caretDownIcon, faCaretUp as caretUpIcon } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import type { Order } from '../helpers/ordering'; +import type { Order } from '../../../src/utils/helpers/ordering'; interface TableOrderIconProps { currentOrder: Order; diff --git a/src/utils/types.ts b/shlink-web-component/utils/types/index.ts similarity index 100% rename from src/utils/types.ts rename to shlink-web-component/utils/types/index.ts diff --git a/shlink-web-component/visits/DomainVisits.tsx b/shlink-web-component/visits/DomainVisits.tsx index 871937c6..17c1c35d 100644 --- a/shlink-web-component/visits/DomainVisits.tsx +++ b/shlink-web-component/visits/DomainVisits.tsx @@ -1,8 +1,8 @@ import { useParams } from 'react-router-dom'; -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 { useGoBack } from '../utils/helpers/hooks'; import type { ReportExporter } from '../utils/services/ReportExporter'; import type { DomainVisits as DomainVisitsState, LoadDomainVisits } from './reducers/domainVisits'; import type { NormalizedVisit } from './types'; diff --git a/shlink-web-component/visits/NonOrphanVisits.tsx b/shlink-web-component/visits/NonOrphanVisits.tsx index 1822ced7..20c38134 100644 --- a/shlink-web-component/visits/NonOrphanVisits.tsx +++ b/shlink-web-component/visits/NonOrphanVisits.tsx @@ -1,6 +1,6 @@ -import { useGoBack } from '../../src/utils/helpers/hooks'; import { boundToMercureHub } from '../mercure/helpers/boundToMercureHub'; import { Topics } from '../mercure/helpers/Topics'; +import { useGoBack } from '../utils/helpers/hooks'; import type { ReportExporter } from '../utils/services/ReportExporter'; import type { LoadVisits, VisitsInfo } from './reducers/types'; import type { NormalizedVisit, VisitsParams } from './types'; diff --git a/shlink-web-component/visits/OrphanVisits.tsx b/shlink-web-component/visits/OrphanVisits.tsx index ff2dafa1..4d3f2111 100644 --- a/shlink-web-component/visits/OrphanVisits.tsx +++ b/shlink-web-component/visits/OrphanVisits.tsx @@ -1,6 +1,6 @@ -import { useGoBack } from '../../src/utils/helpers/hooks'; import { boundToMercureHub } from '../mercure/helpers/boundToMercureHub'; import { Topics } from '../mercure/helpers/Topics'; +import { useGoBack } from '../utils/helpers/hooks'; import type { ReportExporter } from '../utils/services/ReportExporter'; import type { LoadOrphanVisits } from './reducers/orphanVisits'; import type { VisitsInfo } from './reducers/types'; diff --git a/shlink-web-component/visits/ShortUrlVisits.tsx b/shlink-web-component/visits/ShortUrlVisits.tsx index 5dd66980..e2745cea 100644 --- a/shlink-web-component/visits/ShortUrlVisits.tsx +++ b/shlink-web-component/visits/ShortUrlVisits.tsx @@ -1,11 +1,11 @@ import { useEffect } from 'react'; import { useLocation, useParams } from 'react-router-dom'; -import { useGoBack } from '../../src/utils/helpers/hooks'; 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 { useGoBack } from '../utils/helpers/hooks'; import { parseQuery } from '../utils/helpers/query'; import type { ReportExporter } from '../utils/services/ReportExporter'; import type { LoadShortUrlVisits, ShortUrlVisits as ShortUrlVisitsState } from './reducers/shortUrlVisits'; diff --git a/shlink-web-component/visits/TagVisits.tsx b/shlink-web-component/visits/TagVisits.tsx index 9bfc183d..ca77c13b 100644 --- a/shlink-web-component/visits/TagVisits.tsx +++ b/shlink-web-component/visits/TagVisits.tsx @@ -1,8 +1,8 @@ import { useParams } from 'react-router-dom'; -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 { useGoBack } from '../utils/helpers/hooks'; import type { ColorGenerator } from '../utils/services/ColorGenerator'; import type { ReportExporter } from '../utils/services/ReportExporter'; import type { LoadTagVisits, TagVisits as TagVisitsState } from './reducers/tagVisits'; diff --git a/shlink-web-component/visits/VisitsStats.tsx b/shlink-web-component/visits/VisitsStats.tsx index 93facab0..ad0bff0c 100644 --- a/shlink-web-component/visits/VisitsStats.tsx +++ b/shlink-web-component/visits/VisitsStats.tsx @@ -7,15 +7,15 @@ import type { FC, PropsWithChildren } from 'react'; import { useEffect, useMemo, useRef, useState } from 'react'; import { Navigate, Route, Routes, useLocation } from 'react-router-dom'; import { Button, Progress, Row } from 'reactstrap'; -import { ShlinkApiError } from '../../src/api/ShlinkApiError'; import { DateRangeSelector } from '../../src/utils/dates/DateRangeSelector'; -import { ExportBtn } from '../../src/utils/ExportBtn'; import type { DateInterval, DateRange } from '../../src/utils/helpers/dateIntervals'; import { toDateRange } from '../../src/utils/helpers/dateIntervals'; -import { prettify } from '../../src/utils/helpers/numbers'; import { Message } from '../../src/utils/Message'; import { NavPillItem, NavPills } from '../../src/utils/NavPills'; import { Result } from '../../src/utils/Result'; +import { ShlinkApiError } from '../common/ShlinkApiError'; +import { ExportBtn } from '../utils/components/ExportBtn'; +import { prettify } from '../utils/helpers/numbers'; import { useSetting } from '../utils/settings'; import { DoughnutChartCard } from './charts/DoughnutChartCard'; import { LineChartCard } from './charts/LineChartCard'; diff --git a/shlink-web-component/visits/VisitsTable.tsx b/shlink-web-component/visits/VisitsTable.tsx index 7ee7a74d..3c75002d 100644 --- a/shlink-web-component/visits/VisitsTable.tsx +++ b/shlink-web-component/visits/VisitsTable.tsx @@ -4,14 +4,14 @@ import classNames from 'classnames'; import { min, splitEvery } from 'ramda'; import { useEffect, useMemo, useRef, useState } from 'react'; import { UncontrolledTooltip } from 'reactstrap'; -import { SimplePaginator } from '../../src/common/SimplePaginator'; import { Time } from '../../src/utils/dates/Time'; -import { prettify } from '../../src/utils/helpers/numbers'; import type { Order } from '../../src/utils/helpers/ordering'; import { determineOrderDir, sortList } from '../../src/utils/helpers/ordering'; import { SearchField } from '../../src/utils/SearchField'; -import { TableOrderIcon } from '../../src/utils/table/TableOrderIcon'; -import type { MediaMatcher } from '../../src/utils/types'; +import { SimplePaginator } from '../utils/components/SimplePaginator'; +import { prettify } from '../utils/helpers/numbers'; +import { TableOrderIcon } from '../utils/table/TableOrderIcon'; +import type { MediaMatcher } from '../utils/types'; import type { NormalizedOrphanVisit, NormalizedVisit } from './types'; import './VisitsTable.scss'; diff --git a/shlink-web-component/visits/charts/DoughnutChart.tsx b/shlink-web-component/visits/charts/DoughnutChart.tsx index 51e96224..f095e17d 100644 --- a/shlink-web-component/visits/charts/DoughnutChart.tsx +++ b/shlink-web-component/visits/charts/DoughnutChart.tsx @@ -3,8 +3,8 @@ import { keys, values } from 'ramda'; import type { FC } from 'react'; import { memo, useState } from 'react'; import { Doughnut } from 'react-chartjs-2'; -import { renderPieChartLabel } from '../../../src/utils/helpers/charts'; import { isDarkThemeEnabled, PRIMARY_DARK_COLOR, PRIMARY_LIGHT_COLOR } from '../../../src/utils/theme'; +import { renderPieChartLabel } from '../../utils/helpers/charts'; import type { Stats } from '../types'; import { DoughnutChartLegend } from './DoughnutChartLegend'; diff --git a/shlink-web-component/visits/charts/HorizontalBarChart.tsx b/shlink-web-component/visits/charts/HorizontalBarChart.tsx index bef040bf..e272d7ea 100644 --- a/shlink-web-component/visits/charts/HorizontalBarChart.tsx +++ b/shlink-web-component/visits/charts/HorizontalBarChart.tsx @@ -3,9 +3,9 @@ import { keys, values } from 'ramda'; import type { FC, MutableRefObject } from 'react'; import { useRef } from 'react'; import { Bar, getElementAtEvent } from 'react-chartjs-2'; -import { pointerOnHover, renderChartLabel } from '../../../src/utils/helpers/charts'; -import { prettify } from '../../../src/utils/helpers/numbers'; import { HIGHLIGHTED_COLOR, HIGHLIGHTED_COLOR_ALPHA, MAIN_COLOR, MAIN_COLOR_ALPHA } from '../../../src/utils/theme'; +import { pointerOnHover, renderChartLabel } from '../../utils/helpers/charts'; +import { prettify } from '../../utils/helpers/numbers'; import type { Stats } from '../types'; import { fillTheGaps } from '../utils'; diff --git a/shlink-web-component/visits/charts/LineChartCard.tsx b/shlink-web-component/visits/charts/LineChartCard.tsx index b09a3206..2f634e76 100644 --- a/shlink-web-component/visits/charts/LineChartCard.tsx +++ b/shlink-web-component/visits/charts/LineChartCard.tsx @@ -23,13 +23,13 @@ import { DropdownToggle, UncontrolledDropdown, } from 'reactstrap'; -import { pointerOnHover, renderChartLabel } from '../../../src/utils/helpers/charts'; import { STANDARD_DATE_FORMAT } from '../../../src/utils/helpers/date'; -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 { rangeOf } from '../../utils/helpers'; +import { pointerOnHover, renderChartLabel } from '../../utils/helpers/charts'; import { useToggle } from '../../utils/helpers/hooks'; +import { prettify } from '../../utils/helpers/numbers'; import type { NormalizedVisit, Stats } from '../types'; import { fillTheGaps } from '../utils'; import './LineChartCard.scss'; diff --git a/shlink-web-component/visits/charts/SortableBarChartCard.tsx b/shlink-web-component/visits/charts/SortableBarChartCard.tsx index 5cef53ad..65382cb0 100644 --- a/shlink-web-component/visits/charts/SortableBarChartCard.tsx +++ b/shlink-web-component/visits/charts/SortableBarChartCard.tsx @@ -1,12 +1,12 @@ import { fromPairs, pipe, reverse, sortBy, splitEvery, toLower, toPairs, type, zipObj } from 'ramda'; import type { FC, ReactNode } from 'react'; import { useState } from 'react'; -import { SimplePaginator } from '../../../src/common/SimplePaginator'; -import { roundTen } from '../../../src/utils/helpers/numbers'; import type { Order } from '../../../src/utils/helpers/ordering'; import { OrderingDropdown } from '../../../src/utils/OrderingDropdown'; -import { PaginationDropdown } from '../../../src/utils/PaginationDropdown'; -import { rangeOf } from '../../../src/utils/utils'; +import { PaginationDropdown } from '../../utils/components/PaginationDropdown'; +import { SimplePaginator } from '../../utils/components/SimplePaginator'; +import { rangeOf } from '../../utils/helpers'; +import { roundTen } from '../../utils/helpers/numbers'; import type { Stats, StatsRow } from '../types'; import { ChartCard } from './ChartCard'; import type { HorizontalBarChartProps } from './HorizontalBarChart'; diff --git a/shlink-web-component/visits/helpers/VisitsFilterDropdown.tsx b/shlink-web-component/visits/helpers/VisitsFilterDropdown.tsx index 1e54d41a..b6dfc136 100644 --- a/shlink-web-component/visits/helpers/VisitsFilterDropdown.tsx +++ b/shlink-web-component/visits/helpers/VisitsFilterDropdown.tsx @@ -1,7 +1,7 @@ import type { DropdownItemProps } from 'reactstrap'; import { DropdownItem } from 'reactstrap'; import { DropdownBtn } from '../../../src/utils/DropdownBtn'; -import { hasValue } from '../../../src/utils/utils'; +import { hasValue } from '../../utils/helpers'; import type { OrphanVisitType, VisitsFilter } from '../types'; interface VisitsFilterDropdownProps { diff --git a/shlink-web-component/visits/helpers/hooks.ts b/shlink-web-component/visits/helpers/hooks.ts index 05809522..e14b76d6 100644 --- a/shlink-web-component/visits/helpers/hooks.ts +++ b/shlink-web-component/visits/helpers/hooks.ts @@ -5,8 +5,8 @@ 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 type { BooleanString } from '../../../src/utils/utils'; -import { parseBooleanToString } from '../../../src/utils/utils'; +import type { BooleanString } from '../../utils/helpers'; +import { parseBooleanToString } from '../../utils/helpers'; import { parseQuery, stringifyQuery } from '../../utils/helpers/query'; import type { OrphanVisitType, VisitsFilter } from '../types'; diff --git a/shlink-web-component/visits/services/VisitsParser.ts b/shlink-web-component/visits/services/VisitsParser.ts index 2184a682..3a81dfa0 100644 --- a/shlink-web-component/visits/services/VisitsParser.ts +++ b/shlink-web-component/visits/services/VisitsParser.ts @@ -1,5 +1,5 @@ import { isNil, map } from 'ramda'; -import { hasValue } from '../../../src/utils/utils'; +import { hasValue } from '../../utils/helpers'; import type { CityStats, NormalizedVisit, Stats, Visit, VisitsStats } from '../types'; import { isNormalizedOrphanVisit, isOrphanVisit } from '../types/helpers'; import { extractDomain, parseUserAgent } from '../utils'; diff --git a/shlink-web-component/visits/utils/index.ts b/shlink-web-component/visits/utils/index.ts index 44f4a6e3..9f6f2975 100644 --- a/shlink-web-component/visits/utils/index.ts +++ b/shlink-web-component/visits/utils/index.ts @@ -1,7 +1,7 @@ import bowser from 'bowser'; import { zipObj } from 'ramda'; -import type { Empty } from '../../../src/utils/utils'; -import { hasValue } from '../../../src/utils/utils'; +import type { Empty } from '../../utils/helpers'; +import { hasValue } from '../../utils/helpers'; import type { Stats, UserAgent } from '../types'; const DEFAULT = 'Others'; diff --git a/src/common/services/HttpClient.ts b/src/common/services/HttpClient.ts index d43cb031..3c6e9330 100644 --- a/src/common/services/HttpClient.ts +++ b/src/common/services/HttpClient.ts @@ -1,4 +1,4 @@ -import type { Fetch } from '../../utils/types'; +type Fetch = typeof window.fetch; const applicationJsonHeader = { 'Content-Type': 'application/json' }; const withJsonContentType = (options?: RequestInit): RequestInit | undefined => { @@ -37,6 +37,4 @@ export class HttpClient { throw await resp.json(); } }); - - public readonly fetchBlob = (url: string): Promise => this.fetch(url).then((resp) => resp.blob()); } diff --git a/src/common/services/ImageDownloader.ts b/src/common/services/ImageDownloader.ts deleted file mode 100644 index 780de082..00000000 --- a/src/common/services/ImageDownloader.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { saveUrl } from '../../utils/helpers/files'; -import type { HttpClient } from './HttpClient'; - -export class ImageDownloader { - public constructor(private readonly httpClient: HttpClient, private readonly window: Window) {} - - public async saveImage(imgUrl: string, filename: string): Promise { - const data = await this.httpClient.fetchBlob(imgUrl); - const url = URL.createObjectURL(data); - - saveUrl(this.window, url, filename); - } -} diff --git a/src/common/services/provideServices.ts b/src/common/services/provideServices.ts index 8e606bb2..1c6be10d 100644 --- a/src/common/services/provideServices.ts +++ b/src/common/services/provideServices.ts @@ -9,16 +9,13 @@ import { sidebarNotPresent, sidebarPresent } from '../reducers/sidebar'; import { ScrollToTop } from '../ScrollToTop'; import { ShlinkVersionsContainer } from '../ShlinkVersionsContainer'; import { HttpClient } from './HttpClient'; -import { ImageDownloader } from './ImageDownloader'; export const provideServices = (bottle: Bottle, connect: ConnectDecorator) => { // Services bottle.constant('window', window); bottle.constant('console', console); bottle.constant('fetch', window.fetch.bind(window)); - bottle.service('HttpClient', HttpClient, 'fetch'); - bottle.service('ImageDownloader', ImageDownloader, 'HttpClient', 'window'); // Components bottle.serviceFactory('ScrollToTop', () => ScrollToTop); diff --git a/src/utils/helpers/dateIntervals.ts b/src/utils/helpers/dateIntervals.ts index be5d7dd5..e6ff097d 100644 --- a/src/utils/helpers/dateIntervals.ts +++ b/src/utils/helpers/dateIntervals.ts @@ -1,6 +1,5 @@ import { endOfDay, startOfDay, subDays } from 'date-fns'; import { cond, filter, isEmpty, T } from 'ramda'; -import { equals } from '../utils'; import type { DateOrString } from './date'; import { dateOrNull, formatInternational, isBeforeOrEqual, now, parseISO } from './date'; @@ -68,6 +67,7 @@ export const rangeOrIntervalToString = (range?: DateRange | DateInterval): strin const startOfDaysAgo = (daysAgo: number) => startOfDay(subDays(now(), daysAgo)); const endingToday = (startDate: Date): DateRange => ({ startDate, endDate: endOfDay(now()) }); +const equals = (value: any) => (otherValue: any) => value === otherValue; export const intervalToDateRange = cond<[DateInterval | undefined], DateRange>([ [equals('today'), () => endingToday(startOfDay(now()))], diff --git a/src/utils/helpers/version.ts b/src/utils/helpers/version.ts index 91ef66d5..c75645d9 100644 --- a/src/utils/helpers/version.ts +++ b/src/utils/helpers/version.ts @@ -1,18 +1,20 @@ import { compare } from 'compare-versions'; -import { identity, memoizeWith } from 'ramda'; -import type { Empty } from '../utils'; -import { hasValue } from '../utils'; +import { identity, isEmpty, isNil, memoizeWith } from 'ramda'; + +type Empty = null | undefined | '' | never[]; + +const hasValue = (value: T | Empty): value is T => !isNil(value) && !isEmpty(value); type SemVerPatternFragment = `${bigint | '*'}`; -export type SemVerPattern = SemVerPatternFragment +type SemVerPattern = SemVerPatternFragment | `${SemVerPatternFragment}.${SemVerPatternFragment}` | `${SemVerPatternFragment}.${SemVerPatternFragment}.${SemVerPatternFragment}`; -export interface Versions { +type Versions = { maxVersion?: SemVerPattern; minVersion?: SemVerPattern; -} +}; export type SemVer = `${bigint}.${bigint}.${bigint}` | 'latest'; diff --git a/src/utils/services/provideServices.ts b/src/utils/services/provideServices.ts index b7fa4d03..43626843 100644 --- a/src/utils/services/provideServices.ts +++ b/src/utils/services/provideServices.ts @@ -1,5 +1,4 @@ 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 { LocalStorage } from './LocalStorage'; @@ -7,7 +6,6 @@ import { LocalStorage } from './LocalStorage'; export const provideServices = (bottle: Bottle) => { bottle.constant('localStorage', window.localStorage); bottle.service('Storage', LocalStorage, 'localStorage'); - bottle.service('ColorGenerator', ColorGenerator, 'Storage'); bottle.constant('csvToJson', csvToJson); bottle.constant('jsonToCsv', jsonToCsv); diff --git a/src/utils/utils.ts b/src/utils/utils.ts index 243b4b99..ab0f5e48 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -1,36 +1,11 @@ -import { isEmpty, isNil, pipe, range } from 'ramda'; +import { pipe } from 'ramda'; import type { SyntheticEvent } from 'react'; -export const rangeOf = (size: number, mappingFn: (value: number) => T, startAt = 1): T[] => - range(startAt, size + 1).map(mappingFn); - -export type Empty = null | undefined | '' | never[]; - -export const hasValue = (value: T | Empty): value is T => !isNil(value) && !isEmpty(value); - -export const handleEventPreventingDefault = (handler: () => T) => pipe( - (e: SyntheticEvent) => e.preventDefault(), - handler, -); - -export type Nullable = { - [P in keyof T]: T[P] | null -}; - type Optional = T | null | undefined; export type OptionalString = Optional; -export const nonEmptyValueOrNull = (value: T): T | null => (isEmpty(value) ? null : value); - -export const capitalize = (value: T): string => `${value.charAt(0).toUpperCase()}${value.slice(1)}`; - -export const equals = (value: any) => (otherValue: any) => value === otherValue; - -export type BooleanString = 'true' | 'false'; - -export const parseBooleanToString = (value: boolean): BooleanString => (value ? 'true' : 'false'); - -export const parseOptionalBooleanToString = (value?: boolean): BooleanString | undefined => ( - value === undefined ? undefined : parseBooleanToString(value) +export const handleEventPreventingDefault = (handler: () => T) => pipe( + (e: SyntheticEvent) => e.preventDefault(), + handler, ); diff --git a/test/api/ShlinkApiError.test.tsx b/test/api/ShlinkApiError.test.tsx index 1690b5ce..2d9cf2c6 100644 --- a/test/api/ShlinkApiError.test.tsx +++ b/test/api/ShlinkApiError.test.tsx @@ -1,7 +1,7 @@ import { render, screen } from '@testing-library/react'; import { fromPartial } from '@total-typescript/shoehorn'; -import type { ShlinkApiErrorProps } from '../../src/api/ShlinkApiError'; -import { ShlinkApiError } from '../../src/api/ShlinkApiError'; +import type { ShlinkApiErrorProps } from '../../shlink-web-component/common/ShlinkApiError'; +import { ShlinkApiError } from '../../shlink-web-component/common/ShlinkApiError'; import type { InvalidArgumentError, ProblemDetailsError } from '../../src/api/types/errors'; import { ErrorTypeV2, ErrorTypeV3 } from '../../src/api/types/errors'; diff --git a/test/common/SimplePaginator.test.tsx b/test/common/SimplePaginator.test.tsx index f0b9e1ae..fb7476b6 100644 --- a/test/common/SimplePaginator.test.tsx +++ b/test/common/SimplePaginator.test.tsx @@ -1,6 +1,6 @@ import { render, screen } from '@testing-library/react'; -import { SimplePaginator } from '../../src/common/SimplePaginator'; -import { ELLIPSIS } from '../../src/utils/helpers/pagination'; +import { SimplePaginator } from '../../shlink-web-component/utils/components/SimplePaginator'; +import { ELLIPSIS } from '../../shlink-web-component/utils/helpers/pagination'; describe('', () => { const setUp = (pagesCount: number, currentPage = 1) => render( diff --git a/test/common/services/HttpClient.test.ts b/test/common/services/HttpClient.test.ts index b815d835..fbab591f 100644 --- a/test/common/services/HttpClient.test.ts +++ b/test/common/services/HttpClient.test.ts @@ -64,15 +64,4 @@ describe('HttpClient', () => { await expect(httpClient.fetchJson('')).rejects.toEqual(theError); }); }); - - describe('fetchBlob', () => { - it('returns response as blob', async () => { - const theBlob = new Blob(); - fetch.mockResolvedValue({ blob: () => theBlob }); - - const result = await httpClient.fetchBlob(''); - - expect(result).toEqual(theBlob); - }); - }); }); diff --git a/test/common/services/ImageDownloader.test.ts b/test/common/services/ImageDownloader.test.ts index b393ec98..3ecf2529 100644 --- a/test/common/services/ImageDownloader.test.ts +++ b/test/common/services/ImageDownloader.test.ts @@ -1,6 +1,6 @@ import { fromPartial } from '@total-typescript/shoehorn'; +import { ImageDownloader } from '../../../shlink-web-component/utils/services/ImageDownloader'; import type { HttpClient } from '../../../src/common/services/HttpClient'; -import { ImageDownloader } from '../../../src/common/services/ImageDownloader'; import { windowMock } from '../../__mocks__/Window.mock'; describe('ImageDownloader', () => { diff --git a/test/servers/Overview.test.tsx b/test/servers/Overview.test.tsx index dc3775c0..e9dd442e 100644 --- a/test/servers/Overview.test.tsx +++ b/test/servers/Overview.test.tsx @@ -3,7 +3,7 @@ import { fromPartial } from '@total-typescript/shoehorn'; import { MemoryRouter } from 'react-router-dom'; import type { MercureInfo } from '../../shlink-web-component/mercure/reducers/mercureInfo'; import { Overview as overviewCreator } from '../../shlink-web-component/overview/Overview'; -import { prettify } from '../../src/utils/helpers/numbers'; +import { prettify } from '../../shlink-web-component/utils/helpers/numbers'; import { renderWithEvents } from '../__helpers__/setUpTest'; describe('', () => { diff --git a/test/short-urls/Paginator.test.tsx b/test/short-urls/Paginator.test.tsx index 9545aadc..f4bf824f 100644 --- a/test/short-urls/Paginator.test.tsx +++ b/test/short-urls/Paginator.test.tsx @@ -2,8 +2,8 @@ import { render, screen } from '@testing-library/react'; import { fromPartial } from '@total-typescript/shoehorn'; import { MemoryRouter } from 'react-router-dom'; import { Paginator } from '../../shlink-web-component/short-urls/Paginator'; +import { ELLIPSIS } from '../../shlink-web-component/utils/helpers/pagination'; import type { ShlinkPaginator } from '../../src/api/types'; -import { ELLIPSIS } from '../../src/utils/helpers/pagination'; describe('', () => { const buildPaginator = (pagesCount?: number) => fromPartial({ pagesCount, currentPage: 1 }); diff --git a/test/short-urls/helpers/qr-codes/QrErrorCorrectionDropdown.test.tsx b/test/short-urls/helpers/qr-codes/QrErrorCorrectionDropdown.test.tsx index 5a84e76a..29fc18f5 100644 --- a/test/short-urls/helpers/qr-codes/QrErrorCorrectionDropdown.test.tsx +++ b/test/short-urls/helpers/qr-codes/QrErrorCorrectionDropdown.test.tsx @@ -1,6 +1,6 @@ import { screen } from '@testing-library/react'; import { QrErrorCorrectionDropdown } from '../../../../shlink-web-component/short-urls/helpers/qr-codes/QrErrorCorrectionDropdown'; -import type { QrErrorCorrection } from '../../../../src/utils/helpers/qrCodes'; +import type { QrErrorCorrection } from '../../../../shlink-web-component/utils/helpers/qrCodes'; import { renderWithEvents } from '../../../__helpers__/setUpTest'; describe('', () => { diff --git a/test/short-urls/helpers/qr-codes/QrFormatDropdown.test.tsx b/test/short-urls/helpers/qr-codes/QrFormatDropdown.test.tsx index 944fd53c..29133dac 100644 --- a/test/short-urls/helpers/qr-codes/QrFormatDropdown.test.tsx +++ b/test/short-urls/helpers/qr-codes/QrFormatDropdown.test.tsx @@ -1,6 +1,6 @@ import { screen } from '@testing-library/react'; import { QrFormatDropdown } from '../../../../shlink-web-component/short-urls/helpers/qr-codes/QrFormatDropdown'; -import type { QrCodeFormat } from '../../../../src/utils/helpers/qrCodes'; +import type { QrCodeFormat } from '../../../../shlink-web-component/utils/helpers/qrCodes'; import { renderWithEvents } from '../../../__helpers__/setUpTest'; describe('', () => { diff --git a/test/utils/CopyToClipboardIcon.test.tsx b/test/utils/CopyToClipboardIcon.test.tsx index b73fa786..108bd86b 100644 --- a/test/utils/CopyToClipboardIcon.test.tsx +++ b/test/utils/CopyToClipboardIcon.test.tsx @@ -1,4 +1,4 @@ -import { CopyToClipboardIcon } from '../../src/utils/CopyToClipboardIcon'; +import { CopyToClipboardIcon } from '../../shlink-web-component/utils/components/CopyToClipboardIcon'; import { renderWithEvents } from '../__helpers__/setUpTest'; describe('', () => { diff --git a/test/utils/ExportBtn.test.tsx b/test/utils/ExportBtn.test.tsx index 0ed10837..99cca497 100644 --- a/test/utils/ExportBtn.test.tsx +++ b/test/utils/ExportBtn.test.tsx @@ -1,5 +1,5 @@ import { render, screen } from '@testing-library/react'; -import { ExportBtn } from '../../src/utils/ExportBtn'; +import { ExportBtn } from '../../shlink-web-component/utils/components/ExportBtn'; describe('', () => { const setUp = (amount?: number, loading = false) => render(); diff --git a/test/utils/InfoTooltip.test.tsx b/test/utils/InfoTooltip.test.tsx index 388c279c..68072df4 100644 --- a/test/utils/InfoTooltip.test.tsx +++ b/test/utils/InfoTooltip.test.tsx @@ -1,7 +1,7 @@ import type { Placement } from '@popperjs/core'; import { screen, waitFor } from '@testing-library/react'; -import type { InfoTooltipProps } from '../../src/utils/InfoTooltip'; -import { InfoTooltip } from '../../src/utils/InfoTooltip'; +import type { InfoTooltipProps } from '../../shlink-web-component/utils/components/InfoTooltip'; +import { InfoTooltip } from '../../shlink-web-component/utils/components/InfoTooltip'; import { renderWithEvents } from '../__helpers__/setUpTest'; describe('', () => { diff --git a/test/utils/PaginationDropdown.test.tsx b/test/utils/PaginationDropdown.test.tsx index a4188b56..a2246d11 100644 --- a/test/utils/PaginationDropdown.test.tsx +++ b/test/utils/PaginationDropdown.test.tsx @@ -1,5 +1,5 @@ import { screen } from '@testing-library/react'; -import { PaginationDropdown } from '../../src/utils/PaginationDropdown'; +import { PaginationDropdown } from '../../shlink-web-component/utils/components/PaginationDropdown'; import { renderWithEvents } from '../__helpers__/setUpTest'; describe('', () => { diff --git a/test/utils/helpers/numbers.test.ts b/test/utils/helpers/numbers.test.ts index f3bdc3f2..9e18669b 100644 --- a/test/utils/helpers/numbers.test.ts +++ b/test/utils/helpers/numbers.test.ts @@ -1,4 +1,4 @@ -import { roundTen } from '../../../src/utils/helpers/numbers'; +import { roundTen } from '../../../shlink-web-component/utils/helpers/numbers'; describe('numbers', () => { describe('roundTen', () => { diff --git a/test/utils/helpers/qrCodes.test.ts b/test/utils/helpers/qrCodes.test.ts index a1cae693..f8d4947a 100644 --- a/test/utils/helpers/qrCodes.test.ts +++ b/test/utils/helpers/qrCodes.test.ts @@ -1,5 +1,5 @@ -import type { QrCodeFormat, QrErrorCorrection } from '../../../src/utils/helpers/qrCodes'; -import { buildQrCodeUrl } from '../../../src/utils/helpers/qrCodes'; +import type { QrCodeFormat, QrErrorCorrection } from '../../../shlink-web-component/utils/helpers/qrCodes'; +import { buildQrCodeUrl } from '../../../shlink-web-component/utils/helpers/qrCodes'; describe('qrCodes', () => { describe('buildQrCodeUrl', () => { diff --git a/test/utils/table/TableOrderIcon.test.tsx b/test/utils/table/TableOrderIcon.test.tsx index 27a72d9c..7a1dec55 100644 --- a/test/utils/table/TableOrderIcon.test.tsx +++ b/test/utils/table/TableOrderIcon.test.tsx @@ -1,6 +1,6 @@ import { render } from '@testing-library/react'; +import { TableOrderIcon } from '../../../shlink-web-component/utils/table/TableOrderIcon'; import type { OrderDir } from '../../../src/utils/helpers/ordering'; -import { TableOrderIcon } from '../../../src/utils/table/TableOrderIcon'; describe('', () => { const setUp = (field: string, currentDir?: OrderDir, className?: string) => render( diff --git a/test/utils/utils.test.ts b/test/utils/utils.test.ts index aa2d25c3..46953784 100644 --- a/test/utils/utils.test.ts +++ b/test/utils/utils.test.ts @@ -1,5 +1,4 @@ import { - capitalize, nonEmptyValueOrNull, parseBooleanToString, parseOptionalBooleanToString, @@ -45,17 +44,6 @@ describe('utils', () => { }); }); - describe('capitalize', () => { - it.each([ - ['foo', 'Foo'], - ['BAR', 'BAR'], - ['bAZ', 'BAZ'], - ['with spaces', 'With spaces'], - ])('sets first letter in uppercase', (value, expectedResult) => { - expect(capitalize(value)).toEqual(expectedResult); - }); - }); - describe('parseBooleanToString', () => { it.each([ [true, 'true'],