Skip to content

Commit

Permalink
Introduce filters to discount list page (#4594)
Browse files Browse the repository at this point in the history
* Init condition filters

* Filter promotions

* Add get filter from url

* Remove useContainerState

* Fix removable contains

* Update when query change

* Fix type issue

* Add changeset

* Improve filters after CR

* Update left operand test

* asFilterValueFromEmpty

---------

Co-authored-by: Patryk Andrzejewski <vox3r69@gmail.com>
  • Loading branch information
poulch and andrzejewsky committed Jan 12, 2024
1 parent f95e90f commit 27d2a60
Show file tree
Hide file tree
Showing 13 changed files with 166 additions and 29 deletions.
5 changes: 5 additions & 0 deletions .changeset/khaki-cats-smash.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"saleor-dashboard": patch
---

Introduce filters to discount list page
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { FilterAPIProvider } from "@dashboard/components/ConditionalFilter/API/FilterAPIProvider";

export const useDiscountFilterAPIProvider = (): FilterAPIProvider => {
const fetchRightOptions = async () => {
return [];
};

const fetchLeftOptions = async () => {
return [];
};

return {
fetchRightOptions,
fetchLeftOptions,
};
};
3 changes: 2 additions & 1 deletion src/components/ConditionalFilter/UI/constrains.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { Row } from "./types";

export const getItemConstraint = (constraint: Row["constraint"]) => ({
disableRemoveButton: !constraint?.removable,
// eslint-disable-next-line @typescript-eslint/key-spacing, @typescript-eslint/no-unnecessary-boolean-literal-compare
disableRemoveButton: constraint?.removable === false,
disableLeftOperator: constraint?.disabled?.includes("left") ?? false,
disableCondition: constraint?.disabled?.includes("condition") ?? false,
disableRightOperator: constraint?.disabled?.includes("right") ?? false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ const mapToTokens = (urlEntries: Array<ParsedQs | string>): TokenArray =>

const tokenizeUrl = (urlParams: string) => {
const parsedUrl = Object.values(parse(urlParams)) as Array<ParsedQs | string>;

return mapToTokens(parsedUrl);
};

Expand Down Expand Up @@ -98,4 +97,8 @@ export class TokenArray extends Array<string | UrlToken | TokenArray> {
return element;
});
}

public asFilterValueFromEmpty(): FilterContainer {
return this.asFilterValuesFromResponse(InitialStateResponse.empty());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,12 @@ const prepareStructure = (filterValue: FilterContainer): Structure =>
});

export const useUrlValueProvider = (
initialState: InitialAPIState,
locationSearch: string,
initialState?: InitialAPIState,
): FilterValueProvider => {
const router = useRouter();
const params = new URLSearchParams(locationSearch);
const { data, loading, fetchQueries } = initialState;

const [value, setValue] = useState<FilterContainer>([]);

const activeTab = params.get("activeTab");
Expand All @@ -47,14 +47,24 @@ export const useUrlValueProvider = (
const fetchingParams = tokenizedUrl.getFetchingParams();

useEffect(() => {
fetchQueries(fetchingParams);
initialState?.fetchQueries(fetchingParams);
}, [locationSearch]);

useEffect(() => {
if (!initialState) return;

const { data, loading } = initialState;

if (loading) return;

setValue(tokenizedUrl.asFilterValuesFromResponse(data));
}, [data, loading]);
}, [initialState?.data, initialState?.loading]);

useEffect(() => {
if (initialState) return;

setValue(tokenizedUrl.asFilterValueFromEmpty());
}, [locationSearch]);

const persist = (filterValue: FilterContainer) => {
router.history.replace({
Expand Down Expand Up @@ -89,7 +99,7 @@ export const useUrlValueProvider = (

return {
value,
loading,
loading: initialState?.loading || false,
persist,
clear,
isPersisted,
Expand Down
32 changes: 31 additions & 1 deletion src/components/ConditionalFilter/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,16 @@ export const STATIC_CONDITIONS = {
isVisibleInListing: [{ type: "select", label: "is", value: "input-1" }],
hasCategory: [{ type: "select", label: "is", value: "input-1" }],
giftCard: [{ type: "select", label: "is", value: "input-1" }],
startDate: [
{ type: "datetime", label: "lower", value: "input-1" },
{ type: "datetime", label: "greater", value: "input-2" },
{ type: "datetime.range", label: "between", value: "input-3" },
],
endDate: [
{ type: "datetime", label: "lower", value: "input-1" },
{ type: "datetime", label: "greater", value: "input-2" },
{ type: "datetime.range", label: "between", value: "input-3" },
],
};

export const CONSTRAINTS = {
Expand All @@ -34,7 +44,7 @@ export const CONSTRAINTS = {
},
};

export const STATIC_OPTIONS: LeftOperand[] = [
export const STATIC_PRODUCT_OPTIONS: LeftOperand[] = [
{ value: "price", label: "Price", type: "price", slug: "price" },
{ value: "category", label: "Category", type: "category", slug: "category" },
{
Expand Down Expand Up @@ -82,6 +92,26 @@ export const STATIC_OPTIONS: LeftOperand[] = [
},
];

export const STATIC_DISCOUNT_OPTIONS: LeftOperand[] = [
{
value: "startDate",
label: "Start date",
type: "startDate",
slug: "startDate",
},
{
value: "endDate",
label: "End date",
type: "endDate",
slug: "endDate",
},
];

export const STATIC_OPTIONS = [
...STATIC_PRODUCT_OPTIONS,
...STATIC_DISCOUNT_OPTIONS,
];

export const ATTRIBUTE_INPUT_TYPE_CONDITIONS = {
DROPDOWN: [{ type: "multiselect", label: "in", value: "input-2" }],
MULTISELECT: [{ type: "multiselect", label: "in", value: "input-2" }],
Expand Down
33 changes: 31 additions & 2 deletions src/components/ConditionalFilter/context/provider.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import React, { FC } from "react";

import { useDiscountFilterAPIProvider } from "../API/DiscountFiltersAPIProvider";
import { useProductInitialAPIState } from "../API/initialState/useInitialAPIState";
import { useProductFilterAPIProvider } from "../API/ProductFilterAPIProvider";
import { STATIC_DISCOUNT_OPTIONS, STATIC_PRODUCT_OPTIONS } from "../constants";
import { useContainerState } from "../useContainerState";
import { useFilterLeftOperandsProvider } from "../useFilterLeftOperands";
import { useUrlValueProvider } from "../ValueProvider/useUrlValueProvider";
Expand All @@ -12,8 +14,35 @@ export const ConditionalProductFilterProvider: FC<{
}> = ({ children, locationSearch }) => {
const apiProvider = useProductFilterAPIProvider();
const initialState = useProductInitialAPIState();
const valueProvider = useUrlValueProvider(initialState, locationSearch);
const leftOperandsProvider = useFilterLeftOperandsProvider();
const valueProvider = useUrlValueProvider(locationSearch, initialState);
const leftOperandsProvider = useFilterLeftOperandsProvider(
STATIC_PRODUCT_OPTIONS,
);
const containerState = useContainerState(valueProvider);

return (
<ConditionalFilterContext.Provider
value={{
apiProvider,
valueProvider,
leftOperandsProvider,
containerState,
}}
>
{children}
</ConditionalFilterContext.Provider>
);
};

export const ConditionalDiscountFilterProvider: FC<{
locationSearch: string;
}> = ({ children, locationSearch }) => {
const apiProvider = useDiscountFilterAPIProvider();

const valueProvider = useUrlValueProvider(locationSearch);
const leftOperandsProvider = useFilterLeftOperandsProvider(
STATIC_DISCOUNT_OPTIONS,
);
const containerState = useContainerState(valueProvider);

return (
Expand Down
16 changes: 16 additions & 0 deletions src/components/ConditionalFilter/queryVariables.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import {
AttributeInput,
DateTimeFilterInput,
DecimalFilterInput,
GlobalIdFilterInput,
ProductWhereInput,
PromotionWhereInput,
} from "@dashboard/graphql";

import { FilterContainer } from "./FilterElement";
Expand Down Expand Up @@ -165,3 +167,17 @@ export const createProductQueryVariables = (
return p;
}, {} as ProductWhereInput);
};

export const creatDiscountsQueryVariables = (
value: FilterContainer,
): PromotionWhereInput => {
return value.reduce((p, c) => {
if (typeof c === "string" || Array.isArray(c)) return p;

p[c.value.value as "endDate" | "startDate"] = createStaticQueryPart(
c.condition.selected,
) as DateTimeFilterInput;

return p;
}, {} as PromotionWhereInput);
};
10 changes: 6 additions & 4 deletions src/components/ConditionalFilter/useFilterLeftOperands.test.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import { AttributeInputTypeEnum } from "@dashboard/graphql";
import { act, renderHook } from "@testing-library/react-hooks";

import { STATIC_OPTIONS } from "./constants";
import { STATIC_PRODUCT_OPTIONS } from "./constants";
import { useFilterLeftOperandsProvider } from "./useFilterLeftOperands";

describe("ConditionalFilter / useFilterLeftOperandsProvider", () => {
it("should set unique operands", () => {
// Arrange
const { result } = renderHook(() => useFilterLeftOperandsProvider());
const { result } = renderHook(() =>
useFilterLeftOperandsProvider(STATIC_PRODUCT_OPTIONS),
);
// Act
act(() => {
result.current.setOperands([
Expand All @@ -21,7 +23,7 @@ describe("ConditionalFilter / useFilterLeftOperandsProvider", () => {
});
// Assert
expect(result.current.operands).toEqual([
...STATIC_OPTIONS,
...STATIC_PRODUCT_OPTIONS,
{ label: "SKU", value: "sku", type: "DROPDOWN", slug: "sku" },
]);
// Act
Expand All @@ -37,7 +39,7 @@ describe("ConditionalFilter / useFilterLeftOperandsProvider", () => {
});
// Assert
expect(result.current.operands).toEqual([
...STATIC_OPTIONS,
...STATIC_PRODUCT_OPTIONS,
{ label: "SKU", value: "sku", type: "DROPDOWN", slug: "sku" },
]);
});
Expand Down
7 changes: 4 additions & 3 deletions src/components/ConditionalFilter/useFilterLeftOperands.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import unionBy from "lodash/unionBy";
import { useState } from "react";

import { STATIC_OPTIONS } from "./constants";
import { LeftOperand, LeftOperandsProvider } from "./LeftOperandsProvider";

export const useFilterLeftOperandsProvider = (): LeftOperandsProvider => {
const [operands, setOperands] = useState<LeftOperand[]>(STATIC_OPTIONS);
export const useFilterLeftOperandsProvider = (
options: LeftOperand[],
): LeftOperandsProvider => {
const [operands, setOperands] = useState<LeftOperand[]>(options);

return {
operands,
Expand Down
34 changes: 24 additions & 10 deletions src/discounts/components/DiscountListPage/DiscountListPage.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { ExpressionFilters } from "@dashboard/components/AppLayout/ListFilters/components/ExpressionFilters";
import { LegacyFiltersPresetsAlert } from "@dashboard/components/AppLayout/ListFilters/components/LegacyFiltersPresetsAlert";
import SearchInput from "@dashboard/components/AppLayout/ListFilters/components/SearchInput";
import { TopNav } from "@dashboard/components/AppLayout/TopNav";
import { DashboardCard } from "@dashboard/components/Card";
Expand Down Expand Up @@ -102,17 +104,29 @@ const DiscountListPage: React.FC<DiscountListPageProps> = ({
</TopNav>

<DashboardCard>
<Box __width="320px" marginLeft={4} marginBottom={2}>
{/* TODO: remove when new fileters will be implemented */}
<SearchInput
initialSearch={initialSearch}
placeholder={intl.formatMessage({
id: "+bhokL",
defaultMessage: "Search discounts...",
})}
onSearchChange={onSearchChange}
/>
<LegacyFiltersPresetsAlert />
<Box
display="grid"
__gridTemplateColumns="auto 1fr"
gap={4}
paddingBottom={2}
paddingX={6}
>
<Box display="flex" alignItems="center" gap={4}>
<ExpressionFilters data-test-id="filters-button" />
<Box __width="320px">
<SearchInput
initialSearch={initialSearch}
placeholder={intl.formatMessage({
id: "+bhokL",
defaultMessage: "Search discounts...",
})}
onSearchChange={onSearchChange}
/>
</Box>
</Box>
</Box>

<DiscountListDatagrid {...listProps} onRowClick={handleRowClick} />
</DashboardCard>
</ListPageLayout>
Expand Down
7 changes: 6 additions & 1 deletion src/discounts/index.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { ConditionalDiscountFilterProvider } from "@dashboard/components/ConditionalFilter";
import { useFlag } from "@dashboard/featureFlags";
import { sectionNames } from "@dashboard/intl";
import { asSortParams } from "@dashboard/utils/sort";
Expand Down Expand Up @@ -45,7 +46,11 @@ const SaleListView: React.FC<RouteComponentProps<{}>> = ({ location }) => {
qs,
DiscountListUrlSortField,
);
return <DiscountList params={params} />;
return (
<ConditionalDiscountFilterProvider locationSearch={location.search}>
<DiscountList params={params} />;
</ConditionalDiscountFilterProvider>
);
}

return <SaleListViewComponent params={params} />;
Expand Down
7 changes: 6 additions & 1 deletion src/discounts/views/DiscountList/DiscountList.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { useConditionalFilterContext } from "@dashboard/components/ConditionalFilter";
import { creatDiscountsQueryVariables } from "@dashboard/components/ConditionalFilter/queryVariables";
import DeleteFilterTabDialog from "@dashboard/components/DeleteFilterTabDialog";
import SaveFilterTabDialog from "@dashboard/components/SaveFilterTabDialog";
import { WindowTitle } from "@dashboard/components/WindowTitle";
Expand Down Expand Up @@ -44,11 +46,15 @@ export const DiscountList: React.FC<DiscountListProps> = ({ params }) => {
usePaginationReset(discountListUrl, params, settings.rowNumber);
const paginationState = createPaginationState(settings.rowNumber, params);

const { valueProvider } = useConditionalFilterContext();
const where = creatDiscountsQueryVariables(valueProvider.value);

const queryVariables = React.useMemo(
() => ({
...paginationState,
sort: getSortQueryVariables(params),
where: {
...where,
...(params?.query && {
name: { eq: params.query },
}),
Expand All @@ -68,7 +74,6 @@ export const DiscountList: React.FC<DiscountListProps> = ({ params }) => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const [_, resetFilters, handleSearchChange] = createFilterHandlers({
createUrl: discountListUrl,
// TODO: implement getFilterQueryParam when new filter will be implemented
getFilterQueryParam: () => 0,
navigate,
params,
Expand Down

0 comments on commit 27d2a60

Please sign in to comment.