From b4cb44834c3fbcc67acbccefc166dfa3b7b23039 Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Tue, 7 Jan 2020 14:34:45 +0100 Subject: [PATCH] Add filtering to collections --- .../CollectionListPage/CollectionListPage.tsx | 21 ++++- src/collections/types.ts | 6 ++ src/collections/urls.ts | 1 + .../views/CollectionList/CollectionList.tsx | 44 ++++++++-- .../views/CollectionList/filter.ts | 83 ++++++++++++++++++- .../views/CollectionList/messages.ts | 14 ++++ src/intl.ts | 3 + 7 files changed, 158 insertions(+), 14 deletions(-) create mode 100644 src/collections/types.ts create mode 100644 src/collections/views/CollectionList/messages.ts diff --git a/src/collections/components/CollectionListPage/CollectionListPage.tsx b/src/collections/components/CollectionListPage/CollectionListPage.tsx index df72134ba..cf20510bf 100644 --- a/src/collections/components/CollectionListPage/CollectionListPage.tsx +++ b/src/collections/components/CollectionListPage/CollectionListPage.tsx @@ -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, SortPage, TabPageProps { collections: CollectionList_collections_edges_node[]; } const CollectionListPage: React.FC = ({ + currencySymbol, currentTab, disabled, + filterOpts, initialSearch, onAdd, onAll, + onFilterChange, onSearchChange, onTabChange, onTabDelete, @@ -42,6 +50,8 @@ const CollectionListPage: React.FC = ({ }) => { const intl = useIntl(); + const structure = createFilterStructure(intl, filterOpts); + return ( @@ -58,18 +68,21 @@ const CollectionListPage: React.FC = ({ - ; +} diff --git a/src/collections/urls.ts b/src/collections/urls.ts index 908fc998a..d22345b8a 100644 --- a/src/collections/urls.ts +++ b/src/collections/urls.ts @@ -15,6 +15,7 @@ const collectionSectionUrl = "/collections/"; export const collectionListPath = collectionSectionUrl; export enum CollectionListUrlFiltersEnum { + status = "status", query = "query" } export type CollectionListUrlFilters = Filters; diff --git a/src/collections/views/CollectionList/CollectionList.tsx b/src/collections/views/CollectionList/CollectionList.tsx index f5c30df11..4cb9c6d53 100644 --- a/src/collections/views/CollectionList/CollectionList.tsx +++ b/src/collections/views/CollectionList/CollectionList.tsx @@ -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 = ({ 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 = ({ params }) => { : 0 : parseInt(params.activeTab, 0); - const changeFilterField = (filter: CollectionListUrlFilters) => { + const changeFilters = (filter: IFilter) => { 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 = ({ params }) => { }; const handleSort = createSortHandler(navigate, collectionListUrl, params); + const currencySymbol = maybe(() => shop.defaultCurrency, "USD"); return ( @@ -162,11 +191,14 @@ export const CollectionList: React.FC = ({ params }) => { {(collectionBulkPublish, collectionBulkPublishOpts) => ( <> changeFilterField({ query })} + onSearchChange={handleSearchChange} + onFilterChange={changeFilters} onAdd={() => navigate(collectionAddUrl)} - onAll={() => navigate(collectionListUrl())} + onAll={resetFilters} onTabChange={handleTabChange} onTabDelete={() => openModal("delete-search")} onTabSave={() => openModal("save-search")} diff --git a/src/collections/views/CollectionList/filter.ts b/src/collections/views/CollectionList/filter.ts index 47a710945..1e09bfed7 100644 --- a/src/collections/views/CollectionList/filter.ts +++ b/src/collections/views/CollectionList/filter.ts @@ -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 { + 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 +): CollectionListUrlFilters { + const { active, name, value } = filter; + + switch (name) { + case CollectionFilterKeys.status: + if (!active) { + return { + status: undefined + }; + } + + return { + status: value[0] + }; + } +} + export const { deleteFilterTab, getFilterTabs, diff --git a/src/collections/views/CollectionList/messages.ts b/src/collections/views/CollectionList/messages.ts new file mode 100644 index 000000000..3e3f6a327 --- /dev/null +++ b/src/collections/views/CollectionList/messages.ts @@ -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; diff --git a/src/intl.ts b/src/intl.ts index fee264968..afdc1a18b 100644 --- a/src/intl.ts +++ b/src/intl.ts @@ -65,6 +65,9 @@ export const commonMessages = defineMessages({ startHour: { defaultMessage: "Start Hour" }, + status: { + defaultMessage: "Status" + }, summary: { defaultMessage: "Summary" },