Skip to content

Commit 85c9678

Browse files
committed
fix(ui): time bottom sheets
1 parent 0594b50 commit 85c9678

File tree

5 files changed

+132
-175
lines changed

5 files changed

+132
-175
lines changed

src/navigation/bottom-sheet/AppUpdatePrompt.tsx

Lines changed: 33 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,89 +1,80 @@
1-
import React, { memo, ReactElement, useEffect, useMemo } from 'react';
1+
import React, { memo, ReactElement, useEffect } from 'react';
22
import { Trans, useTranslation } from 'react-i18next';
33

44
import BottomSheetScreen from '../../components/BottomSheetScreen';
55
import BottomSheetWrapper from '../../components/BottomSheetWrapper';
66
import { __E2E__ } from '../../constants/env';
77
import { useSnapPoints } from '../../hooks/bottomSheet';
88
import { useAppDispatch, useAppSelector } from '../../hooks/redux';
9-
import {
10-
availableUpdateSelector,
11-
viewControllersSelector,
12-
} from '../../store/reselect/ui';
9+
import { availableUpdateSelector } from '../../store/reselect/ui';
1310
import { ignoreAppUpdateTimestampSelector } from '../../store/reselect/user';
1411
import { ignoreAppUpdate } from '../../store/slices/user';
15-
import { closeSheet, showBottomSheet } from '../../store/utils/ui';
1612
import { Display } from '../../styles/text';
1713
import { openURL } from '../../utils/helpers';
18-
import { objectKeys } from '../../utils/objectKeys';
14+
import { useAllSheetRefs, useSheetRef } from './SheetRefsProvider';
1915

2016
const imageSrc = require('../../assets/illustrations/wand.png');
2117

2218
const ASK_INTERVAL = 1000 * 60 * 60 * 12; // 12h - how long this prompt will be hidden if user taps Later
23-
const CHECK_DELAY = 2500; // how long user needs to stay on Wallets screen before he will see this prompt
19+
const CHECK_DELAY = 2500; // how long user needs to stay on the home screen before he will see this prompt
20+
21+
const sheetId = 'appUpdatePrompt';
2422

2523
const AppUpdatePrompt = (): ReactElement => {
2624
const { t } = useTranslation('other');
2725
const snapPoints = useSnapPoints('large');
2826
const dispatch = useAppDispatch();
29-
const viewControllers = useAppSelector(viewControllersSelector);
27+
const sheetRefs = useAllSheetRefs();
28+
const sheetRef = useSheetRef(sheetId);
3029
const updateInfo = useAppSelector(availableUpdateSelector);
3130
const ignoreTimestamp = useAppSelector(ignoreAppUpdateTimestampSelector);
3231

33-
const anyBottomSheetIsOpen = useMemo(() => {
34-
const viewControllerKeys = objectKeys(viewControllers);
35-
return viewControllerKeys
36-
.filter((view) => view !== 'appUpdatePrompt')
37-
.some((view) => viewControllers[view].isOpen);
38-
}, [viewControllers]);
39-
40-
// if optional app update available
41-
// and user has not seen this prompt for ASK_INTERVAL
42-
// and no other bottom-sheets are shown
43-
// and user on "Wallets" screen for CHECK_DELAY
44-
const shouldShowBottomSheet = useMemo(() => {
45-
const isTimeoutOver = Number(new Date()) - ignoreTimestamp > ASK_INTERVAL;
46-
return (
47-
!__E2E__ &&
48-
updateInfo !== null &&
49-
!updateInfo.critical &&
50-
isTimeoutOver &&
51-
!anyBottomSheetIsOpen
52-
);
53-
}, [updateInfo, ignoreTimestamp, anyBottomSheetIsOpen]);
54-
32+
// biome-ignore lint/correctness/useExhaustiveDependencies: sheetRefs don't change
5533
useEffect(() => {
56-
if (!shouldShowBottomSheet) {
57-
return;
58-
}
34+
// if optional app update available
35+
// and user has not seen this prompt for ASK_INTERVAL
36+
// and no other bottom-sheets are shown
37+
// and user on home screen for CHECK_DELAY
38+
const shouldShow = () => {
39+
const isTimeoutOver = Number(new Date()) - ignoreTimestamp > ASK_INTERVAL;
40+
const isAnySheetOpen = sheetRefs.some(({ ref }) => ref.current?.isOpen());
41+
42+
return (
43+
!__E2E__ &&
44+
!isAnySheetOpen &&
45+
isTimeoutOver &&
46+
updateInfo !== null &&
47+
!updateInfo.critical
48+
);
49+
};
5950

6051
const timer = setTimeout(() => {
61-
showBottomSheet('appUpdatePrompt');
52+
if (shouldShow()) {
53+
sheetRef.current?.present();
54+
}
6255
}, CHECK_DELAY);
6356

64-
return (): void => {
65-
clearTimeout(timer);
66-
};
67-
}, [shouldShowBottomSheet]);
57+
return () => clearTimeout(timer);
58+
}, [ignoreTimestamp, updateInfo]);
6859

6960
const onClose = (): void => {
7061
dispatch(ignoreAppUpdate());
7162
};
7263

7364
const onCancel = (): void => {
7465
dispatch(ignoreAppUpdate());
75-
closeSheet('appUpdatePrompt');
66+
sheetRef.current?.close();
7667
};
7768

7869
const onUpdate = async (): Promise<void> => {
7970
dispatch(ignoreAppUpdate());
8071
await openURL(updateInfo?.url!);
81-
closeSheet('appUpdatePrompt');
72+
sheetRef.current?.close();
8273
};
8374

8475
return (
8576
<BottomSheetWrapper
86-
view="appUpdatePrompt"
77+
view={sheetId}
8778
snapPoints={snapPoints}
8879
onClose={onClose}>
8980
<BottomSheetScreen

src/navigation/bottom-sheet/BackupPrompt.tsx

Lines changed: 33 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { memo, ReactElement, useMemo, useEffect } from 'react';
1+
import React, { memo, ReactElement, useEffect } from 'react';
22
import { Trans, useTranslation } from 'react-i18next';
33

44
import BottomSheetScreen from '../../components/BottomSheetScreen';
@@ -7,38 +7,59 @@ import { __E2E__ } from '../../constants/env';
77
import { useSnapPoints } from '../../hooks/bottomSheet';
88
import { useAppDispatch, useAppSelector } from '../../hooks/redux';
99
import { useBalance } from '../../hooks/wallet';
10-
import { viewControllersSelector } from '../../store/reselect/ui';
1110
import { backupVerifiedSelector } from '../../store/reselect/user';
1211
import { ignoreBackupTimestampSelector } from '../../store/reselect/user';
1312
import { ignoreBackup } from '../../store/slices/user';
1413
import { Display } from '../../styles/text';
15-
import { objectKeys } from '../../utils/objectKeys';
16-
import { useSheetRef } from './SheetRefsProvider';
14+
import { useAllSheetRefs, useSheetRef } from './SheetRefsProvider';
1715

1816
const imageSrc = require('../../assets/illustrations/safe.png');
1917

2018
const ASK_INTERVAL = 1000 * 60 * 60 * 24; // 1 day - how long this prompt will be hidden if user taps Later
21-
const CHECK_DELAY = 2000; // how long user needs to stay on Wallets screen before he will see this prompt
19+
const CHECK_DELAY = 1800; // how long user needs to stay on the home screen before he will see this prompt
2220

2321
const sheetId = 'backupPrompt';
2422

2523
const BackupPrompt = (): ReactElement => {
2624
const dispatch = useAppDispatch();
2725
const { t } = useTranslation('security');
26+
const sheetRefs = useAllSheetRefs();
2827
const sheetRef = useSheetRef(sheetId);
2928
const backupNavigationSheetRef = useSheetRef('backupNavigation');
3029
const snapPoints = useSnapPoints('medium');
31-
const viewControllers = useAppSelector(viewControllersSelector);
3230
const ignoreTimestamp = useAppSelector(ignoreBackupTimestampSelector);
3331
const backupVerified = useAppSelector(backupVerifiedSelector);
3432
const { totalBalance } = useBalance();
3533

36-
const anyBottomSheetIsOpen = useMemo(() => {
37-
const viewControllerKeys = objectKeys(viewControllers);
38-
return viewControllerKeys
39-
.filter((view) => view !== sheetId)
40-
.some((view) => viewControllers[view].isOpen);
41-
}, [viewControllers]);
34+
// biome-ignore lint/correctness/useExhaustiveDependencies: sheetRefs don't change
35+
useEffect(() => {
36+
// if backup has not been verified
37+
// and wallet has balance
38+
// and user has not seen this prompt for ASK_INTERVAL
39+
// and no other bottom-sheets are shown
40+
// and user on home screen for CHECK_DELAY
41+
const shouldShow = () => {
42+
const isAnySheetOpen = sheetRefs.some(({ ref }) => ref.current?.isOpen());
43+
const isTimeoutOver = Number(new Date()) - ignoreTimestamp > ASK_INTERVAL;
44+
const hasBalance = totalBalance > 0;
45+
46+
return (
47+
!__E2E__ &&
48+
!isAnySheetOpen &&
49+
isTimeoutOver &&
50+
!backupVerified &&
51+
hasBalance
52+
);
53+
};
54+
55+
const timer = setTimeout(() => {
56+
if (shouldShow()) {
57+
sheetRef.current?.present();
58+
}
59+
}, CHECK_DELAY);
60+
61+
return () => clearTimeout(timer);
62+
}, [ignoreTimestamp, backupVerified, totalBalance]);
4263

4364
const handleLater = (): void => {
4465
dispatch(ignoreBackup());
@@ -50,37 +71,6 @@ const BackupPrompt = (): ReactElement => {
5071
backupNavigationSheetRef.current?.present();
5172
};
5273

53-
// if backup has not been verified
54-
// and wallet has transactions
55-
// and user has not seen this prompt for ASK_INTERVAL
56-
// and no other bottom-sheets are shown
57-
// and user on "Wallets" screen for CHECK_DELAY
58-
const shouldShowBottomSheet = useMemo(() => {
59-
const isTimeoutOver = Number(new Date()) - ignoreTimestamp > ASK_INTERVAL;
60-
return (
61-
!__E2E__ &&
62-
!backupVerified &&
63-
totalBalance > 0 &&
64-
isTimeoutOver &&
65-
!anyBottomSheetIsOpen
66-
);
67-
}, [backupVerified, totalBalance, ignoreTimestamp, anyBottomSheetIsOpen]);
68-
69-
// biome-ignore lint/correctness/useExhaustiveDependencies: sheetRef doesn't change
70-
useEffect(() => {
71-
if (!shouldShowBottomSheet) {
72-
return;
73-
}
74-
75-
const timer = setTimeout(() => {
76-
sheetRef.current?.present();
77-
}, CHECK_DELAY);
78-
79-
return (): void => {
80-
clearTimeout(timer);
81-
};
82-
}, [shouldShowBottomSheet]);
83-
8474
const text = totalBalance > 0 ? t('backup_funds') : t('backup_funds_no');
8575

8676
return (

src/navigation/bottom-sheet/HighBalanceWarning.tsx

Lines changed: 38 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { memo, ReactElement, useEffect, useMemo } from 'react';
1+
import React, { memo, ReactElement, useEffect } from 'react';
22
import { Trans, useTranslation } from 'react-i18next';
33

44
import BottomSheetScreen from '../../components/BottomSheetScreen';
@@ -7,97 +7,90 @@ import { __E2E__ } from '../../constants/env';
77
import { useSnapPoints } from '../../hooks/bottomSheet';
88
import { useAppDispatch, useAppSelector } from '../../hooks/redux';
99
import { useBalance } from '../../hooks/wallet';
10-
import { viewControllersSelector } from '../../store/reselect/ui';
1110
import {
1211
ignoreHighBalanceCountSelector,
1312
ignoreHighBalanceTimestampSelector,
1413
} from '../../store/reselect/user';
1514
import { exchangeRatesSelector } from '../../store/reselect/wallet';
1615
import { MAX_WARNINGS, ignoreHighBalance } from '../../store/slices/user';
17-
import { closeSheet, showBottomSheet } from '../../store/utils/ui';
1816
import { BodyMB, Display } from '../../styles/text';
1917
import { getFiatDisplayValues } from '../../utils/displayValues';
2018
import { openURL } from '../../utils/helpers';
21-
import { objectKeys } from '../../utils/objectKeys';
19+
import { useAllSheetRefs, useSheetRef } from './SheetRefsProvider';
2220

2321
const imageSrc = require('../../assets/illustrations/exclamation-mark.png');
2422

2523
const BALANCE_THRESHOLD_USD = 500; // how high the balance must be to show this warning to the user (in USD)
2624
const BALANCE_THRESHOLD_SATS = 700000; // how high the balance must be to show this warning to the user (in Sats)
2725
const ASK_INTERVAL = 1000 * 60 * 60 * 24; // 1 day - how long this prompt will be hidden if user taps Later
28-
const CHECK_DELAY = 3000; // how long user needs to stay on Wallets screen before he will see this prompt
26+
const CHECK_DELAY = 2500; // how long user needs to stay on the home screen before he will see this prompt
27+
28+
const sheetId = 'highBalance';
2929

3030
const HighBalanceWarning = (): ReactElement => {
3131
const { t } = useTranslation('other');
3232
const { totalBalance } = useBalance();
3333
const snapPoints = useSnapPoints('large');
3434
const dispatch = useAppDispatch();
35+
const sheetRefs = useAllSheetRefs();
36+
const sheetRef = useSheetRef(sheetId);
3537
const count = useAppSelector(ignoreHighBalanceCountSelector);
3638
const exchangeRates = useAppSelector(exchangeRatesSelector);
37-
const viewControllers = useAppSelector(viewControllersSelector);
3839
const ignoreTimestamp = useAppSelector(ignoreHighBalanceTimestampSelector);
3940

40-
const anyBottomSheetIsOpen = useMemo(() => {
41-
const viewControllerKeys = objectKeys(viewControllers);
42-
return viewControllerKeys
43-
.filter((view) => view !== 'highBalance')
44-
.some((view) => viewControllers[view].isOpen);
45-
}, [viewControllers]);
46-
4741
const { fiatValue } = getFiatDisplayValues({
4842
satoshis: totalBalance,
4943
currency: 'USD',
5044
exchangeRates,
5145
});
5246

53-
// if balance over BALANCE_THRESHOLD
54-
// and not more than MAX_WARNINGS times
55-
// and user has not seen this prompt for ASK_INTERVAL
56-
// and no other bottom-sheets are shown
57-
// and user on "Wallets" screen for CHECK_DELAY
58-
const shouldShowBottomSheet = useMemo(() => {
59-
const thresholdReached =
60-
// fallback in case exchange rates are not available
61-
fiatValue !== 0
62-
? fiatValue > BALANCE_THRESHOLD_USD
63-
: totalBalance > BALANCE_THRESHOLD_SATS;
64-
const belowMaxWarnings = count < MAX_WARNINGS;
65-
const isTimeoutOver = Number(new Date()) - ignoreTimestamp > ASK_INTERVAL;
66-
return (
67-
!__E2E__ &&
68-
thresholdReached &&
69-
belowMaxWarnings &&
70-
isTimeoutOver &&
71-
!anyBottomSheetIsOpen
72-
);
73-
}, [fiatValue, totalBalance, count, ignoreTimestamp, anyBottomSheetIsOpen]);
74-
47+
// biome-ignore lint/correctness/useExhaustiveDependencies: sheetRefs don't change
7548
useEffect(() => {
76-
if (!shouldShowBottomSheet) {
77-
return;
78-
}
49+
// if balance over BALANCE_THRESHOLD
50+
// and not more than MAX_WARNINGS times
51+
// and user has not seen this prompt for ASK_INTERVAL
52+
// and no other bottom-sheets are shown
53+
// and user on home screen for CHECK_DELAY
54+
const shouldShow = () => {
55+
const isTimeoutOver = Number(new Date()) - ignoreTimestamp > ASK_INTERVAL;
56+
const isAnySheetOpen = sheetRefs.some(({ ref }) => ref.current?.isOpen());
57+
const belowMaxWarnings = count < MAX_WARNINGS;
58+
const thresholdReached =
59+
// fallback in case exchange rates are not available
60+
fiatValue !== 0
61+
? fiatValue > BALANCE_THRESHOLD_USD
62+
: totalBalance > BALANCE_THRESHOLD_SATS;
63+
64+
return (
65+
!__E2E__ &&
66+
!isAnySheetOpen &&
67+
isTimeoutOver &&
68+
thresholdReached &&
69+
belowMaxWarnings
70+
);
71+
};
7972

8073
const timer = setTimeout(() => {
81-
showBottomSheet('highBalance');
74+
if (shouldShow()) {
75+
sheetRef.current?.present();
76+
}
8277
}, CHECK_DELAY);
8378

84-
return (): void => {
85-
clearTimeout(timer);
86-
};
87-
}, [shouldShowBottomSheet]);
79+
return () => clearTimeout(timer);
80+
}, [ignoreTimestamp, fiatValue, totalBalance, count]);
8881

8982
const onMore = (): void => {
9083
openURL('https://en.bitcoin.it/wiki/Storing_bitcoins');
9184
};
9285

9386
const onDismiss = (): void => {
9487
dispatch(ignoreHighBalance(true));
95-
closeSheet('highBalance');
88+
sheetRef.current?.close();
9689
};
9790

9891
return (
9992
<BottomSheetWrapper
100-
view="highBalance"
93+
view={sheetId}
10194
snapPoints={snapPoints}
10295
onClose={(): void => {
10396
dispatch(ignoreHighBalance(false));

0 commit comments

Comments
 (0)