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 - Add testcafe tags to attributes, categories, collections and product types - #178 by @dominik-zeglen
- Fix input error style - #183 by @benekex2 - Fix input error style - #183 by @benekex2
- Fix staff return link - #190 by @dominik-zeglen - 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 { export function parseBoolean(a: string): boolean {
if (a === undefined) {
return true;
}
return a === "true"; return a === "true";
} }

View file

@ -101,12 +101,14 @@ interface ProductListProps
ListActions, ListActions,
SortPage<ProductListUrlSortField>, SortPage<ProductListUrlSortField>,
WithStyles<typeof styles> { WithStyles<typeof styles> {
activeAttributeSortId: string;
gridAttributes: AvailableInGridAttributes_grid_edges_node[]; gridAttributes: AvailableInGridAttributes_grid_edges_node[];
products: ProductList_products_edges_node[]; products: ProductList_products_edges_node[];
} }
export const ProductList = withStyles(styles, { name: "ProductList" })( export const ProductList = withStyles(styles, { name: "ProductList" })(
({ ({
activeAttributeSortId,
classes, classes,
settings, settings,
disabled, disabled,
@ -219,23 +221,35 @@ export const ProductList = withStyles(styles, { name: "ProductList" })(
/> />
</TableCellHeader> </TableCellHeader>
</DisplayColumn> </DisplayColumn>
{gridAttributesFromSettings.map(gridAttributeFromSettings => ( {gridAttributesFromSettings.map(gridAttributeFromSettings => {
<TableCell const attributeId = getAttributeIdFromColumnValue(
className={classes.colAttribute} gridAttributeFromSettings
key={gridAttributeFromSettings} );
>
{maybe<React.ReactNode>( return (
() => <TableCellHeader
gridAttributes.find( className={classes.colAttribute}
gridAttribute => direction={
getAttributeIdFromColumnValue( sort.sort === ProductListUrlSortField.attribute &&
gridAttributeFromSettings attributeId === activeAttributeSortId
) === gridAttribute.id ? getArrowDirection(sort.asc)
).name, : undefined
<Skeleton /> }
)} onClick={() =>
</TableCell> onSort(ProductListUrlSortField.attribute, attributeId)
))} }
key={gridAttributeFromSettings}
>
{maybe<React.ReactNode>(
() =>
gridAttributes.find(
gridAttribute => attributeId === gridAttribute.id
).name,
<Skeleton />
)}
</TableCellHeader>
);
})}
<DisplayColumn column="price" displayColumns={settings.columns}> <DisplayColumn column="price" displayColumns={settings.columns}>
<TableCellHeader <TableCellHeader
className={classes.colPrice} className={classes.colPrice}

View file

@ -34,6 +34,7 @@ export interface ProductListPageProps
FilterPageProps<ProductFilterKeys>, FilterPageProps<ProductFilterKeys>,
FetchMoreProps, FetchMoreProps,
SortPage<ProductListUrlSortField> { SortPage<ProductListUrlSortField> {
activeAttributeSortId: string;
availableInGridAttributes: AvailableInGridAttributes_availableInGrid_edges_node[]; availableInGridAttributes: AvailableInGridAttributes_availableInGrid_edges_node[];
currencySymbol: string; currencySymbol: string;
gridAttributes: AvailableInGridAttributes_grid_edges_node[]; gridAttributes: AvailableInGridAttributes_grid_edges_node[];

View file

@ -31,18 +31,22 @@ export enum ProductListUrlFiltersEnum {
} }
export type ProductListUrlFilters = Filters<ProductListUrlFiltersEnum>; export type ProductListUrlFilters = Filters<ProductListUrlFiltersEnum>;
export enum ProductListUrlSortField { export enum ProductListUrlSortField {
attribute = "attribute",
name = "name", name = "name",
productType = "productType", productType = "productType",
status = "status", status = "status",
price = "price" price = "price"
} }
export type ProductListUrlSort = Sort<ProductListUrlSortField>; export type ProductListUrlSort = Sort<ProductListUrlSortField>;
export type ProductListUrlQueryParams = BulkAction & export interface ProductListUrlQueryParams
Dialog<ProductListUrlDialog> & extends BulkAction,
ProductListUrlFilters & Dialog<ProductListUrlDialog>,
ProductListUrlSort & ProductListUrlFilters,
Pagination & ProductListUrlSort,
ActiveTab; Pagination,
ActiveTab {
attributeId?: string;
}
export const productListUrl = (params?: ProductListUrlQueryParams): string => export const productListUrl = (params?: ProductListUrlQueryParams): string =>
productListPath + "?" + stringifyQs(params); productListPath + "?" + stringifyQs(params);

View file

@ -42,6 +42,7 @@ import {
ProductListUrlDialog, ProductListUrlDialog,
ProductListUrlFilters, ProductListUrlFilters,
ProductListUrlQueryParams, ProductListUrlQueryParams,
ProductListUrlSortField,
productUrl productUrl
} from "../../urls"; } from "../../urls";
import { import {
@ -153,6 +154,15 @@ export const ProductList: React.StatelessComponent<ProductListProps> = ({
handleTabChange(tabs.length + 1); handleTabChange(tabs.length + 1);
}; };
const handleSort = (field: ProductListUrlSortField, attributeId?: string) =>
navigate(
productListUrl({
...params,
...getSortUrlVariables(field, params),
attributeId
})
);
const paginationState = createPaginationState(settings.rowNumber, params); const paginationState = createPaginationState(settings.rowNumber, params);
const currencySymbol = maybe(() => shop.defaultCurrency, "USD"); const currencySymbol = maybe(() => shop.defaultCurrency, "USD");
const filter = getFilterVariables(params); const filter = getFilterVariables(params);
@ -230,18 +240,12 @@ export const ProductList: React.StatelessComponent<ProductListProps> = ({
return ( return (
<> <>
<ProductListPage <ProductListPage
activeAttributeSortId={params.attributeId}
sort={{ sort={{
asc: params.asc, asc: params.asc,
sort: params.sort sort: params.sort
}} }}
onSort={field => onSort={handleSort}
navigate(
productListUrl({
...params,
...getSortUrlVariables(field, params)
})
)
}
availableInGridAttributes={maybe( availableInGridAttributes={maybe(
() => () =>
attributes.data.availableInGrid.edges.map( attributes.data.availableInGrid.edges.map(

View file

@ -17,12 +17,20 @@ export function getSortQueryField(
return ProductOrderField.TYPE; return ProductOrderField.TYPE;
case ProductListUrlSortField.status: case ProductListUrlSortField.status:
return ProductOrderField.PUBLISHED; return ProductOrderField.PUBLISHED;
default:
return undefined;
} }
} }
export function getSortQueryVariables( export function getSortQueryVariables(
params: ProductListUrlQueryParams params: ProductListUrlQueryParams
): ProductOrder { ): ProductOrder {
if (params.sort === ProductListUrlSortField.attribute) {
return {
attributeId: params.attributeId,
direction: getOrderDirection(params.asc)
};
}
return { return {
direction: getOrderDirection(params.asc), direction: getOrderDirection(params.asc),
field: getSortQueryField(params.sort) field: getSortQueryField(params.sort)

View file

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

View file

@ -50,7 +50,7 @@ export interface ListProps<TColumns extends string = string> {
export interface SortPage<TSortKey extends string> { export interface SortPage<TSortKey extends string> {
sort: Sort<TSortKey>; sort: Sort<TSortKey>;
onSort: (field: TSortKey) => void; onSort: (field: TSortKey, id?: string) => void;
} }
export interface ListActionsWithoutToolbar { export interface ListActionsWithoutToolbar {
toggle: (id: string) => void; toggle: (id: string) => void;

View file

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