Add filtering to collections
This commit is contained in:
parent
223237d0fd
commit
b4cb44834c
7 changed files with 158 additions and 14 deletions
|
@ -5,34 +5,42 @@ import { FormattedMessage, useIntl } from "react-intl";
|
|||
|
||||
import { Container } from "@saleor/components/Container";
|
||||
import PageHeader from "@saleor/components/PageHeader";
|
||||
import SearchBar from "@saleor/components/SearchBar";
|
||||
import FilterBar from "@saleor/components/FilterBar";
|
||||
import { sectionNames } from "@saleor/intl";
|
||||
import {
|
||||
ListActions,
|
||||
PageListProps,
|
||||
SearchPageProps,
|
||||
FilterPageProps,
|
||||
TabPageProps,
|
||||
SortPage
|
||||
} from "@saleor/types";
|
||||
import { CollectionListUrlSortField } from "@saleor/collections/urls";
|
||||
import {
|
||||
CollectionFilterKeys,
|
||||
createFilterStructure
|
||||
} from "@saleor/collections/views/CollectionList/filter";
|
||||
import { CollectionListFilterOpts } from "@saleor/collections/types";
|
||||
import { CollectionList_collections_edges_node } from "../../types/CollectionList";
|
||||
import CollectionList from "../CollectionList/CollectionList";
|
||||
|
||||
export interface CollectionListPageProps
|
||||
extends PageListProps,
|
||||
ListActions,
|
||||
SearchPageProps,
|
||||
FilterPageProps<CollectionFilterKeys, CollectionListFilterOpts>,
|
||||
SortPage<CollectionListUrlSortField>,
|
||||
TabPageProps {
|
||||
collections: CollectionList_collections_edges_node[];
|
||||
}
|
||||
|
||||
const CollectionListPage: React.FC<CollectionListPageProps> = ({
|
||||
currencySymbol,
|
||||
currentTab,
|
||||
disabled,
|
||||
filterOpts,
|
||||
initialSearch,
|
||||
onAdd,
|
||||
onAll,
|
||||
onFilterChange,
|
||||
onSearchChange,
|
||||
onTabChange,
|
||||
onTabDelete,
|
||||
|
@ -42,6 +50,8 @@ const CollectionListPage: React.FC<CollectionListPageProps> = ({
|
|||
}) => {
|
||||
const intl = useIntl();
|
||||
|
||||
const structure = createFilterStructure(intl, filterOpts);
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<PageHeader title={intl.formatMessage(sectionNames.collections)}>
|
||||
|
@ -58,18 +68,21 @@ const CollectionListPage: React.FC<CollectionListPageProps> = ({
|
|||
</Button>
|
||||
</PageHeader>
|
||||
<Card>
|
||||
<SearchBar
|
||||
<FilterBar
|
||||
allTabLabel={intl.formatMessage({
|
||||
defaultMessage: "All Collections",
|
||||
description: "tab name"
|
||||
})}
|
||||
currencySymbol={currencySymbol}
|
||||
currentTab={currentTab}
|
||||
filterStructure={structure}
|
||||
initialSearch={initialSearch}
|
||||
searchPlaceholder={intl.formatMessage({
|
||||
defaultMessage: "Search Collection"
|
||||
})}
|
||||
tabs={tabs}
|
||||
onAll={onAll}
|
||||
onFilterChange={onFilterChange}
|
||||
onSearchChange={onSearchChange}
|
||||
onTabChange={onTabChange}
|
||||
onTabDelete={onTabDelete}
|
||||
|
|
6
src/collections/types.ts
Normal file
6
src/collections/types.ts
Normal file
|
@ -0,0 +1,6 @@
|
|||
import { FilterOpts } from "@saleor/types";
|
||||
import { CollectionPublished } from "@saleor/types/globalTypes";
|
||||
|
||||
export interface CollectionListFilterOpts {
|
||||
status: FilterOpts<CollectionPublished>;
|
||||
}
|
|
@ -15,6 +15,7 @@ const collectionSectionUrl = "/collections/";
|
|||
|
||||
export const collectionListPath = collectionSectionUrl;
|
||||
export enum CollectionListUrlFiltersEnum {
|
||||
status = "status",
|
||||
query = "query"
|
||||
}
|
||||
export type CollectionListUrlFilters = Filters<CollectionListUrlFiltersEnum>;
|
||||
|
|
|
@ -23,6 +23,9 @@ import { ListViews } from "@saleor/types";
|
|||
import { getSortParams } from "@saleor/utils/sort";
|
||||
import createSortHandler from "@saleor/utils/handlers/sortHandler";
|
||||
import createDialogActionHandlers from "@saleor/utils/handlers/dialogActionHandlers";
|
||||
import { IFilter } from "@saleor/components/Filter";
|
||||
import { getFilterQueryParams } from "@saleor/utils/filters";
|
||||
import useShop from "@saleor/hooks/useShop";
|
||||
import CollectionListPage from "../../components/CollectionListPage/CollectionListPage";
|
||||
import {
|
||||
TypedCollectionBulkDelete,
|
||||
|
@ -45,7 +48,10 @@ import {
|
|||
getActiveFilters,
|
||||
getFilterTabs,
|
||||
getFilterVariables,
|
||||
saveFilterTab
|
||||
saveFilterTab,
|
||||
CollectionFilterKeys,
|
||||
getFilterQueryParam,
|
||||
getFilterOpts
|
||||
} from "./filter";
|
||||
import { getSortQueryVariables } from "./sort";
|
||||
|
||||
|
@ -57,6 +63,7 @@ export const CollectionList: React.FC<CollectionListProps> = ({ params }) => {
|
|||
const navigate = useNavigator();
|
||||
const notify = useNotifier();
|
||||
const paginate = usePaginator();
|
||||
const shop = useShop();
|
||||
const { isSelected, listElements, reset, toggle, toggleAll } = useBulkActions(
|
||||
params.ids
|
||||
);
|
||||
|
@ -88,17 +95,38 @@ export const CollectionList: React.FC<CollectionListProps> = ({ params }) => {
|
|||
: 0
|
||||
: parseInt(params.activeTab, 0);
|
||||
|
||||
const changeFilterField = (filter: CollectionListUrlFilters) => {
|
||||
const changeFilters = (filter: IFilter<CollectionFilterKeys>) => {
|
||||
reset();
|
||||
navigate(
|
||||
collectionListUrl({
|
||||
...getActiveFilters(params),
|
||||
...filter,
|
||||
...params,
|
||||
...getFilterQueryParams(filter, getFilterQueryParam),
|
||||
activeTab: undefined
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
const resetFilters = () => {
|
||||
reset();
|
||||
navigate(
|
||||
collectionListUrl({
|
||||
asc: params.asc,
|
||||
sort: params.sort
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
const handleSearchChange = (query: string) => {
|
||||
reset();
|
||||
navigate(
|
||||
collectionListUrl({
|
||||
...params,
|
||||
activeTab: undefined,
|
||||
query
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
const [openModal, closeModal] = createDialogActionHandlers<
|
||||
CollectionListUrlDialog,
|
||||
CollectionListUrlQueryParams
|
||||
|
@ -154,6 +182,7 @@ export const CollectionList: React.FC<CollectionListProps> = ({ params }) => {
|
|||
};
|
||||
|
||||
const handleSort = createSortHandler(navigate, collectionListUrl, params);
|
||||
const currencySymbol = maybe(() => shop.defaultCurrency, "USD");
|
||||
|
||||
return (
|
||||
<TypedCollectionBulkDelete onCompleted={handleCollectionBulkDelete}>
|
||||
|
@ -162,11 +191,14 @@ export const CollectionList: React.FC<CollectionListProps> = ({ params }) => {
|
|||
{(collectionBulkPublish, collectionBulkPublishOpts) => (
|
||||
<>
|
||||
<CollectionListPage
|
||||
currencySymbol={currencySymbol}
|
||||
currentTab={currentTab}
|
||||
filterOpts={getFilterOpts(params)}
|
||||
initialSearch={params.query || ""}
|
||||
onSearchChange={query => changeFilterField({ query })}
|
||||
onSearchChange={handleSearchChange}
|
||||
onFilterChange={changeFilters}
|
||||
onAdd={() => navigate(collectionAddUrl)}
|
||||
onAll={() => navigate(collectionListUrl())}
|
||||
onAll={resetFilters}
|
||||
onTabChange={handleTabChange}
|
||||
onTabDelete={() => openModal("delete-search")}
|
||||
onTabSave={() => openModal("save-search")}
|
||||
|
|
|
@ -1,24 +1,99 @@
|
|||
import { CollectionFilterInput } from "@saleor/types/globalTypes";
|
||||
import { IntlShape } from "react-intl";
|
||||
|
||||
import {
|
||||
createFilterTabUtils,
|
||||
createFilterUtils
|
||||
} from "../../../utils/filters";
|
||||
CollectionFilterInput,
|
||||
CollectionPublished
|
||||
} from "@saleor/types/globalTypes";
|
||||
import { IFilterElement, IFilter } from "@saleor/components/Filter";
|
||||
import { maybe, findValueInEnum } from "@saleor/misc";
|
||||
import { createOptionsField } from "@saleor/utils/filters/fields";
|
||||
import { commonMessages } from "@saleor/intl";
|
||||
import { CollectionListFilterOpts } from "../../types";
|
||||
import {
|
||||
CollectionListUrlFilters,
|
||||
CollectionListUrlFiltersEnum,
|
||||
CollectionListUrlQueryParams
|
||||
} from "../../urls";
|
||||
import {
|
||||
createFilterTabUtils,
|
||||
createFilterUtils
|
||||
} from "../../../utils/filters";
|
||||
import messages from "./messages";
|
||||
|
||||
export const COLLECTION_FILTERS_KEY = "collectionFilters";
|
||||
|
||||
export enum CollectionFilterKeys {
|
||||
status = "status"
|
||||
}
|
||||
|
||||
export function getFilterOpts(
|
||||
params: CollectionListUrlFilters
|
||||
): CollectionListFilterOpts {
|
||||
return {
|
||||
status: {
|
||||
active: maybe(() => params.status !== undefined, false),
|
||||
value: maybe(() => findValueInEnum(status, CollectionPublished))
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function createFilterStructure(
|
||||
intl: IntlShape,
|
||||
opts: CollectionListFilterOpts
|
||||
): IFilter<CollectionFilterKeys> {
|
||||
return [
|
||||
{
|
||||
...createOptionsField(
|
||||
CollectionFilterKeys.status,
|
||||
intl.formatMessage(commonMessages.status),
|
||||
[opts.status.value],
|
||||
false,
|
||||
[
|
||||
{
|
||||
label: intl.formatMessage(messages.published),
|
||||
value: CollectionPublished.PUBLISHED
|
||||
},
|
||||
{
|
||||
label: intl.formatMessage(messages.hidden),
|
||||
value: CollectionPublished.HIDDEN
|
||||
}
|
||||
]
|
||||
),
|
||||
active: opts.status.active
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
export function getFilterVariables(
|
||||
params: CollectionListUrlFilters
|
||||
): CollectionFilterInput {
|
||||
return {
|
||||
published: params.status
|
||||
? findValueInEnum(params.status, CollectionPublished)
|
||||
: undefined,
|
||||
search: params.query
|
||||
};
|
||||
}
|
||||
|
||||
export function getFilterQueryParam(
|
||||
filter: IFilterElement<CollectionFilterKeys>
|
||||
): CollectionListUrlFilters {
|
||||
const { active, name, value } = filter;
|
||||
|
||||
switch (name) {
|
||||
case CollectionFilterKeys.status:
|
||||
if (!active) {
|
||||
return {
|
||||
status: undefined
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
status: value[0]
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export const {
|
||||
deleteFilterTab,
|
||||
getFilterTabs,
|
||||
|
|
14
src/collections/views/CollectionList/messages.ts
Normal file
14
src/collections/views/CollectionList/messages.ts
Normal file
|
@ -0,0 +1,14 @@
|
|||
import { defineMessages } from "react-intl";
|
||||
|
||||
const messages = defineMessages({
|
||||
hidden: {
|
||||
defaultMessage: "Hidden",
|
||||
description: "collection"
|
||||
},
|
||||
published: {
|
||||
defaultMessage: "Published",
|
||||
description: "collection"
|
||||
}
|
||||
});
|
||||
|
||||
export default messages;
|
|
@ -65,6 +65,9 @@ export const commonMessages = defineMessages({
|
|||
startHour: {
|
||||
defaultMessage: "Start Hour"
|
||||
},
|
||||
status: {
|
||||
defaultMessage: "Status"
|
||||
},
|
||||
summary: {
|
||||
defaultMessage: "Summary"
|
||||
},
|
||||
|
|
Loading…
Reference in a new issue