Add filters and search to gift cards list (#1466)
* Fix filters not handling autocomplete values properly * Add handling single selection to filter autocomplete field * Change giftCardsListUrl function name to GiftCardListUrl for consistency * Update schema * Add gift card currencies query and update types * Add validating function for filter number fields * Add util function for mapping person node to select choice, fix types * Add gift card list filters and search * Add handling of gift card list search and filters dialogs in dialogs provider * Add gift card search bar in gift card list * Update gift card list queries and types, add filters to gift card list provider * Fix types * Fix types * Fix currency filters in gift card list * Update messages * Remove unnecessary usages of maybe * Change gift card balance filters not to be send to api when currency filter not present * Update messages
This commit is contained in:
parent
22db86ed65
commit
185a48b421
25 changed files with 877 additions and 38 deletions
|
@ -3717,6 +3717,62 @@
|
|||
"context": "GiftCardUpdateDetailsCard title",
|
||||
"string": "Details"
|
||||
},
|
||||
"src_dot_giftCards_dot_GiftCardsList_dot_GiftCardListSearchAndFilters_dot_balanceAmount": {
|
||||
"context": "Filter balance amount error",
|
||||
"string": "Balance amount is missing"
|
||||
},
|
||||
"src_dot_giftCards_dot_GiftCardsList_dot_GiftCardListSearchAndFilters_dot_balanceAmountLabel": {
|
||||
"context": "amount filter label",
|
||||
"string": "Amount"
|
||||
},
|
||||
"src_dot_giftCards_dot_GiftCardsList_dot_GiftCardListSearchAndFilters_dot_balanceCurrency": {
|
||||
"context": "Filter balance currency error",
|
||||
"string": "Balance currency is missing"
|
||||
},
|
||||
"src_dot_giftCards_dot_GiftCardsList_dot_GiftCardListSearchAndFilters_dot_currencyLabel": {
|
||||
"context": "currency filter label",
|
||||
"string": "Currency"
|
||||
},
|
||||
"src_dot_giftCards_dot_GiftCardsList_dot_GiftCardListSearchAndFilters_dot_currentBalanceLabel": {
|
||||
"context": "current balance filter label",
|
||||
"string": "Current balance"
|
||||
},
|
||||
"src_dot_giftCards_dot_GiftCardsList_dot_GiftCardListSearchAndFilters_dot_defaultTabLabel": {
|
||||
"context": "gift card default tab label",
|
||||
"string": "All Gift Cards"
|
||||
},
|
||||
"src_dot_giftCards_dot_GiftCardsList_dot_GiftCardListSearchAndFilters_dot_disabledOptionLabel": {
|
||||
"context": "disabled status option label",
|
||||
"string": "Disabled"
|
||||
},
|
||||
"src_dot_giftCards_dot_GiftCardsList_dot_GiftCardListSearchAndFilters_dot_enabledOptionLabel": {
|
||||
"context": "enabled status option label",
|
||||
"string": "Enabled"
|
||||
},
|
||||
"src_dot_giftCards_dot_GiftCardsList_dot_GiftCardListSearchAndFilters_dot_initialBalanceLabel": {
|
||||
"context": "initial balance filter label",
|
||||
"string": "Initial balance"
|
||||
},
|
||||
"src_dot_giftCards_dot_GiftCardsList_dot_GiftCardListSearchAndFilters_dot_productLabel": {
|
||||
"context": "product filter label",
|
||||
"string": "Product"
|
||||
},
|
||||
"src_dot_giftCards_dot_GiftCardsList_dot_GiftCardListSearchAndFilters_dot_searchPlaceholder": {
|
||||
"context": "gift card search placeholder",
|
||||
"string": "Search Gift Cards, e.g {exampleGiftCardCode}"
|
||||
},
|
||||
"src_dot_giftCards_dot_GiftCardsList_dot_GiftCardListSearchAndFilters_dot_statusLabel": {
|
||||
"context": "status filter label",
|
||||
"string": "Status"
|
||||
},
|
||||
"src_dot_giftCards_dot_GiftCardsList_dot_GiftCardListSearchAndFilters_dot_tagLabel": {
|
||||
"context": "tag filter label",
|
||||
"string": "Tags"
|
||||
},
|
||||
"src_dot_giftCards_dot_GiftCardsList_dot_GiftCardListSearchAndFilters_dot_usedByLabel": {
|
||||
"context": "used by filter label",
|
||||
"string": "Used by"
|
||||
},
|
||||
"src_dot_giftCards_dot_GiftCardsList_dot_GiftCardsListTable_dot_GiftCardsListTableHeader_dot_disableLabel": {
|
||||
"context": "GiftCardEnableDisableSection enable label",
|
||||
"string": "Deactivate"
|
||||
|
|
|
@ -2428,6 +2428,7 @@ input GiftCardFilterInput {
|
|||
currency: String
|
||||
currentBalance: PriceRangeInput
|
||||
initialBalance: PriceRangeInput
|
||||
code: String
|
||||
}
|
||||
|
||||
type GiftCardResend {
|
||||
|
@ -5863,6 +5864,7 @@ type Query {
|
|||
menuItems(channel: String, sortBy: MenuItemSortingInput, filter: MenuItemFilterInput, before: String, after: String, first: Int, last: Int): MenuItemCountableConnection
|
||||
giftCard(id: ID!): GiftCard
|
||||
giftCards(sortBy: GiftCardSortingInput, filter: GiftCardFilterInput, before: String, after: String, first: Int, last: Int): GiftCardCountableConnection
|
||||
giftCardCurrencies: [String!]!
|
||||
plugin(id: ID!): Plugin
|
||||
plugins(filter: PluginFilterInput, sortBy: PluginSortingInput, before: String, after: String, first: Int, last: Int): PluginCountableConnection
|
||||
sale(id: ID!, channel: String): Sale
|
||||
|
|
|
@ -9,7 +9,7 @@ import translationIcon from "@assets/images/menu-translation-icon.svg";
|
|||
import { configurationMenuUrl } from "@saleor/configuration";
|
||||
import { getConfigMenuItemsPermissions } from "@saleor/configuration/utils";
|
||||
import { User } from "@saleor/fragments/types/User";
|
||||
import { giftCardsListUrl } from "@saleor/giftCards/urls";
|
||||
import { giftCardListUrl } from "@saleor/giftCards/urls";
|
||||
import { commonMessages, sectionNames } from "@saleor/intl";
|
||||
import { SidebarMenuItem } from "@saleor/macaw-ui";
|
||||
import { IntlShape } from "react-intl";
|
||||
|
@ -66,7 +66,7 @@ function createMenuStructure(intl: IntlShape, user: User): SidebarMenuItem[] {
|
|||
ariaLabel: "giftCards",
|
||||
label: intl.formatMessage(sectionNames.giftCards),
|
||||
id: "giftCards",
|
||||
url: giftCardsListUrl(),
|
||||
url: giftCardListUrl(),
|
||||
permissions: [PermissionEnum.MANAGE_GIFT_CARD]
|
||||
}
|
||||
],
|
||||
|
|
|
@ -69,26 +69,36 @@ const FilterAutocompleteField: React.FC<FilterAutocompleteFieldProps> = ({
|
|||
const displayNoResults =
|
||||
availableOptions.length === 0 && fieldDisplayValues.length === 0;
|
||||
|
||||
const getUpdatedFilterValue = (option: MultiAutocompleteChoiceType) => {
|
||||
if (filterField.multiple) {
|
||||
return toggle(option.value, filterField.value, (a, b) => a === b);
|
||||
}
|
||||
|
||||
return [option.value];
|
||||
};
|
||||
|
||||
const handleChange = (option: MultiAutocompleteChoiceType) => {
|
||||
onFilterPropertyChange({
|
||||
payload: {
|
||||
name: filterField.name,
|
||||
update: {
|
||||
active: true,
|
||||
value: toggle(option.value, filterField.value, (a, b) => a === b)
|
||||
value: getUpdatedFilterValue(option)
|
||||
}
|
||||
},
|
||||
type: "set-property"
|
||||
});
|
||||
|
||||
setDisplayValues({
|
||||
...displayValues,
|
||||
[filterField.name]: toggle(
|
||||
option,
|
||||
fieldDisplayValues,
|
||||
(a, b) => a.value === b.value
|
||||
)
|
||||
});
|
||||
if (filterField.multiple) {
|
||||
setDisplayValues({
|
||||
...displayValues,
|
||||
[filterField.name]: toggle(
|
||||
option,
|
||||
fieldDisplayValues,
|
||||
(a, b) => a.value === b.value
|
||||
)
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const isValueChecked = (displayValue: MultiAutocompleteChoiceType) =>
|
||||
|
@ -106,18 +116,20 @@ const FilterAutocompleteField: React.FC<FilterAutocompleteFieldProps> = ({
|
|||
|
||||
return (
|
||||
<div {...rest}>
|
||||
<TextField
|
||||
data-test="filterFieldAutocompleteInput"
|
||||
className={classes.inputContainer}
|
||||
fullWidth
|
||||
name={filterField.name + "_autocomplete"}
|
||||
InputProps={{
|
||||
classes: {
|
||||
input: classes.input
|
||||
}
|
||||
}}
|
||||
onChange={event => filterField.onSearchChange(event.target.value)}
|
||||
/>
|
||||
{filterField?.onSearchChange && (
|
||||
<TextField
|
||||
data-test="filterFieldAutocompleteInput"
|
||||
className={classes.inputContainer}
|
||||
fullWidth
|
||||
name={filterField.name + "_autocomplete"}
|
||||
InputProps={{
|
||||
classes: {
|
||||
input: classes.input
|
||||
}
|
||||
}}
|
||||
onChange={event => filterField.onSearchChange(event.target.value)}
|
||||
/>
|
||||
)}
|
||||
{filteredValuesChecked.map(displayValue => (
|
||||
<div className={classes.option} key={displayValue.value}>
|
||||
<FormControlLabel
|
||||
|
|
|
@ -119,7 +119,7 @@ const FilterContent: React.FC<FilterContentProps> = ({
|
|||
if (filterField.multipleFields) {
|
||||
return filterField.multipleFields.reduce(
|
||||
getAutocompleteValuesWithNewValues,
|
||||
{}
|
||||
acc
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -227,7 +227,7 @@ const FilterContent: React.FC<FilterContentProps> = ({
|
|||
}
|
||||
/>
|
||||
</ExpansionPanelSummary>
|
||||
{currentFilter.active && (
|
||||
{currentFilter?.active && (
|
||||
<FilterErrorsList
|
||||
errors={errors?.[filter.name]}
|
||||
errorMessages={errorMessages}
|
||||
|
|
|
@ -156,7 +156,7 @@ const FilterContentBody: React.FC<FilterContentBodyProps> = ({
|
|||
/>
|
||||
</div>
|
||||
))}
|
||||
{filter.type === FieldType.autocomplete && filter.multiple && (
|
||||
{filter.type === FieldType.autocomplete && (
|
||||
<FilterAutocompleteField
|
||||
data-test={filterTestingContext}
|
||||
data-test-id={filter.name}
|
||||
|
|
|
@ -16,12 +16,26 @@ export const isAutocompleteFilterFieldValid = function<T extends string>({
|
|||
return !!compact(value).length;
|
||||
};
|
||||
|
||||
export const isNumberFilterFieldValid = function<T extends string>({
|
||||
value
|
||||
}: IFilterElement<T>) {
|
||||
const [min, max] = value;
|
||||
|
||||
if (!min && !max) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
export const isFilterFieldValid = function<T extends string>(
|
||||
filter: IFilterElement<T>
|
||||
) {
|
||||
const { type } = filter;
|
||||
|
||||
switch (type) {
|
||||
case FieldType.number:
|
||||
return isNumberFilterFieldValid(filter);
|
||||
case FieldType.boolean:
|
||||
case FieldType.autocomplete:
|
||||
return isAutocompleteFilterFieldValid(filter);
|
||||
|
|
|
@ -0,0 +1,185 @@
|
|||
import DeleteFilterTabDialog from "@saleor/components/DeleteFilterTabDialog";
|
||||
import FilterBar from "@saleor/components/FilterBar";
|
||||
import SaveFilterTabDialog, {
|
||||
SaveFilterTabDialogFormData
|
||||
} from "@saleor/components/SaveFilterTabDialog";
|
||||
import { DEFAULT_INITIAL_SEARCH_DATA } from "@saleor/config";
|
||||
import useGiftCardTagsSearch from "@saleor/giftCards/components/GiftCardTagInput/useGiftCardTagsSearch";
|
||||
import { giftCardListUrl } from "@saleor/giftCards/urls";
|
||||
import { getSearchFetchMoreProps } from "@saleor/hooks/makeTopLevelSearch/utils";
|
||||
import useNavigator from "@saleor/hooks/useNavigator";
|
||||
import { maybe } from "@saleor/misc";
|
||||
import useCustomerSearch from "@saleor/searches/useCustomerSearch";
|
||||
import useProductSearch from "@saleor/searches/useProductSearch";
|
||||
import createFilterHandlers from "@saleor/utils/handlers/filterHandlers";
|
||||
import { mapEdgesToItems } from "@saleor/utils/maps";
|
||||
import compact from "lodash/compact";
|
||||
import React from "react";
|
||||
import { useIntl } from "react-intl";
|
||||
|
||||
import useGiftCardListDialogs from "../providers/GiftCardListDialogsProvider/hooks/useGiftCardListDialogs";
|
||||
import useGiftCardList from "../providers/GiftCardListProvider/hooks/useGiftCardList";
|
||||
import useGiftCardListBulkActions from "../providers/GiftCardListProvider/hooks/useGiftCardListBulkActions";
|
||||
import { GiftCardListActionParamsEnum } from "../types";
|
||||
import {
|
||||
createFilterStructure,
|
||||
deleteFilterTab,
|
||||
getActiveFilters,
|
||||
getFilterOpts,
|
||||
getFilterQueryParam,
|
||||
getFiltersCurrentTab,
|
||||
getFilterTabs,
|
||||
saveFilterTab
|
||||
} from "./filters";
|
||||
import { giftCardListFilterErrorMessages as errorMessages } from "./messages";
|
||||
import { giftCardListSearchAndFiltersMessages as messages } from "./messages";
|
||||
import { useGiftCardCurrenciesQuery } from "./queries";
|
||||
|
||||
const GiftCardListSearchAndFilters: React.FC = () => {
|
||||
const navigate = useNavigator();
|
||||
const intl = useIntl();
|
||||
|
||||
const { params } = useGiftCardList();
|
||||
const { reset } = useGiftCardListBulkActions();
|
||||
|
||||
const {
|
||||
closeDialog,
|
||||
openSearchDeleteDialog,
|
||||
openSearchSaveDialog
|
||||
} = useGiftCardListDialogs();
|
||||
|
||||
const defaultSearchVariables = {
|
||||
variables: { ...DEFAULT_INITIAL_SEARCH_DATA, first: 5 }
|
||||
};
|
||||
|
||||
const {
|
||||
loadMore: fetchMoreCustomers,
|
||||
search: searchCustomers,
|
||||
result: searchCustomersResult
|
||||
} = useCustomerSearch(defaultSearchVariables);
|
||||
|
||||
const {
|
||||
loadMore: fetchMoreProducts,
|
||||
search: searchProducts,
|
||||
result: searchProductsResult
|
||||
} = useProductSearch(defaultSearchVariables);
|
||||
|
||||
const {
|
||||
loadMore: fetchMoreGiftCardTags,
|
||||
search: searchGiftCardTags,
|
||||
result: searchGiftCardTagsResult
|
||||
} = useGiftCardTagsSearch(defaultSearchVariables);
|
||||
|
||||
const {
|
||||
data: giftCardCurrenciesData,
|
||||
loading: loadingGiftCardCurrencies
|
||||
} = useGiftCardCurrenciesQuery();
|
||||
|
||||
const filterOpts = getFilterOpts({
|
||||
params,
|
||||
productSearchProps: {
|
||||
...getSearchFetchMoreProps(searchProductsResult, fetchMoreProducts),
|
||||
onSearchChange: searchProducts
|
||||
},
|
||||
products: mapEdgesToItems(searchProductsResult?.data?.search),
|
||||
currencies: giftCardCurrenciesData?.giftCardCurrencies,
|
||||
loadingCurrencies: loadingGiftCardCurrencies,
|
||||
customerSearchProps: {
|
||||
...getSearchFetchMoreProps(searchCustomersResult, fetchMoreCustomers),
|
||||
onSearchChange: searchCustomers
|
||||
},
|
||||
customers: mapEdgesToItems(searchCustomersResult?.data?.search),
|
||||
tagSearchProps: {
|
||||
...getSearchFetchMoreProps(
|
||||
searchGiftCardTagsResult,
|
||||
fetchMoreGiftCardTags
|
||||
),
|
||||
onSearchChange: searchGiftCardTags
|
||||
},
|
||||
tags: compact(
|
||||
mapEdgesToItems(searchGiftCardTagsResult?.data?.search)?.map(
|
||||
({ tag }) => tag
|
||||
)
|
||||
)
|
||||
});
|
||||
|
||||
const filterStructure = createFilterStructure(intl, filterOpts);
|
||||
|
||||
const tabs = getFilterTabs();
|
||||
const currentTab = getFiltersCurrentTab(params, tabs);
|
||||
|
||||
const [
|
||||
changeFilters,
|
||||
resetFilters,
|
||||
handleSearchChange
|
||||
] = createFilterHandlers({
|
||||
createUrl: giftCardListUrl,
|
||||
getFilterQueryParam,
|
||||
navigate,
|
||||
params,
|
||||
cleanupFn: reset
|
||||
});
|
||||
|
||||
const handleTabChange = (tab: number) => {
|
||||
reset();
|
||||
navigate(
|
||||
giftCardListUrl({
|
||||
activeTab: tab.toString(),
|
||||
...getFilterTabs()[tab - 1].data
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
const handleTabDelete = () => {
|
||||
deleteFilterTab(currentTab);
|
||||
reset();
|
||||
navigate(giftCardListUrl());
|
||||
};
|
||||
|
||||
const handleTabSave = (data: SaveFilterTabDialogFormData) => {
|
||||
saveFilterTab(data.name, getActiveFilters(params));
|
||||
handleTabChange(tabs.length + 1);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<FilterBar
|
||||
errorMessages={{
|
||||
initialBalanceAmount: errorMessages.balanceAmount,
|
||||
initialBalanceCurrency: errorMessages.balanceCurrency,
|
||||
currentBalanceAmount: errorMessages.balanceAmount,
|
||||
currentBalanceCurrency: errorMessages.balanceCurrency
|
||||
}}
|
||||
tabs={tabs.map(tab => tab.name)}
|
||||
currentTab={currentTab}
|
||||
filterStructure={filterStructure}
|
||||
initialSearch={params?.query || ""}
|
||||
onAll={resetFilters}
|
||||
onFilterChange={changeFilters}
|
||||
onSearchChange={handleSearchChange}
|
||||
onTabChange={handleTabChange}
|
||||
onTabDelete={openSearchDeleteDialog}
|
||||
onTabSave={openSearchSaveDialog}
|
||||
searchPlaceholder={intl.formatMessage(messages.searchPlaceholder, {
|
||||
exampleGiftCardCode: "21F1-39DY-V4U2"
|
||||
})}
|
||||
allTabLabel={intl.formatMessage(messages.defaultTabLabel)}
|
||||
/>
|
||||
<SaveFilterTabDialog
|
||||
open={params.action === GiftCardListActionParamsEnum.SAVE_SEARCH}
|
||||
confirmButtonState="default"
|
||||
onClose={closeDialog}
|
||||
onSubmit={handleTabSave}
|
||||
/>
|
||||
<DeleteFilterTabDialog
|
||||
open={params.action === GiftCardListActionParamsEnum.DELETE_SEARCH}
|
||||
confirmButtonState="default"
|
||||
onClose={closeDialog}
|
||||
onSubmit={handleTabDelete}
|
||||
tabName={maybe(() => tabs[currentTab - 1].name, "...")}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default GiftCardListSearchAndFilters;
|
|
@ -0,0 +1,387 @@
|
|||
import { IFilter, IFilterElement } from "@saleor/components/Filter";
|
||||
import { SearchCustomers_search_edges_node } from "@saleor/searches/types/SearchCustomers";
|
||||
import { SearchProducts_search_edges_node } from "@saleor/searches/types/SearchProducts";
|
||||
import { GiftCardFilterInput } from "@saleor/types/globalTypes";
|
||||
import {
|
||||
createFilterTabUtils,
|
||||
createFilterUtils,
|
||||
dedupeFilter,
|
||||
getMinMaxQueryParam,
|
||||
getMultipleValueQueryParam,
|
||||
getSingleValueQueryParam
|
||||
} from "@saleor/utils/filters";
|
||||
import {
|
||||
createAutocompleteField,
|
||||
createNumberField,
|
||||
createOptionsField
|
||||
} from "@saleor/utils/filters/fields";
|
||||
import {
|
||||
mapNodeToChoice,
|
||||
mapPersonNodeToChoice,
|
||||
mapSingleValueNodeToChoice
|
||||
} from "@saleor/utils/maps";
|
||||
import { defineMessages, IntlShape } from "react-intl";
|
||||
|
||||
import { GiftCardListUrlQueryParams } from "../types";
|
||||
import {
|
||||
GiftCardListFilterKeys,
|
||||
GiftCardListFilterOpts,
|
||||
GiftCardListUrlFilters,
|
||||
GiftCardListUrlFiltersEnum,
|
||||
GiftCardStatusFilterEnum,
|
||||
SearchWithFetchMoreProps
|
||||
} from "./types";
|
||||
|
||||
export const GIFT_CARD_FILTERS_KEY = "giftCardFilters";
|
||||
|
||||
interface GiftCardFilterOptsProps {
|
||||
params: GiftCardListUrlFilters;
|
||||
currencies: string[];
|
||||
loadingCurrencies: boolean;
|
||||
products: SearchProducts_search_edges_node[];
|
||||
productSearchProps: SearchWithFetchMoreProps;
|
||||
customers: SearchCustomers_search_edges_node[];
|
||||
customerSearchProps: SearchWithFetchMoreProps;
|
||||
tags: string[];
|
||||
tagSearchProps: SearchWithFetchMoreProps;
|
||||
}
|
||||
|
||||
export const getFilterOpts = ({
|
||||
params,
|
||||
currencies,
|
||||
loadingCurrencies,
|
||||
products,
|
||||
productSearchProps,
|
||||
customers,
|
||||
customerSearchProps,
|
||||
tags,
|
||||
tagSearchProps
|
||||
}: GiftCardFilterOptsProps): GiftCardListFilterOpts => ({
|
||||
currency: {
|
||||
active: !!params?.currency,
|
||||
value: params?.currency,
|
||||
choices: mapSingleValueNodeToChoice(currencies),
|
||||
displayValues: mapSingleValueNodeToChoice(currencies),
|
||||
initialSearch: "",
|
||||
loading: loadingCurrencies
|
||||
},
|
||||
product: {
|
||||
active: !!params?.product,
|
||||
value: params?.product,
|
||||
choices: mapNodeToChoice(products),
|
||||
displayValues: mapSingleValueNodeToChoice(products),
|
||||
initialSearch: "",
|
||||
hasMore: productSearchProps.hasMore,
|
||||
loading: productSearchProps.loading,
|
||||
onFetchMore: productSearchProps.onFetchMore,
|
||||
onSearchChange: productSearchProps.onSearchChange
|
||||
},
|
||||
usedBy: {
|
||||
active: !!params?.usedBy,
|
||||
value: params?.usedBy,
|
||||
choices: mapPersonNodeToChoice(customers),
|
||||
displayValues: mapPersonNodeToChoice(customers),
|
||||
initialSearch: "",
|
||||
hasMore: customerSearchProps.hasMore,
|
||||
loading: customerSearchProps.loading,
|
||||
onFetchMore: customerSearchProps.onFetchMore,
|
||||
onSearchChange: customerSearchProps.onSearchChange
|
||||
},
|
||||
tag: {
|
||||
active: !!params?.tag,
|
||||
value: dedupeFilter(params?.tag || []),
|
||||
choices: mapSingleValueNodeToChoice(tags),
|
||||
displayValues: mapSingleValueNodeToChoice(tags),
|
||||
initialSearch: "",
|
||||
hasMore: tagSearchProps.hasMore,
|
||||
loading: tagSearchProps.loading,
|
||||
onFetchMore: tagSearchProps.onFetchMore,
|
||||
onSearchChange: tagSearchProps.onSearchChange
|
||||
},
|
||||
initialBalanceAmount: {
|
||||
active:
|
||||
[params.initialBalanceAmountFrom, params.initialBalanceAmountTo].some(
|
||||
field => field !== undefined
|
||||
) || false,
|
||||
value: {
|
||||
max: params.initialBalanceAmountTo || "",
|
||||
min: params.initialBalanceAmountFrom || ""
|
||||
}
|
||||
},
|
||||
currentBalanceAmount: {
|
||||
active:
|
||||
[params.currentBalanceAmountFrom, params.currentBalanceAmountTo].some(
|
||||
field => field !== undefined
|
||||
) || false,
|
||||
value: {
|
||||
max: params.currentBalanceAmountTo || "",
|
||||
min: params.currentBalanceAmountFrom || ""
|
||||
}
|
||||
},
|
||||
status: {
|
||||
active: !!params?.status,
|
||||
value: params?.status
|
||||
}
|
||||
});
|
||||
|
||||
export function getFilterQueryParam(
|
||||
filter: IFilterElement<GiftCardListFilterKeys>
|
||||
): GiftCardListUrlFilters {
|
||||
const { name } = filter;
|
||||
|
||||
const {
|
||||
initialBalanceAmount,
|
||||
currentBalanceAmount,
|
||||
tag,
|
||||
currency,
|
||||
usedBy,
|
||||
product,
|
||||
status
|
||||
} = GiftCardListFilterKeys;
|
||||
|
||||
switch (name) {
|
||||
case currency:
|
||||
case status:
|
||||
return getSingleValueQueryParam(filter, name);
|
||||
|
||||
case tag:
|
||||
case product:
|
||||
case usedBy:
|
||||
return getMultipleValueQueryParam(filter, name);
|
||||
|
||||
case initialBalanceAmount:
|
||||
return getMinMaxQueryParam(
|
||||
filter,
|
||||
GiftCardListUrlFiltersEnum.initialBalanceAmountFrom,
|
||||
GiftCardListUrlFiltersEnum.initialBalanceAmountTo
|
||||
);
|
||||
|
||||
case currentBalanceAmount:
|
||||
return getMinMaxQueryParam(
|
||||
filter,
|
||||
GiftCardListUrlFiltersEnum.currentBalanceAmountFrom,
|
||||
GiftCardListUrlFiltersEnum.currentBalanceAmountTo
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const messages = defineMessages({
|
||||
balanceAmountLabel: {
|
||||
defaultMessage: "Amount",
|
||||
description: "amount filter label"
|
||||
},
|
||||
tagLabel: {
|
||||
defaultMessage: "Tags",
|
||||
description: "tag filter label"
|
||||
},
|
||||
currencyLabel: {
|
||||
defaultMessage: "Currency",
|
||||
description: "currency filter label"
|
||||
},
|
||||
productLabel: {
|
||||
defaultMessage: "Product",
|
||||
description: "product filter label"
|
||||
},
|
||||
usedByLabel: {
|
||||
defaultMessage: "Used by",
|
||||
description: "used by filter label"
|
||||
},
|
||||
statusLabel: {
|
||||
defaultMessage: "Status",
|
||||
description: "status filter label"
|
||||
},
|
||||
enabledOptionLabel: {
|
||||
defaultMessage: "Enabled",
|
||||
description: "enabled status option label"
|
||||
},
|
||||
disabledOptionLabel: {
|
||||
defaultMessage: "Disabled",
|
||||
description: "disabled status option label"
|
||||
},
|
||||
initialBalanceLabel: {
|
||||
defaultMessage: "Initial balance",
|
||||
description: "initial balance filter label"
|
||||
},
|
||||
currentBalanceLabel: {
|
||||
defaultMessage: "Current balance",
|
||||
description: "current balance filter label"
|
||||
}
|
||||
});
|
||||
|
||||
export function createFilterStructure(
|
||||
intl: IntlShape,
|
||||
opts: GiftCardListFilterOpts
|
||||
): IFilter<GiftCardListFilterKeys> {
|
||||
return [
|
||||
{
|
||||
...createNumberField(
|
||||
GiftCardListFilterKeys.initialBalanceAmount,
|
||||
intl.formatMessage(messages.initialBalanceLabel),
|
||||
opts.initialBalanceAmount.value
|
||||
),
|
||||
multiple:
|
||||
opts?.initialBalanceAmount?.value?.min !==
|
||||
opts?.initialBalanceAmount?.value?.max,
|
||||
active: opts.initialBalanceAmount.active
|
||||
},
|
||||
|
||||
{
|
||||
...createNumberField(
|
||||
GiftCardListFilterKeys.currentBalanceAmount,
|
||||
intl.formatMessage(messages.currentBalanceLabel),
|
||||
opts.currentBalanceAmount.value
|
||||
),
|
||||
multiple:
|
||||
opts?.currentBalanceAmount?.value?.min !==
|
||||
opts?.currentBalanceAmount?.value?.max,
|
||||
active: opts.currentBalanceAmount.active
|
||||
},
|
||||
{
|
||||
...createAutocompleteField(
|
||||
GiftCardListFilterKeys.currency,
|
||||
intl.formatMessage(messages.currencyLabel),
|
||||
[opts.currency.value],
|
||||
opts.currency.displayValues,
|
||||
false,
|
||||
opts.currency.choices,
|
||||
{
|
||||
hasMore: opts.currency.hasMore,
|
||||
initialSearch: "",
|
||||
loading: opts.currency.loading,
|
||||
onFetchMore: opts.currency.onFetchMore,
|
||||
onSearchChange: opts.currency.onSearchChange
|
||||
}
|
||||
),
|
||||
active: opts.currency.active
|
||||
},
|
||||
{
|
||||
...createAutocompleteField(
|
||||
GiftCardListFilterKeys.tag,
|
||||
intl.formatMessage(messages.tagLabel),
|
||||
opts.tag.value,
|
||||
opts.tag.displayValues,
|
||||
true,
|
||||
opts.tag.choices,
|
||||
{
|
||||
hasMore: opts.tag.hasMore,
|
||||
initialSearch: "",
|
||||
loading: opts.tag.loading,
|
||||
onFetchMore: opts.tag.onFetchMore,
|
||||
onSearchChange: opts.tag.onSearchChange
|
||||
}
|
||||
),
|
||||
active: opts.tag.active
|
||||
},
|
||||
{
|
||||
...createAutocompleteField(
|
||||
GiftCardListFilterKeys.product,
|
||||
intl.formatMessage(messages.productLabel),
|
||||
opts.product.value,
|
||||
opts.product.displayValues,
|
||||
true,
|
||||
opts.product.choices,
|
||||
{
|
||||
hasMore: opts.product.hasMore,
|
||||
initialSearch: "",
|
||||
loading: opts.product.loading,
|
||||
onFetchMore: opts.product.onFetchMore,
|
||||
onSearchChange: opts.product.onSearchChange
|
||||
}
|
||||
),
|
||||
active: opts.product.active
|
||||
},
|
||||
{
|
||||
...createAutocompleteField(
|
||||
GiftCardListFilterKeys.usedBy,
|
||||
intl.formatMessage(messages.usedByLabel),
|
||||
opts.usedBy.value,
|
||||
opts.usedBy.displayValues,
|
||||
true,
|
||||
opts.usedBy.choices,
|
||||
{
|
||||
hasMore: opts.usedBy.hasMore,
|
||||
initialSearch: "",
|
||||
loading: opts.usedBy.loading,
|
||||
onFetchMore: opts.usedBy.onFetchMore,
|
||||
onSearchChange: opts.usedBy.onSearchChange
|
||||
}
|
||||
),
|
||||
active: opts.usedBy.active
|
||||
},
|
||||
{
|
||||
...createOptionsField(
|
||||
GiftCardListFilterKeys.status,
|
||||
intl.formatMessage(messages.statusLabel),
|
||||
[opts.status.value],
|
||||
false,
|
||||
[
|
||||
{
|
||||
label: intl.formatMessage(messages.enabledOptionLabel),
|
||||
value: GiftCardStatusFilterEnum.enabled
|
||||
},
|
||||
{
|
||||
label: intl.formatMessage(messages.disabledOptionLabel),
|
||||
value: GiftCardStatusFilterEnum.disabled
|
||||
}
|
||||
]
|
||||
),
|
||||
active: opts.status.active
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
export const {
|
||||
deleteFilterTab,
|
||||
getFilterTabs,
|
||||
saveFilterTab
|
||||
} = createFilterTabUtils<GiftCardListUrlFilters>(GIFT_CARD_FILTERS_KEY);
|
||||
|
||||
export const {
|
||||
areFiltersApplied,
|
||||
getActiveFilters,
|
||||
getFiltersCurrentTab
|
||||
} = createFilterUtils<GiftCardListUrlQueryParams, GiftCardListUrlFilters>(
|
||||
GiftCardListUrlFiltersEnum
|
||||
);
|
||||
|
||||
export function getFilterVariables({
|
||||
status,
|
||||
tag,
|
||||
usedBy,
|
||||
product,
|
||||
currency,
|
||||
currentBalanceAmountTo,
|
||||
currentBalanceAmountFrom,
|
||||
initialBalanceAmountTo,
|
||||
initialBalanceAmountFrom,
|
||||
query
|
||||
}: GiftCardListUrlQueryParams): GiftCardFilterInput {
|
||||
const balanceData = currency
|
||||
? {
|
||||
currentBalance:
|
||||
currentBalanceAmountFrom && currentBalanceAmountTo
|
||||
? {
|
||||
gte: parseFloat(currentBalanceAmountFrom),
|
||||
lte: parseFloat(currentBalanceAmountTo)
|
||||
}
|
||||
: undefined,
|
||||
initialBalance:
|
||||
initialBalanceAmountFrom && initialBalanceAmountTo
|
||||
? {
|
||||
gte: parseFloat(initialBalanceAmountFrom),
|
||||
lte: parseFloat(initialBalanceAmountTo)
|
||||
}
|
||||
: undefined
|
||||
}
|
||||
: {};
|
||||
|
||||
return {
|
||||
code: query,
|
||||
isActive: !!status ? status === "enabled" : undefined,
|
||||
tags: tag,
|
||||
usedBy,
|
||||
products: product,
|
||||
currency,
|
||||
...balanceData
|
||||
};
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
export * from "./GiftCardListSearchAndFilters";
|
||||
export { default } from "./GiftCardListSearchAndFilters";
|
|
@ -0,0 +1,23 @@
|
|||
import { defineMessages } from "react-intl";
|
||||
|
||||
export const giftCardListFilterErrorMessages = defineMessages({
|
||||
balanceAmount: {
|
||||
defaultMessage: "Balance amount is missing",
|
||||
description: "Filter balance amount error"
|
||||
},
|
||||
balanceCurrency: {
|
||||
defaultMessage: "Balance currency is missing",
|
||||
description: "Filter balance currency error"
|
||||
}
|
||||
});
|
||||
|
||||
export const giftCardListSearchAndFiltersMessages = defineMessages({
|
||||
searchPlaceholder: {
|
||||
defaultMessage: "Search Gift Cards, e.g {exampleGiftCardCode}",
|
||||
description: "gift card search placeholder"
|
||||
},
|
||||
defaultTabLabel: {
|
||||
defaultMessage: "All Gift Cards",
|
||||
description: "gift card default tab label"
|
||||
}
|
||||
});
|
|
@ -0,0 +1,14 @@
|
|||
import makeQuery from "@saleor/hooks/makeQuery";
|
||||
import gql from "graphql-tag";
|
||||
|
||||
import { GiftCardCurrencies } from "./types/GiftCardCurrencies";
|
||||
|
||||
const useGiftCardCurrencies = gql`
|
||||
query GiftCardCurrencies {
|
||||
giftCardCurrencies
|
||||
}
|
||||
`;
|
||||
|
||||
export const useGiftCardCurrenciesQuery = makeQuery<GiftCardCurrencies, {}>(
|
||||
useGiftCardCurrencies
|
||||
);
|
|
@ -0,0 +1,58 @@
|
|||
import {
|
||||
AutocompleteFilterOpts,
|
||||
FetchMoreProps,
|
||||
FilterOpts,
|
||||
Filters,
|
||||
FiltersWithMultipleValues,
|
||||
MinMax,
|
||||
Search,
|
||||
SearchProps
|
||||
} from "@saleor/types";
|
||||
|
||||
export enum GiftCardListUrlFiltersEnum {
|
||||
currency = "currency",
|
||||
initialBalanceAmountFrom = "initialBalanceAmountFrom",
|
||||
initialBalanceAmountTo = "initialBalanceAmountTo",
|
||||
currentBalanceAmountFrom = "currentBalanceAmountFrom",
|
||||
currentBalanceAmountTo = "currentBalanceAmountTo",
|
||||
status = "status"
|
||||
}
|
||||
|
||||
export enum GiftCardListUrlFiltersWithMultipleValuesEnum {
|
||||
tag = "tag",
|
||||
product = "product",
|
||||
usedBy = "usedBy"
|
||||
}
|
||||
|
||||
export enum GiftCardListFilterKeys {
|
||||
currency = "currency",
|
||||
balance = "balance",
|
||||
initialBalance = "initialBalance",
|
||||
currentBalance = "currentBalance",
|
||||
initialBalanceAmount = "initialBalanceAmount",
|
||||
currentBalanceAmount = "currentBalanceAmount",
|
||||
tag = "tag",
|
||||
product = "product",
|
||||
usedBy = "usedBy",
|
||||
status = "status"
|
||||
}
|
||||
|
||||
export type GiftCardListUrlFilters = Filters<GiftCardListUrlFiltersEnum> &
|
||||
FiltersWithMultipleValues<GiftCardListUrlFiltersWithMultipleValuesEnum>;
|
||||
|
||||
export interface GiftCardListFilterOpts {
|
||||
tag: FilterOpts<string[]> & AutocompleteFilterOpts;
|
||||
currency: FilterOpts<string> & AutocompleteFilterOpts;
|
||||
product: FilterOpts<string[]> & AutocompleteFilterOpts;
|
||||
usedBy: FilterOpts<string[]> & AutocompleteFilterOpts;
|
||||
initialBalanceAmount: FilterOpts<MinMax>;
|
||||
currentBalanceAmount: FilterOpts<MinMax>;
|
||||
status: FilterOpts<string>;
|
||||
}
|
||||
|
||||
export type SearchWithFetchMoreProps = FetchMoreProps & Search & SearchProps;
|
||||
|
||||
export enum GiftCardStatusFilterEnum {
|
||||
enabled = "enabled",
|
||||
disabled = "disabled"
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
// @generated
|
||||
// This file was automatically generated and should not be edited.
|
||||
|
||||
// ====================================================
|
||||
// GraphQL query operation: GiftCardCurrencies
|
||||
// ====================================================
|
||||
|
||||
export interface GiftCardCurrencies {
|
||||
giftCardCurrencies: string[];
|
||||
}
|
|
@ -23,6 +23,7 @@ import React from "react";
|
|||
import { FormattedMessage, useIntl } from "react-intl";
|
||||
|
||||
import { giftCardUpdatePageHeaderMessages as giftCardStatusChipMessages } from "../../GiftCardUpdate/GiftCardUpdatePageHeader/messages";
|
||||
import GiftCardListSearchAndFilters from "../GiftCardListSearchAndFilters";
|
||||
import { giftCardsListTableMessages as messages } from "../messages";
|
||||
import useGiftCardListDialogs from "../providers/GiftCardListDialogsProvider/hooks/useGiftCardListDialogs";
|
||||
import useGiftCardList from "../providers/GiftCardListProvider/hooks/useGiftCardList";
|
||||
|
@ -77,6 +78,7 @@ const GiftCardsListTable: React.FC = () => {
|
|||
|
||||
return (
|
||||
<Card>
|
||||
<GiftCardListSearchAndFilters />
|
||||
<ResponsiveTable>
|
||||
<GiftCardsListTableHeader />
|
||||
<GiftCardsListTableFooter />
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import GiftCardListPageDeleteDialog from "@saleor/giftCards/components/GiftCardDeleteDialog/GiftCardListPageDeleteDialog";
|
||||
import GiftCardCreateDialog from "@saleor/giftCards/GiftCardCreateDialog";
|
||||
import { giftCardsListUrl } from "@saleor/giftCards/urls";
|
||||
import { giftCardListUrl } from "@saleor/giftCards/urls";
|
||||
import useNavigator from "@saleor/hooks/useNavigator";
|
||||
import createDialogActionHandlers from "@saleor/utils/handlers/dialogActionHandlers";
|
||||
import React, { createContext } from "react";
|
||||
|
@ -18,6 +18,8 @@ interface GiftCardListDialogsProviderProps {
|
|||
export interface GiftCardListDialogsConsumerProps {
|
||||
openCreateDialog: () => void;
|
||||
openDeleteDialog: (id?: string | React.MouseEvent) => void;
|
||||
openSearchSaveDialog: () => void;
|
||||
openSearchDeleteDialog: () => void;
|
||||
closeDialog: () => void;
|
||||
id: string;
|
||||
}
|
||||
|
@ -37,7 +39,7 @@ const GiftCardListDialogsProvider: React.FC<GiftCardListDialogsProviderProps> =
|
|||
const [openDialog, closeDialog] = createDialogActionHandlers<
|
||||
GiftCardListActionParamsEnum,
|
||||
GiftCardListUrlQueryParams
|
||||
>(navigate, giftCardsListUrl, params);
|
||||
>(navigate, giftCardListUrl, params);
|
||||
|
||||
const openCreateDialog = () =>
|
||||
openDialog(GiftCardListActionParamsEnum.CREATE);
|
||||
|
@ -55,9 +57,17 @@ const GiftCardListDialogsProvider: React.FC<GiftCardListDialogsProviderProps> =
|
|||
);
|
||||
};
|
||||
|
||||
const openSearchDeleteDialog = () =>
|
||||
openDialog(GiftCardListActionParamsEnum.DELETE_SEARCH);
|
||||
|
||||
const openSearchSaveDialog = () =>
|
||||
openDialog(GiftCardListActionParamsEnum.SAVE_SEARCH);
|
||||
|
||||
const providerValues: GiftCardListDialogsConsumerProps = {
|
||||
openCreateDialog,
|
||||
openDeleteDialog: handleDeleteDialogOpen,
|
||||
openSearchSaveDialog,
|
||||
openSearchDeleteDialog,
|
||||
closeDialog,
|
||||
id
|
||||
};
|
||||
|
|
|
@ -15,6 +15,7 @@ import { ListViews } from "@saleor/types";
|
|||
import { mapEdgesToItems } from "@saleor/utils/maps";
|
||||
import React, { createContext } from "react";
|
||||
|
||||
import { getFilterVariables } from "../../GiftCardListSearchAndFilters/filters";
|
||||
import { useGiftCardListQuery } from "../../queries";
|
||||
import { GiftCardListColummns, GiftCardListUrlQueryParams } from "../../types";
|
||||
import {
|
||||
|
@ -65,7 +66,8 @@ export const GiftCardsListProvider: React.FC<GiftCardsListProviderProps> = ({
|
|||
|
||||
const queryVariables = React.useMemo<GiftCardListVariables>(
|
||||
() => ({
|
||||
...paginationState
|
||||
...paginationState,
|
||||
filter: getFilterVariables(params)
|
||||
}),
|
||||
[params]
|
||||
);
|
||||
|
|
|
@ -9,8 +9,20 @@ import { GiftCardProductsCount } from "./types/GiftCardProductsCount";
|
|||
export const giftCardList = gql`
|
||||
${fragmentUserBase}
|
||||
${fragmentMoney}
|
||||
query GiftCardList($first: Int, $after: String, $last: Int, $before: String) {
|
||||
giftCards(first: $first, after: $after, before: $before, last: $last) {
|
||||
query GiftCardList(
|
||||
$first: Int
|
||||
$after: String
|
||||
$last: Int
|
||||
$before: String
|
||||
$filter: GiftCardFilterInput
|
||||
) {
|
||||
giftCards(
|
||||
first: $first
|
||||
after: $after
|
||||
before: $before
|
||||
last: $last
|
||||
filter: $filter
|
||||
) {
|
||||
edges {
|
||||
node {
|
||||
id
|
||||
|
|
|
@ -1,4 +1,12 @@
|
|||
import { Dialog, Pagination, SingleAction } from "@saleor/types";
|
||||
import {
|
||||
ActiveTab,
|
||||
Dialog,
|
||||
Pagination,
|
||||
Search,
|
||||
SingleAction
|
||||
} from "@saleor/types";
|
||||
|
||||
import { GiftCardListUrlFilters } from "./GiftCardListSearchAndFilters/types";
|
||||
|
||||
export type GiftCardListColummns =
|
||||
| "giftCardCode"
|
||||
|
@ -9,11 +17,16 @@ export type GiftCardListColummns =
|
|||
|
||||
export enum GiftCardListActionParamsEnum {
|
||||
CREATE = "gift-card-create",
|
||||
DELETE = "gift-card-delete"
|
||||
DELETE = "gift-card-delete",
|
||||
SAVE_SEARCH = "save-search",
|
||||
DELETE_SEARCH = "delete-search"
|
||||
}
|
||||
|
||||
export type GiftCardListUrlQueryParams = Pagination &
|
||||
Dialog<GiftCardListActionParamsEnum> &
|
||||
SingleAction;
|
||||
SingleAction &
|
||||
GiftCardListUrlFilters &
|
||||
ActiveTab &
|
||||
Search;
|
||||
|
||||
export const GIFT_CARD_LIST_QUERY = "GiftCardList";
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
// @generated
|
||||
// This file was automatically generated and should not be edited.
|
||||
|
||||
import { GiftCardFilterInput } from "./../../../types/globalTypes";
|
||||
|
||||
// ====================================================
|
||||
// GraphQL query operation: GiftCardList
|
||||
// ====================================================
|
||||
|
@ -67,4 +69,5 @@ export interface GiftCardListVariables {
|
|||
after?: string | null;
|
||||
last?: number | null;
|
||||
before?: string | null;
|
||||
filter?: GiftCardFilterInput | null;
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ export const giftCardsSectionUrlName = "/gift-cards";
|
|||
|
||||
export const giftCardsListPath = `${giftCardsSectionUrlName}/`;
|
||||
|
||||
export const giftCardsListUrl = (params?: GiftCardListUrlQueryParams) =>
|
||||
export const giftCardListUrl = (params?: GiftCardListUrlQueryParams) =>
|
||||
giftCardsListPath + "?" + stringifyQs(params);
|
||||
|
||||
export const giftCardUrl = (
|
||||
|
|
|
@ -209,8 +209,8 @@ export interface FilterOpts<T> {
|
|||
}
|
||||
|
||||
export interface AutocompleteFilterOpts
|
||||
extends FetchMoreProps,
|
||||
SearchPageProps {
|
||||
extends Partial<FetchMoreProps>,
|
||||
Partial<SearchPageProps> {
|
||||
choices: MultiAutocompleteChoiceType[];
|
||||
displayValues: MultiAutocompleteChoiceType[];
|
||||
}
|
||||
|
|
|
@ -2209,6 +2209,18 @@ export interface GiftCardCreateInput {
|
|||
note?: string | null;
|
||||
}
|
||||
|
||||
export interface GiftCardFilterInput {
|
||||
isActive?: boolean | null;
|
||||
tag?: string | null;
|
||||
tags?: (string | null)[] | null;
|
||||
products?: (string | null)[] | null;
|
||||
usedBy?: (string | null)[] | null;
|
||||
currency?: string | null;
|
||||
currentBalance?: PriceRangeInput | null;
|
||||
initialBalance?: PriceRangeInput | null;
|
||||
code?: string | null;
|
||||
}
|
||||
|
||||
export interface GiftCardResendInput {
|
||||
id: string;
|
||||
email?: string | null;
|
||||
|
|
|
@ -83,7 +83,7 @@ export function createOptionsField<T extends string>(
|
|||
export function createAutocompleteField<T extends string>(
|
||||
name: T,
|
||||
label: string,
|
||||
defaultValue: string[],
|
||||
defaultValue: string[] = [],
|
||||
displayValues: MultiAutocompleteChoiceType[],
|
||||
multiple: boolean,
|
||||
options: MultiAutocompleteChoiceType[],
|
||||
|
|
|
@ -4,6 +4,7 @@ import {
|
|||
SingleAutocompleteChoiceType
|
||||
} from "@saleor/components/SingleAutocompleteSelectField";
|
||||
import { MetadataItem } from "@saleor/fragments/types/MetadataItem";
|
||||
import { getFullName } from "@saleor/misc";
|
||||
import { SearchPages_search_edges_node } from "@saleor/searches/types/SearchPages";
|
||||
import { Node, SlugNode, TagNode } from "@saleor/types";
|
||||
import { MetadataInput } from "@saleor/types/globalTypes";
|
||||
|
@ -92,3 +93,22 @@ export function mapSingleValueNodeToChoice<T extends Record<string, any>>(
|
|||
|
||||
return (nodes as T[]).map(node => ({ label: node[key], value: node[key] }));
|
||||
}
|
||||
|
||||
interface Person {
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
id: string;
|
||||
}
|
||||
|
||||
export function mapPersonNodeToChoice<T extends Person>(
|
||||
nodes: T[]
|
||||
): SingleAutocompleteChoiceType[] {
|
||||
if (!nodes) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return nodes.map(({ firstName, lastName, id }) => ({
|
||||
value: id,
|
||||
label: getFullName({ firstName, lastName })
|
||||
}));
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue