Add search to translations
This commit is contained in:
parent
3974b23b15
commit
f9285cec60
23 changed files with 333 additions and 171 deletions
98
src/components/Filter/FilterSearch.tsx
Normal file
98
src/components/Filter/FilterSearch.tsx
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
import { Theme } from "@material-ui/core/styles";
|
||||||
|
import { makeStyles } from "@material-ui/styles";
|
||||||
|
import React from "react";
|
||||||
|
import { FormattedMessage } from "react-intl";
|
||||||
|
|
||||||
|
import { SearchPageProps } from "../../types";
|
||||||
|
import Debounce from "../Debounce";
|
||||||
|
import { FilterActionsOnlySearch } from "../Filter/FilterActions";
|
||||||
|
import Hr from "../Hr";
|
||||||
|
import Link from "../Link";
|
||||||
|
|
||||||
|
export interface FilterSearchProps extends SearchPageProps {
|
||||||
|
displaySearchAction: "save" | "delete" | null;
|
||||||
|
searchPlaceholder: string;
|
||||||
|
onSearchDelete?: () => void;
|
||||||
|
onSearchSave?: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const useStyles = makeStyles(
|
||||||
|
(theme: Theme) => ({
|
||||||
|
tabAction: {
|
||||||
|
display: "inline-block"
|
||||||
|
},
|
||||||
|
tabActionContainer: {
|
||||||
|
borderBottom: "1px solid #e8e8e8",
|
||||||
|
display: "flex",
|
||||||
|
justifyContent: "flex-end",
|
||||||
|
marginTop: theme.spacing.unit,
|
||||||
|
padding: `0 ${theme.spacing.unit * 3}px ${theme.spacing.unit}px`
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
name: "FilterSearch"
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const FilterSearch: React.FC<FilterSearchProps> = props => {
|
||||||
|
const {
|
||||||
|
displaySearchAction,
|
||||||
|
initialSearch,
|
||||||
|
onSearchChange,
|
||||||
|
onSearchDelete,
|
||||||
|
onSearchSave,
|
||||||
|
searchPlaceholder
|
||||||
|
} = props;
|
||||||
|
const classes = useStyles(props);
|
||||||
|
const [search, setSearch] = React.useState(initialSearch);
|
||||||
|
React.useEffect(() => setSearch(initialSearch), [initialSearch]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Debounce debounceFn={onSearchChange}>
|
||||||
|
{debounceSearchChange => {
|
||||||
|
const handleSearchChange = (event: React.ChangeEvent<any>) => {
|
||||||
|
const value = event.target.value;
|
||||||
|
setSearch(value);
|
||||||
|
debounceSearchChange(value);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<FilterActionsOnlySearch
|
||||||
|
{...props}
|
||||||
|
placeholder={searchPlaceholder}
|
||||||
|
search={search}
|
||||||
|
onSearchChange={handleSearchChange}
|
||||||
|
/>
|
||||||
|
{!!displaySearchAction ? (
|
||||||
|
<div className={classes.tabActionContainer}>
|
||||||
|
<div className={classes.tabAction}>
|
||||||
|
{displaySearchAction === "save" ? (
|
||||||
|
<Link onClick={onSearchSave}>
|
||||||
|
<FormattedMessage
|
||||||
|
defaultMessage="Save Custom Search"
|
||||||
|
description="button"
|
||||||
|
/>
|
||||||
|
</Link>
|
||||||
|
) : (
|
||||||
|
<Link onClick={onSearchDelete}>
|
||||||
|
<FormattedMessage
|
||||||
|
defaultMessage="Delete Search"
|
||||||
|
description="button"
|
||||||
|
/>
|
||||||
|
</Link>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<Hr />
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
</Debounce>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
FilterSearch.displayName = "FilterSearch";
|
||||||
|
export default FilterSearch;
|
|
@ -1,13 +1,8 @@
|
||||||
import { Theme } from "@material-ui/core/styles";
|
|
||||||
import { makeStyles } from "@material-ui/styles";
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { FormattedMessage, useIntl } from "react-intl";
|
import { useIntl } from "react-intl";
|
||||||
|
|
||||||
import { SearchPageProps, TabPageProps } from "@saleor/types";
|
import { SearchPageProps, TabPageProps } from "@saleor/types";
|
||||||
import Debounce from "../Debounce";
|
import FilterSearch from "../Filter/FilterSearch";
|
||||||
import { FilterActionsOnlySearch } from "../Filter/FilterActions";
|
|
||||||
import Hr from "../Hr";
|
|
||||||
import Link from "../Link";
|
|
||||||
import FilterTabs, { FilterTab } from "../TableFilter";
|
import FilterTabs, { FilterTab } from "../TableFilter";
|
||||||
|
|
||||||
export interface SearchBarProps extends SearchPageProps, TabPageProps {
|
export interface SearchBarProps extends SearchPageProps, TabPageProps {
|
||||||
|
@ -15,24 +10,6 @@ export interface SearchBarProps extends SearchPageProps, TabPageProps {
|
||||||
searchPlaceholder: string;
|
searchPlaceholder: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const useStyles = makeStyles(
|
|
||||||
(theme: Theme) => ({
|
|
||||||
tabAction: {
|
|
||||||
display: "inline-block"
|
|
||||||
},
|
|
||||||
tabActionContainer: {
|
|
||||||
borderBottom: "1px solid #e8e8e8",
|
|
||||||
display: "flex",
|
|
||||||
justifyContent: "flex-end",
|
|
||||||
marginTop: theme.spacing.unit,
|
|
||||||
padding: `0 ${theme.spacing.unit * 3}px ${theme.spacing.unit}px`
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
{
|
|
||||||
name: "SearchBar"
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
const SearchBar: React.FC<SearchBarProps> = props => {
|
const SearchBar: React.FC<SearchBarProps> = props => {
|
||||||
const {
|
const {
|
||||||
allTabLabel,
|
allTabLabel,
|
||||||
|
@ -46,7 +23,6 @@ const SearchBar: React.FC<SearchBarProps> = props => {
|
||||||
onTabDelete,
|
onTabDelete,
|
||||||
onTabSave
|
onTabSave
|
||||||
} = props;
|
} = props;
|
||||||
const classes = useStyles(props);
|
|
||||||
const [search, setSearch] = React.useState(initialSearch);
|
const [search, setSearch] = React.useState(initialSearch);
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
React.useEffect(() => setSearch(initialSearch), [initialSearch]);
|
React.useEffect(() => setSearch(initialSearch), [initialSearch]);
|
||||||
|
@ -73,49 +49,14 @@ const SearchBar: React.FC<SearchBarProps> = props => {
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</FilterTabs>
|
</FilterTabs>
|
||||||
<Debounce debounceFn={onSearchChange}>
|
<FilterSearch
|
||||||
{debounceSearchChange => {
|
displaySearchAction={!!search ? (isCustom ? "save" : "delete") : null}
|
||||||
const handleSearchChange = (event: React.ChangeEvent<any>) => {
|
initialSearch={initialSearch}
|
||||||
const value = event.target.value;
|
searchPlaceholder={searchPlaceholder}
|
||||||
setSearch(value);
|
onSearchChange={onSearchChange}
|
||||||
debounceSearchChange(value);
|
onSearchDelete={onTabDelete}
|
||||||
};
|
onSearchSave={onTabSave}
|
||||||
|
/>
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<FilterActionsOnlySearch
|
|
||||||
{...props}
|
|
||||||
placeholder={searchPlaceholder}
|
|
||||||
search={search}
|
|
||||||
onSearchChange={handleSearchChange}
|
|
||||||
/>
|
|
||||||
{!!search || (tabs && tabs.length > 0 && currentTab !== 0) ? (
|
|
||||||
<div className={classes.tabActionContainer}>
|
|
||||||
<div className={classes.tabAction}>
|
|
||||||
{isCustom ? (
|
|
||||||
<Link onClick={onTabSave}>
|
|
||||||
<FormattedMessage
|
|
||||||
defaultMessage="Save Custom Search"
|
|
||||||
description="button"
|
|
||||||
/>
|
|
||||||
</Link>
|
|
||||||
) : (
|
|
||||||
<Link onClick={onTabDelete}>
|
|
||||||
<FormattedMessage
|
|
||||||
defaultMessage="Delete Search"
|
|
||||||
description="button"
|
|
||||||
/>
|
|
||||||
</Link>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<Hr />
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
</Debounce>
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,17 +1,19 @@
|
||||||
import Card from "@material-ui/core/Card";
|
import Card from "@material-ui/core/Card";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { useIntl } from "react-intl";
|
import { IntlShape, useIntl } from "react-intl";
|
||||||
|
|
||||||
import AppHeader from "@saleor/components/AppHeader";
|
import AppHeader from "@saleor/components/AppHeader";
|
||||||
import Container from "@saleor/components/Container";
|
import Container from "@saleor/components/Container";
|
||||||
|
import FilterSearch from "@saleor/components/Filter/FilterSearch";
|
||||||
import PageHeader from "@saleor/components/PageHeader";
|
import PageHeader from "@saleor/components/PageHeader";
|
||||||
// tslint:disable no-submodule-imports
|
// tslint:disable no-submodule-imports
|
||||||
import { ShopInfo_shop_languages } from "@saleor/components/Shop/types/ShopInfo";
|
import { ShopInfo_shop_languages } from "@saleor/components/Shop/types/ShopInfo";
|
||||||
import FilterTabs, { FilterTab } from "@saleor/components/TableFilter";
|
import FilterTabs, { FilterTab } from "@saleor/components/TableFilter";
|
||||||
import { maybe } from "@saleor/misc";
|
import { maybe } from "@saleor/misc";
|
||||||
|
import { SearchPageProps } from "@saleor/types";
|
||||||
import { TranslatableEntities } from "../../urls";
|
import { TranslatableEntities } from "../../urls";
|
||||||
|
|
||||||
export interface TranslationsEntitiesListPageProps {
|
export interface TranslationsEntitiesListPageProps extends SearchPageProps {
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
filters: TranslationsEntitiesFilters;
|
filters: TranslationsEntitiesFilters;
|
||||||
language: ShopInfo_shop_languages;
|
language: ShopInfo_shop_languages;
|
||||||
|
@ -31,10 +33,66 @@ export interface TranslationsEntitiesFilters {
|
||||||
|
|
||||||
export type TranslationsEntitiesListFilterTab = keyof typeof TranslatableEntities;
|
export type TranslationsEntitiesListFilterTab = keyof typeof TranslatableEntities;
|
||||||
|
|
||||||
|
function getSearchPlaceholder(
|
||||||
|
tab: TranslationsEntitiesListFilterTab,
|
||||||
|
intl: IntlShape
|
||||||
|
): string {
|
||||||
|
switch (tab) {
|
||||||
|
case "categories":
|
||||||
|
return intl.formatMessage({
|
||||||
|
defaultMessage: "Search Category"
|
||||||
|
});
|
||||||
|
|
||||||
|
case "collections":
|
||||||
|
return intl.formatMessage({
|
||||||
|
defaultMessage: "Search Collection"
|
||||||
|
});
|
||||||
|
|
||||||
|
case "products":
|
||||||
|
return intl.formatMessage({
|
||||||
|
defaultMessage: "Search Product"
|
||||||
|
});
|
||||||
|
|
||||||
|
case "sales":
|
||||||
|
return intl.formatMessage({
|
||||||
|
defaultMessage: "Search Sale"
|
||||||
|
});
|
||||||
|
|
||||||
|
case "vouchers":
|
||||||
|
return intl.formatMessage({
|
||||||
|
defaultMessage: "Search Voucher"
|
||||||
|
});
|
||||||
|
|
||||||
|
case "pages":
|
||||||
|
return intl.formatMessage({
|
||||||
|
defaultMessage: "Search Page"
|
||||||
|
});
|
||||||
|
|
||||||
|
case "productTypes":
|
||||||
|
return intl.formatMessage({
|
||||||
|
defaultMessage: "Search Product Type"
|
||||||
|
});
|
||||||
|
|
||||||
|
default:
|
||||||
|
return "...";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const tabs: TranslationsEntitiesListFilterTab[] = [
|
||||||
|
"categories",
|
||||||
|
"collections",
|
||||||
|
"products",
|
||||||
|
"sales",
|
||||||
|
"vouchers",
|
||||||
|
"pages",
|
||||||
|
"productTypes"
|
||||||
|
];
|
||||||
|
|
||||||
const TranslationsEntitiesListPage: React.StatelessComponent<
|
const TranslationsEntitiesListPage: React.StatelessComponent<
|
||||||
TranslationsEntitiesListPageProps
|
TranslationsEntitiesListPageProps
|
||||||
> = ({ filters, language, onBack, children }) => {
|
> = ({ filters, language, onBack, children, ...searchProps }) => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
const currentTab = tabs.indexOf(filters.current);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container>
|
<Container>
|
||||||
|
@ -55,17 +113,7 @@ const TranslationsEntitiesListPage: React.StatelessComponent<
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
<Card>
|
<Card>
|
||||||
<FilterTabs
|
<FilterTabs currentTab={currentTab}>
|
||||||
currentTab={([
|
|
||||||
"categories",
|
|
||||||
"collections",
|
|
||||||
"products",
|
|
||||||
"sales",
|
|
||||||
"vouchers",
|
|
||||||
"pages",
|
|
||||||
"productTypes"
|
|
||||||
] as TranslationsEntitiesListFilterTab[]).indexOf(filters.current)}
|
|
||||||
>
|
|
||||||
<FilterTab
|
<FilterTab
|
||||||
label={intl.formatMessage({
|
label={intl.formatMessage({
|
||||||
defaultMessage: "Categories"
|
defaultMessage: "Categories"
|
||||||
|
@ -109,6 +157,11 @@ const TranslationsEntitiesListPage: React.StatelessComponent<
|
||||||
onClick={filters.onProductTypesTabClick}
|
onClick={filters.onProductTypesTabClick}
|
||||||
/>
|
/>
|
||||||
</FilterTabs>
|
</FilterTabs>
|
||||||
|
<FilterSearch
|
||||||
|
displaySearchAction={null}
|
||||||
|
searchPlaceholder={getSearchPlaceholder(filters.current, intl)}
|
||||||
|
{...searchProps}
|
||||||
|
/>
|
||||||
{children}
|
{children}
|
||||||
</Card>
|
</Card>
|
||||||
</Container>
|
</Container>
|
||||||
|
|
|
@ -18,9 +18,7 @@ import TranslationsCategoriesComponent, {
|
||||||
import TranslationsCollectionsComponent, {
|
import TranslationsCollectionsComponent, {
|
||||||
TranslationsCollectionsQueryParams
|
TranslationsCollectionsQueryParams
|
||||||
} from "./views/TranslationsCollections";
|
} from "./views/TranslationsCollections";
|
||||||
import TranslationsEntitiesComponent, {
|
import TranslationsEntitiesComponent from "./views/TranslationsEntities";
|
||||||
TranslationsEntitiesListQueryParams
|
|
||||||
} from "./views/TranslationsEntities";
|
|
||||||
import TranslationsLanguageList from "./views/TranslationsLanguageList";
|
import TranslationsLanguageList from "./views/TranslationsLanguageList";
|
||||||
import TranslationsPagesComponent, {
|
import TranslationsPagesComponent, {
|
||||||
TranslationsPagesQueryParams
|
TranslationsPagesQueryParams
|
||||||
|
@ -46,15 +44,11 @@ const TranslationsEntities: React.FC<TranslationsEntitiesRouteProps> = ({
|
||||||
match
|
match
|
||||||
}) => {
|
}) => {
|
||||||
const qs = parseQs(location.search.substr(1));
|
const qs = parseQs(location.search.substr(1));
|
||||||
const params: TranslationsEntitiesListQueryParams = {
|
|
||||||
after: qs.after,
|
|
||||||
before: qs.before,
|
|
||||||
tab: qs.tab
|
|
||||||
};
|
|
||||||
return (
|
return (
|
||||||
<TranslationsEntitiesComponent
|
<TranslationsEntitiesComponent
|
||||||
language={match.params.languageCode}
|
language={match.params.languageCode}
|
||||||
params={params}
|
params={qs}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -217,8 +217,15 @@ const categoryTranslations = gql`
|
||||||
$after: String
|
$after: String
|
||||||
$last: Int
|
$last: Int
|
||||||
$before: String
|
$before: String
|
||||||
|
$filter: CategoryFilterInput
|
||||||
) {
|
) {
|
||||||
categories(before: $before, after: $after, first: $first, last: $last) {
|
categories(
|
||||||
|
before: $before
|
||||||
|
after: $after
|
||||||
|
first: $first
|
||||||
|
last: $last
|
||||||
|
filter: $filter
|
||||||
|
) {
|
||||||
edges {
|
edges {
|
||||||
node {
|
node {
|
||||||
...CategoryTranslationFragment
|
...CategoryTranslationFragment
|
||||||
|
@ -244,8 +251,15 @@ const collectionTranslations = gql`
|
||||||
$after: String
|
$after: String
|
||||||
$last: Int
|
$last: Int
|
||||||
$before: String
|
$before: String
|
||||||
|
$filter: CollectionFilterInput
|
||||||
) {
|
) {
|
||||||
collections(before: $before, after: $after, first: $first, last: $last) {
|
collections(
|
||||||
|
before: $before
|
||||||
|
after: $after
|
||||||
|
first: $first
|
||||||
|
last: $last
|
||||||
|
filter: $filter
|
||||||
|
) {
|
||||||
edges {
|
edges {
|
||||||
node {
|
node {
|
||||||
...CollectionTranslationFragment
|
...CollectionTranslationFragment
|
||||||
|
@ -271,8 +285,15 @@ const productTranslations = gql`
|
||||||
$after: String
|
$after: String
|
||||||
$last: Int
|
$last: Int
|
||||||
$before: String
|
$before: String
|
||||||
|
$filter: ProductFilterInput
|
||||||
) {
|
) {
|
||||||
products(before: $before, after: $after, first: $first, last: $last) {
|
products(
|
||||||
|
before: $before
|
||||||
|
after: $after
|
||||||
|
first: $first
|
||||||
|
last: $last
|
||||||
|
filter: $filter
|
||||||
|
) {
|
||||||
edges {
|
edges {
|
||||||
node {
|
node {
|
||||||
...ProductTranslationFragment
|
...ProductTranslationFragment
|
||||||
|
@ -298,8 +319,15 @@ const pageTranslations = gql`
|
||||||
$after: String
|
$after: String
|
||||||
$last: Int
|
$last: Int
|
||||||
$before: String
|
$before: String
|
||||||
|
$filter: PageFilterInput
|
||||||
) {
|
) {
|
||||||
pages(before: $before, after: $after, first: $first, last: $last) {
|
pages(
|
||||||
|
before: $before
|
||||||
|
after: $after
|
||||||
|
first: $first
|
||||||
|
last: $last
|
||||||
|
filter: $filter
|
||||||
|
) {
|
||||||
edges {
|
edges {
|
||||||
node {
|
node {
|
||||||
...PageTranslationFragment
|
...PageTranslationFragment
|
||||||
|
@ -325,8 +353,15 @@ const voucherTranslations = gql`
|
||||||
$after: String
|
$after: String
|
||||||
$last: Int
|
$last: Int
|
||||||
$before: String
|
$before: String
|
||||||
|
$filter: VoucherFilterInput
|
||||||
) {
|
) {
|
||||||
vouchers(before: $before, after: $after, first: $first, last: $last) {
|
vouchers(
|
||||||
|
before: $before
|
||||||
|
after: $after
|
||||||
|
first: $first
|
||||||
|
last: $last
|
||||||
|
filter: $filter
|
||||||
|
) {
|
||||||
edges {
|
edges {
|
||||||
node {
|
node {
|
||||||
...VoucherTranslationFragment
|
...VoucherTranslationFragment
|
||||||
|
@ -352,8 +387,15 @@ const saleTranslations = gql`
|
||||||
$after: String
|
$after: String
|
||||||
$last: Int
|
$last: Int
|
||||||
$before: String
|
$before: String
|
||||||
|
$filter: SaleFilterInput
|
||||||
) {
|
) {
|
||||||
sales(before: $before, after: $after, first: $first, last: $last) {
|
sales(
|
||||||
|
before: $before
|
||||||
|
after: $after
|
||||||
|
first: $first
|
||||||
|
last: $last
|
||||||
|
filter: $filter
|
||||||
|
) {
|
||||||
edges {
|
edges {
|
||||||
node {
|
node {
|
||||||
...SaleTranslationFragment
|
...SaleTranslationFragment
|
||||||
|
@ -379,8 +421,15 @@ const productTypeTranslations = gql`
|
||||||
$after: String
|
$after: String
|
||||||
$last: Int
|
$last: Int
|
||||||
$before: String
|
$before: String
|
||||||
|
$filter: ProductTypeFilterInput
|
||||||
) {
|
) {
|
||||||
productTypes(before: $before, after: $after, first: $first, last: $last) {
|
productTypes(
|
||||||
|
before: $before
|
||||||
|
after: $after
|
||||||
|
first: $first
|
||||||
|
last: $last
|
||||||
|
filter: $filter
|
||||||
|
) {
|
||||||
edges {
|
edges {
|
||||||
node {
|
node {
|
||||||
...ProductTypeTranslationFragment
|
...ProductTypeTranslationFragment
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
// This file was automatically generated and should not be edited.
|
// This file was automatically generated and should not be edited.
|
||||||
|
|
||||||
import { LanguageCodeEnum } from "./../../types/globalTypes";
|
import { LanguageCodeEnum, CategoryFilterInput } from "./../../types/globalTypes";
|
||||||
|
|
||||||
// ====================================================
|
// ====================================================
|
||||||
// GraphQL query operation: CategoryTranslations
|
// GraphQL query operation: CategoryTranslations
|
||||||
|
@ -62,4 +62,5 @@ export interface CategoryTranslationsVariables {
|
||||||
after?: string | null;
|
after?: string | null;
|
||||||
last?: number | null;
|
last?: number | null;
|
||||||
before?: string | null;
|
before?: string | null;
|
||||||
|
filter?: CategoryFilterInput | null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
// This file was automatically generated and should not be edited.
|
// This file was automatically generated and should not be edited.
|
||||||
|
|
||||||
import { LanguageCodeEnum } from "./../../types/globalTypes";
|
import { LanguageCodeEnum, CollectionFilterInput } from "./../../types/globalTypes";
|
||||||
|
|
||||||
// ====================================================
|
// ====================================================
|
||||||
// GraphQL query operation: CollectionTranslations
|
// GraphQL query operation: CollectionTranslations
|
||||||
|
@ -62,4 +62,5 @@ export interface CollectionTranslationsVariables {
|
||||||
after?: string | null;
|
after?: string | null;
|
||||||
last?: number | null;
|
last?: number | null;
|
||||||
before?: string | null;
|
before?: string | null;
|
||||||
|
filter?: CollectionFilterInput | null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
// This file was automatically generated and should not be edited.
|
// This file was automatically generated and should not be edited.
|
||||||
|
|
||||||
import { LanguageCodeEnum } from "./../../types/globalTypes";
|
import { LanguageCodeEnum, PageFilterInput } from "./../../types/globalTypes";
|
||||||
|
|
||||||
// ====================================================
|
// ====================================================
|
||||||
// GraphQL query operation: PageTranslations
|
// GraphQL query operation: PageTranslations
|
||||||
|
@ -63,4 +63,5 @@ export interface PageTranslationsVariables {
|
||||||
after?: string | null;
|
after?: string | null;
|
||||||
last?: number | null;
|
last?: number | null;
|
||||||
before?: string | null;
|
before?: string | null;
|
||||||
|
filter?: PageFilterInput | null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
// This file was automatically generated and should not be edited.
|
// This file was automatically generated and should not be edited.
|
||||||
|
|
||||||
import { LanguageCodeEnum } from "./../../types/globalTypes";
|
import { LanguageCodeEnum, ProductFilterInput } from "./../../types/globalTypes";
|
||||||
|
|
||||||
// ====================================================
|
// ====================================================
|
||||||
// GraphQL query operation: ProductTranslations
|
// GraphQL query operation: ProductTranslations
|
||||||
|
@ -63,4 +63,5 @@ export interface ProductTranslationsVariables {
|
||||||
after?: string | null;
|
after?: string | null;
|
||||||
last?: number | null;
|
last?: number | null;
|
||||||
before?: string | null;
|
before?: string | null;
|
||||||
|
filter?: ProductFilterInput | null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
// This file was automatically generated and should not be edited.
|
// This file was automatically generated and should not be edited.
|
||||||
|
|
||||||
import { LanguageCodeEnum } from "./../../types/globalTypes";
|
import { LanguageCodeEnum, ProductTypeFilterInput } from "./../../types/globalTypes";
|
||||||
|
|
||||||
// ====================================================
|
// ====================================================
|
||||||
// GraphQL query operation: ProductTypeTranslations
|
// GraphQL query operation: ProductTypeTranslations
|
||||||
|
@ -99,4 +99,5 @@ export interface ProductTypeTranslationsVariables {
|
||||||
after?: string | null;
|
after?: string | null;
|
||||||
last?: number | null;
|
last?: number | null;
|
||||||
before?: string | null;
|
before?: string | null;
|
||||||
|
filter?: ProductTypeFilterInput | null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
// This file was automatically generated and should not be edited.
|
// This file was automatically generated and should not be edited.
|
||||||
|
|
||||||
import { LanguageCodeEnum } from "./../../types/globalTypes";
|
import { LanguageCodeEnum, SaleFilterInput } from "./../../types/globalTypes";
|
||||||
|
|
||||||
// ====================================================
|
// ====================================================
|
||||||
// GraphQL query operation: SaleTranslations
|
// GraphQL query operation: SaleTranslations
|
||||||
|
@ -57,4 +57,5 @@ export interface SaleTranslationsVariables {
|
||||||
after?: string | null;
|
after?: string | null;
|
||||||
last?: number | null;
|
last?: number | null;
|
||||||
before?: string | null;
|
before?: string | null;
|
||||||
|
filter?: SaleFilterInput | null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
// This file was automatically generated and should not be edited.
|
// This file was automatically generated and should not be edited.
|
||||||
|
|
||||||
import { LanguageCodeEnum } from "./../../types/globalTypes";
|
import { LanguageCodeEnum, VoucherFilterInput } from "./../../types/globalTypes";
|
||||||
|
|
||||||
// ====================================================
|
// ====================================================
|
||||||
// GraphQL query operation: VoucherTranslations
|
// GraphQL query operation: VoucherTranslations
|
||||||
|
@ -57,4 +57,5 @@ export interface VoucherTranslationsVariables {
|
||||||
after?: string | null;
|
after?: string | null;
|
||||||
last?: number | null;
|
last?: number | null;
|
||||||
before?: string | null;
|
before?: string | null;
|
||||||
|
filter?: VoucherFilterInput | null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
import { stringify as stringifyQs } from "qs";
|
import { stringify as stringifyQs } from "qs";
|
||||||
import urlJoin from "url-join";
|
import urlJoin from "url-join";
|
||||||
|
|
||||||
|
import { Pagination } from "@saleor/types";
|
||||||
|
import { TranslationsEntitiesListFilterTab } from "./components/TranslationsEntitiesListPage";
|
||||||
|
|
||||||
export enum TranslatableEntities {
|
export enum TranslatableEntities {
|
||||||
categories = "categories",
|
categories = "categories",
|
||||||
products = "products",
|
products = "products",
|
||||||
|
@ -18,12 +21,15 @@ export const languageListUrl = translationsSection;
|
||||||
|
|
||||||
export const languageEntitiesPath = (code: string) =>
|
export const languageEntitiesPath = (code: string) =>
|
||||||
urlJoin(translationsSection, code);
|
urlJoin(translationsSection, code);
|
||||||
export const languageEntitiesUrl = (code: string, tab?: TranslatableEntities) =>
|
export type LanguageEntitiesUrlQueryParams = Pagination &
|
||||||
languageEntitiesPath(code) +
|
Partial<{
|
||||||
"?" +
|
query: string;
|
||||||
stringifyQs({
|
tab: TranslationsEntitiesListFilterTab;
|
||||||
tab
|
}>;
|
||||||
});
|
export const languageEntitiesUrl = (
|
||||||
|
code: string,
|
||||||
|
params: LanguageEntitiesUrlQueryParams
|
||||||
|
) => languageEntitiesPath(code) + "?" + stringifyQs(params);
|
||||||
|
|
||||||
export const languageEntityPath = (
|
export const languageEntityPath = (
|
||||||
code: string,
|
code: string,
|
||||||
|
|
|
@ -104,10 +104,9 @@ const TranslationsCategories: React.FC<TranslationsCategoriesProps> = ({
|
||||||
saveButtonState={saveButtonState}
|
saveButtonState={saveButtonState}
|
||||||
onBack={() =>
|
onBack={() =>
|
||||||
navigate(
|
navigate(
|
||||||
languageEntitiesUrl(
|
languageEntitiesUrl(languageCode, {
|
||||||
languageCode,
|
tab: TranslatableEntities.categories
|
||||||
TranslatableEntities.categories
|
})
|
||||||
)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
onEdit={onEdit}
|
onEdit={onEdit}
|
||||||
|
|
|
@ -109,10 +109,9 @@ const TranslationsCollections: React.FC<TranslationsCollectionsProps> = ({
|
||||||
onDiscard={onDiscard}
|
onDiscard={onDiscard}
|
||||||
onBack={() =>
|
onBack={() =>
|
||||||
navigate(
|
navigate(
|
||||||
languageEntitiesUrl(
|
languageEntitiesUrl(languageCode, {
|
||||||
languageCode,
|
tab: TranslatableEntities.collections
|
||||||
TranslatableEntities.collections
|
})
|
||||||
)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
onLanguageChange={lang =>
|
onLanguageChange={lang =>
|
||||||
|
|
|
@ -8,11 +8,8 @@ import usePaginator, {
|
||||||
import useShop from "@saleor/hooks/useShop";
|
import useShop from "@saleor/hooks/useShop";
|
||||||
import { PAGINATE_BY } from "../../config";
|
import { PAGINATE_BY } from "../../config";
|
||||||
import { maybe } from "../../misc";
|
import { maybe } from "../../misc";
|
||||||
import { Pagination } from "../../types";
|
|
||||||
import TranslationsEntitiesList from "../components/TranslationsEntitiesList";
|
import TranslationsEntitiesList from "../components/TranslationsEntitiesList";
|
||||||
import TranslationsEntitiesListPage, {
|
import TranslationsEntitiesListPage from "../components/TranslationsEntitiesListPage";
|
||||||
TranslationsEntitiesListFilterTab
|
|
||||||
} from "../components/TranslationsEntitiesListPage";
|
|
||||||
import {
|
import {
|
||||||
TypedCategoryTranslations,
|
TypedCategoryTranslations,
|
||||||
TypedCollectionTranslations,
|
TypedCollectionTranslations,
|
||||||
|
@ -24,18 +21,16 @@ import {
|
||||||
} from "../queries";
|
} from "../queries";
|
||||||
import { AttributeTranslationFragment } from "../types/AttributeTranslationFragment";
|
import { AttributeTranslationFragment } from "../types/AttributeTranslationFragment";
|
||||||
import {
|
import {
|
||||||
|
languageEntitiesUrl,
|
||||||
|
LanguageEntitiesUrlQueryParams,
|
||||||
languageEntityUrl,
|
languageEntityUrl,
|
||||||
languageListUrl,
|
languageListUrl,
|
||||||
TranslatableEntities
|
TranslatableEntities
|
||||||
} from "../urls";
|
} from "../urls";
|
||||||
|
|
||||||
export type TranslationsEntitiesListQueryParams = Pagination & {
|
|
||||||
tab: TranslationsEntitiesListFilterTab;
|
|
||||||
};
|
|
||||||
|
|
||||||
interface TranslationsEntitiesProps {
|
interface TranslationsEntitiesProps {
|
||||||
language: string;
|
language: string;
|
||||||
params: TranslationsEntitiesListQueryParams;
|
params: LanguageEntitiesUrlQueryParams;
|
||||||
}
|
}
|
||||||
|
|
||||||
function sumTranslations(
|
function sumTranslations(
|
||||||
|
@ -128,9 +123,29 @@ const TranslationsEntities: React.FC<TranslationsEntitiesProps> = ({
|
||||||
shop.languages.find(languageFromList => languageFromList.code === language)
|
shop.languages.find(languageFromList => languageFromList.code === language)
|
||||||
);
|
);
|
||||||
const paginationState = createPaginationState(PAGINATE_BY, params);
|
const paginationState = createPaginationState(PAGINATE_BY, params);
|
||||||
|
const queryVariables = React.useMemo(
|
||||||
|
() => ({
|
||||||
|
...paginationState,
|
||||||
|
filter: {
|
||||||
|
search: params.query
|
||||||
|
},
|
||||||
|
language: language as any
|
||||||
|
}),
|
||||||
|
[params]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TranslationsEntitiesListPage
|
<TranslationsEntitiesListPage
|
||||||
|
initialSearch={params.query || ""}
|
||||||
|
onSearchChange={query =>
|
||||||
|
navigate(
|
||||||
|
languageEntitiesUrl(language, {
|
||||||
|
...params,
|
||||||
|
query
|
||||||
|
}),
|
||||||
|
true
|
||||||
|
)
|
||||||
|
}
|
||||||
filters={{
|
filters={{
|
||||||
current: params.tab,
|
current: params.tab,
|
||||||
...filterCallbacks
|
...filterCallbacks
|
||||||
|
@ -139,9 +154,7 @@ const TranslationsEntities: React.FC<TranslationsEntitiesProps> = ({
|
||||||
onBack={() => navigate(languageListUrl)}
|
onBack={() => navigate(languageListUrl)}
|
||||||
>
|
>
|
||||||
{params.tab === "categories" ? (
|
{params.tab === "categories" ? (
|
||||||
<TypedCategoryTranslations
|
<TypedCategoryTranslations variables={queryVariables}>
|
||||||
variables={{ language: language as any, ...paginationState }}
|
|
||||||
>
|
|
||||||
{({ data, loading }) => {
|
{({ data, loading }) => {
|
||||||
const { loadNextPage, loadPreviousPage, pageInfo } = paginate(
|
const { loadNextPage, loadPreviousPage, pageInfo } = paginate(
|
||||||
maybe(() => data.categories.pageInfo),
|
maybe(() => data.categories.pageInfo),
|
||||||
|
@ -191,9 +204,7 @@ const TranslationsEntities: React.FC<TranslationsEntitiesProps> = ({
|
||||||
}}
|
}}
|
||||||
</TypedCategoryTranslations>
|
</TypedCategoryTranslations>
|
||||||
) : params.tab === "products" ? (
|
) : params.tab === "products" ? (
|
||||||
<TypedProductTranslations
|
<TypedProductTranslations variables={queryVariables}>
|
||||||
variables={{ language: language as any, ...paginationState }}
|
|
||||||
>
|
|
||||||
{({ data, loading }) => {
|
{({ data, loading }) => {
|
||||||
const { loadNextPage, loadPreviousPage, pageInfo } = paginate(
|
const { loadNextPage, loadPreviousPage, pageInfo } = paginate(
|
||||||
maybe(() => data.products.pageInfo),
|
maybe(() => data.products.pageInfo),
|
||||||
|
@ -243,9 +254,7 @@ const TranslationsEntities: React.FC<TranslationsEntitiesProps> = ({
|
||||||
}}
|
}}
|
||||||
</TypedProductTranslations>
|
</TypedProductTranslations>
|
||||||
) : params.tab === "collections" ? (
|
) : params.tab === "collections" ? (
|
||||||
<TypedCollectionTranslations
|
<TypedCollectionTranslations variables={queryVariables}>
|
||||||
variables={{ language: language as any, ...paginationState }}
|
|
||||||
>
|
|
||||||
{({ data, loading }) => {
|
{({ data, loading }) => {
|
||||||
const { loadNextPage, loadPreviousPage, pageInfo } = paginate(
|
const { loadNextPage, loadPreviousPage, pageInfo } = paginate(
|
||||||
maybe(() => data.collections.pageInfo),
|
maybe(() => data.collections.pageInfo),
|
||||||
|
@ -295,9 +304,7 @@ const TranslationsEntities: React.FC<TranslationsEntitiesProps> = ({
|
||||||
}}
|
}}
|
||||||
</TypedCollectionTranslations>
|
</TypedCollectionTranslations>
|
||||||
) : params.tab === "sales" ? (
|
) : params.tab === "sales" ? (
|
||||||
<TypedSaleTranslations
|
<TypedSaleTranslations variables={queryVariables}>
|
||||||
variables={{ language: language as any, ...paginationState }}
|
|
||||||
>
|
|
||||||
{({ data, loading }) => {
|
{({ data, loading }) => {
|
||||||
const { loadNextPage, loadPreviousPage, pageInfo } = paginate(
|
const { loadNextPage, loadPreviousPage, pageInfo } = paginate(
|
||||||
maybe(() => data.sales.pageInfo),
|
maybe(() => data.sales.pageInfo),
|
||||||
|
@ -335,9 +342,7 @@ const TranslationsEntities: React.FC<TranslationsEntitiesProps> = ({
|
||||||
}}
|
}}
|
||||||
</TypedSaleTranslations>
|
</TypedSaleTranslations>
|
||||||
) : params.tab === "vouchers" ? (
|
) : params.tab === "vouchers" ? (
|
||||||
<TypedVoucherTranslations
|
<TypedVoucherTranslations variables={queryVariables}>
|
||||||
variables={{ language: language as any, ...paginationState }}
|
|
||||||
>
|
|
||||||
{({ data, loading }) => {
|
{({ data, loading }) => {
|
||||||
const { loadNextPage, loadPreviousPage, pageInfo } = paginate(
|
const { loadNextPage, loadPreviousPage, pageInfo } = paginate(
|
||||||
maybe(() => data.vouchers.pageInfo),
|
maybe(() => data.vouchers.pageInfo),
|
||||||
|
@ -379,9 +384,7 @@ const TranslationsEntities: React.FC<TranslationsEntitiesProps> = ({
|
||||||
}}
|
}}
|
||||||
</TypedVoucherTranslations>
|
</TypedVoucherTranslations>
|
||||||
) : params.tab === "pages" ? (
|
) : params.tab === "pages" ? (
|
||||||
<TypedPageTranslations
|
<TypedPageTranslations variables={queryVariables}>
|
||||||
variables={{ language: language as any, ...paginationState }}
|
|
||||||
>
|
|
||||||
{({ data, loading }) => {
|
{({ data, loading }) => {
|
||||||
const { loadNextPage, loadPreviousPage, pageInfo } = paginate(
|
const { loadNextPage, loadPreviousPage, pageInfo } = paginate(
|
||||||
maybe(() => data.pages.pageInfo),
|
maybe(() => data.pages.pageInfo),
|
||||||
|
@ -427,9 +430,7 @@ const TranslationsEntities: React.FC<TranslationsEntitiesProps> = ({
|
||||||
}}
|
}}
|
||||||
</TypedPageTranslations>
|
</TypedPageTranslations>
|
||||||
) : params.tab === "productTypes" ? (
|
) : params.tab === "productTypes" ? (
|
||||||
<TypedProductTypeTranslations
|
<TypedProductTypeTranslations variables={queryVariables}>
|
||||||
variables={{ language: language as any, ...paginationState }}
|
|
||||||
>
|
|
||||||
{({ data, loading }) => {
|
{({ data, loading }) => {
|
||||||
const { loadNextPage, loadPreviousPage, pageInfo } = paginate(
|
const { loadNextPage, loadPreviousPage, pageInfo } = paginate(
|
||||||
maybe(() => data.productTypes.pageInfo),
|
maybe(() => data.productTypes.pageInfo),
|
||||||
|
|
|
@ -14,7 +14,7 @@ const TranslationsLanguageList: React.FC = () => {
|
||||||
<TranslationsLanguageListPage
|
<TranslationsLanguageListPage
|
||||||
languages={maybe(() => shop.languages)}
|
languages={maybe(() => shop.languages)}
|
||||||
// onAdd={undefined}
|
// onAdd={undefined}
|
||||||
onRowClick={code => navigate(languageEntitiesUrl(code))}
|
onRowClick={code => navigate(languageEntitiesUrl(code, {}))}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -104,10 +104,9 @@ const TranslationsPages: React.FC<TranslationsPagesProps> = ({
|
||||||
saveButtonState={saveButtonState}
|
saveButtonState={saveButtonState}
|
||||||
onBack={() =>
|
onBack={() =>
|
||||||
navigate(
|
navigate(
|
||||||
languageEntitiesUrl(
|
languageEntitiesUrl(languageCode, {
|
||||||
languageCode,
|
tab: TranslatableEntities.pages
|
||||||
TranslatableEntities.pages
|
})
|
||||||
)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
onEdit={onEdit}
|
onEdit={onEdit}
|
||||||
|
|
|
@ -144,10 +144,9 @@ const TranslationsProductTypes: React.FC<TranslationsProductTypesProps> = ({
|
||||||
saveButtonState={saveButtonState}
|
saveButtonState={saveButtonState}
|
||||||
onBack={() =>
|
onBack={() =>
|
||||||
navigate(
|
navigate(
|
||||||
languageEntitiesUrl(
|
languageEntitiesUrl(languageCode, {
|
||||||
languageCode,
|
tab: TranslatableEntities.productTypes
|
||||||
TranslatableEntities.productTypes
|
})
|
||||||
)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
onEdit={onEdit}
|
onEdit={onEdit}
|
||||||
|
|
|
@ -104,10 +104,9 @@ const TranslationsProducts: React.FC<TranslationsProductsProps> = ({
|
||||||
saveButtonState={saveButtonState}
|
saveButtonState={saveButtonState}
|
||||||
onBack={() =>
|
onBack={() =>
|
||||||
navigate(
|
navigate(
|
||||||
languageEntitiesUrl(
|
languageEntitiesUrl(languageCode, {
|
||||||
languageCode,
|
tab: TranslatableEntities.products
|
||||||
TranslatableEntities.products
|
})
|
||||||
)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
onEdit={onEdit}
|
onEdit={onEdit}
|
||||||
|
|
|
@ -98,10 +98,9 @@ const TranslationsSales: React.FC<TranslationsSalesProps> = ({
|
||||||
saveButtonState={saveButtonState}
|
saveButtonState={saveButtonState}
|
||||||
onBack={() =>
|
onBack={() =>
|
||||||
navigate(
|
navigate(
|
||||||
languageEntitiesUrl(
|
languageEntitiesUrl(languageCode, {
|
||||||
languageCode,
|
tab: TranslatableEntities.sales
|
||||||
TranslatableEntities.sales
|
})
|
||||||
)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
onEdit={onEdit}
|
onEdit={onEdit}
|
||||||
|
|
|
@ -101,10 +101,9 @@ const TranslationsVouchers: React.FC<TranslationsVouchersProps> = ({
|
||||||
saveButtonState={saveButtonState}
|
saveButtonState={saveButtonState}
|
||||||
onBack={() =>
|
onBack={() =>
|
||||||
navigate(
|
navigate(
|
||||||
languageEntitiesUrl(
|
languageEntitiesUrl(languageCode, {
|
||||||
languageCode,
|
tab: TranslatableEntities.vouchers
|
||||||
TranslatableEntities.vouchers
|
})
|
||||||
)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
onEdit={onEdit}
|
onEdit={onEdit}
|
||||||
|
|
|
@ -187,6 +187,16 @@ export enum PermissionEnum {
|
||||||
MANAGE_USERS = "MANAGE_USERS",
|
MANAGE_USERS = "MANAGE_USERS",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum ProductTypeConfigurable {
|
||||||
|
CONFIGURABLE = "CONFIGURABLE",
|
||||||
|
SIMPLE = "SIMPLE",
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum ProductTypeEnum {
|
||||||
|
DIGITAL = "DIGITAL",
|
||||||
|
SHIPPABLE = "SHIPPABLE",
|
||||||
|
}
|
||||||
|
|
||||||
export enum SaleType {
|
export enum SaleType {
|
||||||
FIXED = "FIXED",
|
FIXED = "FIXED",
|
||||||
PERCENTAGE = "PERCENTAGE",
|
PERCENTAGE = "PERCENTAGE",
|
||||||
|
@ -520,6 +530,10 @@ export interface OrderUpdateShippingInput {
|
||||||
shippingMethod?: string | null;
|
shippingMethod?: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface PageFilterInput {
|
||||||
|
search?: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
export interface PageInput {
|
export interface PageInput {
|
||||||
slug?: string | null;
|
slug?: string | null;
|
||||||
title?: string | null;
|
title?: string | null;
|
||||||
|
@ -560,6 +574,12 @@ export interface ProductFilterInput {
|
||||||
minimalPrice?: PriceRangeInput | null;
|
minimalPrice?: PriceRangeInput | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ProductTypeFilterInput {
|
||||||
|
search?: string | null;
|
||||||
|
configurable?: ProductTypeConfigurable | null;
|
||||||
|
productType?: ProductTypeEnum | null;
|
||||||
|
}
|
||||||
|
|
||||||
export interface ProductTypeInput {
|
export interface ProductTypeInput {
|
||||||
name?: string | null;
|
name?: string | null;
|
||||||
hasVariants?: boolean | null;
|
hasVariants?: boolean | null;
|
||||||
|
|
Loading…
Reference in a new issue