Abstracted logic to parse tags from string to array and back for the query

This commit is contained in:
Alejandro Celaya 2022-03-13 11:14:30 +01:00
parent 47d30aaa34
commit e632c5b04f
3 changed files with 23 additions and 19 deletions

View file

@ -34,7 +34,6 @@ const ShortUrlsFilteringBar = (colorGenerator: ColorGenerator): FC<ShortUrlsFilt
{ selectedServer, className, order, handleOrderBy },
) => {
const [{ search, tags, startDate, endDate, tagsMode = 'any' }, toFirstPage ] = useShortUrlsQuery();
const selectedTags = tags?.split(',') ?? [];
const setDates = pipe(
({ startDate, endDate }: DateRange) => ({
startDate: formatIsoDate(startDate) ?? undefined,
@ -47,9 +46,8 @@ const ShortUrlsFilteringBar = (colorGenerator: ColorGenerator): FC<ShortUrlsFilt
(search) => toFirstPage({ search }),
);
const removeTag = pipe(
(tag: string) => selectedTags.filter((selectedTag) => selectedTag !== tag),
(tagsList) => tagsList.length === 0 ? undefined : tagsList.join(','),
(tags) => toFirstPage({ tags }),
(tag: string) => tags.filter((selectedTag) => selectedTag !== tag),
(updateTags) => toFirstPage({ tags: updateTags }),
);
const canChangeTagsMode = supportsAllTagsFiltering(selectedServer);
const toggleTagsMode = pipe(
@ -80,9 +78,9 @@ const ShortUrlsFilteringBar = (colorGenerator: ColorGenerator): FC<ShortUrlsFilt
</div>
</Row>
{selectedTags.length > 0 && (
{tags.length > 0 && (
<h4 className="mt-3">
{canChangeTagsMode && selectedTags.length > 1 && (
{canChangeTagsMode && tags.length > 1 && (
<div className="float-end ms-2 mt-1">
<TooltipToggleSwitch
checked={tagsMode === 'all'}
@ -94,7 +92,7 @@ const ShortUrlsFilteringBar = (colorGenerator: ColorGenerator): FC<ShortUrlsFilt
</div>
)}
<FontAwesomeIcon icon={tagsIcon} className="short-urls-filtering-bar__tags-icon me-1" />
{selectedTags.map((tag) =>
{tags.map((tag) =>
<Tag colorGenerator={colorGenerator} key={tag} text={tag} clearable onClose={() => removeTag(tag)} />)}
</h4>
)}

View file

@ -1,5 +1,5 @@
import { pipe } from 'ramda';
import { FC, useEffect, useMemo, useState } from 'react';
import { FC, useEffect, useState } from 'react';
import { Card } from 'reactstrap';
import { useLocation, useParams } from 'react-router-dom';
import { determineOrderDir, OrderDir } from '../utils/helpers/ordering';
@ -35,7 +35,6 @@ const ShortUrlsList = (
// This separated state handling is needed to be able to fall back to settings value, but only once when loaded
orderBy ?? settings.shortUrlsList?.defaultOrdering ?? DEFAULT_SHORT_URLS_ORDERING,
);
const selectedTags = useMemo(() => tags?.split(',') ?? [], [ tags ]);
const { pagination } = shortUrlsList?.shortUrls ?? {};
const handleOrderBy = (field?: ShortUrlsOrderableFields, dir?: OrderDir) => {
toFirstPage({ orderBy: { field, dir } });
@ -46,21 +45,21 @@ const ShortUrlsList = (
const renderOrderIcon = (field: ShortUrlsOrderableFields) =>
<TableOrderIcon currentOrder={actualOrderBy} field={field} />;
const addTag = pipe(
(newTag: string) => [ ...new Set([ ...selectedTags, newTag ]) ].join(','),
(tags) => toFirstPage({ tags }),
(newTag: string) => [ ...new Set([ ...tags, newTag ]) ],
(updatedTags) => toFirstPage({ tags: updatedTags }),
);
useEffect(() => {
listShortUrls({
page,
searchTerm: search,
tags: selectedTags,
tags,
startDate,
endDate,
orderBy: actualOrderBy,
tagsMode,
});
}, [ page, search, selectedTags, startDate, endDate, actualOrderBy, tagsMode ]);
}, [ page, search, tags, startDate, endDate, actualOrderBy, tagsMode ]);
return (
<>

View file

@ -14,7 +14,6 @@ export interface ShortUrlListRouteParams {
}
interface ShortUrlsQueryCommon {
tags?: string;
search?: string;
startDate?: string;
endDate?: string;
@ -23,10 +22,12 @@ interface ShortUrlsQueryCommon {
interface ShortUrlsQuery extends ShortUrlsQueryCommon {
orderBy?: string;
tags?: string;
}
interface ShortUrlsFiltering extends ShortUrlsQueryCommon {
orderBy?: ShortUrlsOrder;
tags: string[];
}
export const useShortUrlsQuery = (): [ShortUrlsFiltering, ToFirstPage] => {
@ -37,16 +38,22 @@ export const useShortUrlsQuery = (): [ShortUrlsFiltering, ToFirstPage] => {
const query = useMemo(
pipe(
() => parseQuery<ShortUrlsQuery>(location.search),
({ orderBy, ...rest }: ShortUrlsQuery): ShortUrlsFiltering => !orderBy ? rest : {
...rest,
orderBy: stringToOrder<ShortUrlsOrderableFields>(orderBy),
({ orderBy, tags, ...rest }: ShortUrlsQuery): ShortUrlsFiltering => {
const parsedOrderBy = orderBy ? stringToOrder<ShortUrlsOrderableFields>(orderBy) : undefined;
const parsedTags = tags?.split(',') ?? [];
return { ...rest, orderBy: parsedOrderBy, tags: parsedTags };
},
),
[ location.search ],
);
const toFirstPageWithExtra = (extra: Partial<ShortUrlsFiltering>) => {
const { orderBy, ...mergedQuery } = { ...query, ...extra };
const normalizedQuery: ShortUrlsQuery = { ...mergedQuery, orderBy: orderBy && orderToString(orderBy) };
const { orderBy, tags, ...mergedQuery } = { ...query, ...extra };
const normalizedQuery: ShortUrlsQuery = {
...mergedQuery,
orderBy: orderBy && orderToString(orderBy),
tags: tags.length > 0 ? tags.join(',') : undefined,
};
const evolvedQuery = stringifyQuery(normalizedQuery);
const queryString = isEmpty(evolvedQuery) ? '' : `?${evolvedQuery}`;