Skip to content

Commit 8724759

Browse files
chrisbobbegnprice
authored andcommitted
ui [nfc]: Extract reusable showConfirmationDialog function
This touches a UI area in which we hope to get better at matching the web app -- see https://chat.zulip.org/#narrow/stream/48-mobile/topic/confirm.2Fcancel.20modals/near/1401229 -- and this refactor will make it easier to apply such improvements consistently.
1 parent 20e3d0a commit 8724759

File tree

5 files changed

+73
-69
lines changed

5 files changed

+73
-69
lines changed

src/account-info/ProfileScreen.js

Lines changed: 15 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/* @flow strict-local */
22
import React, { useContext } from 'react';
33
import type { Node } from 'react';
4-
import { ScrollView, View, Alert } from 'react-native';
4+
import { ScrollView, View } from 'react-native';
55
import { SafeAreaView } from 'react-native-safe-area-context';
66

77
import { type UserId } from '../api/idTypes';
@@ -18,6 +18,7 @@ import AwayStatusSwitch from './AwayStatusSwitch';
1818
import { getOwnUser } from '../users/userSelectors';
1919
import { getIdentity } from '../account/accountsSelectors';
2020
import { useNavigation } from '../react-navigation';
21+
import { showConfirmationDialog } from '../utils/info';
2122

2223
const styles = createStyleSheet({
2324
buttonRow: {
@@ -96,25 +97,19 @@ function LogoutButton(props: {||}) {
9697
secondary
9798
text="Log out"
9899
onPress={() => {
99-
Alert.alert(
100-
_('Log out?'),
101-
_('This will log out {email} on {realmUrl} from the mobile app on this device.', {
102-
email: identity.email,
103-
realmUrl: identity.realm.toString(),
104-
}),
105-
[
106-
{ text: _('Cancel'), style: 'cancel' },
107-
{
108-
text: _('Confirm'),
109-
style: 'destructive',
110-
onPress: () => {
111-
dispatch(tryStopNotifications());
112-
dispatch(logout());
113-
},
114-
},
115-
],
116-
{ cancelable: true },
117-
);
100+
showConfirmationDialog({
101+
destructive: true,
102+
title: 'Log out?',
103+
message: {
104+
text: 'This will log out {email} on {realmUrl} from the mobile app on this device.',
105+
values: { email: identity.email, realmUrl: identity.realm.toString() },
106+
},
107+
onPressConfirm: () => {
108+
dispatch(tryStopNotifications());
109+
dispatch(logout());
110+
},
111+
_,
112+
});
118113
}}
119114
/>
120115
);

src/account/AccountPickScreen.js

Lines changed: 13 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import React, { useContext, useCallback } from 'react';
44
import type { Node } from 'react';
5-
import { Alert } from 'react-native';
65

76
import * as api from '../api';
87
import { TranslationContext } from '../boot/TranslationProvider';
@@ -18,7 +17,7 @@ import ViewPlaceholder from '../common/ViewPlaceholder';
1817
import AccountList from './AccountList';
1918
import { accountSwitch, removeAccount } from '../actions';
2019
import type { ApiResponseServerSettings } from '../api/settings/getServerSettings';
21-
import { showErrorAlert } from '../utils/info';
20+
import { showConfirmationDialog, showErrorAlert } from '../utils/info';
2221

2322
type Props = $ReadOnly<{|
2423
navigation: AppNavigationProp<'account-pick'>,
@@ -54,24 +53,18 @@ export default function AccountPickScreen(props: Props): Node {
5453
const handleAccountRemove = useCallback(
5554
(index: number) => {
5655
const { realm, email } = accounts[index];
57-
Alert.alert(
58-
_('Remove account?'),
59-
_('This will make the mobile app on this device forget {email} on {realmUrl}.', {
60-
realmUrl: realm.toString(),
61-
email,
62-
}),
63-
[
64-
{ text: _('Cancel'), style: 'cancel' },
65-
{
66-
text: _('Confirm'),
67-
style: 'destructive',
68-
onPress: () => {
69-
dispatch(removeAccount(index));
70-
},
71-
},
72-
],
73-
{ cancelable: true },
74-
);
56+
showConfirmationDialog({
57+
destructive: true,
58+
title: 'Remove account?',
59+
message: {
60+
text: 'This will make the mobile app on this device forget {email} on {realmUrl}.',
61+
values: { realmUrl: realm.toString(), email },
62+
},
63+
onPressConfirm: () => {
64+
dispatch(removeAccount(index));
65+
},
66+
_,
67+
});
7568
},
7669
[accounts, _, dispatch],
7770
);

src/action-sheets/index.js

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ import { pmUiRecipientsFromKeyRecipients } from '../utils/recipient';
3131
import type { PmKeyRecipients } from '../utils/recipient';
3232
import { isTopicMuted } from '../mute/muteModel';
3333
import * as api from '../api';
34-
import { showToast } from '../utils/info';
34+
import { showConfirmationDialog, showToast } from '../utils/info';
3535
import {
3636
doNarrow,
3737
deleteOutboxMessage,
@@ -268,18 +268,17 @@ const deleteTopic = {
268268
errorMessage: 'Failed to delete topic',
269269
action: async ({ streamId, topic, dispatch, _ }) => {
270270
const confirmed = await new Promise((resolve, reject) => {
271-
Alert.alert(
272-
_('Delete topic', { topic }),
273-
_(
274-
'Deleting a topic will immediately remove it and its messages for everyone. Other users may find this confusing, especially if they had received an email or push notification related to the deleted messages.\n\nAre you sure you want to permanently delete “{topic}”?',
275-
{ topic },
276-
),
277-
[
278-
{ text: _('Cancel'), onPress: () => resolve(false), style: 'cancel' },
279-
{ text: _('Confirm'), onPress: () => resolve(true), style: 'destructive' },
280-
],
281-
{ cancelable: true },
282-
);
271+
showConfirmationDialog({
272+
destructive: true,
273+
title: 'Delete topic',
274+
message: {
275+
text: 'Deleting a topic will immediately remove it and its messages for everyone. Other users may find this confusing, especially if they had received an email or push notification related to the deleted messages.\n\nAre you sure you want to permanently delete “{topic}”?',
276+
values: { topic },
277+
},
278+
onPressConfirm: () => resolve(true),
279+
onPressCancel: () => resolve(false),
280+
_,
281+
});
283282
});
284283
if (confirmed) {
285284
await dispatch(deleteMessagesForTopic(streamId, topic));

src/streams/EditStreamCard.js

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/* @flow strict-local */
22
import React, { useState, useCallback, useMemo, useEffect, useContext } from 'react';
33
import type { Node } from 'react';
4-
import { View, Alert } from 'react-native';
4+
import { View } from 'react-native';
55

66
import type { Privacy } from './streamsActions';
77
import { ensureUnreachable } from '../types';
@@ -27,6 +27,7 @@ import type {
2727
CreateWebPublicStreamPolicyT,
2828
} from '../api/permissionsTypes';
2929
import type { LocalizableText } from '../types';
30+
import { showConfirmationDialog } from '../utils/info';
3031

3132
type PropsBase = $ReadOnly<{|
3233
navigation: AppNavigationMethods,
@@ -309,20 +310,13 @@ export default function EditStreamCard(props: Props): Node {
309310

310311
e.preventDefault();
311312

312-
Alert.alert(
313-
_('Discard changes?'),
314-
_('You have unsaved changes. Leave without saving?'),
315-
[
316-
{ text: _('Cancel'), style: 'cancel' },
317-
{
318-
text: _('Confirm'),
319-
style: 'destructive',
320-
321-
onPress: () => navigation.dispatch(e.data.action),
322-
},
323-
],
324-
{ cancelable: true },
325-
);
313+
showConfirmationDialog({
314+
destructive: true,
315+
title: 'Discard changes?',
316+
message: 'You have unsaved changes. Leave without saving?',
317+
onPressConfirm: () => navigation.dispatch(e.data.action),
318+
_,
319+
});
326320
}),
327321
[_, areInputsTouched, navigation, awaitingUserInput],
328322
);

src/utils/info.js

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import { Alert } from 'react-native';
33
import Toast from 'react-native-simple-toast';
44

5-
import type { GlobalSettingsState } from '../types';
5+
import type { GlobalSettingsState, GetText, LocalizableText } from '../types';
66
import { openLinkWithUserPreference } from './openLink';
77

88
export const showToast = (message: string) => {
@@ -46,3 +46,26 @@ export const showErrorAlert = (
4646

4747
Alert.alert(title, message, buttons, { cancelable: true });
4848
};
49+
50+
export const showConfirmationDialog = (args: {|
51+
+destructive?: true,
52+
+title: LocalizableText,
53+
+message: LocalizableText,
54+
+learnMoreButton?: LearnMoreButton,
55+
+onPressConfirm: () => void,
56+
+onPressCancel?: () => void,
57+
+_: GetText,
58+
|}) => {
59+
const { destructive, title, message, learnMoreButton, onPressConfirm, onPressCancel, _ } = args;
60+
61+
const buttons = [];
62+
if (learnMoreButton) {
63+
buttons.push(makeLearnMoreButton(learnMoreButton));
64+
}
65+
buttons.push(
66+
{ text: _('Cancel'), style: 'cancel', onPress: onPressCancel },
67+
{ text: _('Confirm'), style: destructive ? 'destructive' : 'default', onPress: onPressConfirm },
68+
);
69+
70+
Alert.alert(_(title), _(message), buttons, { cancelable: true });
71+
};

0 commit comments

Comments
 (0)