Skip to content

Commit d0cb8ef

Browse files
authored
Fix deleting server-side voucher codes (#6504)
* Fix deleting voucher codes * Add changeset * Use ActionButton instead of ConfirmButton for the async confirmation * Fix typo * Drop the custom getMutationTransitionState * Fix failing imports in tests
1 parent cb8679d commit d0cb8ef

18 files changed

Lines changed: 223 additions & 98 deletions

File tree

.changeset/curly-hoops-take.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"saleor-dashboard": patch
3+
---
4+
5+
Fix deleting saved, server-side Voucher codes

locale/defaultMessages.json

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1135,9 +1135,6 @@
11351135
"context": "Charge in progress transaction amount, data display header",
11361136
"string": "Pending charge"
11371137
},
1138-
"4gJAm6": {
1139-
"string": "Can't delete saved codes"
1140-
},
11411138
"4hl9rS": {
11421139
"context": "variant price in channel",
11431140
"string": "Price"
@@ -5563,6 +5560,9 @@
55635560
"context": "dialog subheading",
55645561
"string": "Create a manual transaction for non-integrated payments"
55655562
},
5563+
"TV940D": {
5564+
"string": "{count, plural, one {# voucher code deleted} other {# voucher codes deleted}}"
5565+
},
55665566
"TVR4E6": {
55675567
"string": "Open playground"
55685568
},
@@ -6396,6 +6396,9 @@
63966396
"context": "app extensions subsection",
63976397
"string": "Apps"
63986398
},
6399+
"Y8XVvH": {
6400+
"string": "Failed to delete voucher codes"
6401+
},
63996402
"Y9lv8z": {
64006403
"context": "product unavailability",
64016404
"string": "Unavailable for purchase"

src/discounts/components/VoucherCodes/VoucherCodes.test.tsx

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import userEvent from "@testing-library/user-event";
99
import { type ReactNode } from "react";
1010
import { BrowserRouter } from "react-router-dom";
1111

12-
import { type VoucherCode } from "../VoucherCodesDatagrid/types";
12+
import { VOUCHER_CODE_DRAFT_STATUS, type VoucherCode } from "../VoucherCodesDatagrid/types";
1313
import { VoucherCodes, type VoucherCodesProps } from "./VoucherCodes";
1414

1515
jest.mock("@dashboard/components/Datagrid/persistance/usePersistance", () => ({
@@ -36,7 +36,8 @@ const renderVoucherCodes = (props: Partial<VoucherCodesProps>) => {
3636
codes={[]}
3737
loading={false}
3838
onCustomCodeGenerate={jest.fn()}
39-
onDeleteCodes={jest.fn()}
39+
onDeleteCodes={jest.fn().mockResolvedValue(undefined)}
40+
deleteCodesTransitionState="default"
4041
onMultiCodesGenerate={jest.fn()}
4142
onSelectVoucherCodesIds={jest.fn()}
4243
onSettingsChange={jest.fn()}
@@ -99,8 +100,8 @@ describe("VoucherCodes", () => {
99100
// Assert
100101
expect(screen.getByRole("progressbar")).toBeInTheDocument();
101102
});
102-
it("should not allow to delete selected codes when contains saved codes", async () => {
103-
// Arrange & Act
103+
it("should allow to delete selected saved codes", async () => {
104+
// Arrange
104105
const onDeleteCodes = jest.fn();
105106

106107
renderVoucherCodes({
@@ -111,22 +112,35 @@ describe("VoucherCodes", () => {
111112

112113
const deleteButton = screen.getByTestId("bulk-delete-button");
113114

115+
// Act
116+
await act(async () => {
117+
await userEvent.click(deleteButton);
118+
});
119+
// Assert
120+
expect(await screen.findByRole("dialog")).toBeInTheDocument();
121+
expect(
122+
await screen.findByText(/are you sure you want to delete these voucher codes?/i),
123+
).toBeInTheDocument();
124+
// Act
125+
await act(async () => {
126+
await userEvent.click(screen.getByRole("button", { name: /delete/i }));
127+
});
114128
// Assert
115-
expect(deleteButton).toBeDisabled();
129+
expect(onDeleteCodes).toBeCalled();
116130
});
117-
it("should allow to delete selected codes when selected only draft codes", async () => {
131+
it("should allow to delete selected draft codes", async () => {
118132
// Arrange
119133
const onDeleteCodes = jest.fn();
120134

121135
renderVoucherCodes({
122136
onDeleteCodes,
123137
codes: [
124138
...codes,
125-
{ code: "Manual code 1", status: "Draft" },
126-
{ code: "Manual code 2", status: "Draft" },
127-
{ code: "Manual code 3", status: "Draft" },
139+
{ code: "Manual code 1", status: VOUCHER_CODE_DRAFT_STATUS },
140+
{ code: "Manual code 2", status: VOUCHER_CODE_DRAFT_STATUS },
141+
{ code: "Manual code 3", status: VOUCHER_CODE_DRAFT_STATUS },
128142
],
129-
selectedCodesIds: ["Manual code 1", "Manual code 1"],
143+
selectedCodesIds: ["Manual code 1", "Manual code 2"],
130144
});
131145

132146
const deleteButton = screen.getByTestId("bulk-delete-button");

src/discounts/components/VoucherCodes/VoucherCodes.tsx

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { BulkDeleteButton } from "@dashboard/components/BulkDeleteButton";
2+
import { type ConfirmButtonTransitionState } from "@dashboard/components/ConfirmButton";
23
import { type UseListSettings } from "@dashboard/hooks/useListSettings";
34
import { type LocalPagination } from "@dashboard/hooks/useLocalPaginator";
45
import { PaginatorContext } from "@dashboard/hooks/usePaginator";
@@ -15,13 +16,13 @@ import {
1516
} from "../VoucherCodesGenerateDialog";
1617
import { VoucherCodesManualDialog } from "../VoucherCodesManualDialog";
1718
import { type VoucherCodesUrlDialog } from "./types";
18-
import { hasSavedVoucherCodesToDelete } from "./utils";
1919

2020
export interface VoucherCodesProps extends VoucherCodesDatagridProps {
2121
selectedCodesIds: string[];
2222
voucherCodesPagination: LocalPagination;
2323
settings: UseListSettings["settings"];
24-
onDeleteCodes: () => void;
24+
deleteCodesTransitionState: ConfirmButtonTransitionState;
25+
onDeleteCodes: () => Promise<void>;
2526
onSelectVoucherCodesIds: (rows: number[], clearSelection: () => void) => void;
2627
onSettingsChange: UseListSettings["updateListSettings"];
2728
onMultiCodesGenerate: (data: GenerateMultipleVoucherCodeFormData) => void;
@@ -33,12 +34,12 @@ export const VoucherCodes = ({
3334
onMultiCodesGenerate,
3435
onCustomCodeGenerate,
3536
onDeleteCodes,
37+
deleteCodesTransitionState,
3638
voucherCodesPagination,
3739
...datagridProps
3840
}: VoucherCodesProps) => {
3941
const { pageInfo, ...paginationValues } = voucherCodesPagination;
4042
const [openModal, setOpenModal] = useState<VoucherCodesUrlDialog | null>(null);
41-
const hasSavedCodesToDelete = hasSavedVoucherCodesToDelete(selectedCodesIds, datagridProps.codes);
4243
const closeModal = () => {
4344
setOpenModal(null);
4445
};
@@ -59,15 +60,8 @@ export const VoucherCodes = ({
5960
</Text>
6061
<Box display="flex" gap={3}>
6162
{selectedCodesIds.length > 0 && (
62-
<BulkDeleteButton
63-
disabled={hasSavedCodesToDelete}
64-
onClick={() => setOpenModal("delete-codes")}
65-
>
66-
{hasSavedCodesToDelete ? (
67-
<FormattedMessage defaultMessage="Can't delete saved codes" id="4gJAm6" />
68-
) : (
69-
<FormattedMessage defaultMessage="Delete codes" id="UJ97Lb" />
70-
)}
63+
<BulkDeleteButton onClick={() => setOpenModal("delete-codes")}>
64+
<FormattedMessage defaultMessage="Delete codes" id="UJ97Lb" />
7165
</BulkDeleteButton>
7266
)}
7367
<VoucherCodesAddButton
@@ -94,6 +88,7 @@ export const VoucherCodes = ({
9488
<VoucherCodesDeleteDialog
9589
onClose={closeModal}
9690
open={openModal === "delete-codes"}
91+
confirmButtonTransitionState={deleteCodesTransitionState}
9792
onDelete={onDeleteCodes}
9893
/>
9994
</>

src/discounts/components/VoucherCodes/utils.test.ts

Lines changed: 0 additions & 48 deletions
This file was deleted.

src/discounts/components/VoucherCodes/utils.ts

Lines changed: 0 additions & 12 deletions
This file was deleted.

src/discounts/components/VoucherCodesDatagrid/types.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1+
export const VOUCHER_CODE_DRAFT_STATUS = "Draft";
2+
13
export interface VoucherCode {
4+
id?: string;
25
code: string;
36
used?: number;
47
status?: string;

src/discounts/components/VoucherCodesDeleteDialog/VoucherCodesDeleteDialog.tsx

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,29 @@
1+
import {
2+
ConfirmButton,
3+
type ConfirmButtonTransitionState,
4+
} from "@dashboard/components/ConfirmButton";
15
import { DashboardModal } from "@dashboard/components/Modal";
26
import { buttonMessages } from "@dashboard/intl";
37
import { Button, Text } from "@saleor/macaw-ui-next";
48
import { FormattedMessage, useIntl } from "react-intl";
59

610
interface VoucherCodesDeleteDialogProps {
711
open: boolean;
12+
confirmButtonTransitionState: ConfirmButtonTransitionState;
813
onClose: () => void;
9-
onDelete: () => void;
14+
onDelete: () => Promise<void>;
1015
}
1116

1217
export const VoucherCodesDeleteDialog = ({
1318
open,
19+
confirmButtonTransitionState,
1420
onClose,
1521
onDelete,
1622
}: VoucherCodesDeleteDialogProps) => {
1723
const intl = useIntl();
24+
const isDeleting = confirmButtonTransitionState === "loading";
1825
const handleSubmit = async () => {
19-
onDelete();
26+
await onDelete();
2027
onClose();
2128
};
2229

@@ -35,11 +42,18 @@ export const VoucherCodesDeleteDialog = ({
3542
</Text>
3643

3744
<DashboardModal.Actions>
38-
<Button onClick={onClose} variant="secondary">
45+
<Button onClick={onClose} variant="secondary" disabled={isDeleting}>
3946
{intl.formatMessage(buttonMessages.back)}
4047
</Button>
4148

42-
<Button onClick={handleSubmit}>{intl.formatMessage(buttonMessages.delete)}</Button>
49+
<ConfirmButton
50+
transitionState={confirmButtonTransitionState}
51+
onClick={handleSubmit}
52+
variant="error"
53+
data-test-id="submit"
54+
>
55+
{intl.formatMessage(buttonMessages.delete)}
56+
</ConfirmButton>
4357
</DashboardModal.Actions>
4458
</DashboardModal.Content>
4559
</DashboardModal>

src/discounts/components/VoucherCreatePage/VoucherCreatePage.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ const VoucherCreatePage = ({
193193
});
194194
};
195195

196-
const handleDeleteVoucherCodes = () => {
196+
const handleDeleteVoucherCodes = async () => {
197197
clearRowSelection();
198198
set({
199199
codes: data.codes.filter(({ code }) => !selectedRowIds.includes(code)),
@@ -283,6 +283,7 @@ const VoucherCreatePage = ({
283283
<VoucherCodes
284284
codes={paginatedCodes}
285285
onDeleteCodes={handleDeleteVoucherCodes}
286+
deleteCodesTransitionState="default"
286287
onMultiCodesGenerate={handleGenerateMultipleCodes}
287288
onSelectVoucherCodesIds={setSelectedVoucherCodesIds}
288289
onSettingsChange={onSettingsChange}

src/discounts/components/VoucherDetailsPage/VoucherDetailsPage.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,8 @@ interface VoucherDetailsPageProps
128128
openChannelsModal: () => void;
129129
onMultipleVoucherCodesGenerate: (data: GenerateMultipleVoucherCodeFormData) => void;
130130
onCustomVoucherCodeGenerate: (code: string) => void;
131-
onDeleteVoucherCodes: () => void;
131+
deleteVoucherCodesTransitionState: ConfirmButtonTransitionState;
132+
onDeleteVoucherCodes: () => Promise<void>;
132133
onVoucherCodesSettingsChange: UseListSettings["updateListSettings"];
133134
voucherCodesPagination: LocalPagination;
134135
voucherCodesSettings: UseListSettings["settings"];
@@ -164,6 +165,7 @@ const VoucherDetailsPage: React.FC<VoucherDetailsPageProps> = ({
164165
onRemove,
165166
onMultipleVoucherCodesGenerate,
166167
onCustomVoucherCodeGenerate,
168+
deleteVoucherCodesTransitionState,
167169
onDeleteVoucherCodes,
168170
onSubmit,
169171
toggle,
@@ -288,6 +290,7 @@ const VoucherDetailsPage: React.FC<VoucherDetailsPageProps> = ({
288290
selectedCodesIds={selectedVoucherCodesIds}
289291
onSelectVoucherCodesIds={onSelectVoucherCodesIds}
290292
onDeleteCodes={onDeleteVoucherCodes}
293+
deleteCodesTransitionState={deleteVoucherCodesTransitionState}
291294
loading={voucherCodesLoading}
292295
onMultiCodesGenerate={codes => {
293296
triggerChange();

0 commit comments

Comments
 (0)