From 16fc393813a053d6abd3c7d67b789fe274756b97 Mon Sep 17 00:00:00 2001 From: andrey Date: Thu, 14 Nov 2024 12:33:18 +0100 Subject: [PATCH] [#21573] Keycard - Sign up with a new Keycard --- .../contexts/keycard/create/events.cljs | 102 ++++++++++++++++++ .../contexts/keycard/create/view.cljs | 62 +++++++++++ .../contexts/keycard/empty/view.cljs | 26 ++++- src/status_im/contexts/keycard/events.cljs | 1 + .../create_or_sync_profile/view.cljs | 30 ++++-- src/status_im/navigation/screens.cljs | 18 +++- 6 files changed, 226 insertions(+), 13 deletions(-) create mode 100644 src/status_im/contexts/keycard/create/events.cljs create mode 100644 src/status_im/contexts/keycard/create/view.cljs diff --git a/src/status_im/contexts/keycard/create/events.cljs b/src/status_im/contexts/keycard/create/events.cljs new file mode 100644 index 0000000000..95d54f9eed --- /dev/null +++ b/src/status_im/contexts/keycard/create/events.cljs @@ -0,0 +1,102 @@ +(ns status-im.contexts.keycard.create.events + (:require [clojure.string :as string] + [utils.re-frame :as rf] + [utils.security.core :as security])) + +(rf/reg-event-fx :keycard/create.check-empty-card + (fn [_] + {:fx [[:dispatch + [:keycard/connect + {:on-error + (fn [error] + (if (= error :keycard/error.keycard-blank) + (do + (rf/dispatch [:keycard/disconnect]) + (rf/dispatch [:open-modal :screen/keycard.empty-create])) + (rf/dispatch [:keycard/on-application-info-error error])))}]]]})) + +(rf/reg-event-fx :keycard/create.get-phrase + (fn [{:keys [db]}] + {:db (assoc-in db [:keycard :create] nil) + :fx [[:dispatch [:navigate-back]] + [:dispatch + [:open-modal :screen/backup-recovery-phrase-dark + {:on-success #(rf/dispatch [:keycard/create.phrase-backed-up %])}]]]})) + +(rf/reg-event-fx :keycard/create.phrase-backed-up + (fn [{:keys [db]} [masked-phrase-vector]] + {:db (assoc-in db + [:keycard :create :masked-phrase] + (->> masked-phrase-vector + security/safe-unmask-data + (string/join " ") + security/mask-data)) + :fx [[:dispatch [:keycard/create.create-or-enter-pin]]]})) + +(rf/reg-event-fx :keycard/create.create-or-enter-pin + (fn [{:keys [db]}] + (let [{:keys [initialized?]} (get-in db [:keycard :application-info])] + {:fx [[:dispatch [:navigate-back]] + (if initialized? + [:dispatch + [:open-modal :screen/keycard.pin.enter + {:on-complete (fn [new-pin] + (rf/dispatch [:navigate-back]) + (rf/dispatch [:keycard/create.save-pin new-pin]) + (rf/dispatch [:open-modal :screen/keycard.create.ready-to-add]))}]] + [:dispatch + [:open-modal :screen/keycard.pin.create + {:on-complete (fn [new-pin] + (rf/dispatch [:navigate-back]) + (rf/dispatch [:keycard/create.save-pin new-pin]) + (rf/dispatch [:open-modal :screen/keycard.create.ready-to-add]))}]])]}))) + +(rf/reg-event-fx :keycard/create.save-pin + (fn [{:keys [db]} [pin]] + {:db (assoc-in db [:keycard :create :pin] pin)})) + +(rf/reg-event-fx :keycard/create.start + (fn [_] + {:fx [[:dispatch + [:keycard/connect + {:on-error + (fn [error] + (if (= error :keycard/error.keycard-blank) + (rf/dispatch [:keycard/create.continue]) + (rf/dispatch [:keycard/on-application-info-error error])))}]]]})) + +(defn get-application-info-and-continue + [init?] + (rf/dispatch [:keycard/get-application-info + {:on-success #(rf/dispatch [:keycard/create.continue]) + :on-error + (fn [error] + (if (or (= error :keycard/error.keycard-blank) + (and (not init?) (= error :keycard/error.keycard-wrong-profile))) + (rf/dispatch [:keycard/create.continue]) + (rf/dispatch [:keycard/on-application-info-error error])))}])) + +(rf/reg-event-fx :keycard/create.continue + (fn [{:keys [db]}] + (let [{:keys [initialized? has-master-key?]} (get-in db [:keycard :application-info]) + {:keys [masked-phrase pin]} (get-in db [:keycard :create])] + + (cond + + (not initialized?) + {:fx [[:keycard/init-card + {:pin pin + :on-success #(get-application-info-and-continue true)}]]} + + (not has-master-key?) + {:fx [[:effects.keycard/generate-and-load-key + {:mnemonic (security/safe-unmask-data masked-phrase) + :pin pin + :on-success #(get-application-info-and-continue false) + :on-failure #(rf/dispatch [:keycard/on-action-with-pin-error %])}]]} + + :else + {:fx [[:effects.keycard/get-more-keys + {:pin pin + :on-success #(rf/dispatch [:keycard.login/recover-profile-and-login %]) + :on-failure #(rf/dispatch [:keycard/on-action-with-pin-error %])}]]})))) diff --git a/src/status_im/contexts/keycard/create/view.cljs b/src/status_im/contexts/keycard/create/view.cljs new file mode 100644 index 0000000000..9cd0e3dc34 --- /dev/null +++ b/src/status_im/contexts/keycard/create/view.cljs @@ -0,0 +1,62 @@ +(ns status-im.contexts.keycard.create.view + (:require [quo.core :as quo] + [react-native.core :as rn] + [status-im.common.events-helper :as events-helper] + [status-im.common.resources :as resources] + [status-im.constants :as constants] + [utils.i18n :as i18n] + [utils.re-frame :as rf])) + +(defn view + [] + [:<> + [quo/page-nav + {:key :header + :background :blur + :icon-name :i/arrow-left + :on-press events-helper/navigate-back}] + [quo/page-top + {:title (i18n/label :t/create-profile-keycard)}] + [rn/view {:style {:padding-horizontal 20 :padding-top 20}} + [quo/small-option-card + {:variant :main + :title (i18n/label :t/check-keycard) + :subtitle (i18n/label :t/see-keycard-ready) + :button-label (i18n/label :t/scan-keycard) + :accessibility-label :get-keycard + :image (resources/get-image :check-your-keycard) + :on-press #(rf/dispatch [:keycard/create.check-empty-card])}] + [rn/view {:style {:height 12}}] + [quo/small-option-card + {:variant :icon + :title (i18n/label :t/learn-more-keycard) + :subtitle (i18n/label :t/secure-wallet-card) + :accessibility-label :setup-keycard + :image (resources/get-image :use-keycard) + :on-press #(rf/dispatch [:browser.ui/open-url constants/get-keycard-url])}]] + [rn/view {:style {:flex 1}}] + [quo/divider-label (i18n/label :t/tips-scan-keycard)] + [quo/markdown-list {:description (i18n/label :t/remove-phone-case)}] + [quo/markdown-list {:description (i18n/label :t/keep-card-steady)}]]) + +(defn ready-to-add + [] + [:<> + [quo/page-nav + {:icon-name :i/arrow-left + :on-press events-helper/navigate-back}] + [quo/page-top + {:title (i18n/label :t/ready-add-keypair-keycard) + :description :text + :description-text ""}] + [rn/view {:style {:flex 1 :align-items :center :justify-content :center}} + [rn/image + {:resize-mode :contain + :source (resources/get-image :generate-keys1)}]] + [quo/divider-label (i18n/label :t/tips-scan-keycard)] + [quo/markdown-list {:description (i18n/label :t/remove-phone-case)}] + [quo/markdown-list {:description (i18n/label :t/keep-card-steady)}] + [quo/bottom-actions + {:actions :one-action + :button-one-label (i18n/label :t/ready-to-scan) + :button-one-props {:on-press #(rf/dispatch [:keycard/create.start])}}]]) diff --git a/src/status_im/contexts/keycard/empty/view.cljs b/src/status_im/contexts/keycard/empty/view.cljs index 500d2ed162..3d7f4bed82 100644 --- a/src/status_im/contexts/keycard/empty/view.cljs +++ b/src/status_im/contexts/keycard/empty/view.cljs @@ -7,6 +7,30 @@ [utils.i18n :as i18n] [utils.re-frame :as rf])) +(defn create + [] + [:<> + [quo/page-nav + {:icon-name :i/close + :on-press events-helper/navigate-back}] + [quo/page-top + {:title (i18n/label :t/keycard-empty) + :description :text + :description-text (i18n/label :t/what-to-do)}] + [rn/view {:style {:padding-horizontal 28 :padding-top 20}} + [quo/small-option-card + {:variant :main + :title (i18n/label :t/create-new-profile) + :subtitle (i18n/label :t/new-key-pair-keycard) + :button-label (i18n/label :t/lets-go) + :accessibility-label :create-new-profile-keycard + :image (resources/get-image :keycard-buy) + :on-press #(rf/dispatch [:keycard/create.get-phrase])}]] + [quo/information-box + {:type :default + :style {:margin-top 32 :margin-horizontal 28}} + (i18n/label :t/add-key-pair-desktop)]]) + (defn view [] [:<> @@ -23,7 +47,7 @@ :title (i18n/label :t/import-key-pair-keycard) :subtitle (i18n/label :t/use-keycard-login-sign) :button-label (i18n/label :t/import-profile-key-pair) - :accessibility-label :get-keycard + :accessibility-label :import-key-pair-keycard :image (resources/get-image :keycard-buy) :on-press (fn [] (rf/dispatch diff --git a/src/status_im/contexts/keycard/events.cljs b/src/status_im/contexts/keycard/events.cljs index 60ee834124..a1af7520a7 100644 --- a/src/status_im/contexts/keycard/events.cljs +++ b/src/status_im/contexts/keycard/events.cljs @@ -1,5 +1,6 @@ (ns status-im.contexts.keycard.events (:require [re-frame.core :as rf] + status-im.contexts.keycard.create.events status-im.contexts.keycard.login.events status-im.contexts.keycard.migrate.events status-im.contexts.keycard.migrate.re-encrypting.events diff --git a/src/status_im/contexts/onboarding/create_or_sync_profile/view.cljs b/src/status_im/contexts/onboarding/create_or_sync_profile/view.cljs index 5266b03baa..d924d29081 100644 --- a/src/status_im/contexts/onboarding/create_or_sync_profile/view.cljs +++ b/src/status_im/contexts/onboarding/create_or_sync_profile/view.cljs @@ -108,17 +108,25 @@ :image (resources/get-image :ethereum-address) :on-press nav-to-seed-phrase-with-cur-screen}] [rn/view {:style style/space-between-suboptions}] - [quo/small-option-card - {:variant :icon - :title (i18n/label :t/use-keycard) - :subtitle (i18n/label :t/profile-keys-on-keycard) - :accessibility-label :use-keycard-option-card - :image (resources/get-image :use-keycard) - :on-press (fn [] - (rf/dispatch [:open-modal :screen/keycard.check - {:on-press - #(rf/dispatch - [:keycard.login/check-card])}]))}]]])) + (if create-profile? + [quo/small-option-card + {:variant :icon + :title (i18n/label :t/use-keycard) + :subtitle (i18n/label :t/use-keycard-subtitle) + :accessibility-label :use-keycard-option-card + :image (resources/get-image :use-keycard) + :on-press #(rf/dispatch [:open-modal :screen/keycard.create-profile])}] + [quo/small-option-card + {:variant :icon + :title (i18n/label :t/use-keycard) + :subtitle (i18n/label :t/profile-keys-on-keycard) + :accessibility-label :use-keycard-option-card + :image (resources/get-image :use-keycard) + :on-press (fn [] + (rf/dispatch [:open-modal :screen/keycard.check + {:on-press + #(rf/dispatch + [:keycard.login/check-card])}]))}])]])) (defn- navigate-back [] diff --git a/src/status_im/navigation/screens.cljs b/src/status_im/navigation/screens.cljs index 9d3d494bbb..30e1825adc 100644 --- a/src/status_im/navigation/screens.cljs +++ b/src/status_im/navigation/screens.cljs @@ -30,6 +30,7 @@ [status-im.contexts.communities.overview.view :as communities.overview] [status-im.contexts.keycard.authorise.view :as keycard.authorise] [status-im.contexts.keycard.check.view :as keycard.check] + [status-im.contexts.keycard.create.view :as keycard.create] [status-im.contexts.keycard.empty.view :as keycard.empty] [status-im.contexts.keycard.error.view :as keycard.error] [status-im.contexts.keycard.migrate.fail.view :as keycard.migrate.fail] @@ -884,6 +885,11 @@ :insets {:top? true :bottom? true}} :component keycard.empty/view} + {:name :screen/keycard.empty-create + :metrics {:track? :true} + :options {:insets {:top? true :bottom? true}} + :component keycard.empty/create} + {:name :screen/keycard.error :metrics {:track? :true} :options {:theme :dark @@ -951,7 +957,17 @@ :metrics {:track? :true} :options {:theme :dark :insets {:top? true :bottom? true}} - :component keycard.migrate.profile-keys/view}]) + :component keycard.migrate.profile-keys/view} + + {:name :screen/keycard.create-profile + :metrics {:track? :true} + :options {:insets {:top? true :bottom? true}} + :component keycard.create/view} + + {:name :screen/keycard.create.ready-to-add + :metrics {:track? :true} + :options {:insets {:top? true :bottom? true}} + :component keycard.create/ready-to-add}]) (defn screens []