Minor refactorings and function extractions

This commit is contained in:
Alejandro Celaya 2022-11-26 09:11:46 +01:00
parent a3f5095dce
commit 165afa436d
6 changed files with 26 additions and 25 deletions

View file

@ -1,6 +1,5 @@
import { FC } from 'react'; import { FC } from 'react';
import { isEmpty, pipe } from 'ramda'; import { isEmpty, pipe } from 'ramda';
import { parseISO } from 'date-fns';
import { Button, InputGroup, Row, UncontrolledTooltip } from 'reactstrap'; import { Button, InputGroup, Row, UncontrolledTooltip } from 'reactstrap';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faTag, faTags } from '@fortawesome/free-solid-svg-icons'; import { faTag, faTags } from '@fortawesome/free-solid-svg-icons';
@ -8,7 +7,7 @@ import classNames from 'classnames';
import { SearchField } from '../utils/SearchField'; import { SearchField } from '../utils/SearchField';
import { DateRangeSelector } from '../utils/dates/DateRangeSelector'; import { DateRangeSelector } from '../utils/dates/DateRangeSelector';
import { formatIsoDate } from '../utils/helpers/date'; import { formatIsoDate } from '../utils/helpers/date';
import { DateRange } from '../utils/dates/types'; import { DateRange, datesToDateRange } from '../utils/dates/types';
import { supportsAllTagsFiltering } from '../utils/helpers/features'; import { supportsAllTagsFiltering } from '../utils/helpers/features';
import { SelectedServer } from '../servers/data'; import { SelectedServer } from '../servers/data';
import { OrderDir } from '../utils/helpers/ordering'; import { OrderDir } from '../utils/helpers/ordering';
@ -27,8 +26,6 @@ export interface ShortUrlsFilteringProps {
shortUrlsAmount?: number; shortUrlsAmount?: number;
} }
const dateOrNull = (date?: string) => (date ? parseISO(date) : null);
export const ShortUrlsFilteringBar = ( export const ShortUrlsFilteringBar = (
ExportShortUrlsBtn: FC<ExportShortUrlsBtnProps>, ExportShortUrlsBtn: FC<ExportShortUrlsBtnProps>,
TagsSelector: FC<TagsSelectorProps>, TagsSelector: FC<TagsSelectorProps>,
@ -74,10 +71,7 @@ export const ShortUrlsFilteringBar = (
<div className="col-lg-8 col-xl-6 mt-3"> <div className="col-lg-8 col-xl-6 mt-3">
<DateRangeSelector <DateRangeSelector
defaultText="All short URLs" defaultText="All short URLs"
initialDateRange={{ initialDateRange={datesToDateRange(startDate, endDate)}
startDate: dateOrNull(startDate),
endDate: dateOrNull(endDate),
}}
onDatesChange={setDates} onDatesChange={setDates}
/> />
</div> </div>

View file

@ -6,8 +6,6 @@ import { ShortUrlsOrder, ShortUrlsOrderableFields } from '../data';
import { orderToString, stringToOrder } from '../../utils/helpers/ordering'; import { orderToString, stringToOrder } from '../../utils/helpers/ordering';
import { TagsFilteringMode } from '../../api/types'; import { TagsFilteringMode } from '../../api/types';
type ToFirstPage = (extra: Partial<ShortUrlsFiltering>) => void;
interface ShortUrlsQueryCommon { interface ShortUrlsQueryCommon {
search?: string; search?: string;
startDate?: string; startDate?: string;
@ -25,14 +23,16 @@ interface ShortUrlsFiltering extends ShortUrlsQueryCommon {
tags: string[]; tags: string[];
} }
type ToFirstPage = (extra: Partial<ShortUrlsFiltering>) => void;
export const useShortUrlsQuery = (): [ShortUrlsFiltering, ToFirstPage] => { export const useShortUrlsQuery = (): [ShortUrlsFiltering, ToFirstPage] => {
const navigate = useNavigate(); const navigate = useNavigate();
const location = useLocation(); const { search } = useLocation();
const params = useParams<{ serverId: string }>(); const { serverId = '' } = useParams<{ serverId: string }>();
const query = useMemo( const filtering = useMemo(
pipe( pipe(
() => parseQuery<ShortUrlsQuery>(location.search), () => parseQuery<ShortUrlsQuery>(search),
({ orderBy, tags, ...rest }: ShortUrlsQuery): ShortUrlsFiltering => { ({ orderBy, tags, ...rest }: ShortUrlsQuery): ShortUrlsFiltering => {
const parsedOrderBy = orderBy ? stringToOrder<ShortUrlsOrderableFields>(orderBy) : undefined; const parsedOrderBy = orderBy ? stringToOrder<ShortUrlsOrderableFields>(orderBy) : undefined;
const parsedTags = tags?.split(',') ?? []; const parsedTags = tags?.split(',') ?? [];
@ -40,20 +40,20 @@ export const useShortUrlsQuery = (): [ShortUrlsFiltering, ToFirstPage] => {
return { ...rest, orderBy: parsedOrderBy, tags: parsedTags }; return { ...rest, orderBy: parsedOrderBy, tags: parsedTags };
}, },
), ),
[location.search], [search],
); );
const toFirstPageWithExtra = (extra: Partial<ShortUrlsFiltering>) => { const toFirstPageWithExtra = (extra: Partial<ShortUrlsFiltering>) => {
const { orderBy, tags, ...mergedQuery } = { ...query, ...extra }; const { orderBy, tags, ...mergedFiltering } = { ...filtering, ...extra };
const normalizedQuery: ShortUrlsQuery = { const query: ShortUrlsQuery = {
...mergedQuery, ...mergedFiltering,
orderBy: orderBy && orderToString(orderBy), orderBy: orderBy && orderToString(orderBy),
tags: tags.length > 0 ? tags.join(',') : undefined, tags: tags.length > 0 ? tags.join(',') : undefined,
}; };
const evolvedQuery = stringifyQuery(normalizedQuery); const stringifiedQuery = stringifyQuery(query);
const queryString = isEmpty(evolvedQuery) ? '' : `?${evolvedQuery}`; const queryString = isEmpty(stringifiedQuery) ? '' : `?${stringifiedQuery}`;
navigate(`/server/${params.serverId ?? ''}/list-short-urls/1${queryString}`); navigate(`/server/${serverId}/list-short-urls/1${queryString}`);
}; };
return [query, toFirstPageWithExtra]; return [filtering, toFirstPageWithExtra];
}; };

View file

@ -1,6 +1,6 @@
import { subDays, startOfDay, endOfDay } from 'date-fns'; import { subDays, startOfDay, endOfDay } from 'date-fns';
import { cond, filter, isEmpty, T } from 'ramda'; import { cond, filter, isEmpty, T } from 'ramda';
import { DateOrString, formatInternational, isBeforeOrEqual, parseISO } from '../../helpers/date'; import { dateOrNull, DateOrString, formatInternational, isBeforeOrEqual, parseISO } from '../../helpers/date';
export interface DateRange { export interface DateRange {
startDate?: Date | null; startDate?: Date | null;
@ -28,6 +28,11 @@ const INTERVAL_TO_STRING_MAP: Record<DateInterval, string | undefined> = {
export const DATE_INTERVALS = Object.keys(INTERVAL_TO_STRING_MAP).filter((value) => value !== 'all') as DateInterval[]; export const DATE_INTERVALS = Object.keys(INTERVAL_TO_STRING_MAP).filter((value) => value !== 'all') as DateInterval[];
export const datesToDateRange = (startDate?: string, endDate?: string): DateRange => ({
startDate: dateOrNull(startDate),
endDate: dateOrNull(endDate),
});
const dateRangeToString = (range?: DateRange): string | undefined => { const dateRangeToString = (range?: DateRange): string | undefined => {
if (!range || dateRangeIsEmpty(range)) { if (!range || dateRangeIsEmpty(range)) {
return undefined; return undefined;

View file

@ -32,6 +32,8 @@ export const parseDate = (date: string, theFormat: string) => parse(date, theFor
export const parseISO = (date: DateOrString): Date => (isDateObject(date) ? date : stdParseISO(date)); export const parseISO = (date: DateOrString): Date => (isDateObject(date) ? date : stdParseISO(date));
export const dateOrNull = (date?: string): Date | null => (date ? parseISO(date) : null);
export const isBetween = (date: DateOrString, start?: DateOrString, end?: DateOrString): boolean => { export const isBetween = (date: DateOrString, start?: DateOrString, end?: DateOrString): boolean => {
try { try {
return isWithinInterval(parseISO(date), { start: parseISO(start ?? date), end: parseISO(end ?? date) }); return isWithinInterval(parseISO(date), { start: parseISO(start ?? date), end: parseISO(end ?? date) });

View file

@ -36,6 +36,6 @@ export const orderToString = <T>(order: Order<T>): string | undefined => (
); );
export const stringToOrder = <T>(order: string): Order<T> => { export const stringToOrder = <T>(order: string): Order<T> => {
const [field, dir] = order.split('-') as [ T | undefined, OrderDir | undefined ]; const [field, dir] = order.split('-') as [T | undefined, OrderDir | undefined];
return { field, dir }; return { field, dir };
}; };

View file

@ -72,9 +72,9 @@ export const VisitsStats: FC<VisitsStatsProps> = ({
fallbackInterval ?? settings.visits?.defaultInterval ?? 'last30Days', fallbackInterval ?? settings.visits?.defaultInterval ?? 'last30Days',
); );
const [dateRange, setDateRange] = useState<DateRange>(intervalToDateRange(initialInterval)); const [dateRange, setDateRange] = useState<DateRange>(intervalToDateRange(initialInterval));
const [visitsFilter, setVisitsFilter] = useState<VisitsFilter>({});
const [highlightedVisits, setHighlightedVisits] = useState<NormalizedVisit[]>([]); const [highlightedVisits, setHighlightedVisits] = useState<NormalizedVisit[]>([]);
const [highlightedLabel, setHighlightedLabel] = useState<string | undefined>(); const [highlightedLabel, setHighlightedLabel] = useState<string | undefined>();
const [visitsFilter, setVisitsFilter] = useState<VisitsFilter>({});
const botsSupported = supportsBotVisits(selectedServer); const botsSupported = supportsBotVisits(selectedServer);
const isFirstLoad = useRef(true); const isFirstLoad = useRef(true);