Skip to content

Commit

Permalink
refactor(app): use react-call for confirmation modals
Browse files Browse the repository at this point in the history
  • Loading branch information
hbriese committed Aug 15, 2024
1 parent a853df8 commit 78b6a99
Show file tree
Hide file tree
Showing 14 changed files with 146 additions and 156 deletions.
Binary file not shown.
1 change: 1 addition & 0 deletions app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@
"neverthrow": "^7.0.0",
"node-libs-react-native": "^1.2.1",
"react": "18.2.0",
"react-call": "^1.0.1",
"react-compiler-runtime": "file:./src/util/patches/react-compiler-runtime",
"react-content-loader": "^7.0.2",
"react-dom": "18.2.0",
Expand Down
78 changes: 0 additions & 78 deletions app/src/app/(modal)/confirm.tsx

This file was deleted.

12 changes: 7 additions & 5 deletions app/src/app/(nav)/contacts/[address].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import { FormSubmitButton } from '#/fields/FormSubmitButton';
import { FormTextField } from '#/fields/FormTextField';
import { Actions } from '#/layout/Actions';
import { FormResetIcon } from '#/fields/ResetFormIcon';
import { useConfirmRemoval } from '~/hooks/useConfirm';
import { withSuspense } from '#/skeleton/withSuspense';
import { Chain } from 'chains';
import { zodResolver } from '@hookform/resolvers/zod';
Expand All @@ -28,6 +27,7 @@ import { useUpsertContact } from '~/hooks/mutations/useUpsertContact';
import { useRemoveContact } from '~/hooks/mutations/useRemoveContact';
import { Scrollable } from '#/Scrollable';
import { createStyles } from '@theme/styles';
import { Confirm } from '#/Confirm';

const Query = graphql`
query Address_ContactScreenQuery($address: UAddress!, $include: Boolean!) {
Expand Down Expand Up @@ -56,9 +56,6 @@ export interface ContactScreenProps {

function ContactScreen_(props: ContactScreenProps) {
const router = useRouter();
const confirmRemove = useConfirmRemoval({
message: 'Are you sure you want to remove this contact',
});
const selectedChain = useSelectedChain();

const existingAddress = tryAsUAddress(props.address, props.chain);
Expand Down Expand Up @@ -110,7 +107,12 @@ function ContactScreen_(props: ContactScreenProps) {
leadingIcon={RemoveIcon}
title="Remove contact"
onPress={handle(async () => {
if (await confirmRemove()) {
if (
await Confirm.call({
type: 'destructive',
message: 'Are you sure you want to remove this contact',
})
) {
router.back();
remove();
}
Expand Down
2 changes: 2 additions & 0 deletions app/src/app/_layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import { Try } from 'expo-router/build/views/Try';
import { PortalProvider } from '@gorhom/portal';
import { GlobalSubscriptions } from '#/GlobalSubscriptions/GlobalSubscriptions';
import { createStyles, useStyles } from '@theme/styles';
import { Confirm } from '#/Confirm';

export const unstable_settings = {
initialRouteName: `index`,
Expand Down Expand Up @@ -113,6 +114,7 @@ function RootLayout() {
</Suspense>
</Background>
<SnackbarProvider />
<Confirm.Root />
</GestureHandlerRootView>
</IntlProvider>
</Try>
Expand Down
41 changes: 20 additions & 21 deletions app/src/app/auth.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,11 @@ import { secureStorageLocked } from '~/lib/secure-storage';
import { Platform, View } from 'react-native';
import { ICON_SIZE } from '@theme/paper';
import { Splash } from '../components/Splash';
import { useEffect, useState } from 'react';
import { ConfirmModal } from './(modal)/confirm';
import { useEffect } from 'react';
import AsyncStorage from '@react-native-async-storage/async-storage';
import * as Updates from 'expo-updates';
import { Confirm } from '#/Confirm';
import { showInfo } from '#/provider/SnackbarProvider';

const UNLOCKED = new Subject<true>();
const emitAuth = () => UNLOCKED.next(true);
Expand All @@ -42,8 +43,6 @@ function AuthenticateScreen({ onAuth = emitAuth }: AuthenticateScreenProps) {
const biometrics = useBiometrics();
const passwordHash = usePasswordHash();

const [eraseModal, setEraseModal] = useState(false);

const { control, handleSubmit, reset } = useForm<Inputs>({ defaultValues: { password: '' } });

// Automatically auth if none are available
Expand Down Expand Up @@ -125,32 +124,32 @@ function AuthenticateScreen({ onAuth = emitAuth }: AuthenticateScreenProps) {
You can erase all data from this device.
</Text>

<Button mode="text" onPress={() => setEraseModal(true)}>
Erase data
</Button>
</View>

{eraseModal && (
<ConfirmModal
type="destructive"
title="Erase all data from this device?"
message={`This will erase all data from this device. THIS CAN NOT BE UNDONE!\n\nOnce erased, you can re-gain access to your account(s) using other approvers connected to that account`}
confirmLabel="Erase all data"
onDismiss={() => setEraseModal(false)}
onConfirmation={async (confirmed) => {
if (!confirmed) return setEraseModal(false);
<Button
mode="text"
onPress={async () => {
if (
!(await Confirm.call({
type: 'destructive',
title: 'Erase all data from this device?',
message: `This will erase all data from this device. THIS CAN NOT BE UNDONE!\n\nOnce erased, you can re-gain access to your account(s) using other approvers connected to that account`,
confirmLabel: 'Erase all data',
}))
)
return;

await AsyncStorage.clear();
if (Platform.OS === 'web') {
window.location.replace('/');
} /* iOS | Android */ else if (!__DEV__) {
Updates.reloadAsync();
} else {
alert('Data erased. Please reload the app to continue');
showInfo('Data erased. Please reload the app to continue');
}
}}
/>
)}
>
Erase data
</Button>
</View>
</View>
);
}
Expand Down
66 changes: 66 additions & 0 deletions app/src/components/Confirm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { createCallable } from 'react-call';
import { Dialog, Text } from 'react-native-paper';
import { Button } from '#/Button';
import { DialogModal } from '#/Dialog/DialogModal';
import { DialogActions } from '#/Dialog/DialogActions';
import { createStyles, useStyles } from '@theme/styles';

type ConfirmType = 'action' | 'warning' | 'destructive';
export interface ConfirmProps {
title?: string;
message?: string;
confirmLabel?: string;
type?: 'action' | 'warning' | 'destructive';
}

export const Confirm = createCallable<ConfirmProps, boolean>(
({ call, type = 'action', ...props }) => {
const { title, message, confirmLabel } = { ...DEFAULTS[type], ...props };
const { styles } = useStyles(stylesheet);

return (
<DialogModal onDismiss={() => call.end(false)}>
{title && <Dialog.Title>{title}</Dialog.Title>}

{message && (
<Dialog.Content>
<Text variant="bodyMedium">{message}</Text>
</Dialog.Content>
)}

<DialogActions>
<Button textColor={styles.cancel.color} onPress={() => call.end(false)}>
Cancel
</Button>

<Button textColor={styles[type].color} onPress={() => call.end(true)}>
{confirmLabel || 'Ok'}
</Button>
</DialogActions>
</DialogModal>
);
},
);

const stylesheet = createStyles(({ colors }) => ({
cancel: {
color: colors.onSurfaceVariant,
},
action: {
color: colors.primary,
},
warning: {
color: colors.warning,
},
destructive: {
color: colors.error,
},
}));

const DEFAULTS: Partial<Record<ConfirmType, Partial<ConfirmProps>>> = {
destructive: {
title: 'Remove?',
message: 'Are you sure you want to remove?',
confirmLabel: 'Remove',
},
};
13 changes: 7 additions & 6 deletions app/src/components/message/useRemoveMessage.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { Confirm } from '#/Confirm';
import { useRouter } from 'expo-router';
import { useFragment } from 'react-relay';
import { graphql, SelectorStoreUpdater } from 'relay-runtime';
Expand All @@ -9,8 +10,6 @@ import {
useRemoveMessageMutation$data,
} from '~/api/__generated__/useRemoveMessageMutation.graphql';
import { useRemoveMessageUpdatableQuery } from '~/api/__generated__/useRemoveMessageUpdatableQuery.graphql';
import { useConfirmRemoval } from '~/hooks/useConfirm';
import { useSelectedAccount } from '~/hooks/useSelectedAccount';

graphql`
fragment useRemoveMessage_assignable_message on Message @assignable {
Expand Down Expand Up @@ -48,9 +47,6 @@ export function useRemoveMessage(params: RemoveMessageParams) {
const account = useFragment(Account, params.account);
const m = useFragment(Message, params.message);
const router = useRouter();
const confirmRemoval = useConfirmRemoval({
message: 'Are you sure you want to remove this message proposal?',
});

const commit = useMutation<useRemoveMessageMutation>(
graphql`
Expand All @@ -64,7 +60,12 @@ export function useRemoveMessage(params: RemoveMessageParams) {
if (m.signature) return null;

return async () => {
if (await confirmRemoval()) {
if (
await Confirm.call({
type: 'destructive',
message: 'Are you sure you want to remove this message?',
})
) {
router.replace({
pathname: '/(nav)/[account]/(home)/activity',
params: { account: account.address },
Expand Down
15 changes: 9 additions & 6 deletions app/src/components/policy/PolicySideSheet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { FormSubmitButton } from '#/fields/FormSubmitButton';
import { usePolicyDraft } from '~/lib/policy/policyAsDraft';
import { showError } from '#/provider/SnackbarProvider';
import { SideSheet } from '../SideSheet/SideSheet';
import { useConfirmRemoval } from '~/hooks/useConfirm';
import { Button } from '../Button';
import { createStyles, useStyles } from '@theme/styles';
import { useEffect } from 'react';
Expand All @@ -17,6 +16,7 @@ import { useMutation } from '~/api';
import { PolicySideSheet_renameMutation } from '~/api/__generated__/PolicySideSheet_renameMutation.graphql';
import { useRemovePolicy } from '~/hooks/mutations/useRemovePolicy';
import { BOUND_STR_RULES } from '~/util/form.rules';
import { Confirm } from '#/Confirm';

const trimmed = (v: string) => v.trim();

Expand Down Expand Up @@ -69,10 +69,6 @@ export function PolicySideSheet(props: PolicySideSheetProps) {
const policy = useFragment(Policy, props.policy);
const rename = useMutation<PolicySideSheet_renameMutation>(Rename);
const remove = useRemovePolicy();
const confirmRemove = useConfirmRemoval({
title: 'Remove policy',
message: 'Are you sure you want to remove this policy?',
});

const [draft, updateDraft] = usePolicyDraft();
const { control, handleSubmit, reset } = useForm<Inputs>({
Expand Down Expand Up @@ -100,7 +96,14 @@ export function PolicySideSheet(props: PolicySideSheetProps) {
style={styles.removeButton}
labelStyle={styles.removeLabel}
onPress={async () => {
if (await confirmRemove()) await remove(account.address, policy.key);
if (
await Confirm.call({
type: 'destructive',
title: 'Remove policy',
message: 'Are you sure you want to remove this policy?',
})
)
await remove(account.address, policy.key);
}}
>
Remove policy
Expand Down
Loading

0 comments on commit 78b6a99

Please sign in to comment.