Skip to content

Commit

Permalink
Introduce discount rule context (#4642)
Browse files Browse the repository at this point in the history
* Refactor rule model

* Add changeset

* Add discount type component

* Add type to initial form values

* Bump macaw

* Refactor Add button

* Update test

* Refactor DiscountRule isLoaded

* Add type support

* Remve useeffect

* Add changeset

* Extract messages

* Init context

* Context intro

* Remove empty import

* Fix tests, fix useDiscountRulesContext imports

* Add changeset
  • Loading branch information
poulch authored Jan 30, 2024
1 parent 9fae33f commit a423387
Show file tree
Hide file tree
Showing 17 changed files with 145 additions and 85 deletions.
5 changes: 5 additions & 0 deletions .changeset/clever-humans-compare.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"saleor-dashboard": minor
---

Introduce discount context
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { Rule } from "@dashboard/discounts/models";
import { sortRules } from "@dashboard/discounts/utils";
import {} from "@dashboard/graphql";
import { useEffect, useState } from "react";

export const useRulesHandlers = (
Expand Down
24 changes: 20 additions & 4 deletions src/discounts/components/DiscountRules/DiscountRules.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { Rule } from "@dashboard/discounts/models";
import { ChannelFragment, RewardValueTypeEnum } from "@dashboard/graphql";
import { ThemeProvider as LegacyThemeProvider } from "@saleor/macaw-ui";
import { ThemeProvider } from "@saleor/macaw-ui-next";
import { act, render, screen } from "@testing-library/react";
import { act, render, screen, waitFor } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import React, { ReactNode } from "react";

Expand Down Expand Up @@ -148,7 +148,7 @@ describe("DiscountRules", () => {
).toBeInTheDocument();
});

it("should render discount rules", () => {
it("should render discount rules", async () => {
// Arrange & Act
render(
<DiscountRules
Expand All @@ -165,6 +165,12 @@ describe("DiscountRules", () => {
{ wrapper: Wrapper },
);

await waitFor(() => {
expect(
screen.getByText(/catalog rule: catalog rule 2/i),
).toBeInTheDocument();
});

// Assert
expect(
screen.getByText(/catalog rule: catalog rule 2/i),
Expand Down Expand Up @@ -197,6 +203,12 @@ describe("DiscountRules", () => {
{ wrapper: Wrapper },
);

await waitFor(() => {
expect(
screen.getByRole("button", { name: /add rule/i }),
).toBeInTheDocument();
});

// Act
await act(async () => {
await userEvent.click(screen.getByRole("button", { name: /add rule/i }));
Expand Down Expand Up @@ -238,8 +250,8 @@ describe("DiscountRules", () => {
},
conditions: [
{
type: "is",
id: "product",
type: "is",
value: [
{
label: "Apple Juice",
Expand Down Expand Up @@ -312,6 +324,10 @@ describe("DiscountRules", () => {
{ wrapper: Wrapper },
);

await waitFor(() => {
expect(screen.getAllByTestId("rule-edit-button")[0]).toBeInTheDocument();
});

// Act
await act(async () => {
await userEvent.click(screen.getAllByTestId("rule-edit-button")[0]);
Expand Down Expand Up @@ -344,8 +360,8 @@ describe("DiscountRules", () => {
},
conditions: [
{
type: "is",
id: "product",
type: "is",
value: [
{
label: "Product-1",
Expand Down
79 changes: 43 additions & 36 deletions src/discounts/components/DiscountRules/DiscountRules.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { AddButton } from "./componenets/AddButton";
import { RuleDeleteModal } from "./componenets/RuleDeleteModal/RuleDeleteModal";
import { RuleFormModal } from "./componenets/RuleFormModal";
import { RulesList } from "./componenets/RulesList";
import { DiscountRulesContextProvider } from "./context";
import { messages } from "./messages";

export type DiscountRulesErrors<ErrorCode> = Array<
Expand Down Expand Up @@ -84,43 +85,49 @@ export const DiscountRules = <ErrorCode,>({
};

return (
<DashboardCard marginBottom={20}>
<DashboardCard.Title>
<Box display="flex" justifyContent="space-between" alignItems="center">
{intl.formatMessage(messages.title)}
<AddButton disabled={disabled} onClick={() => setIsModalOpen(true)} />
</Box>
</DashboardCard.Title>
<DashboardCard.Content>
<RulesList
disabled={disabled}
loading={!isLoaded || loading}
rules={rules}
onRuleEdit={handleRuleEdit}
onRuleDelete={handleOpenRuleDeleteModal}
channels={channels}
errors={errors}
/>
</DashboardCard.Content>
<DiscountRulesContextProvider
discountType="catalog"
channels={channels}
disabled={disabled}
>
<DashboardCard marginBottom={20}>
<DashboardCard.Title>
<Box
display="flex"
justifyContent="space-between"
alignItems="center"
>
{intl.formatMessage(messages.title)}
<AddButton onClick={() => setIsModalOpen(true)} />
</Box>
</DashboardCard.Title>
<DashboardCard.Content>
<RulesList
loading={!isLoaded || loading}
rules={rules}
onRuleEdit={handleRuleEdit}
onRuleDelete={handleOpenRuleDeleteModal}
errors={errors}
/>
</DashboardCard.Content>

{isModalOpen && (
<RuleFormModal
disabled={disabled}
confimButtonState={getRuleConfirmButtonState(ruleEditIndex)}
onClose={handleRuleModalClose}
channels={channels}
initialFormValues={ruleInitialValues}
errors={errors}
onSubmit={handleRuleModalSubmit}
/>
)}
{isModalOpen && (
<RuleFormModal
confimButtonState={getRuleConfirmButtonState(ruleEditIndex)}
onClose={handleRuleModalClose}
initialFormValues={ruleInitialValues}
errors={errors}
onSubmit={handleRuleModalSubmit}
/>
)}

<RuleDeleteModal
open={ruleDeleteIndex !== null}
onClose={() => setRuleDeleteIndex(null)}
onSubmit={handleRuleDelete}
confimButtonState={deleteButtonState}
/>
</DashboardCard>
<RuleDeleteModal
open={ruleDeleteIndex !== null}
onClose={() => setRuleDeleteIndex(null)}
onSubmit={handleRuleDelete}
confimButtonState={deleteButtonState}
/>
</DashboardCard>
</DiscountRulesContextProvider>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,16 @@ import { Button, PlusIcon } from "@saleor/macaw-ui-next";
import React from "react";
import { useIntl } from "react-intl";

import { useDiscountRulesContext } from "../../context";
import { messages } from "../../messages";

interface AddButtonProps {
onClick: () => void;
disabled?: boolean;
}

export const AddButton = ({ onClick, disabled }: AddButtonProps) => {
export const AddButton = ({ onClick }: AddButtonProps) => {
const intl = useIntl();
const { disabled = false } = useDiscountRulesContext();

return (
<Button
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import {
createEmptyCodition,
Rule as RuleType,
} from "@dashboard/discounts/models";
import { ChannelFragment, RewardValueTypeEnum } from "@dashboard/graphql";
import { RewardValueTypeEnum } from "@dashboard/graphql";
import { commonMessages } from "@dashboard/intl";
import { getFormErrors } from "@dashboard/utils/errors";
import {
Expand All @@ -17,6 +17,7 @@ import { useController, useFormContext } from "react-hook-form";
import { useIntl } from "react-intl";

import { ConditionType } from "../../../../types";
import { useDiscountRulesContext } from "../../context";
import { getCurencySymbol } from "../../utils";
import { FetchOptions } from "./components/RuleConditionRow";
import { RuleConditions } from "./components/RuleConditions";
Expand All @@ -25,19 +26,16 @@ import { RuleInputWrapper } from "./components/RuleInputWrapper/RuleInputWrapper
import { RuleReward } from "./components/RuleReward";

interface RuleFormProps<ErrorCode> {
channels: ChannelFragment[];
disabled?: boolean;
errors: Array<CommonError<ErrorCode>>;
typeToFetchMap: Record<ConditionType, FetchOptions>;
}

export const RuleForm = <ErrorCode,>({
channels,
disabled = false,
errors,
typeToFetchMap,
}: RuleFormProps<ErrorCode>) => {
const intl = useIntl();
const { disabled, channels } = useDiscountRulesContext();
const { watch, getValues, setValue, formState } = useFormContext<RuleType>();
const formErrors = getFormErrors(["rewardValue"], errors);

Expand Down Expand Up @@ -118,18 +116,16 @@ export const RuleForm = <ErrorCode,>({
</Box>

<RuleConditions
disabled={disabled}
hasSelectedChannels={hasSelectedChannel}
typeToFetchMap={typeToFetchMap}
/>

<RuleReward
disabled={disabled}
currencySymbol={currencySymbol}
error={getCommonFormFieldErrorMessage(formErrors.rewardValue, intl)}
/>

<RuleDescription disabled={disabled} />
<RuleDescription />

<button type="submit" hidden>
Submit
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { useDiscountRulesContext } from "@dashboard/discounts/components/DiscountRules/context";
import { RewardValueTypeEnum } from "@dashboard/graphql";
import { Box, Switch, Text } from "@saleor/macaw-ui-next";
import React from "react";

interface DiscountTypeSwitchProps {
disabled?: boolean;
selected: RewardValueTypeEnum;
currencySymbol: string | null;
onChange: (type: string) => void;
Expand All @@ -14,9 +14,10 @@ const PERCENT_SYMBOL = "%";
export const DiscountTypeSwitch = ({
selected,
currencySymbol,
disabled,
onChange,
}: DiscountTypeSwitchProps) => {
const { disabled } = useDiscountRulesContext();

return (
<Switch
disabled={disabled}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Combobox, Multiselect } from "@dashboard/components/Combobox";
import { useDiscountRulesContext } from "@dashboard/discounts/components/DiscountRules/context";
import { Condition, isArrayOfOptions, Rule } from "@dashboard/discounts/models";
import { ConditionType } from "@dashboard/discounts/types";
import { getSearchFetchMoreProps } from "@dashboard/hooks/makeTopLevelSearch/utils";
Expand All @@ -17,7 +18,6 @@ export interface FetchOptions {
options: Option[];
}
interface DiscountConditionRowProps {
disabled?: boolean;
conditionIndex: number;
onRemove: () => void;
updateCondition: (index: number, value: Condition) => void;
Expand All @@ -31,9 +31,9 @@ export const RuleConditionRow = ({
typeToFetchMap,
isConditionTypeSelected,
updateCondition,
disabled = false,
}: DiscountConditionRowProps) => {
const intl = useIntl();
const { disabled } = useDiscountRulesContext();

const ruleConditionTypeFieldName = `conditions.${conditionIndex}.id` as const;
const { field: typeField } = useController<
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { useDiscountRulesContext } from "@dashboard/discounts/components/DiscountRules/context";
import { createEmptyCodition, Rule } from "@dashboard/discounts/models";
import { ConditionType } from "@dashboard/discounts/types";
import { Box, Button, Text } from "@saleor/macaw-ui-next";
Expand All @@ -16,11 +17,11 @@ interface RuleConditionsProps {
}

export const RuleConditions = ({
disabled = false,
hasSelectedChannels,
typeToFetchMap,
}: RuleConditionsProps) => {
const intl = useIntl();
const { disabled } = useDiscountRulesContext();

const { watch } = useFormContext<Rule>();

Expand Down Expand Up @@ -76,7 +77,6 @@ export const RuleConditions = ({
{fields.map((condition, conditionIndex) => (
<RuleConditionRow
key={condition.id || conditionIndex}
disabled={disabled}
typeToFetchMap={typeToFetchMap}
isConditionTypeSelected={isConditionTypeSelected}
conditionIndex={conditionIndex}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import RichTextEditor from "@dashboard/components/RichTextEditor";
import { RichTextEditorLoading } from "@dashboard/components/RichTextEditor/RichTextEditorLoading";
import { useDiscountRulesContext } from "@dashboard/discounts/components/DiscountRules/context";
import { Rule } from "@dashboard/discounts/models";
import { commonMessages } from "@dashboard/intl";
import { useRichTextContext } from "@dashboard/utils/richText/context";
Expand All @@ -11,15 +12,12 @@ import { useIntl } from "react-intl";
import { RuleInputWrapper } from "../RuleInputWrapper/RuleInputWrapper";

interface RuleDescriptionProps {
disabled?: boolean;
error?: boolean;
}

export const RuleDescription = ({
disabled = false,
error = false,
}: RuleDescriptionProps) => {
export const RuleDescription = ({ error = false }: RuleDescriptionProps) => {
const intl = useIntl();
const { disabled } = useDiscountRulesContext();
const { defaultValue, editorRef, isReadyForMount, handleChange } =
useRichTextContext();

Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { useDiscountRulesContext } from "@dashboard/discounts/components/DiscountRules/context";
import { Rule } from "@dashboard/discounts/models";
import { Box, Input, Text } from "@saleor/macaw-ui-next";
import React from "react";
Expand All @@ -9,17 +10,13 @@ import { DiscountTypeSwitch } from "../DiscountTypeSwitch";
import { RuleInputWrapper } from "../RuleInputWrapper/RuleInputWrapper";

interface RuleRewardProps {
disabled?: boolean;
currencySymbol: string | null;
error: string | undefined;
}

export const RuleReward = ({
currencySymbol,
disabled,
error,
}: RuleRewardProps) => {
export const RuleReward = ({ currencySymbol, error }: RuleRewardProps) => {
const intl = useIntl();
const { disabled } = useDiscountRulesContext();
const { watch, formState } = useFormContext<Rule>();
const { field: rewardTypeField } = useController<Rule, "rewardValueType">({
name: "rewardValueType",
Expand All @@ -35,7 +32,6 @@ export const RuleReward = ({
<Text as="p">{intl.formatMessage(messages.reward)}</Text>
<Box display="flex" gap={4}>
<DiscountTypeSwitch
disabled={disabled}
onChange={type => rewardTypeField.onChange(type)}
selected={discountType}
currencySymbol={currencySymbol}
Expand Down
Loading

0 comments on commit a423387

Please sign in to comment.