diff --git a/.changeset/flat-squids-bow.md b/.changeset/flat-squids-bow.md new file mode 100644 index 00000000000..bed8eab6b73 --- /dev/null +++ b/.changeset/flat-squids-bow.md @@ -0,0 +1,5 @@ +--- +"saleor-dashboard": patch +--- + +You can now save, update, and delete filter presets on a product types list \ No newline at end of file diff --git a/locale/defaultMessages.json b/locale/defaultMessages.json index a32f6309c4e..86bf8507a34 100644 --- a/locale/defaultMessages.json +++ b/locale/defaultMessages.json @@ -582,10 +582,6 @@ "context": "expiry date section header", "string": "Expiry date" }, - "1KSqnn": { - "context": "tab name", - "string": "All Product Types" - }, "1LBYpE": { "context": "dialog header", "string": "Delete Menus" @@ -4015,6 +4011,10 @@ "context": "header field name, header", "string": "Name" }, + "Nqh0na": { + "context": "Product types search input placeholder", + "string": "Search product types..." + }, "NqxvFh": { "context": "navigator placeholder", "string": "Type Command" @@ -7270,6 +7270,10 @@ "ivJ1qt": { "string": "Manage your permission groups and their permissions" }, + "ivmwpV": { + "context": "tab name", + "string": "All product types" + }, "ixjvkM": { "string": "We’ve created your default token. Make sure to copy your new personal access token now. You won’t be able to see it again." }, @@ -8572,9 +8576,6 @@ "context": "expires in label", "string": "Expires in" }, - "rpFdD1": { - "string": "Search Product Type" - }, "rqiCWU": { "string": "Saved changes" }, diff --git a/src/productTypes/components/ProductTypeListPage/ProductTypeListPage.tsx b/src/productTypes/components/ProductTypeListPage/ProductTypeListPage.tsx index 30327eb944b..7501f5742f5 100644 --- a/src/productTypes/components/ProductTypeListPage/ProductTypeListPage.tsx +++ b/src/productTypes/components/ProductTypeListPage/ProductTypeListPage.tsx @@ -1,32 +1,29 @@ -// @ts-strict-ignore +import { ListFilters } from "@dashboard/components/AppLayout/ListFilters"; import { TopNav } from "@dashboard/components/AppLayout/TopNav"; -import { Button } from "@dashboard/components/Button"; import { DashboardCard } from "@dashboard/components/Card"; -import FilterBar from "@dashboard/components/FilterBar"; -import { configurationMenuUrl } from "@dashboard/configuration"; +import { FilterPresetsSelect } from "@dashboard/components/FilterPresetsSelect"; +import { ListPageLayout } from "@dashboard/components/Layouts"; import { ProductTypeFragment } from "@dashboard/graphql"; +import useNavigator from "@dashboard/hooks/useNavigator"; import { sectionNames } from "@dashboard/intl"; import ProductTypeList from "@dashboard/productTypes/components/ProductTypeList/ProductTypeList"; import { productTypeAddUrl, ProductTypeListUrlSortField } from "@dashboard/productTypes/urls"; -import React from "react"; +import { Box, Button, ChevronRightIcon } from "@saleor/macaw-ui-next"; +import React, { useState } from "react"; import { FormattedMessage, useIntl } from "react-intl"; -import { - FilterPageProps, - ListActions, - PageListProps, - SortPage, - TabPageProps, -} from "../../../types"; +import { FilterPageProps, ListActions, PageListProps, SortPage } from "../../../types"; import { createFilterStructure, ProductTypeFilterKeys, ProductTypeListFilterOpts } from "./filters"; export interface ProductTypeListPageProps extends PageListProps, ListActions, - FilterPageProps, - SortPage, - TabPageProps { + Omit, "onTabDelete">, + SortPage { productTypes: ProductTypeFragment[]; + onTabUpdate: (tabName: string) => void; + onTabDelete: (id: number) => void; + hasPresetsChanged: () => boolean; } const ProductTypeListPage: React.FC = ({ @@ -39,44 +36,81 @@ const ProductTypeListPage: React.FC = ({ onTabChange, onTabDelete, onTabSave, + onTabUpdate, tabs, + hasPresetsChanged, + disabled, ...listProps }) => { const intl = useIntl(); - const structure = createFilterStructure(intl, filterOpts); + const navigate = useNavigator(); + const [isFilterPresetOpen, setFilterPresetOpen] = useState(false); + const filterStructure = createFilterStructure(intl, filterOpts); return ( - <> - - + + + + + + + + + + + + + + - - + - + + - + ); }; diff --git a/src/productTypes/views/ProductTypeList/ProductTypeList.tsx b/src/productTypes/views/ProductTypeList/ProductTypeList.tsx index c9f41c7cc9e..396414030df 100644 --- a/src/productTypes/views/ProductTypeList/ProductTypeList.tsx +++ b/src/productTypes/views/ProductTypeList/ProductTypeList.tsx @@ -1,10 +1,8 @@ -// @ts-strict-ignore import DeleteFilterTabDialog from "@dashboard/components/DeleteFilterTabDialog"; -import SaveFilterTabDialog, { - SaveFilterTabDialogFormData, -} from "@dashboard/components/SaveFilterTabDialog"; +import SaveFilterTabDialog from "@dashboard/components/SaveFilterTabDialog"; import { useProductTypeBulkDeleteMutation, useProductTypeListQuery } from "@dashboard/graphql"; import useBulkActions from "@dashboard/hooks/useBulkActions"; +import { useFilterPresets } from "@dashboard/hooks/useFilterPresets"; import useListSettings from "@dashboard/hooks/useListSettings"; import useNavigator from "@dashboard/hooks/useNavigator"; import useNotifier from "@dashboard/hooks/useNotifier"; @@ -33,16 +31,7 @@ import { ProductTypeListUrlDialog, ProductTypeListUrlQueryParams, } from "../../urls"; -import { - deleteFilterTab, - getActiveFilters, - getFilterOpts, - getFilterQueryParam, - getFiltersCurrentTab, - getFilterTabs, - getFilterVariables, - saveFilterTab, -} from "./filters"; +import { getFilterOpts, getFilterQueryParam, getFilterVariables, storageUtils } from "./filters"; import { getSortQueryVariables } from "./sort"; interface ProductTypeListProps { @@ -77,8 +66,6 @@ export const ProductTypeList: React.FC = ({ params }) => { displayLoader: true, variables: queryVariables, }); - const tabs = getFilterTabs(); - const currentTab = getFiltersCurrentTab(params, tabs); const [changeFilters, resetFilters, handleSearchChange] = createFilterHandlers({ cleanupFn: reset, createUrl: productTypeListUrl, @@ -90,31 +77,31 @@ export const ProductTypeList: React.FC = ({ params }) => { ProductTypeListUrlDialog, ProductTypeListUrlQueryParams >(navigate, productTypeListUrl, params); - const handleTabChange = (tab: number) => { - reset(); - navigate( - productTypeListUrl({ - activeTab: tab.toString(), - ...getFilterTabs()[tab - 1].data, - }), - ); - }; - const handleTabDelete = () => { - deleteFilterTab(currentTab); - reset(); - navigate(productTypeListUrl()); - }; - const handleTabSave = (data: SaveFilterTabDialogFormData) => { - saveFilterTab(data.name, getActiveFilters(params)); - handleTabChange(tabs.length + 1); - }; + + const { + selectedPreset, + presets, + hasPresetsChanged, + onPresetChange, + onPresetDelete, + onPresetSave, + onPresetUpdate, + setPresetIdToDelete, + getPresetNameToDelete, + } = useFilterPresets({ + params, + reset, + getUrl: productTypeListUrl, + storageUtils, + }); + const paginationValues = usePaginator({ - pageInfo: maybe(() => data.productTypes.pageInfo), + pageInfo: maybe(() => data?.productTypes?.pageInfo), paginationState, queryString: params, }); const handleSort = createSortHandler(navigate, productTypeListUrl, params); - const productTypesData = mapEdgesToItems(data?.productTypes); + const productTypesData = mapEdgesToItems(data?.productTypes) ?? []; const productTypeDeleteData = useProductTypeDelete({ selectedTypes: selectedProductTypes, @@ -123,7 +110,7 @@ export const ProductTypeList: React.FC = ({ params }) => { }); const [productTypeBulkDelete, productTypeBulkDeleteOpts] = useProductTypeBulkDeleteMutation({ onCompleted: data => { - if (data.productTypeBulkDelete.errors.length === 0) { + if (data?.productTypeBulkDelete?.errors?.length === 0) { notify({ status: "success", text: intl.formatMessage(commonMessages.savedChanges), @@ -143,23 +130,27 @@ export const ProductTypeList: React.FC = ({ params }) => { const onProductTypeBulkDelete = () => productTypeBulkDelete({ variables: { - ids: params.ids, + ids: params.ids ?? [], }, }); return ( openModal("delete-search")} + onTabChange={onPresetChange} + onTabDelete={(id: number) => { + setPresetIdToDelete(id); + openModal("delete-search"); + }} onTabSave={() => openModal("save-search")} - tabs={tabs.map(tab => tab.name)} + onTabUpdate={onPresetUpdate} + tabs={presets.map(tab => tab.name)} disabled={loading} productTypes={productTypesData} onSort={handleSort} @@ -182,6 +173,7 @@ export const ProductTypeList: React.FC = ({ params }) => { } + hasPresetsChanged={hasPresetsChanged} /> {productTypesData && ( = ({ params }) => { open={params.action === "save-search"} confirmButtonState="default" onClose={closeModal} - onSubmit={handleTabSave} + onSubmit={onPresetSave} /> tabs[currentTab - 1].name, "...")} + onSubmit={onPresetDelete} + tabName={getPresetNameToDelete()} /> ); diff --git a/src/productTypes/views/ProductTypeList/filters.ts b/src/productTypes/views/ProductTypeList/filters.ts index 8cba86f2edd..e494d2372fe 100644 --- a/src/productTypes/views/ProductTypeList/filters.ts +++ b/src/productTypes/views/ProductTypeList/filters.ts @@ -61,8 +61,7 @@ export function getFilterQueryParam( } } -export const { deleteFilterTab, getFilterTabs, saveFilterTab } = - createFilterTabUtils(PRODUCT_TYPE_FILTERS_KEY); +export const storageUtils = createFilterTabUtils(PRODUCT_TYPE_FILTERS_KEY); export const { areFiltersApplied, getActiveFilters, getFiltersCurrentTab } = createFilterUtils< ProductTypeListUrlQueryParams,