From 85a2bfee4e514fc87d5b9d830425da3fd04757a7 Mon Sep 17 00:00:00 2001 From: J M Rossy Date: Tue, 22 Oct 2019 11:40:54 +0200 Subject: [PATCH] [Wallet] Implement new backup flows including social backup (#1399) * Implement new backup flow designs * Add support for social backup (aka Safeguards) * Do some cleanup in the locales json files * Convert the Edit Profile button in Account screen to a row item --- .../mobile/locales/en-US/accountScreen10.json | 1 - .../mobile/locales/en-US/backupKeyFlow6.json | 119 +- packages/mobile/locales/en-US/global.json | 10 +- .../locales/es-419/accountScreen10.json | 1 - .../mobile/locales/es-419/backupKeyFlow6.json | 138 +- packages/mobile/locales/es-419/global.json | 20 +- packages/mobile/package.json | 1 - packages/mobile/src/account/Account.test.tsx | 56 +- packages/mobile/src/account/Account.tsx | 31 +- .../mobile/src/account/InviteReview.test.tsx | 10 +- .../__snapshots__/Account.test.tsx.snap | 334 +- packages/mobile/src/account/actions.ts | 21 + packages/mobile/src/account/reducer.ts | 14 + packages/mobile/src/analytics/constants.ts | 38 +- packages/mobile/src/app/ErrorMessages.ts | 7 +- packages/mobile/src/backup/Backup.test.tsx | 38 - packages/mobile/src/backup/Backup.tsx | 191 - .../mobile/src/backup/BackupComplete.test.tsx | 22 +- packages/mobile/src/backup/BackupComplete.tsx | 133 +- .../src/backup/BackupIntroduction.test.tsx | 70 +- .../mobile/src/backup/BackupIntroduction.tsx | 301 +- .../mobile/src/backup/BackupPhrase.test.tsx | 27 +- packages/mobile/src/backup/BackupPhrase.tsx | 188 +- .../src/backup/BackupPhraseContainer.test.tsx | 6 +- .../src/backup/BackupPhraseContainer.tsx | 99 +- .../mobile/src/backup/BackupQuestion.test.tsx | 89 - packages/mobile/src/backup/BackupQuestion.tsx | 214 - .../mobile/src/backup/BackupQuiz.test.tsx | 58 + packages/mobile/src/backup/BackupQuiz.tsx | 295 ++ .../mobile/src/backup/BackupSocial.test.tsx | 41 + packages/mobile/src/backup/BackupSocial.tsx | 193 + .../src/backup/BackupSocialIntro.test.tsx | 18 + .../mobile/src/backup/BackupSocialIntro.tsx | 116 + .../backup/__snapshots__/Backup.test.tsx.snap | 802 ---- .../BackupComplete.test.tsx.snap | 532 +-- .../BackupIntroduction.test.tsx.snap | 1404 +++---- .../__snapshots__/BackupPhrase.test.tsx.snap | 510 ++- .../BackupPhraseContainer.test.tsx.snap | 60 +- .../BackupQuestion.test.tsx.snap | 3456 ----------------- .../__snapshots__/BackupQuiz.test.tsx.snap | 1127 ++++++ .../__snapshots__/BackupSocial.test.tsx.snap | 498 +++ .../BackupSocialIntro.test.tsx.snap | 171 + packages/mobile/src/backup/utils.test.ts | 63 +- packages/mobile/src/backup/utils.ts | 94 +- .../mobile/src/components/DevSkipButton.tsx | 5 +- .../mobile/src/home/NotificationBox.test.tsx | 2 +- packages/mobile/src/home/NotificationBox.tsx | 8 +- .../NotificationBox.test.tsx.snap | 111 +- packages/mobile/src/index.d.ts | 1 - .../EnterInviteCode.test.tsx.snap | 10 +- packages/mobile/src/navigator/Navigator.tsx | 27 +- packages/mobile/src/navigator/Screens.tsx | 8 +- ...dPaymentReminderNotification.test.tsx.snap | 22 +- ...ntrequestSummaryNotification.test.tsx.snap | 33 +- .../SimpleNotification.test.tsx.snap | 11 +- .../PaymentRequestListItem.test.tsx.snap | 22 +- .../PaymentRequestListScreen.test.tsx.snap | 66 +- packages/mobile/src/redux/selectors.test.ts | 2 +- packages/mobile/src/redux/selectors.ts | 2 +- packages/mobile/src/shared/BackupPrompt.tsx | 2 +- .../__snapshots__/BackupPrompt.test.tsx.snap | 5 +- .../__snapshots__/NoActivity.test.tsx.snap | 5 +- packages/mobile/test/schemas.ts | 1 + packages/mobile/test/values.ts | 3 + packages/react-components/components/Link.tsx | 9 +- .../components/SmallButton.tsx | 49 +- 66 files changed, 4765 insertions(+), 7256 deletions(-) delete mode 100644 packages/mobile/src/backup/Backup.test.tsx delete mode 100644 packages/mobile/src/backup/Backup.tsx delete mode 100644 packages/mobile/src/backup/BackupQuestion.test.tsx delete mode 100644 packages/mobile/src/backup/BackupQuestion.tsx create mode 100644 packages/mobile/src/backup/BackupQuiz.test.tsx create mode 100644 packages/mobile/src/backup/BackupQuiz.tsx create mode 100644 packages/mobile/src/backup/BackupSocial.test.tsx create mode 100644 packages/mobile/src/backup/BackupSocial.tsx create mode 100644 packages/mobile/src/backup/BackupSocialIntro.test.tsx create mode 100644 packages/mobile/src/backup/BackupSocialIntro.tsx delete mode 100644 packages/mobile/src/backup/__snapshots__/Backup.test.tsx.snap delete mode 100644 packages/mobile/src/backup/__snapshots__/BackupQuestion.test.tsx.snap create mode 100644 packages/mobile/src/backup/__snapshots__/BackupQuiz.test.tsx.snap create mode 100644 packages/mobile/src/backup/__snapshots__/BackupSocial.test.tsx.snap create mode 100644 packages/mobile/src/backup/__snapshots__/BackupSocialIntro.test.tsx.snap diff --git a/packages/mobile/locales/en-US/accountScreen10.json b/packages/mobile/locales/en-US/accountScreen10.json index 6faaba98784..37a2a933e0b 100644 --- a/packages/mobile/locales/en-US/accountScreen10.json +++ b/packages/mobile/locales/en-US/accountScreen10.json @@ -1,5 +1,4 @@ { - "backupKey": "Backup Key", "invite": "Invite", "celoRewards": "Celo Rewards", "languageSettings": "Language Settings", diff --git a/packages/mobile/locales/en-US/backupKeyFlow6.json b/packages/mobile/locales/en-US/backupKeyFlow6.json index b4d8337d0bc..df9242ca187 100644 --- a/packages/mobile/locales/en-US/backupKeyFlow6.json +++ b/packages/mobile/locales/en-US/backupKeyFlow6.json @@ -1,83 +1,70 @@ { - "readOnlyMode": "Read Only Mode Set Backup Key to continue sending and receiving {{CeloDollars}}", "getBackupKey": "Get Backup Key", - "learnBackupKey": "Learn Your Backup Key", - "editProfile": "Edit Profile", + "getYourKey": "Get Your Key", + "viewBackupKey": "View Backup Key", + "setUpSocialBackup": "Set Up Safeguards", + "viewSafeguards": "View Safeguards", + "failedFetchMnemonic": "Failed to fetch your Backup Key", + "backupAndRecovery": "Backup and Recovery", "backupKey": "Backup Key", + "yourBackupKey": "Your Backup Key", "delayBackup": "Dismiss for an hour", - "inviteFriends": "Invite Friends", - "verifierApp": "Verifier App", - "languageSettings": "Language Settings", - "cancel": "Cancel", - "backupKeyImportance": { + "backupKeyNotification": "Without a Backup Key, you may lose access to your wallet.", + "backupKeyIntro": { "0": - "If you lose your phone or delete the Celo app, you will lose all of the gold and {{dollars}} in your wallet.", - "1": - "You can back up your wallet by writing down a Backup Key on a piece of paper and storing it securely. This allows you to restore your wallet in the future if you need to.", - "2": - "Don’t take a screenshot or save it in your phone notes. Make sure to write the Backup Key down and keep it safe." + "Your Backup Key is the one and only key to your Celo Wallet. With this key, you can access your funds anytime, anywhere.", + "1": "KEEP THIS KEY SAFE AND PRIVATE.", + "2": "Congrats, you’ve sucessfully retrieved your Backup Key! A reminder, ", + "3": "KEEP THIS KEY SAFE.", + "4": "For more security set up Safeguards for your wallet.", + "5": + "You’ve also set up Safeguards! You’ll be able to restore your account with the help of the two friends. ", + "6": "KEEP YOUR SAFEGUARDS SECRET" }, - "setBackupKey": "Set Backup Key", - "areYouSure": "Are you sure?", "backupSkipText": { "0": "Without a Backup Key, you can lose access to your wallet ", "1": "forever." }, - "shareBackupKey": "Share Backup Key", "backupRecovery": "Share your Backup Key with only one other person who you completely trust.", - "sendWhatsApp": "Send with WhatsApp", - "continue": "Continue", - "securityTips": "Security Tips", - "backupKeySummary": { - "0": "Write this phrase down on a piece of paper and keep it somewhere safe.", - "1": "Don’t show your phrase to anyone else. They can access your wallet if they see it." - }, - "learnYourKey": "Write down or memorize your Backup Key.", - "keyWillBeVerified": "Once you have finished, we will verify that you know the key correctly.", - "question": "Question", - "questionPhrase": { - "0": "What is the ", - "1": " word of your Backup Key?" + "securityTip": "If you lose your backup key, you will lose access to your Celo Dollars and Gold.", + "backupKeySummary": + "Please write down your Backup Key. If your phone is stolen or lost, you will need the Backup Key to access your Celo Wallet.", + "bothBackupsDone": { + "0": "Congratulations!", + "1": + "You're all done! If you would like to review your recovery secrets, you can always return here later." }, - "question1": "What is the 1st word of your Backup Key?", - "question2": "What is the 2nd word of your Backup Key?", - "question3": "What is the 3rd word of your Backup Key?", - "question4": "What is the 4th word of your Backup Key?", - "question5": "What is the 5th word of your Backup Key?", - "question6": "What is the 6th word of your Backup Key?", - "question7": "What is the 7th word of your Backup Key?", - "question8": "What is the 8th word of your Backup Key?", - "question9": "What is the 9th word of your Backup Key?", - "question10": "What is the 10th word of your Backup Key?", - "question11": "What is the 11th word of your Backup Key?", - "question12": "What is the 12th word of your Backup Key?", - "question13": "What is the 13th word of your Backup Key?", - "question14": "What is the 14th word of your Backup Key?", - "question15": "What is the 15th word of your Backup Key?", - "question16": "What is the 16th word of your Backup Key?", - "question17": "What is the 17th word of your Backup Key?", - "question18": "What is the 18th word of your Backup Key?", - "question19": "What is the 19th word of your Backup Key?", - "question20": "What is the 20th word of your Backup Key?", - "question21": "What is the 21st word of your Backup Key?", - "question22": "What is the 22nd word of your Backup Key?", - "question23": "What is the 23rd word of your Backup Key?", - "question24": "What is the 24th word of your Backup Key?", - "submit": "Submit", - "dontKnow": "Don't Know? ", - "return": "Return to backup key", - "tryAgain": "Try Again", - "backToKey": - "We will take you back to the screen with your backup key so that you ensure you wrote it down correctly.", - "seeBackupKey": "See Backup Key", - "backupKeySet": "Backup Key Set", "dontLoseIt": "Please do not lose this key. It is critical that you maintain this in a safe place, as this is the only way to unlock your wallet should you lose your phone.", - "done": "Done", - "whatsappMessage": - "Important: please keep this private. \n\nI'm sending you the Backup Phrase to my Celo Wallet: ", "backupPrompt": "For the security of your funds, your account is frozen until you get your Backup Key", - "copyToClipboard": "Copy To Clipboard", - "copiedToClipboard": "Copied To Clipboard" + "copied": "Key copied to clipboard", + "savedConfirmation": "I have saved my Backup Key.", + "confirmBackupKey": "Confirm Your Backup Key", + "backupQuizInfo": + "Please verify your Backup Key by selecting the words below in the correct order.", + "backupQuizWordCount": "Word {{index}} of {{total}}", + "invalidBackupPhrase": "Invalid Backup Key", + "importBackupFailed": "Importing Wallet Failed", + "backupQuizFailed": "Incorrect Backup Key, please try again", + "backupComplete": { + "0": "Success!", + "1": "Next, you can set up Safeguards.", + "2": "You’re all set!" + }, + "socialBackupIntro": { + "header": "Introducing Safeguards", + "body": + "Safeguards is an additional layer of protection for your account in case you lose your Backup Key. Once set up, you’ll be able to restore your account with the help of two friends or family members. ", + "warning": "NEVER TELL ANYONE YOUR SAFEGUARDS’ IDENTITIES.", + "skip": "Skip For Now" + }, + "socialBackup": { + "body": + "Share each phrase below with a friend. Be sure to send only one phrase to each person.", + "confirmation": "I have sent each Safeguard phrase to a trusted friend.", + "phrase1": "Safeguard Phrase 1", + "phrase2": "Safeguard Phrase 2", + "yourSafeguards": "Your Safeguards" + } } diff --git a/packages/mobile/locales/en-US/global.json b/packages/mobile/locales/en-US/global.json index db9a3014954..1f8680a22e1 100644 --- a/packages/mobile/locales/en-US/global.json +++ b/packages/mobile/locales/en-US/global.json @@ -8,6 +8,12 @@ "save": "Save", "next": "Next", "skip": "Skip", + "copy": "Copy", + "goBack": "Go Back", + "reset": "Reset", + "done": "Done", + "tip": "Tip: ", + "warning": "Warning ", "downloadRewards": "Download Celo Rewards", "chooseLanguage": "Choose Language", "wallet": "Wallet", @@ -24,7 +30,6 @@ "refreshFailedUnexpectedly": "Failed to refresh, please check your connectivity", "edit": "Edit", "receivedPayment": "Received Payment", - "getBackupKey": "Get Backup Key", "readOnlyState": "Read Only Mode Set Backup Key to continue sending and receiving {{CeloDollars}}", "getStarted": "Get Started", @@ -33,7 +38,6 @@ "startEarning": "Start Earning", "backToWallet": "Back to Wallet", "exchangeForGold": "Exchange for Gold", - "invalidKey": "Invalid Backup Key ", "invalidPhone": "Invalid Phone Number", "cantSelectInvalidPhone": "Cannot select contact: invalid phone number", "needMoreFundsToSend": "Need more funds to send payment", @@ -62,8 +66,6 @@ "canNotRequestFromUnverified": "Can not request from unverified users", "restartApp": "Restart App", "loading": "Loading…", - "invalidBackupPhrase": "Invalid Backup Key", - "importBackupFailed": "Importing Wallet Failed", "inviteFailed": "Failure sending invite", "importContactsFailed": "Failed to import contacts", "sendPaymentFailed": "Failure sending payment", diff --git a/packages/mobile/locales/es-419/accountScreen10.json b/packages/mobile/locales/es-419/accountScreen10.json index acd51bba54f..b0c62240532 100755 --- a/packages/mobile/locales/es-419/accountScreen10.json +++ b/packages/mobile/locales/es-419/accountScreen10.json @@ -1,5 +1,4 @@ { - "backupKey": "Clave de respaldo", "invite": "Invitar", "celoRewards": "Recompensas Celo", "languageSettings": "Configuración de idioma", diff --git a/packages/mobile/locales/es-419/backupKeyFlow6.json b/packages/mobile/locales/es-419/backupKeyFlow6.json index a64be76e736..df9242ca187 100755 --- a/packages/mobile/locales/es-419/backupKeyFlow6.json +++ b/packages/mobile/locales/es-419/backupKeyFlow6.json @@ -1,86 +1,70 @@ { - "readOnlyMode": - "Modo de solo lectura: cree la clave de respaldo para seguir enviando y recibiendo {{CeloDollars}}", - "getBackupKey": "Obtener clave de respaldo", - "learnBackupKey": "Aprenda tu clave de respaldo", - "editProfile": "Editar perfil", - "backupKey": "Clave de respaldo", - "delayBackup": "Despedir por una hora", - "inviteFriends": "Invitar a amigos", - "verifierApp": "Apli del verificador", - "languageSettings": "Configuración de idioma", - "cancel": "Cancelar", - "backupKeyImportance": { + "getBackupKey": "Get Backup Key", + "getYourKey": "Get Your Key", + "viewBackupKey": "View Backup Key", + "setUpSocialBackup": "Set Up Safeguards", + "viewSafeguards": "View Safeguards", + "failedFetchMnemonic": "Failed to fetch your Backup Key", + "backupAndRecovery": "Backup and Recovery", + "backupKey": "Backup Key", + "yourBackupKey": "Your Backup Key", + "delayBackup": "Dismiss for an hour", + "backupKeyNotification": "Without a Backup Key, you may lose access to your wallet.", + "backupKeyIntro": { "0": - "Si pierde tu teléfono o elimina la aplicación de Celo, perderá todo el oro y los {{dollars}} de tu monedero.", - "1": - "Puede hacer un respaldo del monedero si escribe una clave de respaldo en un papel y la guarda en algún sitio seguro. Así, podrá restaurar el monedero en el futuro de ser necesario.", - "2": - "No haga una captura de pantalla ni la guarde en las notas de tu teléfono. Asegúrese de escribir la clave de respaldo a mano y mantenerla segura." + "Your Backup Key is the one and only key to your Celo Wallet. With this key, you can access your funds anytime, anywhere.", + "1": "KEEP THIS KEY SAFE AND PRIVATE.", + "2": "Congrats, you’ve sucessfully retrieved your Backup Key! A reminder, ", + "3": "KEEP THIS KEY SAFE.", + "4": "For more security set up Safeguards for your wallet.", + "5": + "You’ve also set up Safeguards! You’ll be able to restore your account with the help of the two friends. ", + "6": "KEEP YOUR SAFEGUARDS SECRET" }, - "setBackupKey": "Crear clave de respaldo", - "areYouSure": "¿Está seguro?", - "shareBackupKey": "Compartir clave de respaldo", - "backupRecovery": - "Comparta la clave de respaldo con una sola persona en la que confíe plenamente.", "backupSkipText": { - "0": "Comparta la clave de respaldo con una sola persona en la que confíe ", - "1": "plenamente." - }, - "sendWhatsApp": "Enviar por WhatsApp", - "continue": "Continuar", - "securityTips": "Consejos de seguridad", - "backupKeySummary": { - "0": "Escriba esta frase en un papel y guárdela en algún sitio seguro.", - "1": "No le muestre la frase a nadie. Si alguien la sabe, podrá acceder a tu monedero." + "0": "Without a Backup Key, you can lose access to your wallet ", + "1": "forever." }, - "learnYourKey": "Escriba o memorice tu clave de respaldo.", - "keyWillBeVerified": - "Una vez que haya terminado, verificaremos que conoce la clave correctamente.", - "question": "Pregunta", - "questionPhrase": { - "0": "¿Cuál es la ", - "1": " palabra de tu clave de respaldo?" + "backupRecovery": "Share your Backup Key with only one other person who you completely trust.", + "securityTip": "If you lose your backup key, you will lose access to your Celo Dollars and Gold.", + "backupKeySummary": + "Please write down your Backup Key. If your phone is stolen or lost, you will need the Backup Key to access your Celo Wallet.", + "bothBackupsDone": { + "0": "Congratulations!", + "1": + "You're all done! If you would like to review your recovery secrets, you can always return here later." }, - "question1": "¿Cuál es la 1.ª palabra de tu clave de respaldo?", - "question2": "¿Cuál es la 2.ª palabra de tu clave de respaldo?", - "question3": "¿Cuál es la 3.ª palabra de tu clave de respaldo?", - "question4": "¿Cuál es la 4.ª palabra de tu clave de respaldo?", - "question5": "¿Cuál es la 5.ª palabra de tu clave de respaldo?", - "question6": "¿Cuál es la 6.ª palabra de tu clave de respaldo?", - "question7": "¿Cuál es la 7.ª palabra de tu clave de respaldo?", - "question8": "¿Cuál es la 8.ª palabra de tu clave de respaldo?", - "question9": "¿Cuál es la 9.ª palabra de tu clave de respaldo?", - "question10": "¿Cuál es la 10.ª palabra de tu clave de respaldo?", - "question11": "¿Cuál es la 11.ª palabra de tu clave de respaldo?", - "question12": "¿Cuál es la 12.ª palabra de tu clave de respaldo?", - "question13": "¿Cuál es la 13.ª palabra de tu clave de respaldo?", - "question14": "¿Cuál es la 14.ª palabra de tu clave de respaldo?", - "question15": "¿Cuál es la 15.ª palabra de tu clave de respaldo?", - "question16": "¿Cuál es la 16.ª palabra de tu clave de respaldo?", - "question17": "¿Cuál es la 17.ª palabra de tu clave de respaldo?", - "question18": "¿Cuál es la 18.ª palabra de tu clave de respaldo?", - "question19": "¿Cuál es la 19.ª palabra de tu clave de respaldo?", - "question20": "¿Cuál es la 20.ª palabra de tu clave de respaldo?", - "question21": "¿Cuál es la 21.ª palabra de tu clave de respaldo?", - "question22": "¿Cuál es la 22.ª palabra de tu clave de respaldo?", - "question23": "¿Cuál es la 23.ª palabra de tu clave de respaldo?", - "question24": "¿Cuál es la 24.ª palabra de tu clave de respaldo?", - "submit": "Enviar", - "dontKnow": "¿No la sabe? ", - "return": "Vuelva a la clave de respaldo", - "tryAgain": "Reintentar", - "backToKey": - "Le llevaremos a la pantalla con tu clave de respaldo para que verifique que la escribió correctamente.", - "seeBackupKey": "Ver clave de respaldo", - "backupKeySet": "Clave de respaldo creada", "dontLoseIt": - "No pierda esta clave. Es de suma importancia que la mantenga en un lugar seguro, ya que es la única forma de desbloquear tu monedero si pierde tu celular.", - "done": "Listo", - "whatsappMessage": - "Importante: por favor mantenga esto privado. \n\nTe estoy enviando la frase de respaldo a mi Monedero Celo: ", + "Please do not lose this key. It is critical that you maintain this in a safe place, as this is the only way to unlock your wallet should you lose your phone.", "backupPrompt": - "Para la seguridad de sus fondos, tu cuenta está congelada hasta que obtenga tu clave de respaldo", - "copyToClipboard": "Copiar al portapapeles", - "copiedToClipboard": "Copiada al portapapeles" + "For the security of your funds, your account is frozen until you get your Backup Key", + "copied": "Key copied to clipboard", + "savedConfirmation": "I have saved my Backup Key.", + "confirmBackupKey": "Confirm Your Backup Key", + "backupQuizInfo": + "Please verify your Backup Key by selecting the words below in the correct order.", + "backupQuizWordCount": "Word {{index}} of {{total}}", + "invalidBackupPhrase": "Invalid Backup Key", + "importBackupFailed": "Importing Wallet Failed", + "backupQuizFailed": "Incorrect Backup Key, please try again", + "backupComplete": { + "0": "Success!", + "1": "Next, you can set up Safeguards.", + "2": "You’re all set!" + }, + "socialBackupIntro": { + "header": "Introducing Safeguards", + "body": + "Safeguards is an additional layer of protection for your account in case you lose your Backup Key. Once set up, you’ll be able to restore your account with the help of two friends or family members. ", + "warning": "NEVER TELL ANYONE YOUR SAFEGUARDS’ IDENTITIES.", + "skip": "Skip For Now" + }, + "socialBackup": { + "body": + "Share each phrase below with a friend. Be sure to send only one phrase to each person.", + "confirmation": "I have sent each Safeguard phrase to a trusted friend.", + "phrase1": "Safeguard Phrase 1", + "phrase2": "Safeguard Phrase 2", + "yourSafeguards": "Your Safeguards" + } } diff --git a/packages/mobile/locales/es-419/global.json b/packages/mobile/locales/es-419/global.json index ac19d046e6b..0076dc4d25f 100755 --- a/packages/mobile/locales/es-419/global.json +++ b/packages/mobile/locales/es-419/global.json @@ -8,24 +8,28 @@ "save": "Guarda", "next": "Siguiente", "skip": "Saltar", + "copy": "Copiar", + "goBack": "Regresa", + "reset": "Reiniciar", + "done": "Hecho", + "tip": "Punta: ", + "warning": "Advertencia ", "downloadRewards": "Descargar Recompensas Celo", "chooseLanguage": "Elegir idioma", "wallet": "Monedero", - "payments": "Pagos", "send": "Envío", + "payments": "Pagos", "exchange": "Cambio", "learnMore": "Saber más", "activity": "Actividad", "history": "Historial", - "exchangeFailed": "Intercambio fallido, por favor vuelva a intentarlo", - "transactionFailed": "Transacción fallido, por favor vuelva a intentarlo", "notEnoughDollarsError": "No hay suficientes {{CeloDollars}} para cambiarlos", "notEnoughGoldError": "No hay suficiente Celo Oro para cambiarlo", + "exchangeFailed": "Intercambio fallido, por favor vuelva a intentarlo", + "transactionFailed": "Transacción fallido, por favor vuelva a intentarlo", "refreshFailedUnexpectedly": "Error al actualizar, por favor revise tu conectividad", "edit": "Editar", - "needMoreFundsToSend": "Necesita más fondos para enviar el pago", "receivedPayment": "Pago recibido", - "getBackupKey": "Obtener clave de respaldo", "readOnlyState": "Modo de solo lectura: cree la clave de respaldo para seguir enviando y recibiendo {{CeloDollars}}", "getStarted": "Primeros pasos", @@ -34,9 +38,9 @@ "startEarning": "Comenzar a ganar", "backToWallet": "Volver a el Monedero", "exchangeForGold": "Cambiar a Oro", - "cantSelectInvalidPhone": "No se puede seleccionar el contacto: número de teléfono no válido", - "invalidKey": "Clave de respaldo inválida ", "invalidPhone": "Número de teléfono inválido", + "cantSelectInvalidPhone": "No se puede seleccionar el contacto: número de teléfono no válido", + "needMoreFundsToSend": "Necesita más fondos para enviar el pago", "invalidAmount": "Monto invalido", "invalidCode": "Código de verificación inválido", "confirm": "Confirmar", @@ -62,8 +66,6 @@ "canNotRequestFromUnverified": "No se puede solicitar a usuarios no verificados.", "restartApp": "Reiniciar la aplicación", "loading": "Cargando…", - "invalidBackupPhrase": "Clave de respaldo inválida", - "importBackupFailed": "No se pudo importar el monedero", "inviteFailed": "Falló el envío de la invitación", "importContactsFailed": "Error al importar contactos", "sendPaymentFailed": "Falla en el envío de pago", diff --git a/packages/mobile/package.json b/packages/mobile/package.json index 63129e05ba3..2f6f923c6d7 100644 --- a/packages/mobile/package.json +++ b/packages/mobile/package.json @@ -100,7 +100,6 @@ "react-native-localize": "^1.2.1", "react-native-mail": "^3.0.7", "react-native-modal": "^6.1.0", - "react-native-modal-dropdown": "^0.6.2", "react-native-permissions": "^1.1.1", "react-native-progress": "^3.4.0", "react-native-qrcode-svg": "^5.1.2", diff --git a/packages/mobile/src/account/Account.test.tsx b/packages/mobile/src/account/Account.test.tsx index 50b3485b967..290a19509c6 100644 --- a/packages/mobile/src/account/Account.test.tsx +++ b/packages/mobile/src/account/Account.test.tsx @@ -1,18 +1,19 @@ -const { mockNavigationServiceFor } = require('test/utils') -const { navigate } = mockNavigationServiceFor('Account') - import * as React from 'react' import 'react-native' -import { fireEvent, render } from 'react-native-testing-library' import { Provider } from 'react-redux' import * as renderer from 'react-test-renderer' import Account from 'src/account/Account' -import { Screens } from 'src/navigator/Screens' import { createMockStore } from 'test/utils' -jest.useFakeTimers() - describe('Account', () => { + beforeAll(() => { + jest.useFakeTimers() + }) + + afterAll(() => { + jest.useRealTimers() + }) + it('renders correctly', () => { const tree = renderer.create( @@ -22,33 +23,18 @@ describe('Account', () => { expect(tree).toMatchSnapshot() }) - describe('when Edit Profile Pressed', () => { - it('navigates to Profile', () => { - const account = render( - - - - ) - - fireEvent.press(account.getByTestId('editProfileButton')) - expect(navigate).toBeCalledWith(Screens.Profile) - }) - }) - - describe('when dev mode active', () => { - it('renders correctly', () => { - const tree = renderer.create( - - - - ) - expect(tree).toMatchSnapshot() - }) + it('renders correctly when dev mode active', () => { + const tree = renderer.create( + + + + ) + expect(tree).toMatchSnapshot() }) }) diff --git a/packages/mobile/src/account/Account.tsx b/packages/mobile/src/account/Account.tsx index 6865c11aff9..dde2fdf30ed 100644 --- a/packages/mobile/src/account/Account.tsx +++ b/packages/mobile/src/account/Account.tsx @@ -1,5 +1,4 @@ import Link from '@celo/react-components/components/Link' -import SmallButton from '@celo/react-components/components/SmallButton' import colors from '@celo/react-components/styles/colors' import { fontStyles } from '@celo/react-components/styles/fonts' import { anonymizedPhone, isE164Number } from '@celo/utils/src/phoneNumbers' @@ -10,7 +9,7 @@ import DeviceInfo from 'react-native-device-info' import SafeAreaView from 'react-native-safe-area-view' import { Sentry } from 'react-native-sentry' import { connect } from 'react-redux' -import { devModeTriggerClicked } from 'src/account/actions' +import { devModeTriggerClicked, resetBackupState } from 'src/account/actions' import SettingsItem from 'src/account/SettingsItem' import CeloAnalytics from 'src/analytics/CeloAnalytics' import { CustomEventNames } from 'src/analytics/constants' @@ -25,7 +24,6 @@ import { headerWithBackButton } from 'src/navigator/Headers' import { navigate } from 'src/navigator/NavigationService' import { Screens } from 'src/navigator/Screens' import { RootState } from 'src/redux/reducers' -import DisconnectBanner from 'src/shared/DisconnectBanner' import { navigateToURI, navigateToVerifierApp } from 'src/utils/linking' import Logger from 'src/utils/Logger' @@ -34,6 +32,7 @@ interface DispatchProps { setNumberVerified: typeof setNumberVerified resetAppOpenedState: typeof resetAppOpenedState setAnalyticsEnabled: typeof setAnalyticsEnabled + resetBackupState: typeof resetBackupState devModeTriggerClicked: typeof devModeTriggerClicked } @@ -64,6 +63,7 @@ const mapDispatchToProps = { setNumberVerified, resetAppOpenedState, setAnalyticsEnabled, + resetBackupState, devModeTriggerClicked, } @@ -86,7 +86,7 @@ export class Account extends React.Component { } backupScreen() { - navigate(Screens.Backup) + navigate(Screens.BackupIntroduction) } goToInvite() { @@ -135,6 +135,10 @@ export class Account extends React.Component { this.props.revokeVerification() } + resetBackupState = () => { + this.props.resetBackupState() + } + showDebugScreen = async () => { navigate(Screens.Debug) } @@ -185,6 +189,11 @@ export class Account extends React.Component { Reset app opened state + + + Reset backup state + + Show Debug Screen @@ -206,7 +215,6 @@ export class Account extends React.Component { return ( - @@ -218,17 +226,14 @@ export class Account extends React.Component { - - + + {features.SHOW_SHOW_REWARDS_APP_LINK && ( )} diff --git a/packages/mobile/src/account/InviteReview.test.tsx b/packages/mobile/src/account/InviteReview.test.tsx index 9db23d9bac7..e76f174efc9 100644 --- a/packages/mobile/src/account/InviteReview.test.tsx +++ b/packages/mobile/src/account/InviteReview.test.tsx @@ -1,5 +1,3 @@ -jest.useFakeTimers() - import Button from '@celo/react-components/components/Button' import * as React from 'react' import 'react-native' @@ -19,6 +17,14 @@ jest.mock('src/identity/verification', () => { }) describe('InviteReview', () => { + beforeAll(() => { + jest.useFakeTimers() + }) + + afterAll(() => { + jest.useRealTimers() + }) + it('renders correctly', () => { const tree = renderer.create( diff --git a/packages/mobile/src/account/__snapshots__/Account.test.tsx.snap b/packages/mobile/src/account/__snapshots__/Account.test.tsx.snap index db6bf4e7f5f..eb0270b754d 100644 --- a/packages/mobile/src/account/__snapshots__/Account.test.tsx.snap +++ b/packages/mobile/src/account/__snapshots__/Account.test.tsx.snap @@ -152,16 +152,19 @@ exports[`Account renders correctly 1`] = ` + + - - editProfile - + + + backupKeyFlow6:backupAndRecovery + + + + + + + + - - - backupKey + invite - invite + editProfile `; -exports[`Account when dev mode active renders correctly 1`] = ` +exports[`Account renders correctly when dev mode active 1`] = ` + + - - editProfile - + + + backupKeyFlow6:backupAndRecovery + + + + + + + + - - - backupKey + invite - invite + editProfile + + + + Reset backup state + + + ({ type: Actions.SET_BACKUP_DELAYED_ACTION, }) +export const setSocialBackupCompleted = (): SetSocialBackupCompletedAction => ({ + type: Actions.SET_SOCIAL_BACKUP_COMPLETED_ACTION, +}) + +export const resetBackupState = (): ResetBackupState => ({ + type: Actions.RESET_BACKUP_STATE, +}) + export const updatePaymentRequests = ( paymentRequests: PaymentRequest[] ): UpdatePaymentRequestsAction => ({ diff --git a/packages/mobile/src/account/reducer.ts b/packages/mobile/src/account/reducer.ts index 491dec6b593..b3d2453fa99 100644 --- a/packages/mobile/src/account/reducer.ts +++ b/packages/mobile/src/account/reducer.ts @@ -18,6 +18,7 @@ export interface State { accountCreationTime: number backupCompleted: boolean backupDelayedTime: number + socialBackupCompleted: boolean paymentRequests: PaymentRequest[] dismissedEarnRewards: boolean dismissedInviteFriends: boolean @@ -51,6 +52,7 @@ export const initialState = { paymentRequests: [], backupCompleted: false, backupDelayedTime: 0, + socialBackupCompleted: false, dismissedEarnRewards: false, dismissedInviteFriends: false, } @@ -115,6 +117,18 @@ export const reducer = (state: State | undefined = initialState, action: ActionT ...state, backupDelayedTime: getRemoteTime(), } + case Actions.SET_SOCIAL_BACKUP_COMPLETED_ACTION: + return { + ...state, + socialBackupCompleted: true, + } + case Actions.RESET_BACKUP_STATE: + return { + ...state, + backupCompleted: false, + socialBackupCompleted: false, + backupDelayedTime: 0, + } case Actions.UPDATE_PAYMENT_REQUESTS: return { ...state, diff --git a/packages/mobile/src/analytics/constants.ts b/packages/mobile/src/analytics/constants.ts index 31c7370b351..74fc059eb09 100644 --- a/packages/mobile/src/analytics/constants.ts +++ b/packages/mobile/src/analytics/constants.ts @@ -86,30 +86,32 @@ export enum CustomEventNames { // Screen name: Backup_Phrase, Backup_Insist, Backup_Share, Backup_Set set_backup_phrase = 'set_backup_phrase', // (count # of taps on “Set Backup Phrase” in Backup_Phrase) [we should not track the actual value of this field, just whether the user filled it out] + set_social_backup = 'set_social_backup', // (count # of taps on "Set up Social Backup") delay_backup = 'delay_backup', // (Count # of taps on "Delay" button in Backup_Phrase) skip_backup = 'skip_backup', // (count # of taps on “Skip” button in Backup_Phrase) + view_backup_phrase = 'view_backup_phrase', // (count # of taps on "View Backup Phrase" after already backed up) + view_social_backup = 'view_social_backup', // (count # of taps on "View Social Backup" after already set up) + skip_social_backup = 'skip_social_backup', // (count # of taps on "Skip Social Backup" ) backup_cancel = 'backup_cancel', // (count # of taps on "Cancel" button in Backup_Phrase) insist_backup_phrase = 'insist_backup_phrase', // (count # of taps on “Set Backup Phrase” in Backup_Insist) insist_skip_backup = 'insist_skip_backup', // (count # of taps on “Do Later” in Backup_Insist) whatsapp_backup = 'whatsapp_backup', // (count # of taps on “Send with Whatsapp” in Backup_Share) - share_backup_continue = 'share_backup_continue', // (count # of taps on “Continue” button in Backup_Share) - confirm_backup_phrase = 'confirm_backup_phrase', // (count # of taps on “Set Backup Phrase” button in Backup_Set) - - // Screen name: Question_1, Question_2, Question_3, Question_4, Question_Incorrect, Backup_Confirmed - question_select1 = 'question_select1', // (track # of input selections on Question_1 screen) - question_select2 = 'question_select2', // (track # of input selections on Question_2 screen) - question_select3 = 'question_select3', // (track # of input selections on Question_3 screen) - question_select4 = 'question_select4', // (track # of input selections on Question_4 screen) - question_submit1 = 'question_submit1', // (track # of taps on “Submit” button for Question_1 screen) - question_submit2 = 'question_submit2', // (track # of taps on “Submit” button for Question_2 screen) - question_submit3 = 'question_submit3', // (track # of taps on “Submit” button for Question_3 screen) - question_submit4 = 'question_submit4', // (track # of taps on “Submit” button for Question_4 screen) - question_cancel1 = 'questions_cancel1', // (track # of taps on "Cancel" button on the Question_1 Screens) - question_cancel2 = 'questions_cancel2', // (track # of taps on "Cancel" button on the Question_2 Screens) - question_cancel3 = 'questions_cancel3', // (track # of taps on "Cancel" button on the Question_3 Screens) - question_cancel4 = 'questions_cancel4', // (track # of taps on "Cancel" button on the Question_4 Screens) - question_incorrect = 'question_incorrect', // (track # of taps on “See Backup Phrase” in Question_Incorrect) - questions_done = 'questions_done', // (track # of taps on “Done” button on the Backup_Confirmed screen) + backup_continue = 'backup_continue', // (count # of taps on “Continue” button in Backup_Phrase) + social_backup_continue = 'social_backup_continue', // (Count # of taps on "Backup with Friends" in Backup_Phrase) + + // Screen name: Backup_Quiz, Question_Incorrect, Backup_Confirmed + question_select = 'question_select', // (track # of input selections on Backup_Verify screen) + question_submit = 'question_submit', // (track # of taps on “Submit” button for Backup_Quiz screen) + question_cancel = 'questions_cancel', // (track # of taps on "Cancel" button on the Backup_Quiz Screens) + question_incorrect = 'question_incorrect', // (track # of taps on “See Backup Phrase” in Backup_Quiz) + question_done = 'question_done', // (track # of taps on “Done” button on the Backup_Confirmed screen) + + // Screen name: Backup_Verify + backup_paste = 'backup_paste', // (track # of pastes in input field for Backup_Verify screen) + backup_paste_submit = 'backup_paste_submit', // (track # of taps on "Submit" button for Backup_Verify screen) + backup_paste_cancel = 'backup_paste_cancel', // (track # of taps on "Cancel" button on the Backup_Verify screen) + backup_paste_incorrect = 'backup_paste_incorrect', // (track # of taps on "See Backup Phrase" in Backup_Verify screen) + backup_paste_done = 'backup_paste_done', // (track # of taps on "Done" button on the Backup_Verify screen) // Screens: Exchange_Tutorial, Exchange_Home, Exchange_Currency exchange_button = 'exchange_button', // count # of taps on the exchange button in Exchange_Home diff --git a/packages/mobile/src/app/ErrorMessages.ts b/packages/mobile/src/app/ErrorMessages.ts index 6eebd9c425a..f635e7ab954 100644 --- a/packages/mobile/src/app/ErrorMessages.ts +++ b/packages/mobile/src/app/ErrorMessages.ts @@ -8,9 +8,9 @@ export enum ErrorMessages { NSF_DOLLARS = 'notEnoughDollarsError', NSF_TO_SEND = 'needMoreFundsToSend', INVALID_AMOUNT = 'invalidAmount', - INVALID_BACKUP_PHRASE = 'invalidBackupPhrase', - EMPTY_BACKUP_PHRASE = 'emptyBackupPhrase', - IMPORT_BACKUP_FAILED = 'importBackupFailed', + INVALID_BACKUP_PHRASE = 'backupKeyFlow6:invalidBackupPhrase', + IMPORT_BACKUP_FAILED = 'backupKeyFlow6:importBackupFailed', + BACKUP_QUIZ_FAILED = 'backupKeyFlow6:backupQuizFailed', INVALID_PHONE_NUMBER = 'nuxVerification2:invalidPhone', NOT_READY_FOR_CODE = 'nuxVerification2:notReadyForCode', EMPTY_ATTESTATION_CODE = 'nuxVerification2:emptyVerificationCode', @@ -41,4 +41,5 @@ export enum ErrorMessages { QR_FAILED_INVALID_ADDRESS = 'qrFailedInvalidAddress', CORRUPTED_CHAIN_DELETED = 'corruptedChainDeleted', CALCULATE_FEE_FAILED = 'calculateFeeFailed', + FAILED_FETCH_MNEMONIC = 'failedFetchMnemonic', } diff --git a/packages/mobile/src/backup/Backup.test.tsx b/packages/mobile/src/backup/Backup.test.tsx deleted file mode 100644 index 4ceaa5f3021..00000000000 --- a/packages/mobile/src/backup/Backup.test.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import * as React from 'react' -import 'react-native' -import * as renderer from 'react-test-renderer' -import { Backup } from 'src/backup/Backup' - -describe('Backup', () => { - it('renders correctly if backup not completed', () => { - const tree = renderer.create( - - ) - expect(tree).toMatchSnapshot() - }) - - it('renders correctly if backup completed', () => { - const tree = renderer.create( - - ) - expect(tree).toMatchSnapshot() - }) -}) diff --git a/packages/mobile/src/backup/Backup.tsx b/packages/mobile/src/backup/Backup.tsx deleted file mode 100644 index 3460aeeb776..00000000000 --- a/packages/mobile/src/backup/Backup.tsx +++ /dev/null @@ -1,191 +0,0 @@ -import * as React from 'react' -import { connect } from 'react-redux' -import { setBackupCompleted, setBackupDelayed } from 'src/account/actions' -import componentWithAnalytics from 'src/analytics/wrapper' -import { enterBackupFlow, exitBackupFlow } from 'src/app/actions' -import BackupComplete from 'src/backup/BackupComplete' -import BackupIntroduction from 'src/backup/BackupIntroduction' -import BackupPhrase from 'src/backup/BackupPhrase' -import BackupQuestion from 'src/backup/BackupQuestion' -import { createQuizWordList, getStoredMnemonic, selectQuizWordOptions } from 'src/backup/utils' -import { navigateBack } from 'src/navigator/NavigationService' -import { RootState } from 'src/redux/reducers' -import { isBackupTooLate } from 'src/redux/selectors' -import Logger from 'src/utils/Logger' - -export const DAYS_TO_BACKUP = 1 -export const DAYS_TO_DELAY = 1 / 24 // 1 hour delay - -const OPTIONS_PER_QUESTION = 4 -const INDICES_TO_TEST = [0, 2, 3, 6] -const NUMBER_OF_TEST_QUESTIONS = INDICES_TO_TEST.length - -interface State { - mnemonic: string - currentQuestion: number | null - wordsForBackupQuiz: string[] -} - -interface StateProps { - language: string | null - backupCompleted: boolean - backupTooLate: boolean - backupDelayedTime: number -} - -interface DispatchProps { - setBackupCompleted: typeof setBackupCompleted - setBackupDelayed: typeof setBackupDelayed - enterBackupFlow: typeof enterBackupFlow - exitBackupFlow: typeof exitBackupFlow -} - -type Props = StateProps & DispatchProps - -const mapStateToProps = (state: RootState): StateProps => { - return { - language: state.app.language, - backupCompleted: state.account.backupCompleted, - backupTooLate: isBackupTooLate(state), - backupDelayedTime: state.account.backupDelayedTime, - } -} - -export class Backup extends React.Component { - static navigationOptions = { header: null } - - state = { - mnemonic: '', - currentQuestion: -1, - wordsForBackupQuiz: [], - } - - async componentDidMount() { - this.props.enterBackupFlow() - await this.retrieveMnemonic() - } - - componentWillUnmount() { - // Exit backup flow in unmount instead of cancel, as back button will not trigger onCancel(). - this.props.exitBackupFlow() - } - - retrieveMnemonic = async () => { - if (this.state.mnemonic) { - return - } - - try { - const mnemonic = await getStoredMnemonic() - if (!mnemonic) { - throw new Error('Mnemonic not stored in key store') - } - this.setState({ mnemonic }) - - const wordsForBackupQuiz = await createQuizWordList(mnemonic, this.props.language) - this.setState({ wordsForBackupQuiz }) - } catch (e) { - Logger.error('backup/retrieveMnemonic', e) - // TODO(Rossy): use error banner - Logger.showError('Error retrieving mnemonic') - } - } - - showBackupPhrase = () => { - this.setState({ currentQuestion: 0 }) - } - - showQuiz = () => { - this.setState({ currentQuestion: 1 }) - } - - showNextQuestion = () => { - this.setState({ currentQuestion: this.state.currentQuestion + 1 }) - } - - returnToPhrase = () => { - this.setState({ currentQuestion: 0 }) - } - - onCancel = async () => { - navigateBack() - } - - onDelay = () => { - this.props.setBackupDelayed() - navigateBack() - } - - onFinish = async () => { - this.props.setBackupCompleted() - navigateBack() - } - - render() { - const { mnemonic, currentQuestion, wordsForBackupQuiz } = this.state - const { backupCompleted, backupDelayedTime, backupTooLate } = this.props - - if (backupCompleted) { - return ( - - ) - } - - if (currentQuestion === -1) { - return ( - - ) - } - if (currentQuestion === 0) { - return ( - - ) - } - if (mnemonic && currentQuestion > 0 && currentQuestion <= NUMBER_OF_TEST_QUESTIONS) { - const indexToTest = INDICES_TO_TEST[currentQuestion - 1] - const correctWord = mnemonic.split(' ')[indexToTest] - const wordOptions = selectQuizWordOptions( - correctWord, - wordsForBackupQuiz, - OPTIONS_PER_QUESTION - ) - - return ( - - ) - } - if (currentQuestion > NUMBER_OF_TEST_QUESTIONS) { - return - } - } -} - -export default componentWithAnalytics( - connect( - mapStateToProps, - { setBackupCompleted, setBackupDelayed, enterBackupFlow, exitBackupFlow } - )(Backup) -) diff --git a/packages/mobile/src/backup/BackupComplete.test.tsx b/packages/mobile/src/backup/BackupComplete.test.tsx index 07f0e64a7a9..d4e9c86a319 100644 --- a/packages/mobile/src/backup/BackupComplete.test.tsx +++ b/packages/mobile/src/backup/BackupComplete.test.tsx @@ -1,17 +1,31 @@ import * as React from 'react' import 'react-native' +import { Provider } from 'react-redux' import * as renderer from 'react-test-renderer' import BackupComplete from 'src/backup/BackupComplete' +import { createMockStore } from 'test/utils' describe('BackupComplete', () => { - it('renders correctly if backup not completed', () => { - const tree = renderer.create() + it('renders correctly when social backup is not complete', () => { + const tree = renderer.create( + + + + ) expect(tree).toMatchSnapshot() }) - it('renders correctly if backup completed', () => { + it('renders correctly when social backup is complete', () => { const tree = renderer.create( - + + + ) expect(tree).toMatchSnapshot() }) diff --git a/packages/mobile/src/backup/BackupComplete.tsx b/packages/mobile/src/backup/BackupComplete.tsx index 48a8db952d0..0f804109832 100644 --- a/packages/mobile/src/backup/BackupComplete.tsx +++ b/packages/mobile/src/backup/BackupComplete.tsx @@ -1,77 +1,70 @@ -import Button, { BtnTypes } from '@celo/react-components/components/Button' -import SmallButton from '@celo/react-components/components/SmallButton' import colors from '@celo/react-components/styles/colors' import { fontStyles } from '@celo/react-components/styles/fonts' import * as React from 'react' import { WithNamespaces, withNamespaces } from 'react-i18next' -import { Clipboard, ScrollView, StyleSheet, Text } from 'react-native' +import { StyleSheet, Text, View } from 'react-native' import SafeAreaView from 'react-native-safe-area-view' -import CeloAnalytics from 'src/analytics/CeloAnalytics' -import { CustomEventNames } from 'src/analytics/constants' +import { connect } from 'react-redux' import componentWithAnalytics from 'src/analytics/wrapper' -import BackupPhraseContainer from 'src/backup/BackupPhraseContainer' +import { exitBackupFlow } from 'src/app/actions' import { Namespaces } from 'src/i18n' import NuxLogo from 'src/icons/NuxLogo' -import Logger from 'src/utils/Logger' +import { navigate, navigateHome } from 'src/navigator/NavigationService' +import { Screens } from 'src/navigator/Screens' +import { RootState } from 'src/redux/reducers' -type Props = { - onPress: () => void - mnemonic: string | null - backupCompleted?: boolean -} & WithNamespaces +interface StateProps { + backupCompleted: boolean + socialBackupCompleted: boolean +} -interface State { - selectedAnswer: string | null +interface DispatchProps { + exitBackupFlow: typeof exitBackupFlow } -class BackupComplete extends React.Component { - static navigationOptions = { header: null } +type Props = StateProps & DispatchProps & WithNamespaces - state = { - selectedAnswer: null, +const mapStateToProps = (state: RootState): StateProps => { + return { + backupCompleted: state.account.backupCompleted, + socialBackupCompleted: state.account.socialBackupCompleted, } +} - onSelectAnswer = (word: string) => this.setState({ selectedAnswer: word }) - - onDone = () => { - const { backupCompleted } = this.props - - // Only track when going through backup flow, not viewing the backup again - if (!backupCompleted) { - CeloAnalytics.track(CustomEventNames.questions_done) - } - this.props.onPress() - } +class BackupComplete extends React.Component { + static navigationOptions = { header: null } - copyToClipboard = () => { - const { t } = this.props - Clipboard.setString(this.props.mnemonic || '') - Logger.showMessage(t('copiedToClipboard')) + componentDidMount() { + // Show success text for a while before leaving screen + const { backupCompleted, socialBackupCompleted } = this.props + setTimeout(() => { + if (socialBackupCompleted) { + this.props.exitBackupFlow() + navigateHome() + } else if (backupCompleted) { + navigate(Screens.BackupIntroduction) + } else { + throw new Error('Backup complete screen should not be reachable without completing backup') + } + }, 2000) } render() { - const { t, backupCompleted, mnemonic } = this.props + const { t, backupCompleted, socialBackupCompleted } = this.props return ( - - - - {t(backupCompleted ? 'backupKey' : 'backupKeySet')} - - {t('dontLoseIt')} - {backupCompleted && } - - -