Merge pull request #180 from mirumee/add/attribute-sort

Allow sorting products by attribute
This commit is contained in:
Marcin Gębala 2019-09-30 14:36:54 +02:00 committed by GitHub
commit eb0f60cc88
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 456 additions and 38 deletions

View file

@ -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

File diff suppressed because it is too large Load diff

View file

@ -480,5 +480,8 @@ export function findInEnum<TEnum extends object>(
}
export function parseBoolean(a: string): boolean {
if (a === undefined) {
return true;
}
return a === "true";
}

View file

@ -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
{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 =>
getAttributeIdFromColumnValue(
gridAttributeFromSettings
) === gridAttribute.id
gridAttribute => attributeId === gridAttribute.id
).name,
<Skeleton />
)}
</TableCell>
))}
</TableCellHeader>
);
})}
<DisplayColumn column="price" displayColumns={settings.columns}>
<TableCellHeader
className={classes.colPrice}

View file

@ -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[];

View file

@ -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);

View file

@ -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(

View file

@ -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)

View file

@ -34,6 +34,7 @@ const props: ProductListPageProps = {
sort: ProductListUrlSortField.name
}
},
activeAttributeSortId: undefined,
availableInGridAttributes: attributes,
defaultSettings: defaultListSettings[ListViews.PRODUCT_LIST],
gridAttributes: attributes,

View file

@ -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;

View file

@ -589,7 +589,8 @@ export interface ProductFilterInput {
}
export interface ProductOrder {
field: ProductOrderField;
field?: ProductOrderField | null;
attributeId?: string | null;
direction: OrderDirection;
}