Split filters, searches and tabs
This commit is contained in:
parent
f4e3149f89
commit
544d13754a
16 changed files with 392 additions and 178 deletions
109
src/components/Filter/FilterActions.tsx
Normal file
109
src/components/Filter/FilterActions.tsx
Normal file
|
@ -0,0 +1,109 @@
|
||||||
|
import { Theme } from "@material-ui/core/styles";
|
||||||
|
import TextField, { TextFieldProps } from "@material-ui/core/TextField";
|
||||||
|
import { makeStyles } from "@material-ui/styles";
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
import { FilterContentSubmitData, IFilter } from "../Filter";
|
||||||
|
import Filter from "./Filter";
|
||||||
|
|
||||||
|
const useInputStyles = makeStyles({
|
||||||
|
input: {
|
||||||
|
padding: "10px 12px"
|
||||||
|
},
|
||||||
|
root: {
|
||||||
|
flex: 1
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const Search: React.FC<TextFieldProps> = props => {
|
||||||
|
const classes = useInputStyles({});
|
||||||
|
return (
|
||||||
|
<TextField
|
||||||
|
{...props}
|
||||||
|
className={classes.root}
|
||||||
|
inputProps={{
|
||||||
|
className: classes.input
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const useStyles = makeStyles(
|
||||||
|
(theme: Theme) => ({
|
||||||
|
actionContainer: {
|
||||||
|
display: "flex",
|
||||||
|
flexWrap: "wrap",
|
||||||
|
padding: `${theme.spacing.unit * 1.5}px ${theme.spacing.unit * 3}px ${
|
||||||
|
theme.spacing.unit
|
||||||
|
}px`
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
name: "FilterActions"
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
export interface FilterActionsPropsSearch {
|
||||||
|
placeholder: string;
|
||||||
|
search: string;
|
||||||
|
onSearchChange: (event: React.ChangeEvent<any>) => void;
|
||||||
|
}
|
||||||
|
export interface FilterActionsPropsFilters {
|
||||||
|
currencySymbol: string;
|
||||||
|
menu: IFilter;
|
||||||
|
filterLabel: string;
|
||||||
|
onFilterAdd: (filter: FilterContentSubmitData) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const FilterActionsOnlySearch: React.FC<
|
||||||
|
FilterActionsPropsSearch
|
||||||
|
> = props => {
|
||||||
|
const { onSearchChange, placeholder, search } = props;
|
||||||
|
const classes = useStyles(props);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={classes.actionContainer}>
|
||||||
|
<Search
|
||||||
|
fullWidth
|
||||||
|
placeholder={placeholder}
|
||||||
|
value={search}
|
||||||
|
onChange={onSearchChange}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export type FilterActionsProps = FilterActionsPropsSearch &
|
||||||
|
FilterActionsPropsFilters;
|
||||||
|
const FilterActions: React.FC<FilterActionsProps> = props => {
|
||||||
|
const {
|
||||||
|
currencySymbol,
|
||||||
|
filterLabel,
|
||||||
|
menu,
|
||||||
|
onFilterAdd,
|
||||||
|
onSearchChange,
|
||||||
|
placeholder,
|
||||||
|
search
|
||||||
|
} = props;
|
||||||
|
const classes = useStyles(props);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={classes.actionContainer}>
|
||||||
|
<Filter
|
||||||
|
currencySymbol={currencySymbol}
|
||||||
|
menu={menu}
|
||||||
|
filterLabel={filterLabel}
|
||||||
|
onFilterAdd={onFilterAdd}
|
||||||
|
/>
|
||||||
|
<Search
|
||||||
|
fullWidth
|
||||||
|
placeholder={placeholder}
|
||||||
|
value={search}
|
||||||
|
onChange={onSearchChange}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
FilterActions.displayName = "FilterActions";
|
||||||
|
export default FilterActions;
|
|
@ -6,9 +6,8 @@ import Debounce from "../Debounce";
|
||||||
import { IFilter } from "../Filter/types";
|
import { IFilter } from "../Filter/types";
|
||||||
import FilterTabs, { FilterChips, FilterTab } from "../TableFilter";
|
import FilterTabs, { FilterChips, FilterTab } from "../TableFilter";
|
||||||
|
|
||||||
export interface FilterBarProps<TUrlFilters = object, TFilterKeys = any>
|
export interface FilterBarProps extends FilterProps {
|
||||||
extends FilterProps<TUrlFilters, TFilterKeys> {
|
filterMenu: IFilter;
|
||||||
filterMenu: IFilter<TFilterKeys>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const FilterBar: React.FC<FilterBarProps> = ({
|
const FilterBar: React.FC<FilterBarProps> = ({
|
||||||
|
@ -16,32 +15,32 @@ const FilterBar: React.FC<FilterBarProps> = ({
|
||||||
currencySymbol,
|
currencySymbol,
|
||||||
filterLabel,
|
filterLabel,
|
||||||
filtersList,
|
filtersList,
|
||||||
filterTabs,
|
|
||||||
filterMenu,
|
filterMenu,
|
||||||
currentTab,
|
currentTab,
|
||||||
initialSearch,
|
initialSearch,
|
||||||
searchPlaceholder,
|
searchPlaceholder,
|
||||||
|
tabs,
|
||||||
onAll,
|
onAll,
|
||||||
onSearchChange,
|
onSearchChange,
|
||||||
onFilterAdd,
|
onFilterAdd,
|
||||||
onFilterSave,
|
|
||||||
onTabChange,
|
onTabChange,
|
||||||
onFilterDelete
|
onTabDelete,
|
||||||
|
onTabSave
|
||||||
}) => {
|
}) => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const [search, setSearch] = React.useState(initialSearch);
|
const [search, setSearch] = React.useState(initialSearch);
|
||||||
React.useEffect(() => setSearch(initialSearch), [currentTab, initialSearch]);
|
React.useEffect(() => setSearch(initialSearch), [currentTab, initialSearch]);
|
||||||
|
|
||||||
const isCustom = currentTab === filterTabs.length + 1;
|
const isCustom = currentTab === tabs.length + 1;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<FilterTabs currentTab={currentTab}>
|
<FilterTabs currentTab={currentTab}>
|
||||||
<FilterTab label={allTabLabel} onClick={onAll} />
|
<FilterTab label={allTabLabel} onClick={onAll} />
|
||||||
{filterTabs.map((tab, tabIndex) => (
|
{tabs.map((tab, tabIndex) => (
|
||||||
<FilterTab
|
<FilterTab
|
||||||
onClick={() => onTabChange(tabIndex + 1)}
|
onClick={() => onTabChange(tabIndex + 1)}
|
||||||
label={tab.name}
|
label={tab}
|
||||||
key={tabIndex}
|
key={tabIndex}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
|
@ -72,9 +71,9 @@ const FilterBar: React.FC<FilterBarProps> = ({
|
||||||
search={search}
|
search={search}
|
||||||
onSearchChange={handleSearchChange}
|
onSearchChange={handleSearchChange}
|
||||||
onFilterAdd={onFilterAdd}
|
onFilterAdd={onFilterAdd}
|
||||||
onFilterSave={onFilterSave}
|
onFilterSave={onTabDelete}
|
||||||
isCustomSearch={isCustom}
|
isCustomSearch={isCustom}
|
||||||
onFilterDelete={onFilterDelete}
|
onFilterDelete={onTabSave}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
|
|
122
src/components/SearchBar/SearchBar.tsx
Normal file
122
src/components/SearchBar/SearchBar.tsx
Normal file
|
@ -0,0 +1,122 @@
|
||||||
|
import { Theme } from "@material-ui/core/styles";
|
||||||
|
import { makeStyles } from "@material-ui/styles";
|
||||||
|
import React from "react";
|
||||||
|
import { FormattedMessage, useIntl } from "react-intl";
|
||||||
|
|
||||||
|
import { SearchPageProps, TabPageProps } from "@saleor/types";
|
||||||
|
import Debounce from "../Debounce";
|
||||||
|
import { FilterActionsOnlySearch } from "../Filter/FilterActions";
|
||||||
|
import Hr from "../Hr";
|
||||||
|
import Link from "../Link";
|
||||||
|
import FilterTabs, { FilterTab } from "../TableFilter";
|
||||||
|
|
||||||
|
export interface SearchBarProps extends SearchPageProps, TabPageProps {
|
||||||
|
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`
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
const SearchBar: React.FC<SearchBarProps> = props => {
|
||||||
|
const {
|
||||||
|
currentTab,
|
||||||
|
initialSearch,
|
||||||
|
onSearchChange,
|
||||||
|
searchPlaceholder,
|
||||||
|
tabs,
|
||||||
|
onAll,
|
||||||
|
onTabChange,
|
||||||
|
onTabDelete,
|
||||||
|
onTabSave
|
||||||
|
} = props;
|
||||||
|
const classes = useStyles(props);
|
||||||
|
const [search, setSearch] = React.useState(initialSearch);
|
||||||
|
const intl = useIntl();
|
||||||
|
React.useEffect(() => setSearch(initialSearch), [initialSearch]);
|
||||||
|
|
||||||
|
const isCustom = currentTab === tabs.length + 1;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<FilterTabs currentTab={currentTab}>
|
||||||
|
<FilterTab
|
||||||
|
label={intl.formatMessage({
|
||||||
|
defaultMessage: "All Attributes",
|
||||||
|
description: "tab name"
|
||||||
|
})}
|
||||||
|
onClick={onAll}
|
||||||
|
/>
|
||||||
|
{tabs.map((tab, tabIndex) => (
|
||||||
|
<FilterTab
|
||||||
|
onClick={() => onTabChange(tabIndex + 1)}
|
||||||
|
label={tab}
|
||||||
|
key={tabIndex}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
{isCustom && (
|
||||||
|
<FilterTab
|
||||||
|
onClick={() => undefined}
|
||||||
|
label={intl.formatMessage({
|
||||||
|
defaultMessage: "Custom Filter"
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</FilterTabs>
|
||||||
|
<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}
|
||||||
|
/>
|
||||||
|
<div className={classes.tabActionContainer}>
|
||||||
|
<div className={classes.tabAction}>
|
||||||
|
{search || (tabs && tabs.length) > 0 ? (
|
||||||
|
isCustom ? (
|
||||||
|
<Link onClick={onTabSave}>
|
||||||
|
<FormattedMessage
|
||||||
|
defaultMessage="Save Custom Search"
|
||||||
|
description="button"
|
||||||
|
/>
|
||||||
|
</Link>
|
||||||
|
) : (
|
||||||
|
<Link onClick={onTabDelete}>
|
||||||
|
<FormattedMessage
|
||||||
|
defaultMessage="Delete Search"
|
||||||
|
description="button"
|
||||||
|
/>
|
||||||
|
</Link>
|
||||||
|
)
|
||||||
|
) : (
|
||||||
|
<Hr />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
</Debounce>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
SearchBar.displayName = "SearchBar";
|
||||||
|
export default SearchBar;
|
2
src/components/SearchBar/index.ts
Normal file
2
src/components/SearchBar/index.ts
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
export { default } from "./SearchBar";
|
||||||
|
export * from "./SearchBar";
|
|
@ -1,14 +1,14 @@
|
||||||
import ButtonBase from "@material-ui/core/ButtonBase";
|
import ButtonBase from "@material-ui/core/ButtonBase";
|
||||||
import { Theme } from "@material-ui/core/styles";
|
import { Theme } from "@material-ui/core/styles";
|
||||||
import { fade } from "@material-ui/core/styles/colorManipulator";
|
import { fade } from "@material-ui/core/styles/colorManipulator";
|
||||||
import TextField, { TextFieldProps } from "@material-ui/core/TextField";
|
|
||||||
import Typography from "@material-ui/core/Typography";
|
import Typography from "@material-ui/core/Typography";
|
||||||
import ClearIcon from "@material-ui/icons/Clear";
|
import ClearIcon from "@material-ui/icons/Clear";
|
||||||
import { createStyles, makeStyles, useTheme } from "@material-ui/styles";
|
import { makeStyles, useTheme } from "@material-ui/styles";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { FormattedMessage } from "react-intl";
|
import { FormattedMessage } from "react-intl";
|
||||||
|
|
||||||
import Filter, { FilterContentSubmitData, IFilter } from "../Filter";
|
import Filter from "../Filter";
|
||||||
|
import FilterActions, { FilterActionsProps } from "../Filter/FilterActions";
|
||||||
import Hr from "../Hr";
|
import Hr from "../Hr";
|
||||||
import Link from "../Link";
|
import Link from "../Link";
|
||||||
|
|
||||||
|
@ -17,38 +17,8 @@ export interface Filter {
|
||||||
onClick: () => void;
|
onClick: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const useInputStyles = makeStyles({
|
|
||||||
input: {
|
|
||||||
padding: "10px 12px"
|
|
||||||
},
|
|
||||||
root: {
|
|
||||||
flex: 1
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const Search: React.FC<TextFieldProps> = props => {
|
|
||||||
const classes = useInputStyles({});
|
|
||||||
return (
|
|
||||||
<TextField
|
|
||||||
{...props}
|
|
||||||
className={classes.root}
|
|
||||||
inputProps={{
|
|
||||||
className: classes.input
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const useStyles = makeStyles(
|
const useStyles = makeStyles(
|
||||||
(theme: Theme) =>
|
(theme: Theme) => ({
|
||||||
createStyles({
|
|
||||||
actionContainer: {
|
|
||||||
display: "flex",
|
|
||||||
flexWrap: "wrap",
|
|
||||||
padding: `${theme.spacing.unit * 2}px ${theme.spacing.unit * 3}px ${
|
|
||||||
theme.spacing.unit
|
|
||||||
}px ${theme.spacing.unit * 3}px`
|
|
||||||
},
|
|
||||||
filterButton: {
|
filterButton: {
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
backgroundColor: fade(theme.palette.primary.main, 0.8),
|
backgroundColor: fade(theme.palette.primary.main, 0.8),
|
||||||
|
@ -105,16 +75,10 @@ const useStyles = makeStyles(
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
interface FilterChipProps<TFilterKeys = string> {
|
interface FilterChipProps extends FilterActionsProps {
|
||||||
currencySymbol: string;
|
|
||||||
menu: IFilter<TFilterKeys>;
|
|
||||||
filtersList: Filter[];
|
filtersList: Filter[];
|
||||||
filterLabel: string;
|
|
||||||
placeholder: string;
|
|
||||||
search: string;
|
search: string;
|
||||||
isCustomSearch: boolean;
|
isCustomSearch: boolean;
|
||||||
onSearchChange: (event: React.ChangeEvent<any>) => void;
|
|
||||||
onFilterAdd: (filter: FilterContentSubmitData<TFilterKeys>) => void;
|
|
||||||
onFilterDelete: () => void;
|
onFilterDelete: () => void;
|
||||||
onFilterSave: () => void;
|
onFilterSave: () => void;
|
||||||
}
|
}
|
||||||
|
@ -137,20 +101,15 @@ export const FilterChips: React.FC<FilterChipProps> = ({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className={classes.actionContainer}>
|
<FilterActions
|
||||||
<Filter
|
|
||||||
currencySymbol={currencySymbol}
|
currencySymbol={currencySymbol}
|
||||||
menu={menu}
|
menu={menu}
|
||||||
filterLabel={filterLabel}
|
filterLabel={filterLabel}
|
||||||
|
placeholder={placeholder}
|
||||||
|
search={search}
|
||||||
|
onSearchChange={onSearchChange}
|
||||||
onFilterAdd={onFilterAdd}
|
onFilterAdd={onFilterAdd}
|
||||||
/>
|
/>
|
||||||
<Search
|
|
||||||
fullWidth
|
|
||||||
placeholder={placeholder}
|
|
||||||
value={search}
|
|
||||||
onChange={onSearchChange}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
{search || (filtersList && filtersList.length) ? (
|
{search || (filtersList && filtersList.length) ? (
|
||||||
<div className={classes.filterContainer}>
|
<div className={classes.filterContainer}>
|
||||||
<div className={classes.filterChipContainer}>
|
<div className={classes.filterChipContainer}>
|
||||||
|
|
|
@ -3,7 +3,9 @@ import {
|
||||||
FetchMoreProps,
|
FetchMoreProps,
|
||||||
FilterPageProps,
|
FilterPageProps,
|
||||||
ListActions,
|
ListActions,
|
||||||
PageListProps
|
PageListProps,
|
||||||
|
SearchPageProps,
|
||||||
|
TabPageProps
|
||||||
} from "./types";
|
} from "./types";
|
||||||
|
|
||||||
const pageInfo = {
|
const pageInfo = {
|
||||||
|
@ -46,23 +48,26 @@ export const countries = [
|
||||||
{ code: "AS", label: "American Samoa" }
|
{ code: "AS", label: "American Samoa" }
|
||||||
];
|
];
|
||||||
|
|
||||||
export const filterPageProps: FilterPageProps<{}, unknown> = {
|
export const tabPageProps: TabPageProps = {
|
||||||
currencySymbol: "USD",
|
|
||||||
currentTab: 0,
|
currentTab: 0,
|
||||||
filterTabs: [
|
|
||||||
{
|
|
||||||
data: {},
|
|
||||||
name: "Tab X"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
filtersList: [],
|
|
||||||
initialSearch: "",
|
|
||||||
onAll: () => undefined,
|
onAll: () => undefined,
|
||||||
onFilterAdd: () => undefined,
|
onTabChange: () => undefined,
|
||||||
onFilterDelete: () => undefined,
|
onTabDelete: () => undefined,
|
||||||
onFilterSave: () => undefined,
|
onTabSave: () => undefined,
|
||||||
onSearchChange: () => undefined,
|
tabs: ["Tab X"]
|
||||||
onTabChange: () => undefined
|
};
|
||||||
|
|
||||||
|
export const searchPageProps: SearchPageProps = {
|
||||||
|
initialSearch: "",
|
||||||
|
onSearchChange: () => undefined
|
||||||
|
};
|
||||||
|
|
||||||
|
export const filterPageProps: FilterPageProps = {
|
||||||
|
...searchPageProps,
|
||||||
|
...tabPageProps,
|
||||||
|
currencySymbol: "USD",
|
||||||
|
filtersList: [],
|
||||||
|
onFilterAdd: () => undefined
|
||||||
};
|
};
|
||||||
|
|
||||||
export const filters: Filter[] = [
|
export const filters: Filter[] = [
|
||||||
|
|
|
@ -8,9 +8,8 @@ import FilterBar from "@saleor/components/FilterBar";
|
||||||
import TimezoneContext from "@saleor/components/Timezone";
|
import TimezoneContext from "@saleor/components/Timezone";
|
||||||
import { FilterProps } from "../../../types";
|
import { FilterProps } from "../../../types";
|
||||||
import { OrderStatusFilter } from "../../../types/globalTypes";
|
import { OrderStatusFilter } from "../../../types/globalTypes";
|
||||||
import { OrderListUrlFilters } from "../../urls";
|
|
||||||
|
|
||||||
type OrderListFilterProps = FilterProps<OrderListUrlFilters, OrderFilterKeys>;
|
type OrderListFilterProps = FilterProps;
|
||||||
|
|
||||||
export enum OrderFilterKeys {
|
export enum OrderFilterKeys {
|
||||||
date = "date",
|
date = "date",
|
||||||
|
|
|
@ -10,14 +10,13 @@ import { sectionNames } from "@saleor/intl";
|
||||||
import { OrderFilterKeys } from "@saleor/orders/components/OrderListFilter";
|
import { OrderFilterKeys } from "@saleor/orders/components/OrderListFilter";
|
||||||
import { FilterPageProps, ListActions, PageListProps } from "@saleor/types";
|
import { FilterPageProps, ListActions, PageListProps } from "@saleor/types";
|
||||||
import { OrderList_orders_edges_node } from "../../types/OrderList";
|
import { OrderList_orders_edges_node } from "../../types/OrderList";
|
||||||
import { OrderListUrlFilters } from "../../urls";
|
|
||||||
import OrderList from "../OrderList";
|
import OrderList from "../OrderList";
|
||||||
import OrderListFilter from "../OrderListFilter";
|
import OrderListFilter from "../OrderListFilter";
|
||||||
|
|
||||||
export interface OrderListPageProps
|
export interface OrderListPageProps
|
||||||
extends PageListProps,
|
extends PageListProps,
|
||||||
ListActions,
|
ListActions,
|
||||||
FilterPageProps<OrderListUrlFilters, OrderFilterKeys> {
|
FilterPageProps {
|
||||||
orders: OrderList_orders_edges_node[];
|
orders: OrderList_orders_edges_node[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,8 +24,8 @@ const OrderListPage: React.FC<OrderListPageProps> = ({
|
||||||
currencySymbol,
|
currencySymbol,
|
||||||
currentTab,
|
currentTab,
|
||||||
filtersList,
|
filtersList,
|
||||||
filterTabs,
|
|
||||||
initialSearch,
|
initialSearch,
|
||||||
|
tabs,
|
||||||
onAdd,
|
onAdd,
|
||||||
onAll,
|
onAll,
|
||||||
onSearchChange,
|
onSearchChange,
|
||||||
|
@ -59,7 +58,7 @@ const OrderListPage: React.FC<OrderListPageProps> = ({
|
||||||
filterLabel={intl.formatMessage({
|
filterLabel={intl.formatMessage({
|
||||||
defaultMessage: "Select all orders where:"
|
defaultMessage: "Select all orders where:"
|
||||||
})}
|
})}
|
||||||
filterTabs={filterTabs}
|
filterTabs={tabs}
|
||||||
filtersList={filtersList}
|
filtersList={filtersList}
|
||||||
initialSearch={initialSearch}
|
initialSearch={initialSearch}
|
||||||
searchPlaceholder={intl.formatMessage({
|
searchPlaceholder={intl.formatMessage({
|
||||||
|
|
|
@ -8,7 +8,8 @@ import {
|
||||||
Filters,
|
Filters,
|
||||||
FiltersWithMultipleValues,
|
FiltersWithMultipleValues,
|
||||||
Pagination,
|
Pagination,
|
||||||
SingleAction
|
SingleAction,
|
||||||
|
TabActionDialog
|
||||||
} from "../types";
|
} from "../types";
|
||||||
|
|
||||||
const orderSectionUrl = "/orders";
|
const orderSectionUrl = "/orders";
|
||||||
|
@ -25,7 +26,7 @@ export enum OrderListUrlFiltersWithMultipleValuesEnum {
|
||||||
}
|
}
|
||||||
export type OrderListUrlFilters = Filters<OrderListUrlFiltersEnum> &
|
export type OrderListUrlFilters = Filters<OrderListUrlFiltersEnum> &
|
||||||
FiltersWithMultipleValues<OrderListUrlFiltersWithMultipleValuesEnum>;
|
FiltersWithMultipleValues<OrderListUrlFiltersWithMultipleValuesEnum>;
|
||||||
export type OrderListUrlDialog = "cancel" | "save-search" | "delete-search";
|
export type OrderListUrlDialog = "cancel" | TabActionDialog;
|
||||||
export type OrderListUrlQueryParams = BulkAction &
|
export type OrderListUrlQueryParams = BulkAction &
|
||||||
Dialog<OrderListUrlDialog> &
|
Dialog<OrderListUrlDialog> &
|
||||||
OrderListUrlFilters &
|
OrderListUrlFilters &
|
||||||
|
|
|
@ -236,7 +236,7 @@ export const OrderList: React.StatelessComponent<OrderListProps> = ({
|
||||||
onFilterDelete={() => openModal("delete-search")}
|
onFilterDelete={() => openModal("delete-search")}
|
||||||
onTabChange={handleTabChange}
|
onTabChange={handleTabChange}
|
||||||
initialSearch={params.email || ""}
|
initialSearch={params.email || ""}
|
||||||
filterTabs={getFilterTabs()}
|
filterTabs={getFilterTabs().map(tab => tab.name)}
|
||||||
onAll={() =>
|
onAll={() =>
|
||||||
changeFilters({
|
changeFilters({
|
||||||
status: undefined
|
status: undefined
|
||||||
|
|
|
@ -5,11 +5,10 @@ import { FieldType, IFilter } from "@saleor/components/Filter";
|
||||||
import FilterBar from "@saleor/components/FilterBar";
|
import FilterBar from "@saleor/components/FilterBar";
|
||||||
import { FilterProps } from "@saleor/types";
|
import { FilterProps } from "@saleor/types";
|
||||||
import { StockAvailability } from "@saleor/types/globalTypes";
|
import { StockAvailability } from "@saleor/types/globalTypes";
|
||||||
import { ProductListUrlFilters } from "../../urls";
|
|
||||||
|
|
||||||
type ProductListFilterProps = FilterProps<
|
type ProductListFilterProps = Omit<
|
||||||
ProductListUrlFilters,
|
FilterProps,
|
||||||
ProductFilterKeys
|
"allTabLabel" | "filterLabel" | "searchPlaceholder"
|
||||||
>;
|
>;
|
||||||
|
|
||||||
export enum ProductFilterKeys {
|
export enum ProductFilterKeys {
|
||||||
|
@ -133,7 +132,22 @@ const ProductListFilter: React.FC<ProductListFilterProps> = props => {
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
return <FilterBar {...props} filterMenu={filterMenu} />;
|
return (
|
||||||
|
<FilterBar
|
||||||
|
{...props}
|
||||||
|
allTabLabel={intl.formatMessage({
|
||||||
|
defaultMessage: "All Products",
|
||||||
|
description: "tab name"
|
||||||
|
})}
|
||||||
|
filterMenu={filterMenu}
|
||||||
|
filterLabel={intl.formatMessage({
|
||||||
|
defaultMessage: "Select all products where:"
|
||||||
|
})}
|
||||||
|
searchPlaceholder={intl.formatMessage({
|
||||||
|
defaultMessage: "Search Products..."
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
ProductListFilter.displayName = "ProductListFilter";
|
ProductListFilter.displayName = "ProductListFilter";
|
||||||
export default ProductListFilter;
|
export default ProductListFilter;
|
||||||
|
|
|
@ -24,14 +24,13 @@ import {
|
||||||
ListActions,
|
ListActions,
|
||||||
PageListProps
|
PageListProps
|
||||||
} from "@saleor/types";
|
} from "@saleor/types";
|
||||||
import { ProductListUrlFilters } from "../../urls";
|
|
||||||
import ProductList from "../ProductList";
|
import ProductList from "../ProductList";
|
||||||
import ProductListFilter, { ProductFilterKeys } from "../ProductListFilter";
|
import ProductListFilter, { ProductFilterKeys } from "../ProductListFilter";
|
||||||
|
|
||||||
export interface ProductListPageProps
|
export interface ProductListPageProps
|
||||||
extends PageListProps<ProductListColumns>,
|
extends PageListProps<ProductListColumns>,
|
||||||
ListActions,
|
ListActions,
|
||||||
FilterPageProps<ProductListUrlFilters, ProductFilterKeys>,
|
FilterPageProps,
|
||||||
FetchMoreProps {
|
FetchMoreProps {
|
||||||
availableInGridAttributes: AvailableInGridAttributes_availableInGrid_edges_node[];
|
availableInGridAttributes: AvailableInGridAttributes_availableInGrid_edges_node[];
|
||||||
currencySymbol: string;
|
currencySymbol: string;
|
||||||
|
@ -52,13 +51,13 @@ export const ProductListPage: React.FC<ProductListPageProps> = props => {
|
||||||
currentTab,
|
currentTab,
|
||||||
defaultSettings,
|
defaultSettings,
|
||||||
filtersList,
|
filtersList,
|
||||||
filterTabs,
|
|
||||||
gridAttributes,
|
gridAttributes,
|
||||||
availableInGridAttributes,
|
availableInGridAttributes,
|
||||||
hasMore,
|
hasMore,
|
||||||
initialSearch,
|
initialSearch,
|
||||||
loading,
|
loading,
|
||||||
settings,
|
settings,
|
||||||
|
tabs,
|
||||||
totalGridAttributes,
|
totalGridAttributes,
|
||||||
onAdd,
|
onAdd,
|
||||||
onAll,
|
onAll,
|
||||||
|
@ -137,21 +136,11 @@ export const ProductListPage: React.FC<ProductListPageProps> = props => {
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
<Card>
|
<Card>
|
||||||
<ProductListFilter
|
<ProductListFilter
|
||||||
allTabLabel={intl.formatMessage({
|
|
||||||
defaultMessage: "All Products",
|
|
||||||
description: "tab name"
|
|
||||||
})}
|
|
||||||
currencySymbol={currencySymbol}
|
currencySymbol={currencySymbol}
|
||||||
currentTab={currentTab}
|
currentTab={currentTab}
|
||||||
filterLabel={intl.formatMessage({
|
|
||||||
defaultMessage: "Select all products where:"
|
|
||||||
})}
|
|
||||||
filterTabs={filterTabs}
|
|
||||||
filtersList={filtersList}
|
filtersList={filtersList}
|
||||||
initialSearch={initialSearch}
|
initialSearch={initialSearch}
|
||||||
searchPlaceholder={intl.formatMessage({
|
tabs={tabs}
|
||||||
defaultMessage: "Search Products..."
|
|
||||||
})}
|
|
||||||
onAll={onAll}
|
onAll={onAll}
|
||||||
onSearchChange={onSearchChange}
|
onSearchChange={onSearchChange}
|
||||||
onFilterAdd={onFilterAdd}
|
onFilterAdd={onFilterAdd}
|
||||||
|
|
|
@ -1,7 +1,14 @@
|
||||||
import { stringify as stringifyQs } from "qs";
|
import { stringify as stringifyQs } from "qs";
|
||||||
import urlJoin from "url-join";
|
import urlJoin from "url-join";
|
||||||
|
|
||||||
import { ActiveTab, BulkAction, Dialog, Filters, Pagination } from "../types";
|
import {
|
||||||
|
ActiveTab,
|
||||||
|
BulkAction,
|
||||||
|
Dialog,
|
||||||
|
Filters,
|
||||||
|
Pagination,
|
||||||
|
TabActionDialog
|
||||||
|
} from "../types";
|
||||||
|
|
||||||
const productSection = "/products/";
|
const productSection = "/products/";
|
||||||
|
|
||||||
|
@ -13,8 +20,7 @@ export type ProductListUrlDialog =
|
||||||
| "publish"
|
| "publish"
|
||||||
| "unpublish"
|
| "unpublish"
|
||||||
| "delete"
|
| "delete"
|
||||||
| "save-search"
|
| TabActionDialog;
|
||||||
| "delete-search";
|
|
||||||
export enum ProductListUrlFiltersEnum {
|
export enum ProductListUrlFiltersEnum {
|
||||||
isPublished = "isPublished",
|
isPublished = "isPublished",
|
||||||
priceFrom = "priceFrom",
|
priceFrom = "priceFrom",
|
||||||
|
|
|
@ -355,7 +355,7 @@ export const ProductList: React.StatelessComponent<ProductListProps> = ({
|
||||||
onFilterDelete={() => openModal("delete-search")}
|
onFilterDelete={() => openModal("delete-search")}
|
||||||
onTabChange={handleTabChange}
|
onTabChange={handleTabChange}
|
||||||
initialSearch={params.query || ""}
|
initialSearch={params.query || ""}
|
||||||
filterTabs={getFilterTabs()}
|
tabs={getFilterTabs().map(tab => tab.name)}
|
||||||
/>
|
/>
|
||||||
<ActionDialog
|
<ActionDialog
|
||||||
open={params.action === "delete"}
|
open={params.action === "delete"}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { defineMessages, IntlShape } from "react-intl";
|
import { defineMessages, IntlShape } from "react-intl";
|
||||||
|
|
||||||
import { FilterContentSubmitData } from "../../../components/Filter";
|
import { FilterContentSubmitData } from "../../../components/Filter";
|
||||||
import { Filter } from "../../../components/TableFilter";
|
import { Filter } from "../../../components/TableFilter";
|
||||||
import {
|
import {
|
||||||
|
|
37
src/types.ts
37
src/types.ts
|
@ -2,7 +2,6 @@ import { MutationResult } from "react-apollo";
|
||||||
|
|
||||||
import { FilterContentSubmitData } from "./components/Filter";
|
import { FilterContentSubmitData } from "./components/Filter";
|
||||||
import { Filter } from "./components/TableFilter";
|
import { Filter } from "./components/TableFilter";
|
||||||
import { GetFilterTabsOutput } from "./utils/filters";
|
|
||||||
|
|
||||||
export interface UserError {
|
export interface UserError {
|
||||||
field: string;
|
field: string;
|
||||||
|
@ -65,24 +64,32 @@ export interface PageListProps<TColumns extends string = string>
|
||||||
defaultSettings?: ListSettings<TColumns>;
|
defaultSettings?: ListSettings<TColumns>;
|
||||||
onAdd: () => void;
|
onAdd: () => void;
|
||||||
}
|
}
|
||||||
export interface FilterPageProps<TUrlFilters, TFilterKeys> {
|
|
||||||
currencySymbol: string;
|
export interface SearchPageProps {
|
||||||
currentTab: number;
|
|
||||||
filterTabs: GetFilterTabsOutput<TUrlFilters>;
|
|
||||||
filtersList: Filter[];
|
|
||||||
initialSearch: string;
|
initialSearch: string;
|
||||||
onAll: () => void;
|
|
||||||
onSearchChange: (value: string) => void;
|
onSearchChange: (value: string) => void;
|
||||||
onFilterAdd: (filter: FilterContentSubmitData<TFilterKeys>) => void;
|
|
||||||
onFilterDelete: () => void;
|
|
||||||
onFilterSave: () => void;
|
|
||||||
onTabChange: (tab: number) => void;
|
|
||||||
}
|
}
|
||||||
export interface FilterProps<TUrlFilters, TFilterKeys>
|
export interface FilterPageProps extends SearchPageProps, TabPageProps {
|
||||||
extends FilterPageProps<TUrlFilters, TFilterKeys> {
|
currencySymbol: string;
|
||||||
|
filtersList: Filter[];
|
||||||
|
onFilterAdd: (filter: FilterContentSubmitData) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SearchProps {
|
||||||
|
searchPlaceholder: string;
|
||||||
|
}
|
||||||
|
export interface FilterProps extends FilterPageProps, SearchProps {
|
||||||
allTabLabel: string;
|
allTabLabel: string;
|
||||||
filterLabel: string;
|
filterLabel: string;
|
||||||
searchPlaceholder: string;
|
}
|
||||||
|
|
||||||
|
export interface TabPageProps {
|
||||||
|
currentTab: number;
|
||||||
|
tabs: string[];
|
||||||
|
onAll: () => void;
|
||||||
|
onTabChange: (tab: number) => void;
|
||||||
|
onTabDelete: () => void;
|
||||||
|
onTabSave: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PartialMutationProviderOutput<
|
export interface PartialMutationProviderOutput<
|
||||||
|
@ -134,3 +141,5 @@ export interface FetchMoreProps {
|
||||||
hasMore: boolean;
|
hasMore: boolean;
|
||||||
onFetchMore: () => void;
|
onFetchMore: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type TabActionDialog = "save-search" | "delete-search";
|
||||||
|
|
Loading…
Reference in a new issue