Merge pull request #180 from mirumee/add/attribute-sort
Allow sorting products by attribute
This commit is contained in:
commit
eb0f60cc88
11 changed files with 456 additions and 38 deletions
|
@ -28,3 +28,4 @@ All notable, unreleased changes to this project will be documented in this file.
|
|||
- Add testcafe tags to attributes, categories, collections and product types - #178 by @dominik-zeglen
|
||||
- Fix input error style - #183 by @benekex2
|
||||
- Fix staff return link - #190 by @dominik-zeglen
|
||||
- Allow sorting products by attribute - #180 by @dominik-zeglen
|
||||
|
|
391
schema.graphql
391
schema.graphql
File diff suppressed because it is too large
Load diff
|
@ -480,5 +480,8 @@ export function findInEnum<TEnum extends object>(
|
|||
}
|
||||
|
||||
export function parseBoolean(a: string): boolean {
|
||||
if (a === undefined) {
|
||||
return true;
|
||||
}
|
||||
return a === "true";
|
||||
}
|
||||
|
|
|
@ -101,12 +101,14 @@ interface ProductListProps
|
|||
ListActions,
|
||||
SortPage<ProductListUrlSortField>,
|
||||
WithStyles<typeof styles> {
|
||||
activeAttributeSortId: string;
|
||||
gridAttributes: AvailableInGridAttributes_grid_edges_node[];
|
||||
products: ProductList_products_edges_node[];
|
||||
}
|
||||
|
||||
export const ProductList = withStyles(styles, { name: "ProductList" })(
|
||||
({
|
||||
activeAttributeSortId,
|
||||
classes,
|
||||
settings,
|
||||
disabled,
|
||||
|
@ -219,23 +221,35 @@ export const ProductList = withStyles(styles, { name: "ProductList" })(
|
|||
/>
|
||||
</TableCellHeader>
|
||||
</DisplayColumn>
|
||||
{gridAttributesFromSettings.map(gridAttributeFromSettings => (
|
||||
<TableCell
|
||||
className={classes.colAttribute}
|
||||
key={gridAttributeFromSettings}
|
||||
>
|
||||
{maybe<React.ReactNode>(
|
||||
() =>
|
||||
gridAttributes.find(
|
||||
gridAttribute =>
|
||||
getAttributeIdFromColumnValue(
|
||||
gridAttributeFromSettings
|
||||
) === gridAttribute.id
|
||||
).name,
|
||||
<Skeleton />
|
||||
)}
|
||||
</TableCell>
|
||||
))}
|
||||
{gridAttributesFromSettings.map(gridAttributeFromSettings => {
|
||||
const attributeId = getAttributeIdFromColumnValue(
|
||||
gridAttributeFromSettings
|
||||
);
|
||||
|
||||
return (
|
||||
<TableCellHeader
|
||||
className={classes.colAttribute}
|
||||
direction={
|
||||
sort.sort === ProductListUrlSortField.attribute &&
|
||||
attributeId === activeAttributeSortId
|
||||
? getArrowDirection(sort.asc)
|
||||
: undefined
|
||||
}
|
||||
onClick={() =>
|
||||
onSort(ProductListUrlSortField.attribute, attributeId)
|
||||
}
|
||||
key={gridAttributeFromSettings}
|
||||
>
|
||||
{maybe<React.ReactNode>(
|
||||
() =>
|
||||
gridAttributes.find(
|
||||
gridAttribute => attributeId === gridAttribute.id
|
||||
).name,
|
||||
<Skeleton />
|
||||
)}
|
||||
</TableCellHeader>
|
||||
);
|
||||
})}
|
||||
<DisplayColumn column="price" displayColumns={settings.columns}>
|
||||
<TableCellHeader
|
||||
className={classes.colPrice}
|
||||
|
|
|
@ -34,6 +34,7 @@ export interface ProductListPageProps
|
|||
FilterPageProps<ProductFilterKeys>,
|
||||
FetchMoreProps,
|
||||
SortPage<ProductListUrlSortField> {
|
||||
activeAttributeSortId: string;
|
||||
availableInGridAttributes: AvailableInGridAttributes_availableInGrid_edges_node[];
|
||||
currencySymbol: string;
|
||||
gridAttributes: AvailableInGridAttributes_grid_edges_node[];
|
||||
|
|
|
@ -31,18 +31,22 @@ export enum ProductListUrlFiltersEnum {
|
|||
}
|
||||
export type ProductListUrlFilters = Filters<ProductListUrlFiltersEnum>;
|
||||
export enum ProductListUrlSortField {
|
||||
attribute = "attribute",
|
||||
name = "name",
|
||||
productType = "productType",
|
||||
status = "status",
|
||||
price = "price"
|
||||
}
|
||||
export type ProductListUrlSort = Sort<ProductListUrlSortField>;
|
||||
export type ProductListUrlQueryParams = BulkAction &
|
||||
Dialog<ProductListUrlDialog> &
|
||||
ProductListUrlFilters &
|
||||
ProductListUrlSort &
|
||||
Pagination &
|
||||
ActiveTab;
|
||||
export interface ProductListUrlQueryParams
|
||||
extends BulkAction,
|
||||
Dialog<ProductListUrlDialog>,
|
||||
ProductListUrlFilters,
|
||||
ProductListUrlSort,
|
||||
Pagination,
|
||||
ActiveTab {
|
||||
attributeId?: string;
|
||||
}
|
||||
export const productListUrl = (params?: ProductListUrlQueryParams): string =>
|
||||
productListPath + "?" + stringifyQs(params);
|
||||
|
||||
|
|
|
@ -42,6 +42,7 @@ import {
|
|||
ProductListUrlDialog,
|
||||
ProductListUrlFilters,
|
||||
ProductListUrlQueryParams,
|
||||
ProductListUrlSortField,
|
||||
productUrl
|
||||
} from "../../urls";
|
||||
import {
|
||||
|
@ -153,6 +154,15 @@ export const ProductList: React.StatelessComponent<ProductListProps> = ({
|
|||
handleTabChange(tabs.length + 1);
|
||||
};
|
||||
|
||||
const handleSort = (field: ProductListUrlSortField, attributeId?: string) =>
|
||||
navigate(
|
||||
productListUrl({
|
||||
...params,
|
||||
...getSortUrlVariables(field, params),
|
||||
attributeId
|
||||
})
|
||||
);
|
||||
|
||||
const paginationState = createPaginationState(settings.rowNumber, params);
|
||||
const currencySymbol = maybe(() => shop.defaultCurrency, "USD");
|
||||
const filter = getFilterVariables(params);
|
||||
|
@ -230,18 +240,12 @@ export const ProductList: React.StatelessComponent<ProductListProps> = ({
|
|||
return (
|
||||
<>
|
||||
<ProductListPage
|
||||
activeAttributeSortId={params.attributeId}
|
||||
sort={{
|
||||
asc: params.asc,
|
||||
sort: params.sort
|
||||
}}
|
||||
onSort={field =>
|
||||
navigate(
|
||||
productListUrl({
|
||||
...params,
|
||||
...getSortUrlVariables(field, params)
|
||||
})
|
||||
)
|
||||
}
|
||||
onSort={handleSort}
|
||||
availableInGridAttributes={maybe(
|
||||
() =>
|
||||
attributes.data.availableInGrid.edges.map(
|
||||
|
|
|
@ -17,12 +17,20 @@ export function getSortQueryField(
|
|||
return ProductOrderField.TYPE;
|
||||
case ProductListUrlSortField.status:
|
||||
return ProductOrderField.PUBLISHED;
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
export function getSortQueryVariables(
|
||||
params: ProductListUrlQueryParams
|
||||
): ProductOrder {
|
||||
if (params.sort === ProductListUrlSortField.attribute) {
|
||||
return {
|
||||
attributeId: params.attributeId,
|
||||
direction: getOrderDirection(params.asc)
|
||||
};
|
||||
}
|
||||
return {
|
||||
direction: getOrderDirection(params.asc),
|
||||
field: getSortQueryField(params.sort)
|
||||
|
|
|
@ -34,6 +34,7 @@ const props: ProductListPageProps = {
|
|||
sort: ProductListUrlSortField.name
|
||||
}
|
||||
},
|
||||
activeAttributeSortId: undefined,
|
||||
availableInGridAttributes: attributes,
|
||||
defaultSettings: defaultListSettings[ListViews.PRODUCT_LIST],
|
||||
gridAttributes: attributes,
|
||||
|
|
|
@ -50,7 +50,7 @@ export interface ListProps<TColumns extends string = string> {
|
|||
|
||||
export interface SortPage<TSortKey extends string> {
|
||||
sort: Sort<TSortKey>;
|
||||
onSort: (field: TSortKey) => void;
|
||||
onSort: (field: TSortKey, id?: string) => void;
|
||||
}
|
||||
export interface ListActionsWithoutToolbar {
|
||||
toggle: (id: string) => void;
|
||||
|
|
|
@ -589,7 +589,8 @@ export interface ProductFilterInput {
|
|||
}
|
||||
|
||||
export interface ProductOrder {
|
||||
field: ProductOrderField;
|
||||
field?: ProductOrderField | null;
|
||||
attributeId?: string | null;
|
||||
direction: OrderDirection;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue