Skip to content

Commit ce19c26

Browse files
authored
fix(useAlertDialogAPI): improved promise api (#807)
1 parent ed517ce commit ce19c26

File tree

5 files changed

+140
-3
lines changed

5 files changed

+140
-3
lines changed

.changeset/clean-cameras-hunt.md

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
---
2+
"@cube-dev/ui-kit": minor
3+
---
4+
5+
**Breaking Change:** AlertDialog API cancel button behavior changed
6+
7+
The `cancel` button in AlertDialog now rejects the promise instead of resolving with `'cancel'` status, aligning it with the dismiss (Escape key) behavior.
8+
9+
**Migration Guide:**
10+
11+
**Before:**
12+
```typescript
13+
alertDialogAPI.open({...})
14+
.then((status) => {
15+
if (status === 'cancel') {
16+
// Handle cancel
17+
} else if (status === 'confirm') {
18+
// Handle confirm
19+
}
20+
})
21+
```
22+
23+
**After:**
24+
```typescript
25+
alertDialogAPI.open({...})
26+
.then((status) => {
27+
if (status === 'confirm') {
28+
// Handle confirm
29+
} else if (status === 'secondary') {
30+
// Handle secondary action
31+
}
32+
})
33+
.catch(() => {
34+
// Handle cancel or dismiss
35+
})
36+
```
37+
38+
**Note:** `AlertDialogResolveStatus` type no longer includes `'cancel'` - it now only contains `'confirm' | 'secondary'`.

src/components/overlays/AlertDialog/AlertDialogApiProvider.tsx

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,19 @@ export function AlertDialogApiProvider(props) {
129129
* cancelToken: abortDialog.signal
130130
* });
131131
*
132-
* openedDialog.then(() => console.log('closed'))
132+
* openedDialog
133+
* .then((status) => {
134+
* // User confirmed or used secondary action
135+
* if (status === 'confirm') {
136+
* // Handle confirm
137+
* } else if (status === 'secondary') {
138+
* // Handle secondary action
139+
* }
140+
* })
141+
* .catch(() => {
142+
* // User cancelled or dismissed the dialog
143+
* // Handle cancel/dismiss
144+
* })
133145
*
134146
* return () => {
135147
* abortDialog.abort();
@@ -141,6 +153,14 @@ export function AlertDialogApiProvider(props) {
141153
*
142154
* const onPress = useCallback(() => {
143155
* alertDialogAPI.open({...})
156+
* .then((status) => {
157+
* if (status === 'confirm') {
158+
* // Handle confirm
159+
* }
160+
* })
161+
* .catch(() => {
162+
* // Handle cancel/dismiss
163+
* })
144164
* }, [])
145165
*
146166
* return <Button onPress={onPress}>New issue</Button>

src/components/overlays/AlertDialog/AlertDialogZone.tsx

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,20 @@ export function AlertDialogZone(props: DialogZoneProps) {
6464
return {
6565
confirm: mergeActionProps(actions.confirm, 'confirm'),
6666
secondary: mergeActionProps(actions.secondary, 'secondary'),
67-
cancel: mergeActionProps(actions.cancel, 'cancel'),
67+
cancel:
68+
typeof actions.cancel === 'undefined'
69+
? undefined
70+
: typeof actions.cancel === 'boolean'
71+
? actions.cancel
72+
? { onPress: () => reject(undefined) }
73+
: false
74+
: {
75+
...(actions.cancel as CubeButtonProps),
76+
onPress: (e) => {
77+
(actions.cancel as CubeButtonProps).onPress?.(e);
78+
reject(undefined);
79+
},
80+
},
6881
};
6982
})();
7083

src/components/overlays/AlertDialog/tests/use-alert-dialog-api.test.tsx

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,4 +89,70 @@ describe('useAlertDialogApi()', () => {
8989
expect(onReject).toHaveBeenCalled();
9090
await expect(dialogPromise).rejects.toEqual(undefined);
9191
});
92+
93+
it('should reject when cancel button (boolean) is clicked', async () => {
94+
const { getByRole } = renderWithRoot(
95+
<TestComponent actions={{ cancel: true }} />,
96+
);
97+
const showDialogButton = getByRole('button', { name: 'Open Dialog' });
98+
99+
await userEvent.click(showDialogButton);
100+
101+
const cancelButton = getByRole('button', { name: 'Cancel' });
102+
103+
await userEvent.click(cancelButton);
104+
105+
expect(onReject).toHaveBeenCalled();
106+
await expect(dialogPromise).rejects.toEqual(undefined);
107+
});
108+
109+
it('should reject when cancel button (object) is clicked', async () => {
110+
const { getByRole } = renderWithRoot(
111+
<TestComponent actions={{ cancel: { label: 'No thanks' } }} />,
112+
);
113+
const showDialogButton = getByRole('button', { name: 'Open Dialog' });
114+
115+
await userEvent.click(showDialogButton);
116+
117+
const cancelButton = getByRole('button', { name: 'No thanks' });
118+
119+
await userEvent.click(cancelButton);
120+
121+
expect(onReject).toHaveBeenCalled();
122+
await expect(dialogPromise).rejects.toEqual(undefined);
123+
});
124+
125+
it('should resolve when confirm button is clicked', async () => {
126+
const { getByRole } = renderWithRoot(
127+
<TestComponent actions={{ confirm: true }} />,
128+
);
129+
const showDialogButton = getByRole('button', { name: 'Open Dialog' });
130+
131+
await userEvent.click(showDialogButton);
132+
133+
const confirmButton = getByRole('button', { name: 'Ok' });
134+
135+
await userEvent.click(confirmButton);
136+
137+
expect(onResolve).toHaveBeenCalledWith('confirm');
138+
await expect(dialogPromise).resolves.toEqual('confirm');
139+
});
140+
141+
it('should resolve when secondary button is clicked', async () => {
142+
const { getByRole } = renderWithRoot(
143+
<TestComponent
144+
actions={{ confirm: true, secondary: { label: 'Later' } }}
145+
/>,
146+
);
147+
const showDialogButton = getByRole('button', { name: 'Open Dialog' });
148+
149+
await userEvent.click(showDialogButton);
150+
151+
const secondaryButton = getByRole('button', { name: 'Later' });
152+
153+
await userEvent.click(secondaryButton);
154+
155+
expect(onResolve).toHaveBeenCalledWith('secondary');
156+
await expect(dialogPromise).resolves.toEqual('secondary');
157+
});
92158
});

src/components/overlays/AlertDialog/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ export interface DialogProps
2222
content: ReactNode | (({ resolve, reject }) => ReactNode);
2323
}
2424

25-
export type AlertDialogResolveStatus = 'confirm' | 'cancel' | 'secondary';
25+
export type AlertDialogResolveStatus = 'confirm' | 'secondary';
2626

2727
interface AlertDialogMeta {
2828
id: number;

0 commit comments

Comments
 (0)