Skip to content

Commit 5d043d5

Browse files
committed
Import: Enhancement - add import progress messages
1 parent 4a1a4b0 commit 5d043d5

6 files changed

Lines changed: 289 additions & 78 deletions

File tree

src/components/modal/ongoing-process/OngoingProcess.tsx

Lines changed: 0 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -25,50 +25,6 @@ const {height: SCREEN_HEIGHT, width: SCREEN_WIDTH} = Dimensions.get(
2525
Platform.OS === 'android' ? 'screen' : 'window',
2626
);
2727

28-
export type OnGoingProcessMessages =
29-
| 'GENERAL_AWAITING'
30-
| 'CREATING_KEY'
31-
| 'LOGGING_IN'
32-
| 'LOGGING_OUT'
33-
| 'PAIRING'
34-
| 'CREATING_ACCOUNT'
35-
| 'UPDATING_ACCOUNT'
36-
| 'IMPORTING'
37-
| 'IMPORT_SCANNING_FUNDS'
38-
| 'DELETING_KEY'
39-
| 'ADDING_WALLET'
40-
| 'ADDING_ACCOUNT'
41-
| 'ADDING_EVM_CHAINS'
42-
| 'ADDING_SPL_CHAINS'
43-
| 'LOADING'
44-
| 'FETCHING_PAYMENT_OPTIONS'
45-
| 'FETCHING_PAYMENT_INFO'
46-
| 'JOIN_WALLET'
47-
| 'SENDING_PAYMENT'
48-
| 'ACCEPTING_PAYMENT'
49-
| 'GENERATING_ADDRESS'
50-
| 'GENERATING_GIFT_CARD'
51-
| 'SYNCING_WALLETS'
52-
| 'REJECTING_CALL_REQUEST'
53-
| 'SAVING_LAYOUT'
54-
| 'SAVING_ADDRESSES'
55-
| 'EXCHANGE_GETTING_DATA'
56-
| 'CALCULATING_FEE'
57-
| 'CONNECTING_COINBASE'
58-
| 'FETCHING_COINBASE_DATA'
59-
| 'UPDATING_TXP'
60-
| 'CREATING_TXP'
61-
| 'SENDING_EMAIL'
62-
| 'REDIRECTING'
63-
| 'REMOVING_BILL'
64-
| 'BROADCASTING_TXP'
65-
| 'SWEEPING_WALLET'
66-
| 'SCANNING_FUNDS'
67-
| 'SCANNING_FUNDS_WITH_PASSPHRASE'
68-
| 'CREATING_PASSKEY'
69-
| 'DELETING_PASSKEY'
70-
| 'WAITING_FOR_MAX_AMOUNT';
71-
7228
const Row = styled.View`
7329
background-color: ${({theme}) => (theme.dark ? LightBlack : White)};
7430
border-radius: 10px;

src/contexts/OngoingProcessContext.tsx

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import React, {
66
useEffect,
77
} from 'react';
88
import {
9+
OngoingProcessData,
910
ongoingProcessManager,
1011
OnGoingProcessMessages,
1112
OngoingProcessState,
@@ -15,7 +16,10 @@ import {logManager} from '../managers/LogManager';
1516
interface OngoingProcessContextType {
1617
isVisible: boolean;
1718
message: string | undefined;
18-
showOngoingProcess: (key: OnGoingProcessMessages) => void;
19+
showOngoingProcess: (
20+
key: OnGoingProcessMessages,
21+
data?: OngoingProcessData,
22+
) => void;
1923
hideOngoingProcess: () => void;
2024
}
2125

@@ -65,8 +69,11 @@ export const OngoingProcessProvider: React.FC<{children: ReactNode}> = ({
6569
const contextValue: OngoingProcessContextType = {
6670
isVisible: state.isVisible,
6771
message: state.message,
68-
showOngoingProcess: (key: OnGoingProcessMessages) => {
69-
ongoingProcessManager.show(key);
72+
showOngoingProcess: (
73+
key: OnGoingProcessMessages,
74+
data?: OngoingProcessData,
75+
) => {
76+
ongoingProcessManager.show(key, data);
7077
},
7178
hideOngoingProcess: () => {
7279
ongoingProcessManager.hide();

src/managers/OngoingProcessManager.tsx

Lines changed: 165 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import i18n from 'i18next';
22
import {logManager} from './LogManager';
33

4-
export type OnGoingProcessMessages =
4+
export type BaseOnGoingProcessMessages =
55
| 'GENERAL_AWAITING'
66
| 'CREATING_KEY'
77
| 'LOGGING_IN'
@@ -45,12 +45,71 @@ export type OnGoingProcessMessages =
4545
| 'DELETING_PASSKEY'
4646
| 'WAITING_FOR_MAX_AMOUNT';
4747

48+
export type ImportProgressMessages =
49+
| 'keyConfig.count'
50+
| 'keyConfig.start'
51+
| 'keyConfig.keyCreated'
52+
| 'keyConfig.noCopayersFound'
53+
| 'chainPermutations.count'
54+
| 'chainPermutations.getKey'
55+
| 'findingCopayers'
56+
| 'foundCopayers'
57+
| 'foundCopayers.count'
58+
| 'creatingCredentials'
59+
| 'gettingStatuses'
60+
| 'gatheringWalletsInfos'
61+
| 'walletInfo.gatheringTokens'
62+
| 'walletInfo.gatheringTokens.error'
63+
| 'walletInfo.importingToken'
64+
| 'walletInfo.gatheringMultisig'
65+
| 'walletInfo.multisig.creatingCredentials'
66+
| 'walletInfo.multisig.importingToken';
67+
68+
export type OnGoingProcessMessages =
69+
| BaseOnGoingProcessMessages
70+
| ImportProgressMessages;
71+
4872
export interface OngoingProcessState {
4973
isVisible: boolean;
5074
message: string | undefined;
5175
}
5276

53-
const translations: Record<OnGoingProcessMessages, () => string> = {
77+
export type OngoingProcessObjectData = {
78+
chain?: string;
79+
tokenName?: string;
80+
walletName?: string;
81+
count?: number;
82+
iteration?: number;
83+
};
84+
85+
export type OngoingProcessData = number | OngoingProcessObjectData | undefined;
86+
87+
const isNumberData = (data: OngoingProcessData): data is number =>
88+
typeof data === 'number';
89+
90+
const getChain = (data?: OngoingProcessData): string | undefined =>
91+
typeof data === 'object' && data !== null ? data.chain : undefined;
92+
93+
const getTokenName = (data?: OngoingProcessData): string | undefined =>
94+
typeof data === 'object' && data !== null ? data.tokenName : undefined;
95+
96+
const getWalletName = (data?: OngoingProcessData): string | undefined =>
97+
typeof data === 'object' && data !== null ? data.walletName : undefined;
98+
99+
const getIteration = (data?: OngoingProcessData): number =>
100+
typeof data === 'object' && data !== null ? data.iteration ?? 1 : 1;
101+
102+
const getCount = (data?: OngoingProcessData): number =>
103+
typeof data === 'object' && data !== null
104+
? data.count ?? 0
105+
: isNumberData(data)
106+
? data
107+
: 0;
108+
109+
const translations: Record<
110+
OnGoingProcessMessages,
111+
(data?: OngoingProcessData) => string
112+
> = {
54113
GENERAL_AWAITING: () =>
55114
i18n.t("Just a second, we're setting a few things up"),
56115
CREATING_KEY: () =>
@@ -97,13 +156,114 @@ const translations: Record<OnGoingProcessMessages, () => string> = {
97156
CREATING_PASSKEY: () => i18n.t('Creating Passkey...'),
98157
DELETING_PASSKEY: () => i18n.t('Deleting Passkey...'),
99158
WAITING_FOR_MAX_AMOUNT: () => i18n.t('Calculating maximum amount...'),
159+
'keyConfig.count': data =>
160+
i18n.t('Checking {{count}} key configurations...', {
161+
count: isNumberData(data) ? data : 0,
162+
}),
163+
'keyConfig.start': data =>
164+
i18n.t('Checking key configuration {{index}}...', {
165+
index: isNumberData(data) ? data + 1 : 1,
166+
}),
167+
'keyConfig.keyCreated': () => i18n.t('Key created, searching for wallets...'),
168+
'keyConfig.noCopayersFound': () =>
169+
i18n.t('No wallets found for this configuration, trying next...'),
170+
'chainPermutations.count': data =>
171+
i18n.t('Checking {{count}} chain permutations...', {
172+
count: isNumberData(data) ? data : 0,
173+
}),
174+
'chainPermutations.getKey': data =>
175+
i18n.t('Deriving key for chain permutation {{index}}...', {
176+
index: isNumberData(data) ? data + 1 : 1,
177+
}),
178+
findingCopayers: data =>
179+
getIteration(data) > 1
180+
? i18n.t('Checking for additional wallets...')
181+
: i18n.t('Searching for your wallets...'),
182+
foundCopayers: data => {
183+
const iteration = getIteration(data);
184+
const count = getCount(data);
185+
if (iteration > 1 && count === 0) {
186+
return i18n.t('No more wallets found...');
187+
}
188+
if (iteration > 1) {
189+
return i18n.t('{{count}} more wallets found! Loading details...', {
190+
count,
191+
});
192+
}
193+
if (iteration === 1 && count === 0) {
194+
return i18n.t('No wallets found...');
195+
}
196+
return count === 1
197+
? i18n.t('Found 1 wallet! Loading details...')
198+
: i18n.t('Found {{count}} wallets! Loading details...', {count});
199+
},
200+
'foundCopayers.count': data => {
201+
const count = getCount(data);
202+
return count === 1
203+
? i18n.t('Found 1 wallet! Loading details...')
204+
: i18n.t('Found {{count}} wallets! Loading details...', {count});
205+
},
206+
creatingCredentials: () => i18n.t('Almost there...'),
207+
gettingStatuses: () => i18n.t('Getting wallet info...'),
208+
gatheringWalletsInfos: data => {
209+
const count = getCount(data);
210+
return count === 1
211+
? i18n.t('Loading 1 wallet...')
212+
: i18n.t('Loading {{count}} wallets...', {count});
213+
},
214+
'walletInfo.gatheringTokens': data => {
215+
const chain = getChain(data);
216+
return i18n.t('Loading {{chain}} tokens...', {chain});
217+
},
218+
'walletInfo.gatheringTokens.error': () =>
219+
i18n.t('Some tokens could not be loaded, continuing...'),
220+
'walletInfo.importingToken': data => {
221+
const tokenName = getTokenName(data);
222+
return i18n.t('Adding {{tokenName}}...', {tokenName});
223+
},
224+
'walletInfo.gatheringMultisig': data => {
225+
const chain = getChain(data);
226+
return i18n.t('Loading {{chain}} shared wallets...', {chain});
227+
},
228+
'walletInfo.multisig.creatingCredentials': data => {
229+
const walletName = getWalletName(data);
230+
return i18n.t('Setting up {{walletName}}...', {walletName});
231+
},
232+
233+
'walletInfo.multisig.importingToken': data => {
234+
const tokenName = getTokenName(data);
235+
return i18n.t('Adding {{tokenName}}...', {tokenName});
236+
},
100237
};
101238

239+
export const importProgressEvents: ImportProgressMessages[] = [
240+
'keyConfig.count',
241+
'keyConfig.start',
242+
'keyConfig.keyCreated',
243+
'keyConfig.noCopayersFound',
244+
'chainPermutations.count',
245+
'chainPermutations.getKey',
246+
'findingCopayers',
247+
'foundCopayers',
248+
'foundCopayers.count',
249+
'creatingCredentials',
250+
'gettingStatuses',
251+
'gatheringWalletsInfos',
252+
'walletInfo.gatheringTokens',
253+
'walletInfo.gatheringTokens.error',
254+
'walletInfo.importingToken',
255+
'walletInfo.gatheringMultisig',
256+
'walletInfo.multisig.creatingCredentials',
257+
'walletInfo.multisig.importingToken',
258+
];
259+
102260
const LONG_RUNNING_PROCESSES: OnGoingProcessMessages[] = [
103261
'IMPORTING',
104262
'IMPORT_SCANNING_FUNDS',
105263
'SCANNING_FUNDS_WITH_PASSPHRASE',
106264
'CREATING_KEY',
265+
'SYNCING_WALLETS',
266+
...importProgressEvents,
107267
];
108268

109269
class OngoingProcessManager {
@@ -124,23 +284,21 @@ class OngoingProcessManager {
124284
return OngoingProcessManager.instance;
125285
}
126286

127-
/**
128-
* Obtiene el estado actual
129-
*/
130287
getState(): OngoingProcessState {
131288
return {
132289
isVisible: this.state.isVisible,
133290
message: this.state.message,
134291
};
135292
}
136293

137-
show(key: OnGoingProcessMessages): void {
294+
show(key: OnGoingProcessMessages, data?: OngoingProcessData): void {
138295
if (this.timeoutRef) {
139296
clearTimeout(this.timeoutRef);
140297
this.timeoutRef = null;
141298
}
142299

143-
const translatedMessage = translations[key]();
300+
const translatedMessage = translations[key]?.(data) ?? i18n.t('Loading');
301+
144302
this.state = {
145303
isVisible: true,
146304
message: translatedMessage,

src/navigation/wallet/components/FileOrText.tsx

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import React, {useEffect, useRef, useState} from 'react';
22
import {ScreenGutter} from '../../../components/styled/Containers';
3-
import Button from '../../../components/button/Button';
3+
import Button, {ButtonState} from '../../../components/button/Button';
44
import BoxInput, {INPUT_HEIGHT} from '../../../components/form/BoxInput';
55
import styled, {css} from 'styled-components/native';
66
import {yupResolver} from '@hookform/resolvers/yup';
@@ -239,6 +239,7 @@ const FileOrText = () => {
239239
const plainTextRef = useRef<TextInput>(null);
240240
const {clearSensitive} = useSensitiveRefClear([plainTextRef]);
241241

242+
const [importButtonState, setImportButtonState] = useState<ButtonState>();
242243
const [uploadedFileName, setUploadedFileName] = useState<string>('');
243244
const [isFromClipboard, setIsFromClipboard] = useState(false);
244245
const [fileFocused, setFileFocused] = useState(false);
@@ -255,6 +256,7 @@ const FileOrText = () => {
255256
opts: Partial<KeyOptions>,
256257
) => {
257258
try {
259+
setImportButtonState('loading');
258260
showOngoingProcess('IMPORTING');
259261
await sleep(1000);
260262
// @ts-ignore
@@ -282,6 +284,11 @@ const FileOrText = () => {
282284

283285
dispatch(setHomeCarouselConfig({id: key.id, show: true}));
284286

287+
setImportButtonState('success');
288+
await sleep(500);
289+
setImportButtonState(undefined);
290+
hideOngoingProcess();
291+
285292
backupRedirect({
286293
context: route.params?.context,
287294
navigation,
@@ -296,10 +303,12 @@ const FileOrText = () => {
296303
}),
297304
);
298305

299-
hideOngoingProcess();
300306
} catch (err: any) {
301307
const errMsg = err instanceof Error ? err.message : JSON.stringify(err);
302308
logger.error(errMsg);
309+
setImportButtonState('failed');
310+
await sleep(500);
311+
setImportButtonState(undefined);
303312
hideOngoingProcess();
304313
await sleep(1000);
305314
showErrorModal(errMsg);
@@ -618,6 +627,7 @@ const FileOrText = () => {
618627
testID="import-wallet-button"
619628
accessibilityLabel="Import wallet"
620629
buttonStyle={'primary'}
630+
state={importButtonState}
621631
onPress={onSubmit}>
622632
{t('Import Wallet')}
623633
</Button>

0 commit comments

Comments
 (0)