Skip to content

Commit 6ef0617

Browse files
authored
Adding ability to pass in a ReactNode into the modal body (#205)
* Accepting react node in confirmation modal * adding test * fixing bug * fixing api
1 parent e8a048a commit 6ef0617

File tree

4 files changed

+49
-45
lines changed

4 files changed

+49
-45
lines changed

src/App.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -435,7 +435,7 @@ const App = () => {
435435
<ConfirmationDialog
436436
title="Confirmation Dialog Example"
437437
message="This is a simple dialog that will be reused across the application"
438-
onPrimaryActionClick={() => {
438+
onConfirm={() => {
439439
console.log("close");
440440
}}
441441
>

src/components/ConfirmationDialog/ConfirmationDialog.stories.tsx

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { Link } from "@/components";
21
import { GridCenter } from "../commonElement";
32
import {
43
ConfirmationDialog,
@@ -10,21 +9,20 @@ const ConfirmationDialogComponent = ({
109
title,
1110
message,
1211
primaryActionLabel,
13-
onPrimaryActionClick,
12+
onConfirm,
1413
secondaryActionLabel,
15-
onOpenChange,
14+
onCancel,
1615
}: ConfirmationDialogProps) => (
1716
<GridCenter>
1817
<ConfirmationDialog
1918
open={open}
2019
title={title}
2120
message={message}
22-
onOpenChange={onOpenChange}
21+
onCancel={onCancel}
2322
primaryActionLabel={primaryActionLabel}
24-
onPrimaryActionClick={onPrimaryActionClick}
23+
onConfirm={onConfirm}
2524
secondaryActionLabel={secondaryActionLabel}
2625
>
27-
<Link>Open dialog</Link>
2826
</ConfirmationDialog>
2927
</GridCenter>
3028
);
@@ -50,7 +48,7 @@ export const Playground = {
5048
onOpenChange: (b: boolean) => {
5149
void b;
5250
},
53-
onPrimaryAcyionClick: () => {
51+
onPrimaryActionClick: () => {
5452
console.log("Click");
5553
},
5654
primaryActionLabel: "Confirm",

src/components/ConfirmationDialog/ConfirmationDialog.test.tsx

Lines changed: 22 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,16 @@ import {
44
ConfirmationDialogProps,
55
} from "@/components/ConfirmationDialog/ConfirmationDialog";
66
import { fireEvent } from "@testing-library/dom";
7-
import { Button } from "@/components";
87

98
describe("Dialog Component", () => {
109
const renderDialog = (
1110
{
1211
title = "Dialog Title",
1312
message = "Are you sure you want to proceed?",
14-
onPrimaryActionClick = () => {
13+
onConfirm = () => {
1514
void undefined;
1615
},
17-
onOpenChange,
16+
onCancel,
1817
open,
1918
primaryActionLabel = "Confirm",
2019
secondaryActionLabel = "Cancel",
@@ -25,10 +24,10 @@ describe("Dialog Component", () => {
2524
<ConfirmationDialog
2625
title={title}
2726
message={message}
28-
onPrimaryActionClick={onPrimaryActionClick}
27+
onConfirm={onConfirm}
2928
primaryActionLabel={primaryActionLabel}
3029
secondaryActionLabel={secondaryActionLabel}
31-
onOpenChange={onOpenChange}
30+
onCancel={onCancel}
3231
open={open}
3332
children={children}
3433
/>
@@ -65,40 +64,34 @@ describe("Dialog Component", () => {
6564
it("closes the dialog on primary action click", () => {
6665
const title = "Dialog Title";
6766
const primaryActionLabel = "PrimaryAction";
68-
const triggerLabel = "Open Dialog";
69-
const children = <Button label={triggerLabel} />;
7067

68+
let open = true;
7169
const { getByText, queryAllByText } = renderDialog({
7270
title,
7371
primaryActionLabel,
74-
children,
72+
open,
73+
onCancel: () => open = false
7574
});
7675

77-
const triggerBtn = getByText(triggerLabel);
78-
fireEvent.click(triggerBtn);
7976
expect(queryAllByText(title).length).toEqual(1);
8077
const primaryBtn = getByText(primaryActionLabel);
8178
fireEvent.click(primaryBtn);
82-
expect(queryAllByText(title).length).toEqual(0);
79+
expect(open).toEqual(false);
8380
});
8481

8582
it("executes the primary action on primary action click", () => {
8683
let counter = 0;
8784
const title = "Dialog Title";
8885
const primaryActionLabel = "PrimaryAction";
89-
const triggerLabel = "Open Dialog";
90-
const onPrimaryActionClick = () => counter++;
91-
const children = <Button label={triggerLabel} />;
86+
const onConfirm = () => counter++;
9287

9388
const { getByText } = renderDialog({
9489
title,
9590
primaryActionLabel,
96-
onPrimaryActionClick,
97-
children,
91+
onConfirm,
92+
open: true,
9893
});
9994

100-
const triggerBtn = getByText(triggerLabel);
101-
fireEvent.click(triggerBtn);
10295
const primaryBtn = getByText(primaryActionLabel);
10396
fireEvent.click(primaryBtn);
10497
expect(counter).toEqual(1);
@@ -114,20 +107,25 @@ describe("Dialog Component", () => {
114107
it("closes the dialog on secondary action click", () => {
115108
const title = "Dialog Title";
116109
const secondaryActionLabel = "SecondaryAction";
117-
const triggerLabel = "Open Dialog";
118-
const children = <Button label={triggerLabel} />;
119110

111+
let open = true;
120112
const { getByText, queryAllByText } = renderDialog({
121113
title,
122114
secondaryActionLabel,
123-
children,
115+
open,
116+
onCancel: () => open = false
124117
});
125118

126-
const triggerBtn = getByText(triggerLabel);
127-
fireEvent.click(triggerBtn);
128119
expect(queryAllByText(title).length).toEqual(1);
129120
const secondaryActionBtn = getByText(secondaryActionLabel);
130121
fireEvent.click(secondaryActionBtn);
131-
expect(queryAllByText(title).length).toEqual(0);
122+
expect(open).toEqual(false);
123+
});
124+
125+
it("fails to render in case you provide both children and message props", () => {
126+
const children = <div>test</div>;
127+
const message = "this is a test message";
128+
129+
expect(() => renderDialog({ children, message, open: true })).toThrowError("You can't pass children and message props at the same time");
132130
});
133131
});

src/components/ConfirmationDialog/ConfirmationDialog.tsx

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,15 @@ type DialogPrimaryAction = "primary" | "danger";
66

77
export interface ConfirmationDialogProps {
88
open?: boolean;
9-
onOpenChange?: (b: boolean) => void;
9+
onCancel?: () => void;
1010
title: string;
11-
message: string;
1211
primaryActionType?: DialogPrimaryAction;
1312
primaryActionLabel?: string;
1413
secondaryActionLabel?: string;
15-
onPrimaryActionClick?: (() => void) | (() => Promise<void>);
14+
message?: string;
1615
children?: ReactNode;
16+
loading?: boolean;
17+
onConfirm?: (() => void) | (() => Promise<void>);
1718
}
1819

1920
const ActionsWrapper = styled.div`
@@ -24,35 +25,42 @@ const ActionsWrapper = styled.div`
2425

2526
export const ConfirmationDialog = ({
2627
open,
27-
onOpenChange,
28+
onCancel,
2829
title,
2930
message,
31+
loading,
3032
primaryActionType = "primary",
3133
primaryActionLabel = "Confirm",
3234
secondaryActionLabel = "Cancel",
33-
onPrimaryActionClick,
35+
onConfirm,
3436
children,
3537
}: ConfirmationDialogProps): ReactElement => {
38+
if (children && message) {
39+
throw new Error(
40+
"You can't pass children and message props at the same time"
41+
);
42+
}
43+
3644
return (
3745
<Dialog
3846
open={open}
39-
onOpenChange={onOpenChange}
47+
onOpenChange={(open: boolean) => {
48+
!open && onCancel && onCancel();
49+
}}
4050
>
41-
{children && <Dialog.Trigger>{children}</Dialog.Trigger>}
4251
<Dialog.Content title={title}>
43-
<Text>{message}</Text>
52+
{children ? children : <Text>{message}</Text>}
4453
<Separator size="xl" />
4554
<ActionsWrapper>
4655
<Dialog.Close label={secondaryActionLabel} />
4756
<Dialog.Close
57+
loading={!!loading}
58+
disabled={!!loading}
4859
type={primaryActionType}
4960
label={primaryActionLabel}
5061
onClick={() => {
51-
if (onPrimaryActionClick) {
52-
onPrimaryActionClick();
53-
}
54-
if (onOpenChange) {
55-
onOpenChange(false);
62+
if (onConfirm) {
63+
onConfirm();
5664
}
5765
}}
5866
/>

0 commit comments

Comments
 (0)