diff --git a/src/categories/components/CategoryListPage/CategoryListPage.tsx b/src/categories/components/CategoryListPage/CategoryListPage.tsx index 2e147f1e7..90a64ba09 100644 --- a/src/categories/components/CategoryListPage/CategoryListPage.tsx +++ b/src/categories/components/CategoryListPage/CategoryListPage.tsx @@ -65,7 +65,7 @@ export const CategoryListPage: React.StatelessComponent = ({ currentTab={currentTab} initialSearch={initialSearch} searchPlaceholder={intl.formatMessage({ - defaultMessage: "Search Attribute" + defaultMessage: "Search Category" })} tabs={tabs} onAll={onAll} diff --git a/src/categories/views/CategoryList/filter.ts b/src/categories/views/CategoryList/filter.ts index a1e3fa703..f61179a63 100644 --- a/src/categories/views/CategoryList/filter.ts +++ b/src/categories/views/CategoryList/filter.ts @@ -9,7 +9,7 @@ import { CategoryListUrlQueryParams } from "../../urls"; -export const PRODUCT_FILTERS_KEY = "productFilters"; +export const CATEGORY_FILTERS_KEY = "categoryFilters"; export function getFilterVariables( params: CategoryListUrlFilters @@ -23,7 +23,7 @@ export const { deleteFilterTab, getFilterTabs, saveFilterTab -} = createFilterTabUtils(PRODUCT_FILTERS_KEY); +} = createFilterTabUtils(CATEGORY_FILTERS_KEY); export const { areFiltersApplied, getActiveFilters } = createFilterUtils< CategoryListUrlQueryParams, diff --git a/src/collections/components/CollectionList/CollectionList.tsx b/src/collections/components/CollectionList/CollectionList.tsx index 3690c39ea..68d7302df 100644 --- a/src/collections/components/CollectionList/CollectionList.tsx +++ b/src/collections/components/CollectionList/CollectionList.tsx @@ -1,4 +1,3 @@ -import Card from "@material-ui/core/Card"; import { createStyles, Theme, @@ -74,118 +73,110 @@ const CollectionList = withStyles(styles, { name: "CollectionList" })( const intl = useIntl(); return ( - - - - - - - - - - - - - - - - - - - - {renderCollection( - collections, - collection => { - const isSelected = collection - ? isChecked(collection.id) - : false; - return ( - - - toggle(collection.id)} - /> - - - {maybe( - () => collection.name, - - )} - - - {maybe( - () => collection.products.totalCount, - - )} - - - {maybe( - () => ( - - ), - - )} - - - ); - }, - () => ( - - - +
+ + + + + + + + + + + + + + + + + + {renderCollection( + collections, + collection => { + const isSelected = collection ? isChecked(collection.id) : false; + return ( + + + toggle(collection.id)} + /> + + + {maybe( + () => collection.name, + + )} + + + {maybe( + () => collection.products.totalCount, + + )} + + + {maybe( + () => ( + + ), + + )} - ) - )} - -
-
+ ); + }, + () => ( + + + + + + ) + )} + + ); } ); diff --git a/src/collections/components/CollectionListPage/CollectionListPage.tsx b/src/collections/components/CollectionListPage/CollectionListPage.tsx index 5138840db..3992dc011 100644 --- a/src/collections/components/CollectionListPage/CollectionListPage.tsx +++ b/src/collections/components/CollectionListPage/CollectionListPage.tsx @@ -1,22 +1,40 @@ import Button from "@material-ui/core/Button"; - +import Card from "@material-ui/core/Card"; import React from "react"; 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 { sectionNames } from "@saleor/intl"; -import { ListActions, PageListProps } from "@saleor/types"; +import { + ListActions, + PageListProps, + SearchPageProps, + TabPageProps +} from "@saleor/types"; import { CollectionList_collections_edges_node } from "../../types/CollectionList"; import CollectionList from "../CollectionList/CollectionList"; -export interface CollectionListPageProps extends PageListProps, ListActions { +export interface CollectionListPageProps + extends PageListProps, + ListActions, + SearchPageProps, + TabPageProps { collections: CollectionList_collections_edges_node[]; } const CollectionListPage: React.StatelessComponent = ({ + currentTab, disabled, + initialSearch, onAdd, + onAll, + onSearchChange, + onTabChange, + onTabDelete, + onTabSave, + tabs, ...listProps }) => { const intl = useIntl(); @@ -36,7 +54,22 @@ const CollectionListPage: React.StatelessComponent = ({ /> - + + + + ); }; diff --git a/src/collections/queries.ts b/src/collections/queries.ts index f13bcc24e..bc2a67d1a 100644 --- a/src/collections/queries.ts +++ b/src/collections/queries.ts @@ -60,8 +60,15 @@ export const collectionList = gql` $after: String $last: Int $before: String + $filter: CollectionFilterInput ) { - collections(first: $first, after: $after, before: $before, last: $last) { + collections( + first: $first + after: $after + before: $before + last: $last + filter: $filter + ) { edges { node { ...CollectionFragment diff --git a/src/collections/types/CollectionList.ts b/src/collections/types/CollectionList.ts index c17574dc0..93c2af1c7 100644 --- a/src/collections/types/CollectionList.ts +++ b/src/collections/types/CollectionList.ts @@ -2,6 +2,8 @@ /* eslint-disable */ // This file was automatically generated and should not be edited. +import { CollectionFilterInput } from "./../../types/globalTypes"; + // ==================================================== // GraphQL query operation: CollectionList // ==================================================== @@ -47,4 +49,5 @@ export interface CollectionListVariables { after?: string | null; last?: number | null; before?: string | null; + filter?: CollectionFilterInput | null; } diff --git a/src/collections/urls.ts b/src/collections/urls.ts index e6770071e..e17cfca21 100644 --- a/src/collections/urls.ts +++ b/src/collections/urls.ts @@ -1,13 +1,30 @@ import { stringify as stringifyQs } from "qs"; import urlJoin from "url-join"; -import { BulkAction, Dialog, Pagination } from "../types"; +import { + ActiveTab, + BulkAction, + Dialog, + Filters, + Pagination, + TabActionDialog +} from "../types"; const collectionSectionUrl = "/collections/"; export const collectionListPath = collectionSectionUrl; -export type CollectionListUrlDialog = "publish" | "unpublish" | "remove"; -export type CollectionListUrlQueryParams = BulkAction & +export enum CollectionListUrlFiltersEnum { + query = "query" +} +export type CollectionListUrlFilters = Filters; +export type CollectionListUrlDialog = + | "publish" + | "unpublish" + | "remove" + | TabActionDialog; +export type CollectionListUrlQueryParams = ActiveTab & + BulkAction & + CollectionListUrlFilters & Dialog & Pagination; export const collectionListUrl = (params?: CollectionListUrlQueryParams) => diff --git a/src/collections/views/CollectionList.tsx b/src/collections/views/CollectionList/CollectionList.tsx similarity index 78% rename from src/collections/views/CollectionList.tsx rename to src/collections/views/CollectionList/CollectionList.tsx index 0b7345126..04eed042a 100644 --- a/src/collections/views/CollectionList.tsx +++ b/src/collections/views/CollectionList/CollectionList.tsx @@ -5,7 +5,12 @@ import DeleteIcon from "@material-ui/icons/Delete"; import React from "react"; import { FormattedMessage, useIntl } from "react-intl"; +import { CategoryListUrlFilters } from "@saleor/categories/urls"; import ActionDialog from "@saleor/components/ActionDialog"; +import DeleteFilterTabDialog from "@saleor/components/DeleteFilterTabDialog"; +import SaveFilterTabDialog, { + SaveFilterTabDialogFormData +} from "@saleor/components/SaveFilterTabDialog"; import useBulkActions from "@saleor/hooks/useBulkActions"; import useListSettings from "@saleor/hooks/useListSettings"; import useNavigator from "@saleor/hooks/useNavigator"; @@ -16,21 +21,29 @@ import usePaginator, { import { commonMessages } from "@saleor/intl"; import { getMutationState, maybe } from "@saleor/misc"; import { ListViews } from "@saleor/types"; -import CollectionListPage from "../components/CollectionListPage/CollectionListPage"; +import CollectionListPage from "../../components/CollectionListPage/CollectionListPage"; import { TypedCollectionBulkDelete, TypedCollectionBulkPublish -} from "../mutations"; -import { TypedCollectionListQuery } from "../queries"; -import { CollectionBulkDelete } from "../types/CollectionBulkDelete"; -import { CollectionBulkPublish } from "../types/CollectionBulkPublish"; +} from "../../mutations"; +import { TypedCollectionListQuery } from "../../queries"; +import { CollectionBulkDelete } from "../../types/CollectionBulkDelete"; +import { CollectionBulkPublish } from "../../types/CollectionBulkPublish"; import { collectionAddUrl, collectionListUrl, CollectionListUrlDialog, CollectionListUrlQueryParams, collectionUrl -} from "../urls"; +} from "../../urls"; +import { + areFiltersApplied, + deleteFilterTab, + getActiveFilters, + getFilterTabs, + getFilterVariables, + saveFilterTab +} from "./filter"; interface CollectionListProps { params: CollectionListUrlQueryParams; @@ -50,6 +63,26 @@ export const CollectionList: React.StatelessComponent = ({ ); const intl = useIntl(); + const tabs = getFilterTabs(); + + const currentTab = + params.activeTab === undefined + ? areFiltersApplied(params) + ? tabs.length + 1 + : 0 + : parseInt(params.activeTab, 0); + + const changeFilterField = (filter: CategoryListUrlFilters) => { + reset(); + navigate( + collectionListUrl({ + ...getActiveFilters(params), + ...filter, + activeTab: undefined + }) + ); + }; + const closeModal = () => navigate( collectionListUrl({ @@ -60,17 +93,47 @@ export const CollectionList: React.StatelessComponent = ({ true ); - const openModal = (action: CollectionListUrlDialog, ids: string[]) => + const openModal = (action: CollectionListUrlDialog, ids?: string[]) => navigate( collectionListUrl({ + ...params, action, ids }) ); + const handleTabChange = (tab: number) => { + reset(); + navigate( + collectionListUrl({ + activeTab: tab.toString(), + ...getFilterTabs()[tab - 1].data + }) + ); + }; + + const handleTabDelete = () => { + deleteFilterTab(currentTab); + reset(); + navigate(collectionListUrl()); + }; + + const handleTabSave = (data: SaveFilterTabDialogFormData) => { + saveFilterTab(data.name, getActiveFilters(params)); + handleTabChange(tabs.length + 1); + }; + const paginationState = createPaginationState(settings.rowNumber, params); + const queryVariables = React.useMemo( + () => ({ + ...paginationState, + filter: getFilterVariables(params) + }), + [params] + ); + return ( - + {({ data, loading, refetch }) => { const { loadNextPage, loadPreviousPage, pageInfo } = paginate( maybe(() => data.collections.pageInfo), @@ -130,7 +193,15 @@ export const CollectionList: React.StatelessComponent = ({ return ( <> changeFilterField({ query })} onAdd={() => navigate(collectionAddUrl)} + onAll={() => navigate(collectionListUrl())} + onTabChange={handleTabChange} + onTabDelete={() => openModal("delete-search")} + onTabSave={() => openModal("save-search")} + tabs={tabs.map(tab => tab.name)} disabled={loading} collections={maybe(() => data.collections.edges.map(edge => edge.node) @@ -289,6 +360,19 @@ export const CollectionList: React.StatelessComponent = ({ /> + + tabs[currentTab - 1].name, "...")} + /> ); }} diff --git a/src/collections/views/CollectionList/filter.ts b/src/collections/views/CollectionList/filter.ts new file mode 100644 index 000000000..47a710945 --- /dev/null +++ b/src/collections/views/CollectionList/filter.ts @@ -0,0 +1,31 @@ +import { CollectionFilterInput } from "@saleor/types/globalTypes"; +import { + createFilterTabUtils, + createFilterUtils +} from "../../../utils/filters"; +import { + CollectionListUrlFilters, + CollectionListUrlFiltersEnum, + CollectionListUrlQueryParams +} from "../../urls"; + +export const COLLECTION_FILTERS_KEY = "collectionFilters"; + +export function getFilterVariables( + params: CollectionListUrlFilters +): CollectionFilterInput { + return { + search: params.query + }; +} + +export const { + deleteFilterTab, + getFilterTabs, + saveFilterTab +} = createFilterTabUtils(COLLECTION_FILTERS_KEY); + +export const { areFiltersApplied, getActiveFilters } = createFilterUtils< + CollectionListUrlQueryParams, + CollectionListUrlFilters +>(CollectionListUrlFiltersEnum); diff --git a/src/collections/views/CollectionList/index.ts b/src/collections/views/CollectionList/index.ts new file mode 100644 index 000000000..4f5db2333 --- /dev/null +++ b/src/collections/views/CollectionList/index.ts @@ -0,0 +1,2 @@ +export { default } from "./CollectionList"; +export * from "./CollectionList"; diff --git a/src/types/globalTypes.ts b/src/types/globalTypes.ts index fc5f03ddd..d23152cac 100644 --- a/src/types/globalTypes.ts +++ b/src/types/globalTypes.ts @@ -33,6 +33,11 @@ export enum AuthorizationKeyType { GOOGLE_OAUTH2 = "GOOGLE_OAUTH2", } +export enum CollectionPublished { + HIDDEN = "HIDDEN", + PUBLISHED = "PUBLISHED", +} + export enum ConfigurationTypeFieldEnum { BOOLEAN = "BOOLEAN", STRING = "STRING", @@ -343,6 +348,11 @@ export interface CollectionCreateInput { products?: (string | null)[] | null; } +export interface CollectionFilterInput { + published?: CollectionPublished | null; + search?: string | null; +} + export interface CollectionInput { isPublished?: boolean | null; name?: string | null;