diff --git a/shlink-web-component/short-urls/ShortUrlForm.tsx b/shlink-web-component/short-urls/ShortUrlForm.tsx index 93c33313..be6021ee 100644 --- a/shlink-web-component/short-urls/ShortUrlForm.tsx +++ b/shlink-web-component/short-urls/ShortUrlForm.tsx @@ -9,10 +9,10 @@ import { useEffect, useState } from 'react'; import { Button, FormGroup, Input, Row } from 'reactstrap'; import type { InputType } from 'reactstrap/types/lib/Input'; import { Checkbox } from '../../src/utils/Checkbox'; -import { IconInput } from '../../src/utils/IconInput'; import { SimpleCard } from '../../src/utils/SimpleCard'; import type { DomainSelectorProps } from '../domains/DomainSelector'; import type { TagsSelectorProps } from '../tags/helpers/TagsSelector'; +import { IconInput } from '../utils/components/IconInput'; import type { DateTimeInputProps } from '../utils/dates/DateTimeInput'; import { DateTimeInput } from '../utils/dates/DateTimeInput'; import { formatIsoDate } from '../utils/dates/helpers/date'; diff --git a/shlink-web-component/short-urls/helpers/hooks.ts b/shlink-web-component/short-urls/helpers/hooks.ts index 00f4078d..9cf21ad8 100644 --- a/shlink-web-component/short-urls/helpers/hooks.ts +++ b/shlink-web-component/short-urls/helpers/hooks.ts @@ -1,5 +1,5 @@ import { isEmpty, pipe } from 'ramda'; -import { useMemo } from 'react'; +import { useCallback, useMemo } from 'react'; import { useLocation, useNavigate } from 'react-router-dom'; import { orderToString, stringToOrder } from '../../../src/utils/helpers/ordering'; import type { TagsFilteringMode } from '../../api-contract'; @@ -57,7 +57,7 @@ export const useShortUrlsQuery = (): [ShortUrlsFiltering, ToFirstPage] => { ), [search], ); - const toFirstPageWithExtra = (extra: Partial) => { + const toFirstPageWithExtra = useCallback((extra: Partial) => { const merged = { ...filtering, ...extra }; const { orderBy, tags, excludeBots, excludeMaxVisitsReached, excludePastValidUntil, ...mergedFiltering } = merged; const query: ShortUrlsQuery = { @@ -72,7 +72,7 @@ export const useShortUrlsQuery = (): [ShortUrlsFiltering, ToFirstPage] => { const queryString = isEmpty(stringifiedQuery) ? '' : `?${stringifiedQuery}`; navigate(`${routesPrefix}/list-short-urls/1${queryString}`); - }; + }, [filtering, navigate, routesPrefix]); return [filtering, toFirstPageWithExtra]; }; diff --git a/src/utils/IconInput.scss b/shlink-web-component/utils/components/IconInput.scss similarity index 84% rename from src/utils/IconInput.scss rename to shlink-web-component/utils/components/IconInput.scss index 3e3e6d04..8a07ea92 100644 --- a/src/utils/IconInput.scss +++ b/shlink-web-component/utils/components/IconInput.scss @@ -1,5 +1,5 @@ -@import './mixins/vertical-align'; -@import './base'; +@import '../../../src/utils/mixins/vertical-align'; +@import '../../../src/utils/base'; .icon-input-container { position: relative; diff --git a/src/utils/IconInput.tsx b/shlink-web-component/utils/components/IconInput.tsx similarity index 92% rename from src/utils/IconInput.tsx rename to shlink-web-component/utils/components/IconInput.tsx index 9b0e45d4..f631f7f6 100644 --- a/src/utils/IconInput.tsx +++ b/shlink-web-component/utils/components/IconInput.tsx @@ -4,7 +4,7 @@ import classNames from 'classnames'; import type { FC } from 'react'; import type { InputProps } from 'reactstrap'; import { Input } from 'reactstrap'; -import { useElementRef } from './helpers/hooks'; +import { useElementRef } from '../../../src/utils/helpers/hooks'; import './IconInput.scss'; type IconInputProps = InputProps & { diff --git a/shlink-web-component/utils/dates/DateRangeSelector.tsx b/shlink-web-component/utils/dates/DateRangeSelector.tsx index 01a9660d..1235c9bc 100644 --- a/shlink-web-component/utils/dates/DateRangeSelector.tsx +++ b/shlink-web-component/utils/dates/DateRangeSelector.tsx @@ -1,7 +1,7 @@ import { useState } from 'react'; import { DropdownItem } from 'reactstrap'; import { DropdownBtn } from '../../../src/utils/DropdownBtn'; -import { useEffectExceptFirstTime } from '../../../src/utils/helpers/hooks'; +import { useEffectExceptFirstTime } from '../helpers/hooks'; import { DateIntervalDropdownItems } from './DateIntervalDropdownItems'; import { DateRangeRow } from './DateRangeRow'; import type { diff --git a/shlink-web-component/utils/dates/helpers/date.ts b/shlink-web-component/utils/dates/helpers/date.ts index 95acd092..6f6793cb 100644 --- a/shlink-web-component/utils/dates/helpers/date.ts +++ b/shlink-web-component/utils/dates/helpers/date.ts @@ -1,5 +1,4 @@ import { format, formatISO, isBefore, isEqual, isWithinInterval, parse, parseISO as stdParseISO } from 'date-fns'; -import type { OptionalString } from '../../../../src/utils/utils'; export const STANDARD_DATE_FORMAT = 'yyyy-MM-dd'; @@ -13,7 +12,7 @@ export const now = () => new Date(); export const isDateObject = (date: DateOrString): date is Date => typeof date !== 'string'; -const formatDateFromFormat = (date?: NullableDate, theFormat?: string): OptionalString => { +const formatDateFromFormat = (date?: NullableDate, theFormat?: string): string | null | undefined => { if (!date || !isDateObject(date)) { return date; } diff --git a/shlink-web-component/utils/helpers/hooks.ts b/shlink-web-component/utils/helpers/hooks.ts index d51cb13a..5a7c94c6 100644 --- a/shlink-web-component/utils/helpers/hooks.ts +++ b/shlink-web-component/utils/helpers/hooks.ts @@ -1,6 +1,6 @@ import type { DependencyList, EffectCallback } from 'react'; import { useEffect, useRef, useState } from 'react'; -import { useLocation, useNavigate } from 'react-router-dom'; +import { useNavigate } from 'react-router-dom'; import { useSwipeable as useReactSwipeable } from 'react-swipeable'; import { v4 as uuid } from 'uuid'; import { parseQuery, stringifyQuery } from './query'; @@ -28,13 +28,6 @@ export const useTimeoutToggle = ( 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( @@ -83,9 +76,11 @@ export const useGoBack = () => { return () => navigate(-1); }; -export const useParsedQuery = (): T => { - const { search } = useLocation(); - return parseQuery(search); +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 useDomId = (): string => { diff --git a/src/settings/reducers/settings.ts b/src/settings/reducers/settings.ts index 2b578f58..51888901 100644 --- a/src/settings/reducers/settings.ts +++ b/src/settings/reducers/settings.ts @@ -1,8 +1,9 @@ import type { PayloadAction, PrepareAction } from '@reduxjs/toolkit'; import { createSlice } from '@reduxjs/toolkit'; import { mergeDeepRight } from 'ramda'; -import type { ShortUrlsOrder } from '../../../shlink-web-component/short-urls/data'; -import type { Settings } from '../../../shlink-web-component/utils/settings'; +import type { Settings } from '../../../shlink-web-component'; + +type ShortUrlsOrder = Exclude['defaultOrdering'], undefined>; export const DEFAULT_SHORT_URLS_ORDERING: ShortUrlsOrder = { field: 'dateCreated', diff --git a/src/utils/helpers/hooks.ts b/src/utils/helpers/hooks.ts index 2c405800..9321d9d4 100644 --- a/src/utils/helpers/hooks.ts +++ b/src/utils/helpers/hooks.ts @@ -1,5 +1,4 @@ -import type { DependencyList, EffectCallback } from 'react'; -import { useEffect, useRef, useState } from 'react'; +import { useRef, useState } from 'react'; import { useLocation, useNavigate } from 'react-router-dom'; import { v4 as uuid } from 'uuid'; import { parseQuery } from '../../../shlink-web-component/utils/helpers/query'; @@ -27,22 +26,6 @@ export const useTimeoutToggle = ( 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 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); @@ -53,6 +36,13 @@ export const useParsedQuery = (): T => { return parseQuery(search); }; +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 useDomId = (): string => { const { current: id } = useRef(`dom-${uuid()}`); return id; diff --git a/src/utils/helpers/ordering.ts b/src/utils/helpers/ordering.ts index dafe7b69..06ac3608 100644 --- a/src/utils/helpers/ordering.ts +++ b/src/utils/helpers/ordering.ts @@ -22,7 +22,7 @@ export const determineOrderDir = ( return currentOrderDir ? newOrderMap[currentOrderDir] : 'ASC'; }; -export const sortList = (list: List[], { field, dir }: Order>) => ( +export const sortList = (list: List[], { field, dir }: Order) => ( !field || !dir ? list : list.sort((a, b) => { const greaterThan = dir === 'ASC' ? 1 : -1; const smallerThan = dir === 'ASC' ? -1 : 1; diff --git a/test/utils/IconInput.test.tsx b/test/utils/IconInput.test.tsx index a5d863d0..5c1e1e6a 100644 --- a/test/utils/IconInput.test.tsx +++ b/test/utils/IconInput.test.tsx @@ -1,7 +1,7 @@ import type { IconProp } from '@fortawesome/fontawesome-svg-core'; import { faAppleAlt, faCalendar, faTable } from '@fortawesome/free-solid-svg-icons'; import { screen } from '@testing-library/react'; -import { IconInput } from '../../src/utils/IconInput'; +import { IconInput } from '../../shlink-web-component/utils/components/IconInput'; import { renderWithEvents } from '../__helpers__/setUpTest'; describe('', () => {