Skip to content

Commit

Permalink
Migrate gift card modals to new macaw-ui (#5114)
Browse files Browse the repository at this point in the history
* migrate gift card modals to new macaw-ui

* fix e2e tests

* migrate export component

* fix tests

* update macaw-ui

* fix tests

* fix style

* fix product test

* fix text-area selector

* fix e2e tests

* cr fixes

* cleanup

* cr fixes

* add tests

* radiogroup cleanup

* show component migration

---------

Co-authored-by: Paweł Chyła <[email protected]>
  • Loading branch information
Cloud11PL and poulch committed Sep 4, 2024
1 parent 7624638 commit ece769a
Show file tree
Hide file tree
Showing 27 changed files with 347 additions and 303 deletions.
5 changes: 5 additions & 0 deletions .changeset/poor-queens-doubt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"saleor-dashboard": patch
---

The gift card modals now use new macaw-ui components.
12 changes: 8 additions & 4 deletions playwright/pages/dialogs/issueGiftCardDialog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ export class IssueGiftCardDialog extends BasePage {
readonly giftCardExpireFields = page.getByTestId("gift-card-expire-data-fields"),
readonly sendToCustomerCheckbox = page
.getByTestId("send-to-customer-section")
.locator('input[type="checkbox"]'),
readonly sendExpireDateCheckbox = page.getByTestId("expiry-section").locator("input"),
.locator('button[role="checkbox"]'),
readonly sendExpireDateCheckbox = page.getByTestId("expiry-section").locator("button"),
readonly customerInput = page.getByTestId("customer-field"),
readonly noteTextArea = page.getByTestId("note-field").locator('[name="note"]'),
readonly noteTextArea = page.getByTestId("note-field"),
readonly requiresActivationCheckbox = page
.getByTestId("requires-activation-section")
.locator("input"),
.locator('button[role="checkbox"]'),
readonly issueButton = page.getByTestId("submit"),
readonly okButton = page.getByTestId("submit"),
readonly copyCodeButton = page.getByTestId("copy-code-button"),
Expand Down Expand Up @@ -94,4 +94,8 @@ export class IssueGiftCardDialog extends BasePage {

return allTexts[0];
}

async blur() {
await this.page.click("[data-test-id='gift-card-dialog']");
}
}
4 changes: 4 additions & 0 deletions playwright/pages/dialogs/resendGiftCardCodeDialog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ export class ResendGiftCardCodeDialog {
this.page = page;
}

async blur() {
await this.page.keyboard.press("Tab");
}

async clickResendButton() {
await this.resendButton.click();
await this.resendButton.waitFor({ state: "hidden" });
Expand Down
4 changes: 3 additions & 1 deletion playwright/pages/giftCardsPage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@ export class GiftCardsPage extends BasePage {
readonly resendCodeButton = page.getByTestId("resend-code"),
readonly deactivateButton = page.getByTestId("enable-button"),
readonly saveButton = page.getByTestId("button-bar-confirm"),
readonly cardExpiresCheckboxOnModal = page.getByTestId("expiry-section").locator("input"),
readonly cardExpiresCheckboxOnModal = page
.getByTestId("expiry-section")
.locator('button[role="checkbox"]'),
readonly giftCardExpiresCheckbox = page
.getByTestId("gift-card-expire-section")
.locator("input"),
Expand Down
4 changes: 4 additions & 0 deletions playwright/tests/giftCards.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ test("TC: SALEOR_105 Issue gift card @e2e @gift", async () => {
await giftCardsPage.clickIssueCardButton();
await giftCardsPage.issueGiftCardDialog.typeAmount("50");
await giftCardsPage.issueGiftCardDialog.typeCustomTag("super ultra automation discount");
await giftCardsPage.issueGiftCardDialog.blur();
await giftCardsPage.issueGiftCardDialog.clickRequiresActivationCheckbox();
await giftCardsPage.issueGiftCardDialog.clickIssueButton();
await expect(giftCardsPage.issueGiftCardDialog.cardCode).toBeVisible();
Expand Down Expand Up @@ -68,6 +69,9 @@ test("TC: SALEOR_106 Issue gift card with specific customer and expiry date @e2e
test("TC: SALEOR_107 Resend code @e2e @gift", async () => {
await giftCardsPage.clickListRowBasedOnContainingText(GIFT_CARDS.giftCardToResendCode.name);
await giftCardsPage.clickResendCodeButton();
// This is a workaround for the issue with the dropdown focusing on dialog open
// Dropdown can cover the resend button and cause test to fail
await giftCardsPage.resendGiftCardCodeDialog.blur();
await giftCardsPage.resendGiftCardCodeDialog.clickResendButton();
await giftCardsPage.expectSuccessBanner();
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
// @ts-strict-ignore
import { ChannelData } from "@dashboard/channels/utils";
import { DateTimeTimezoneField } from "@dashboard/components/DateTimeTimezoneField";
import { RadioGroup } from "@dashboard/components/RadioGroup";
import { StopPropagation } from "@dashboard/components/StopPropagation";
import useCurrentDate from "@dashboard/hooks/useCurrentDate";
import useDateLocalize from "@dashboard/hooks/useDateLocalize";
import { getFormErrors, getProductErrorMessage } from "@dashboard/utils/errors";
import { Box, Checkbox, Divider, Text } from "@saleor/macaw-ui-next";
import { Box, Checkbox, Divider, RadioGroup, Text } from "@saleor/macaw-ui-next";
import React, { useState } from "react";
import { useIntl } from "react-intl";

Expand Down Expand Up @@ -56,41 +56,48 @@ export const ChannelAvailabilityItemContent: React.FC<ChannelContentProps> = ({

return (
<Box display="flex" gap={3} paddingTop={3} flexDirection="column">
<RadioGroup
value={String(isPublished)}
onValueChange={value => {
onChange(id, {
...formData,
isPublished: value === "true",
publishedAt: value === "false" ? null : publishedAt,
});
}}
disabled={disabled}
display="flex"
flexDirection="column"
gap={3}
>
<RadioGroup.Item id={`${id}-isPublished-true`} value="true" name="isPublished">
<Box display="flex" alignItems="baseline" gap={2}>
<Text>{messages.visibleLabel}</Text>
{isPublished && publishedAt && Date.parse(publishedAt) < dateNow && (
<Text size={2} color="default2">
{messages.visibleSecondLabel || visibleMessage(publishedAt)}
</Text>
)}
</Box>
</RadioGroup.Item>
<RadioGroup.Item id={`${id}-isPublished-false`} value="false" name="isPublished">
<Box display="flex" alignItems="baseline" gap={2}>
<Text>{messages.hiddenLabel}</Text>
{publishedAt && !isPublished && Date.parse(publishedAt) >= dateNow && (
<Text size={2} color="default2">
{messages.hiddenSecondLabel}
</Text>
)}
</Box>
</RadioGroup.Item>
</RadioGroup>
{/**
* StopPropagation is used here to block onClick events from RadioGroup that cause throw error in datagrid
* Datagrid listing for all on click event but RadioGroup emitted couple of events at once
* Radix issue: https://github.com/radix-ui/primitives/issues/1982
*/}
<StopPropagation>
<RadioGroup
value={String(isPublished)}
onValueChange={value => {
onChange(id, {
...formData,
isPublished: value === "true",
publishedAt: value === "false" ? null : publishedAt,
});
}}
disabled={disabled}
display="flex"
flexDirection="column"
gap={3}
>
<RadioGroup.Item id={`${id}-isPublished-true`} value="true" name="isPublished">
<Box display="flex" alignItems="baseline" gap={2}>
<Text>{messages.visibleLabel}</Text>
{isPublished && publishedAt && Date.parse(publishedAt) < dateNow && (
<Text size={2} color="default2">
{messages.visibleSecondLabel || visibleMessage(publishedAt)}
</Text>
)}
</Box>
</RadioGroup.Item>
<RadioGroup.Item id={`${id}-isPublished-false`} value="false" name="isPublished">
<Box display="flex" alignItems="baseline" gap={2}>
<Text>{messages.hiddenLabel}</Text>
{publishedAt && !isPublished && Date.parse(publishedAt) >= dateNow && (
<Text size={2} color="default2">
{messages.hiddenSecondLabel}
</Text>
)}
</Box>
</RadioGroup.Item>
</RadioGroup>
</StopPropagation>
{!isPublished && (
<Box display="flex" flexDirection="column" alignItems="start" gap={1}>
<Checkbox
Expand Down
19 changes: 0 additions & 19 deletions src/components/RadioGroup/RadioGroup.tsx

This file was deleted.

1 change: 0 additions & 1 deletion src/components/RadioGroup/index.ts

This file was deleted.

3 changes: 3 additions & 0 deletions src/components/RadioGroupField/RadioGroupField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import clsx from "clsx";
import React from "react";
import { FormattedMessage } from "react-intl";

import { SimpleRadioGroupField } from "../SimpleRadioGroupField";
import { useStyles } from "./styles";

export interface RadioGroupFieldChoice<T extends string | number = string | number> {
Expand All @@ -34,6 +35,8 @@ interface RadioGroupFieldProps {
onChange: (event: React.ChangeEvent<any>) => void;
}

export const NewRadioGroupField = SimpleRadioGroupField;

export const RadioGroupField: React.FC<RadioGroupFieldProps> = props => {
const {
alignTop,
Expand Down
98 changes: 98 additions & 0 deletions src/components/SimpleRadioGroupField.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import "@testing-library/jest-dom/extend-expect";

import { fireEvent, render, screen } from "@testing-library/react";
import React from "react";

import { SimpleRadioGroupField } from "./SimpleRadioGroupField";

const choices = [
{ label: "Choice 1", value: "choice1" },
{ label: "Choice 2", value: "choice2", disabled: true },
{ label: "Choice 3", value: "choice3" },
];

describe("SimpleRadioGroupField", () => {
it("renders radio fields correctly", () => {
// Arrange & Act
render(
<SimpleRadioGroupField
name="testRadioGroup"
value="choice1"
onChange={jest.fn()}
choices={choices}
/>,
);

// Assert
expect(screen.getByText("Choice 1")).toBeInTheDocument();
expect(screen.getByText("Choice 2")).toBeInTheDocument();
expect(screen.getByText("Choice 3")).toBeInTheDocument();
});

it("calls onChange when a radio button is clicked", () => {
// Arrange
const handleChange = jest.fn();

render(
<SimpleRadioGroupField
name="testRadioGroup"
value="choice1"
onChange={handleChange}
choices={choices}
/>,
);

// Act
const radioButton = screen.getByLabelText("Choice 3");

fireEvent.click(radioButton);

// Assert
expect(handleChange).toHaveBeenCalledWith({
target: { value: "choice3", name: "testRadioGroup" },
});
});

it("doesn't call onChange when `disabled` item is clicked", () => {
// Arrange
const handleChange = jest.fn();

render(
<SimpleRadioGroupField
name="testRadioGroup"
value="choice1"
onChange={handleChange}
choices={choices}
/>,
);

// Act
const radioButton = screen.getByLabelText("Choice 2");

fireEvent.click(radioButton);

// Assert
expect(handleChange).not.toHaveBeenCalledWith({
target: { value: "choice2", name: "testRadioGroup" },
});
});

it("displays the error message when provided", () => {
// Arrange & Act
const errorMessage = "Error message";

render(
<SimpleRadioGroupField
name="testRadioGroup"
value="choice1"
onChange={jest.fn()}
choices={choices}
errorMessage={errorMessage}
error
/>,
);

// Assert
expect(screen.getByText(errorMessage)).toBeInTheDocument();
});
});
64 changes: 64 additions & 0 deletions src/components/SimpleRadioGroupField.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { ChangeEvent } from "@dashboard/hooks/useForm";
import { RadioGroup, RadioGroupRootProps, Text } from "@saleor/macaw-ui-next";
import React from "react";

type RadioGroupFieldChoice = {
label: string | React.ReactNode;
value: string;
disabled?: boolean;
};

interface SimpleRadioGroupFieldProps
extends Omit<RadioGroupRootProps, "onChange" | "children" | "name"> {
name: string;
onChange: (event: ChangeEvent) => void;
choices: RadioGroupFieldChoice[];
size?: RadioGroupRootProps["size"];
errorMessage?: string;
}

// SimpleRadioGroupField is a migration of RadioGroupField "@dashboard/components/RadioGroupField" using Macaw UI
// While migrating to this component note that it doesn't have a label, hint or 'no choices' message.
export const SimpleRadioGroupField: React.FC<SimpleRadioGroupFieldProps> = ({
name,
value,
error,
onChange,
choices,
size = "large",
errorMessage,
...props
}) => {
return (
<>
<RadioGroup
size={size}
value={value}
name={name}
error={error}
onValueChange={value => onChange({ target: { value, name } })}
{...props}
>
{choices.map(({ label, value, disabled }) => (
<RadioGroup.Item
key={value}
value={value}
id={value}
disabled={disabled}
marginBottom={2}
data-test-id={value}
>
<Text
color={disabled ? "defaultDisabled" : "default1"}
style={{ verticalAlign: "middle" }}
>
{label}
</Text>
</RadioGroup.Item>
))}
</RadioGroup>

{errorMessage && <Text color="critical1">{errorMessage}</Text>}
</>
);
};
Loading

0 comments on commit ece769a

Please sign in to comment.