diff --git a/.env b/.env index 1d1fbb817b..5b9a41a622 100644 --- a/.env +++ b/.env @@ -13,3 +13,4 @@ RN_BRIDGE_THRESHOLD_WARNINGS=0 COMPILE_VIEWS_ENABLED=0 POW_TARGET=0.001 POW_TIME=1 +MIXPANEL_TOKEN=3f2e1a8970f159aa2a3d5dc5d65eab38 diff --git a/.env.jenkins b/.env.jenkins index 67a65e82b1..f871802d09 100644 --- a/.env.jenkins +++ b/.env.jenkins @@ -11,5 +11,6 @@ QUEUE_MESSAGE_ENABLED=1 MANY_WHISPER_TOPICS_ENABLED=0 RN_BRIDGE_THRESHOLD_WARNINGS=0 COMPILE_VIEWS_ENABLED=0 +MIXPANEL_TOKEN=3f2e1a8970f159aa2a3d5dc5d65eab38 POW_TARGET=0.001 POW_TIME=1 diff --git a/.env.prod b/.env.prod index 4358e52974..4ca850aa22 100644 --- a/.env.prod +++ b/.env.prod @@ -11,5 +11,6 @@ QUEUE_MESSAGE_ENABLED=0 MANY_WHISPER_TOPICS_ENABLED=0 RN_BRIDGE_THRESHOLD_WARNINGS=0 COMPILE_VIEWS_ENABLED=0 +MIXPANEL_TOKEN=2584e00100d319d12e538cc4d0fa9fc1 POW_TARGET=0.2 POW_TIME=1 diff --git a/src/status_im/chat/events/commands.cljs b/src/status_im/chat/events/commands.cljs index 4c6f0a0f93..75ad74f86f 100644 --- a/src/status_im/chat/events/commands.cljs +++ b/src/status_im/chat/events/commands.cljs @@ -12,7 +12,7 @@ (defn- generate-context "Generates context for jail call" [current-account-id chat-id to group-id] - (merge {:platform platform/platform + (merge {:platform platform/os :from current-account-id :to to :chat {:chat-id chat-id diff --git a/src/status_im/ui/screens/accounts/events.cljs b/src/status_im/ui/screens/accounts/events.cljs index 4c7eb619c8..0161630a0a 100644 --- a/src/status_im/ui/screens/accounts/events.cljs +++ b/src/status_im/ui/screens/accounts/events.cljs @@ -109,7 +109,7 @@ ::account-created [re-frame/trim-v (re-frame/inject-cofx :get-new-keypair!) (re-frame/inject-cofx ::get-signing-phrase) (re-frame/inject-cofx ::get-status)] - (fn [{:keys [keypair signing-phrase status db] :as cofx} [{:keys [pubkey address mnemonic]} password]] + (fn [{:keys [keypair signing-phrase status db]} [{:keys [pubkey address mnemonic]} password]] (let [normalized-address (utils.hex/normalize-hex address) account {:public-key pubkey :address normalized-address @@ -208,6 +208,12 @@ :dispatch [:navigate-to-clean :usage-data]} (account-update {:name (:name create)})))) +(handlers/register-handler-fx + :account-finalized + (fn [{db :db} _] + {:db db + :dispatch [:navigate-to-clean :home]})) + (handlers/register-handler-fx :update-sign-in-time (fn [{db :db now :now} _] @@ -221,4 +227,4 @@ (handlers/register-handler-fx :switch-dev-mode (fn [{db :db} [_ dev-mode]] - (account-update {:db db} {:dev-mode? dev-mode}))) \ No newline at end of file + (account-update {:db db} {:dev-mode? dev-mode}))) diff --git a/src/status_im/ui/screens/accounts/login/events.cljs b/src/status_im/ui/screens/accounts/login/events.cljs index bb143e8fb9..6c5250350a 100644 --- a/src/status_im/ui/screens/accounts/login/events.cljs +++ b/src/status_im/ui/screens/accounts/login/events.cljs @@ -120,13 +120,14 @@ (register-handler-fx :change-account-handler - (fn [{{:keys [view-id] :as db} :db} [_ error address]] + (fn [{{:keys [accounts/accounts view-id] :as db} :db} [_ error address]] (if (nil? error) {:db (cond-> (dissoc db :accounts/login) (= view-id :create-account) (assoc-in [:accounts/create :step] :enter-name)) :dispatch-n (concat [[:stop-debugging] + (when (:sharing-usage-data? (accounts address)) [:register-mixpanel-tracking address]) [:initialize-account address (when (not= view-id :create-account) [[:navigate-to-clean :home]])]])} diff --git a/src/status_im/ui/screens/contacts/events.cljs b/src/status_im/ui/screens/contacts/events.cljs index 14796c1c5b..1857eb6a5d 100644 --- a/src/status_im/ui/screens/contacts/events.cljs +++ b/src/status_im/ui/screens/contacts/events.cljs @@ -5,7 +5,6 @@ [clojure.string :as s] [status-im.protocol.core :as protocol] [status-im.utils.contacts :as utils.contacts] - [status-im.utils.utils :refer [http-post]] [status-im.utils.random :as random] [taoensso.timbre :as log] [cljs.reader :refer [read-string]] diff --git a/src/status_im/ui/screens/events.cljs b/src/status_im/ui/screens/events.cljs index 4d29fd7fe7..b5f2267349 100644 --- a/src/status_im/ui/screens/events.cljs +++ b/src/status_im/ui/screens/events.cljs @@ -34,12 +34,15 @@ [status-im.js-dependencies :as dependencies] [status-im.ui.screens.db :refer [app-db]] [status-im.utils.datetime :as time] + [status-im.utils.ethereum.core :as ethereum] [status-im.utils.random :as random] [status-im.utils.config :as config] [status-im.utils.crypt :as crypt] [status-im.utils.notifications :as notifications] [status-im.utils.handlers :as handlers] + [status-im.utils.http :as http] [status-im.utils.instabug :as inst] + [status-im.utils.mixpanel :as mixpanel] [status-im.utils.platform :as platform] [status-im.utils.types :as types] [status-im.utils.utils :as utils] @@ -113,14 +116,14 @@ (let [on-success #(re-frame/dispatch (success-event-creator %)) on-error #(re-frame/dispatch (failure-event-creator %)) opts {:timeout-ms timeout-ms}] - (utils/http-post action data on-success on-error opts)))) + (http/post action data on-success on-error opts)))) (defn- http-get [{:keys [url response-validator success-event-creator failure-event-creator timeout-ms]}] (let [on-success #(re-frame/dispatch (success-event-creator %)) on-error #(re-frame/dispatch (failure-event-creator %)) opts {:valid-response? response-validator :timeout-ms timeout-ms}] - (utils/http-get url on-success on-error opts))) + (http/get url on-success on-error opts))) (re-frame/reg-fx :http-get @@ -204,7 +207,6 @@ :close-application (fn [] (status/close-application))) - ;;;; Handlers (handlers/register-handler-db @@ -220,13 +222,13 @@ (handlers/register-handler-fx :initialize-app (fn [_ _] - {::testfairy-alert nil - :dispatch-n [[:initialize-db] - [:load-accounts] - [:initialize-views] - [:listen-to-network-status] - [:initialize-crypt] - [:initialize-geth]]})) + {::testfairy-alert nil + :dispatch-n [[:initialize-db] + [:load-accounts] + [:initialize-views] + [:listen-to-network-status] + [:initialize-crypt] + [:initialize-geth]]})) (handlers/register-handler-fx :initialize-db @@ -250,8 +252,7 @@ status-module-initialized? status-node-started? inbox/wnode] :or [network (get app-db :network) - wnode (get app-db :inbox/wnode)] - :as db} [_ address]] + wnode (get app-db :inbox/wnode)]} [_ address]] (let [console-contact (get contacts console-chat-id)] (cond-> (assoc app-db :access-scope->commands-responses access-scope->commands-responses @@ -332,6 +333,25 @@ (fn [_ _] {::get-fcm-token-fx nil})) +(defn- track [id event] + (let [anonid (ethereum/sha3 id)] + (doseq [{:keys [label properties]} (mixpanel/matching-events event mixpanel/event-by-trigger)] + (mixpanel/track anonid label properties)))) + +(def hook-id :mixpanel-callback) + +(handlers/register-handler-fx + :register-mixpanel-tracking + (fn [_ [_ id]] + (re-frame/add-post-event-callback hook-id #(track id %)) + nil)) + +(handlers/register-handler-fx + :unregister-mixpanel-tracking + (fn [] + (re-frame/remove-post-event-callback hook-id) + nil)) + ;; Because we send command to jail in params and command `:ref` is a lookup vector with ;; keyword in it (for example `["transactor" :command 51 "send"]`), we lose that keyword ;; information in the process of converting to/from JSON, and we need to restore it diff --git a/src/status_im/ui/screens/profile/user/views.cljs b/src/status_im/ui/screens/profile/user/views.cljs index a2a0433f40..e50df7a3d2 100644 --- a/src/status_im/ui/screens/profile/user/views.cljs +++ b/src/status_im/ui/screens/profile/user/views.cljs @@ -107,20 +107,22 @@ :icon-content [components.common/counter {:size 22} 1]}] [profile.components/settings-item-separator]])]) -(defn navigate-to-accounts [] +(defn navigate-to-accounts [sharing-usage-data?] ;; TODO(rasom): probably not the best place for this call (protocol/stop-whisper!) - (re-frame/dispatch [:navigate-to :accounts])) + (re-frame/dispatch [:navigate-to :accounts]) + (when sharing-usage-data? + (re-frame/dispatch [:unregister-mixpanel-tracking]))) -(defn handle-logout [] +(defn handle-logout [sharing-usage-data?] (utils/show-confirmation (i18n/label :t/logout-title) (i18n/label :t/logout-are-you-sure) - (i18n/label :t/logout) navigate-to-accounts)) + (i18n/label :t/logout) #(navigate-to-accounts sharing-usage-data?))) -(defn logout [] +(defn logout [sharing-usage-data?] [react/view {} [react/touchable-highlight - {:on-press handle-logout + {:on-press #(handle-logout sharing-usage-data?) :accessibility-label :log-out-button} [react/view profile.components.styles/settings-item [react/text {:style styles/logout-text @@ -159,7 +161,7 @@ :action-fn #(re-frame/dispatch [:switch-dev-mode %])}]])])) (defview my-profile [] - (letsubs [{:keys [public-key] :as current-account} [:get-current-account] + (letsubs [{:keys [public-key sharing-usage-data?] :as current-account} [:get-current-account] editing? [:get :my-profile/editing?] changed-account [:get :my-profile/profile]] (let [shown-account (merge current-account changed-account)] @@ -174,5 +176,5 @@ [share-contact-code current-account public-key]] [react/view styles/my-profile-info-container [my-profile-settings current-account]] - [logout] - [advanced shown-account]]]))) \ No newline at end of file + [logout sharing-usage-data?] + [advanced shown-account]]]))) diff --git a/src/status_im/ui/screens/qr_scanner/styles.cljs b/src/status_im/ui/screens/qr_scanner/styles.cljs index 461d40d6d7..fcb37754f7 100644 --- a/src/status_im/ui/screens/qr_scanner/styles.cljs +++ b/src/status_im/ui/screens/qr_scanner/styles.cljs @@ -1,16 +1,13 @@ (ns status-im.ui.screens.qr-scanner.styles - (:require [status-im.ui.components.styles :refer [color-white]] - [status-im.ui.components.toolbar.styles :as toolbar.styles] - [status-im.utils.platform :as p])) + (:require [status-im.ui.components.colors :as colors] + [status-im.ui.components.toolbar.styles :as toolbar.styles])) (def barcode-scanner-container {:flex 1 :background-color :white}) (def barcode-scanner - {:flex 1 - :justify-content :flex-end - :align-items :center}) + {:flex 1}) (def rectangle-container {:position :absolute @@ -73,5 +70,5 @@ (def import-text {:flex 1 :flex-direction :column - :color color-white + :color colors/white :margin-left 8}) diff --git a/src/status_im/ui/screens/usage_data/events.cljs b/src/status_im/ui/screens/usage_data/events.cljs index 7a2f999918..419aa2edd3 100644 --- a/src/status_im/ui/screens/usage_data/events.cljs +++ b/src/status_im/ui/screens/usage_data/events.cljs @@ -4,7 +4,9 @@ (handlers/register-handler-fx :help-improve-handler - (fn [{db :db} [_ yes?]] + (fn [{db :db} [_ yes? address]] (merge (when yes? (accounts/account-update {:db db} {:sharing-usage-data? true})) - {:dispatch [:navigate-to-clean :home]}))) \ No newline at end of file + {:dispatch-n [(when yes? [:register-mixpanel-tracking address]) + [:account-finalized]]}))) + diff --git a/src/status_im/ui/screens/usage_data/views.cljs b/src/status_im/ui/screens/usage_data/views.cljs index d4b95d8ba7..18b36a67ca 100644 --- a/src/status_im/ui/screens/usage_data/views.cljs +++ b/src/status_im/ui/screens/usage_data/views.cljs @@ -1,5 +1,5 @@ (ns status-im.ui.screens.usage-data.views - (:require-macros [status-im.utils.views :refer [defview letsubs]]) + (:require-macros [status-im.utils.views :as views]) (:require [status-im.ui.components.react :as react] [re-frame.core :as re-frame] [status-im.react-native.resources :as resources] @@ -8,23 +8,24 @@ [status-im.i18n :as i18n] [status-im.ui.components.status-bar.view :as status-bar])) -(defview usage-data [] - [react/view {:style styles/usage-data-view} - [status-bar/status-bar {:flat? true}] - [react/view {:style styles/logo-container} - [components.common/logo styles/logo] - [react/image {:source (:analytics-image resources/ui) - :style styles/usage-data-image}]] - [react/text {:style styles/help-improve-text} - (i18n/label :t/help-improve)] - [react/view - [react/text {:style styles/help-improve-text-description} - (i18n/label :t/help-improve-description)]] - [react/view styles/buttons-container - [components.common/button {:style {:flex-direction :row} - :on-press #(re-frame/dispatch [:help-improve-handler true]) - :label (i18n/label :t/share-usage-data)}] - [react/view styles/bottom-button-container - [components.common/button {:on-press #(re-frame/dispatch [:help-improve-handler false]) - :label (i18n/label :t/dont-want-to-share) - :background? false}]]]]) \ No newline at end of file +(views/defview usage-data [] + (views/letsubs [account [:get-current-account]] + [react/view {:style styles/usage-data-view} + [status-bar/status-bar {:flat? true}] + [react/view {:style styles/logo-container} + [components.common/logo styles/logo] + [react/image {:source (:analytics-image resources/ui) + :style styles/usage-data-image}]] + [react/text {:style styles/help-improve-text} + (i18n/label :t/help-improve)] + [react/view + [react/text {:style styles/help-improve-text-description} + (i18n/label :t/help-improve-description)]] + [react/view styles/buttons-container + [components.common/button {:style {:flex-direction :row} + :on-press #(re-frame/dispatch [:help-improve-handler true (:address account)]) + :label (i18n/label :t/share-usage-data)}] + [react/view styles/bottom-button-container + [components.common/button {:on-press #(re-frame/dispatch [:help-improve-handler false (:address account)]) + :label (i18n/label :t/dont-want-to-share) + :background? false}]]]])) diff --git a/src/status_im/utils/build.clj b/src/status_im/utils/build.clj index 61f620d4cc..bae675c0fe 100644 --- a/src/status_im/utils/build.clj +++ b/src/status_im/utils/build.clj @@ -1,13 +1,12 @@ (ns status-im.utils.build - (:require [cljs.analyzer :as analyzer])) + (:require [cljs.analyzer :as analyzer] + [clojure.java.shell :as shell])) ;; Some warnings are unavoidable due to dependencies. For example, reagent 0.6.0 ;; has a warning in its util.cljs namespace. Adjust this as is necessary and ;; unavoidable warnings arise. (def acceptable-warning? - #{ - "Protocol IFn implements method -invoke with variadic signature (&)" ;; reagent 0.6.0 reagent/impl/util.cljs:61 - }) + #{"Protocol IFn implements method -invoke with variadic signature (&)"}) ;; reagent 0.6.0 reagent/impl/util.cljs:61 (defn nil-acceptable-warning [s] (when-not (acceptable-warning? s) @@ -19,3 +18,6 @@ (binding [*out* *err*] (println (analyzer/message env (str "\u001B[31mWARNING\u001B[0m: " s)))) (System/exit 1)))) + +(defmacro git-short-version [] + (:out (shell/sh "bash" "-c" "git describe --always"))) diff --git a/src/status_im/utils/build.cljs b/src/status_im/utils/build.cljs new file mode 100644 index 0000000000..92dfc87458 --- /dev/null +++ b/src/status_im/utils/build.cljs @@ -0,0 +1,4 @@ +(ns status-im.utils.build + (:require-macros [status-im.utils.build :refer [git-short-version]])) + +(def version (git-short-version)) diff --git a/src/status_im/utils/config.cljs b/src/status_im/utils/config.cljs index 3e00af0766..9ef991ed7e 100644 --- a/src/status_im/utils/config.cljs +++ b/src/status_im/utils/config.cljs @@ -33,6 +33,7 @@ (def many-whisper-topics-enabled? (enabled? (get-config :MANY_WHISPER_TOPICS_ENABLED 0))) (def rn-bridge-threshold-warnings-enabled? (enabled? (get-config :RN_BRIDGE_THRESHOLD_WARNINGS 0))) (def compile-views-enabled? (enabled? (get-config :COMPILE_VIEWS_ENABLED 0))) +(def mixpanel-token (get-config :MIXPANEL_TOKEN)) (def pow-target (js/parseFloat (get-config :POW_TARGET "0.001"))) (def pow-time (js/parseInt (get-config :POW_TIME "1"))) diff --git a/src/status_im/utils/handlers.cljs b/src/status_im/utils/handlers.cljs index 987be1f4de..180b9bf9a9 100644 --- a/src/status_im/utils/handlers.cljs +++ b/src/status_im/utils/handlers.cljs @@ -18,6 +18,12 @@ (handler db params) db)) +(defn- pretty-print-event [ctx] + (let [[first second] (get-coeffect ctx :event)] + (if (map? second) + first + (str first " " second)))) + (def debug-handlers-names "Interceptor which logs debug information to js/console for each event." (->interceptor @@ -26,13 +32,12 @@ [context] (when @pre-event-callback (@pre-event-callback (get-coeffect context :event))) - (log/debug "Handling re-frame event: " (first (get-coeffect context :event))) + (log/debug "Handling re-frame event: " (pretty-print-event context)) context))) (defn- check-spec-msg-path-problem [problem] - (let [pred (:pred problem)] - (str "Spec: " (-> problem :via last) "\n" - "Predicate: " (subs (str (:pred problem)) 0 50)))) + (str "Spec: " (-> problem :via last) "\n" + "Predicate: " (subs (str (:pred problem)) 0 50))) (defn- check-spec-msg-path-problems [path path-problems] (str "Key path: " path "\n" diff --git a/src/status_im/utils/http.cljs b/src/status_im/utils/http.cljs new file mode 100644 index 0000000000..96a42ed6d1 --- /dev/null +++ b/src/status_im/utils/http.cljs @@ -0,0 +1,61 @@ +(ns status-im.utils.http + (:require [status-im.constants :as const] + [status-im.utils.utils :as utils] + [status-im.react-native.js-dependencies :as rn-dependencies]) + (:refer-clojure :exclude [get])) + +;; Default HTTP request timeout ms +(def http-request-default-timeout-ms 3000) + +(defn post + "Performs an HTTP POST request" + ([action data on-success] + (post action data on-success nil)) + ([action data on-success on-error] + (post action data on-success on-error nil)) + ([action data on-success on-error {:keys [timeout-ms]}] + (-> (rn-dependencies/fetch (str const/server-address action) + (clj->js {:method "POST" + :headers {:accept "application/json" + :content-type "application/json"} + :body (.stringify js/JSON (clj->js data)) + :timeout (or timeout-ms http-request-default-timeout-ms)})) + (.then (fn [response] + (.text response))) + (.then (fn [text] + (let [json (.parse js/JSON text) + obj (js->clj json :keywordize-keys true)] + (on-success obj)))) + (.catch (or on-error + (fn [error] + (utils/show-popup "Error" (str error)))))))) + +(defn get + "Performs an HTTP GET request" + ([url] (get url nil)) + ([url on-success] (get url on-success nil)) + ([url on-success on-error] + (get url on-success on-error nil)) + ([url on-success on-error {:keys [valid-response? timeout-ms]}] + (-> (rn-dependencies/fetch url + (clj->js {:method "GET" + :headers {"Cache-Control" "no-cache"} + :timeout (or timeout-ms http-request-default-timeout-ms)})) + (.then (fn [response] + (let [ok? (.-ok response) + ok?' (if valid-response? + (and ok? (valid-response? response)) + ok?)] + [(.-_bodyText response) ok?']))) + (.then (fn [[response ok?]] + (cond + (and on-success ok?) + (on-success response) + + (and on-error (not ok?)) + (on-error response) + + :else false))) + (.catch (or on-error + (fn [error] + (utils/show-popup "Error" (str error)))))))) diff --git a/src/status_im/utils/mixpanel.cljs b/src/status_im/utils/mixpanel.cljs new file mode 100644 index 0000000000..22a2b97b76 --- /dev/null +++ b/src/status_im/utils/mixpanel.cljs @@ -0,0 +1,48 @@ +(ns status-im.utils.mixpanel + (:require-macros [status-im.utils.slurp :as slurp]) + (:require [cljs.reader :as reader] + [goog.crypt.base64 :as b64] + [status-im.utils.build :as build] + [status-im.utils.config :as config] + [status-im.utils.datetime :as datetime] + [status-im.utils.http :as http] + [status-im.utils.platform :as platform] + [status-im.utils.types :as types])) + +(def base-url "http://api.mixpanel.com/") +(def base-track-url (str base-url "track/")) + +(defn encode [m] + (b64/encodeString (types/clj->json m))) + +(defn- build-url [id label props] + (str base-track-url + "?data=" + (encode {:event label + :properties (merge + {:token config/mixpanel-token + :distinct_id id + :os platform/os + :os-version platform/version + :app-version build/version + :time (datetime/timestamp)} + props)}))) + +(defn track [id label props] + (http/get (build-url id label props))) + +;; Mixpanel events definition + +(def events (reader/read-string (slurp/slurp "./src/status_im/utils/mixpanel_events.edn"))) +(def event-by-trigger (reduce-kv #(assoc %1 (:trigger %3) %3) {} events)) + +(defn matches? [event trigger] + (if (= 1 (count trigger)) + (= (first event) (first trigger)) + (and + (= (first event) (first trigger)) + (= (second event) (second trigger))))) + +(defn matching-events [event definitions] + (reduce-kv #(if (matches? event %2) (conj %1 %3) %1) [] definitions)) + diff --git a/src/status_im/utils/mixpanel_events.edn b/src/status_im/utils/mixpanel_events.edn new file mode 100644 index 0000000000..0988b52118 --- /dev/null +++ b/src/status_im/utils/mixpanel_events.edn @@ -0,0 +1,146 @@ +;; This file is supposed to be edited by Chad. +;; Chad loves mixpanel. When Chad was a child he dreamed of being a mixpanel tamer. + +[;; Account creation + + {:label "Account created" + :trigger [:account-finalized]} + {:label "Account restored" + :trigger [:account-recovered]} + + ;; Account lifecycle + + {:label "Login" + :trigger [:initialize-account]} + + {:label "Logout" + :trigger [:navigate-to :accounts]} + + ;; Tab navigation + + {:label "Tap" + :trigger [:navigate-to-clean :home] + :properties {:target :home}} + {:label "Tap" + :trigger [:navigate-to-tab :home] + :properties {:target :home}} + {:label "Tap" + :trigger [:navigate-to-tab :my-profile] + :properties {:target :my-profile}} + {:label "Tap" + :trigger [:navigate-to-clean :wallet] + :properties {:target :wallet}} + {:label "Tap" + :trigger [:navigate-to-tab :wallet] + :properties {:target :wallet}} + + ;; New + {:label "Tap" + :trigger [:navigate-to-tab :new] + :properties {:target :new}} + {:label "Tap" + :trigger [:navigate-to :new-chat] + :properties {:target :new-chat}} + {:label "Tap" + :trigger [:scan-qr-code] + :properties {:target :new-chat-qr-code}} + {:label "Tap" + :trigger [:show-profile] + :properties {:target :show-profile}} + {:label "Tap" + :trigger [:open-contact-toggle-list :chat-group] + :properties {:target :new-group-chat}} + {:label "Tap" + :trigger [:navigate-to :new-public-chat] + :properties {:target :new-public-chat}} + {:label "Tap" + :trigger [:navigate-to :open-dapp] + :properties {:target :open-dapp}} + {:label "Tap" + :trigger [:navigate-to :dapp-description] + :properties {:target :open-dapp-description}} + {:label "Tap" + :trigger [:open-dapp-in-browser] + :properties {:target :open-selected-dapp}} + {:label "Tap" + :trigger [:navigate-to :new-group] + :properties {:target :start-group-chat-next}} + {:label "Tap" + :trigger [:create-new-public-chat] + :properties {:target :create-public-chat}} + {:label "Tap" + :trigger [:navigate-to :new-public-chat] + :properties {:target :join-public-chat}} + + ;; Chat + + {:label "Tap" + :trigger [:navigate-to-chat] + :properties {:target :open-existing-chat}} + {:label "Tap" + :trigger [:navigate-to :browser] + :properties {:target :open-existing-dapp}} + {:label "Tap" + :trigger [:start-chat] + :properties {:target :start-chat}} + {:label "Tap" + :trigger [:send-current-message] + :properties {:target :send-current-message}} + + ;; Wallet + {:label "Tap" + :trigger [:navigate-to :wallet-send-transaction] + :properties {:target :wallet-send-transaction}} + {:label "Tap" + :trigger [:navigate-to :wallet-request-transaction] + :properties {:target :wallet-request-transaction}} + {:label "Tap" + :trigger [:navigate-to :transactions-history] + :properties {:target :transactions-history}} + {:label "Tap" + :trigger [:navigate-to :recent-recipients] + :properties {:target :select-recipient + :type :recent-recipients}} + {:label "Tap" + :trigger [:navigate-to :recipient-qr-code] + :properties {:target :select-recipient + :type :recipient-qr-code}} + {:label "Tap" + :trigger [:navigate-to :contact-code] + :properties {:target :select-recipient + :type :contact-code}} + {:label "Tap" + :trigger [:navigate-to :wallet-send-assets] + :properties {:target :wallet-send-assets}} + {:label "Tap" + :trigger [:wallet.send/toggle-advanced] + :properties {:target :wallet-advanced}} + {:label "Tap" + :trigger [:wallet.send/set-signing?] + :properties {:target :wallet-open-sign-transaction}} + {:label "Tap" + :trigger [:wallet/sign-transaction] + :properties {:target :wallet-sign-transaction}} + {:label "Tap" + :trigger [:navigate-to-clean :wallet] + :properties {:target :wallet-got-it}} + {:label "Tap" + :trigger [:navigate-to :wallet-transaction-sent] + :properties {:target :wallet-transaction-sent}} + + + ;;Profile + {:label "Tap" + :trigger [:my-profile/start-editing-profile] + :properties {:target :edit-profile}} + {:label "Tap" + :trigger [:my-profile/update-picture] + :properties {:target :edit-image + :type :gallery}} + {:label "Tap" + :trigger [:navigate-to :profile-photo-capture] + :properties {:target :edit-image + :type :capture}} + {:label "Tap" + :trigger [:navigate-to :profile-qr-viewer] + :properties {:target :share-contact-code}}] diff --git a/src/status_im/utils/platform.cljs b/src/status_im/utils/platform.cljs index 6dece9b624..a45b832cac 100644 --- a/src/status_im/utils/platform.cljs +++ b/src/status_im/utils/platform.cljs @@ -4,11 +4,18 @@ [status-im.react-native.js-dependencies :as rn-dependencies])) (def platform - (when-let [pl (.-Platform rn-dependencies/react-native)] - (.-OS pl))) + (.-Platform rn-dependencies/react-native)) -(def android? (= platform "android")) -(def ios? (= platform "ios")) +(def os + (when platform + (.-OS platform))) + +(def version + (when platform + (.-Version platform))) + +(def android? (= os "android")) +(def ios? (= os "ios")) (def iphone-x? (and ios? (ios/iphone-x-dimensions?))) (def platform-specific diff --git a/src/status_im/utils/prices.cljs b/src/status_im/utils/prices.cljs index 77d06cfbd3..4c1d1f96cf 100644 --- a/src/status_im/utils/prices.cljs +++ b/src/status_im/utils/prices.cljs @@ -1,5 +1,5 @@ (ns status-im.utils.prices - (:require [status-im.utils.utils :as utils] + (:require [status-im.utils.http :as http] [status-im.utils.types :as types])) ;; Responsible for interacting with Cryptocompare API to get current prices for @@ -25,7 +25,7 @@ :last-day (:OPEN24HOUR entry)})) (defn get-prices [from to on-success on-error] - (utils/http-get + (http/get (gen-price-url from to) (fn [resp] (on-success (format-price-resp from to resp))) on-error)) diff --git a/src/status_im/utils/styles.clj b/src/status_im/utils/styles.clj index b32a1a1a4b..aaaf8945e6 100644 --- a/src/status_im/utils/styles.clj +++ b/src/status_im/utils/styles.clj @@ -4,10 +4,10 @@ (defn wrap-first-time "Allows to avoid - \"Use of undeclared Var status-im.utils.platform/platform\" + \"Use of undeclared Var status-im.utils.platform/os\" warning. When defstyle or defnstyle is called first time status-im.utils.platform namespace will be explicitly required so that clojurescript compiler will compile - it before using status-im.utils.platform/platform in macro" + it before using status-im.utils.platform/os in macro" [body] `(do ~@[(when @first-time @@ -18,7 +18,7 @@ (defn body [style] `(let [style# ~style common# (dissoc style# :android :ios) - platform# (keyword status-im.utils.platform/platform) + platform# (keyword status-im.utils.platform/os) platform-specific# (get style# platform#)] (if platform-specific# (merge common# platform-specific#) diff --git a/src/status_im/utils/transactions.cljs b/src/status_im/utils/transactions.cljs index bfae3ab69c..ba1b2f5e38 100644 --- a/src/status_im/utils/transactions.cljs +++ b/src/status_im/utils/transactions.cljs @@ -1,5 +1,5 @@ (ns status-im.utils.transactions - (:require [status-im.utils.utils :as utils] + (:require [status-im.utils.http :as http] [status-im.utils.types :as types])) (defn- get-network-subdomain [network] @@ -52,6 +52,6 @@ {}))) (defn get-transactions [network account on-success on-error] - (utils/http-get (get-transaction-url network account) - #(on-success (format-transactions-response % account)) - on-error)) + (http/get (get-transaction-url network account) + #(on-success (format-transactions-response % account)) + on-error)) diff --git a/src/status_im/utils/types.cljs b/src/status_im/utils/types.cljs index ac029eec50..25c075ae86 100644 --- a/src/status_im/utils/types.cljs +++ b/src/status_im/utils/types.cljs @@ -5,9 +5,6 @@ (name s) s)) -(defn to-edn-string [value] - (with-out-str (pr value))) - (defn clj->json [data] (.stringify js/JSON (clj->js data))) diff --git a/src/status_im/utils/utils.cljs b/src/status_im/utils/utils.cljs index 6dde77cd2c..103e249cd0 100644 --- a/src/status_im/utils/utils.cljs +++ b/src/status_im/utils/utils.cljs @@ -1,12 +1,7 @@ (ns status-im.utils.utils - (:require [status-im.constants :as const] - [status-im.i18n :as i18n] - [clojure.string :as str] + (:require [status-im.i18n :as i18n] [status-im.react-native.js-dependencies :as rn-dependencies])) -;; Default HTTP request timeout ms -(def http-request-default-timeout-ms 3000) - (defn show-popup [title content] (.alert (.-Alert rn-dependencies/react-native) title @@ -47,56 +42,6 @@ :onPress on-accept :accessibility-label :yes-button}))))) -(defn http-post - "Performs an HTTP POST request" - ([action data on-success] - (http-post action data on-success nil)) - ([action data on-success on-error] - (http-post action data on-success on-error nil)) - ([action data on-success on-error {:keys [timeout-ms] :as opts}] - (-> (rn-dependencies/fetch (str const/server-address action) - (clj->js {:method "POST" - :headers {:accept "application/json" - :content-type "application/json"} - :body (.stringify js/JSON (clj->js data)) - :timeout (or timeout-ms http-request-default-timeout-ms)})) - (.then (fn [response] - (.text response))) - (.then (fn [text] - (let [json (.parse js/JSON text) - obj (js->clj json :keywordize-keys true)] - (on-success obj)))) - (.catch (or on-error - (fn [error] - (show-popup "Error" (str error)))))))) - -(defn http-get - "Performs an HTTP GET request" - ([url on-success on-error] - (http-get url on-success on-error nil)) - ([url on-success on-error {:keys [valid-response? timeout-ms] :as opts}] - (-> (rn-dependencies/fetch url - (clj->js {:method "GET" - :headers {"Cache-Control" "no-cache"} - :timeout (or timeout-ms http-request-default-timeout-ms)})) - (.then (fn [response] - (let [ok? (.-ok response) - ok?' (if valid-response? - (and ok? (valid-response? response)) - ok?)] - [(.-_bodyText response) ok?']))) - (.then (fn [[response ok?]] - (cond - ok? (on-success response) - - (and on-error (not ok?)) - (on-error response) - - :else false))) - (.catch (or on-error - (fn [error] - (show-popup "Error" (str error)))))))) - ;; background-timer (defn set-timeout [cb ms] diff --git a/test/cljs/status_im/react_native/js_dependencies.cljs b/test/cljs/status_im/react_native/js_dependencies.cljs index 85071933b3..128f8cfaed 100644 --- a/test/cljs/status_im/react_native/js_dependencies.cljs +++ b/test/cljs/status_im/react_native/js_dependencies.cljs @@ -36,6 +36,7 @@ (def snoopy-bars #js {:default #js {}}) (def snoopy-buffer #js {:default #js {}}) (def EventEmmiter #js {}) +(def fetch #js {}) (def background-timer #js {:setTimeout js/setTimeout :setInterval js/setInterval diff --git a/test/cljs/status_im/test/runner.cljs b/test/cljs/status_im/test/runner.cljs index 4e68bb1294..539fbada45 100644 --- a/test/cljs/status_im/test/runner.cljs +++ b/test/cljs/status_im/test/runner.cljs @@ -23,7 +23,8 @@ [status-im.test.utils.signing-phrase.core] [status-im.test.utils.transducers] [status-im.test.utils.async] - [status-im.test.utils.datetime])) + [status-im.test.utils.datetime] + [status-im.test.utils.mixpanel])) (enable-console-print!) @@ -57,4 +58,5 @@ 'status-im.test.utils.gfycat.core 'status-im.test.utils.signing-phrase.core 'status-im.test.utils.transducers - 'status-im.test.utils.datetime) + 'status-im.test.utils.datetime + 'status-im.test.utils.mixpanel) diff --git a/test/cljs/status_im/test/utils/mixpanel.cljs b/test/cljs/status_im/test/utils/mixpanel.cljs new file mode 100644 index 0000000000..2b65cec55f --- /dev/null +++ b/test/cljs/status_im/test/utils/mixpanel.cljs @@ -0,0 +1,20 @@ +(ns status-im.test.utils.mixpanel + (:require [cljs.test :refer-macros [deftest is testing async]] + [status-im.utils.mixpanel :as mixpanel])) + +(deftest events + (is (not (nil? mixpanel/events)))) + +(deftest matches? + (is (true? (mixpanel/matches? [:key] [:key]))) + (is (false? (mixpanel/matches? [:key1] [:key2]))) + (is (true? (mixpanel/matches? [:key :subkey] [:key]))) + (is (false? (mixpanel/matches? [:key] [:key :subkey])))) + +(def definitions {[:key] {:trigger [:key]} [:key :subkey] {:trigger [:key :subkey]}}) + +(deftest matching-event + (is (empty? (mixpanel/matching-events [:non-existing] definitions))) + (is (= 1 (count (mixpanel/matching-events [:key] definitions)))) + (is (= 2 (count (mixpanel/matching-events [:key :subkey] definitions)))) + (is (empty? (mixpanel/matching-events [:key1 :another-subkey] definitions))))