diff --git a/src/status_im/bots/events.cljs b/src/status_im/bots/events.cljs index 5d714a090a..e343abb8e7 100644 --- a/src/status_im/bots/events.cljs +++ b/src/status_im/bots/events.cljs @@ -1,5 +1,6 @@ (ns status-im.bots.events (:require [re-frame.core :as re-frame] + [status-im.utils.utils :as utils] [status-im.utils.handlers :as handlers] [status-im.chat.models.input :as input-model] [taoensso.timbre :as log])) @@ -12,65 +13,85 @@ {} sub-params)) -;; TODO(janherich): do this properly instead of the ugly hack with hardcoded bot-db key -;; und uneffective lookup of the owner of selected-chat-command (defn- check-subscriptions-fx - [{:keys [bot-db bot-subscriptions chats current-chat-id] :as app-db} path] - (let [owner-id (some-> app-db - (input-model/selected-chat-command current-chat-id (get-in app-db [:chats current-chat-id :input-text])) - :command - :owner-id)] - (when-let [subscriptions (and owner-id (get-in bot-subscriptions (concat [owner-id] [path])))] - {:call-jail-function-n - (for [[sub-name sub-params] subscriptions] - {:chat-id owner-id - :function :subscription - :parameters {:name sub-name - :subscriptions (subscription-values sub-params - (get bot-db current-chat-id))} - :callback-events-creator (fn [jail-response] - [[::calculated-subscription - {:bot current-chat-id - :path [sub-name] - :result jail-response}]])})}))) + [{:keys [bot-db bot-subscriptions] :as app-db} {:keys [bot path]}] + (when-let [subscriptions (and bot (get-in bot-subscriptions (concat [bot] [path])))] + {:call-jail-function-n + (for [[sub-name sub-params] subscriptions] + {:chat-id bot + :function :subscription + :parameters {:name sub-name + :subscriptions (subscription-values sub-params (get bot-db bot))} + :callback-events-creator (fn [jail-response] + [[::calculated-subscription + {:bot bot + :path [sub-name] + :result jail-response}]])})})) (defn set-in-bot-db - [{:keys [current-chat-id] :as app-db} {:keys [bot path value] :as params}] - (let [bot (or bot current-chat-id) - new-db (assoc-in app-db (concat [:bot-db bot] path) value)] + "Associates value at specified path in bot-db and checks if there are any subscriptions + dependent on that path, if yes, adds effects for calling jail-functions to recalculate + relevant subscriptions." + [app-db {:keys [bot path value] :as params}] + (let [new-db (assoc-in app-db (concat [:bot-db bot] path) value)] (merge {:db new-db} - (check-subscriptions-fx new-db path)))) + (check-subscriptions-fx new-db params)))) (defn update-bot-db - [{:keys [current-chat-id] :as app-db} {:keys [bot db]}] - (let [bot (or bot current-chat-id)] - (update-in app-db [:bot-db bot] merge db))) + [app-db {:keys [bot db]}] + (update-in app-db [:bot-db bot] merge db)) (defn clear-bot-db - [{:keys [current-chat-id] :as app-db}] - (assoc-in app-db [:bot-db current-chat-id] nil)) + [app-db bot-id] + (assoc-in app-db [:bot-db bot-id] nil)) (def ^:private keywordize-vector (partial mapv keyword)) -;; TODO(janherich): do something with this horrible triple nested reduce so it's more readable +(defn- transform-bot-subscriptions + "Transforms bot subscriptions as returned from jail in the following format: + + `{:calculatedFee {:subscriptions {:value [\"sliderValue\"] + :tx [\"transaction\"]}} + :feeExplanation {:subscriptions {:value [\"sliderValue\"]}}}` + + into data-structure better suited for subscription lookups based on changes + in `:bot-db`: + + `{[:sliderValue] {:calculatedFee {:value [:sliderValue] + :tx [:transaction]} + :feeExplanation {:value [:sliderValue]}} + [:transaction] {:calculatedFee {:value [:sliderValue] + :tx [:transaction]}}}` + + In the resulting data-structure, the top level keys are the (keywordized) paths + in the `:bot-db` data structure, so it's quick and easy to look-up all the + subscriptions which must be recalculated when something in their path changes." + [bot-subscriptions] + (reduce-kv (fn [acc sub-key {:keys [subscriptions]}] + (reduce-kv (fn [acc sub-param-key sub-param-path] + (update acc + (keywordize-vector sub-param-path) + assoc sub-key + (utils/map-values subscriptions keywordize-vector))) + acc + subscriptions)) + {} + bot-subscriptions)) + (defn add-active-bot-subscriptions + "Add subscriptions for selected bot identities into app-db" [app-db bot-identities] - (let [relevant-bots (select-keys (:contacts/contacts app-db) bot-identities) - active-subscriptions (reduce (fn [acc [bot-id {:keys [subscriptions]}]] - (reduce (fn [acc [sub-key {:keys [subscriptions]}]] - (reduce (fn [acc [sub-param-key sub-param-path]] - (update-in acc [bot-id (keywordize-vector sub-param-path)] - assoc sub-key (into {} - (map (fn [[k v]] - [k (keywordize-vector v)])) - subscriptions))) - acc - subscriptions)) - acc - subscriptions)) - {} - relevant-bots)] - (assoc app-db :bot-subscriptions active-subscriptions))) + (assoc app-db :bot-subscriptions (-> app-db + :contacts/contacts + (select-keys bot-identities) + (utils/map-values (comp transform-bot-subscriptions :subscriptions))))) + +(defn calculated-subscription + [db {:keys [bot path] + {:keys [error result]} :result}] + (if error + db + (assoc-in db (concat [:bot-db bot] path) (:returned result)))) ;;;; Handlers @@ -89,8 +110,5 @@ (handlers/register-handler-db ::calculated-subscription [re-frame/trim-v] - (fn [db [{:keys [bot path] - {:keys [error result]} :result}]] - (if error - db - (assoc-in db (concat [:bot-db bot] path) (:returned result))))) + (fn [db [params]] + (calculated-subscription db params))) diff --git a/src/status_im/bots/subs.cljs b/src/status_im/bots/subs.cljs index b7f298d4d3..1389b28644 100644 --- a/src/status_im/bots/subs.cljs +++ b/src/status_im/bots/subs.cljs @@ -1,8 +1,13 @@ (ns status-im.bots.subs - (:require [re-frame.core :refer [reg-sub subscribe]])) + (:require [re-frame.core :as re-frame] + [status-im.chat.models.input :as input-model])) -(reg-sub +(re-frame/reg-sub :current-bot-db (fn [db] - (let [chat-id (subscribe [:get-current-chat-id])] - (get-in db [:bot-db @chat-id])))) + (let [current-chat-id (re-frame/subscribe [:get-current-chat-id]) + command-owner (-> db + (input-model/selected-chat-command @current-chat-id) + :command + :owner-id)] + [command-owner (get-in db [:bot-db command-owner])]))) diff --git a/src/status_im/chat/events/input.cljs b/src/status_im/chat/events/input.cljs index d4fce35ab7..aca3f7d90a 100644 --- a/src/status_im/chat/events/input.cljs +++ b/src/status_im/chat/events/input.cljs @@ -52,9 +52,7 @@ (defn update-suggestions "Update suggestions for current chat input, takes db as the only argument - and returns map with keys :db (new db with up-to-date suggestions) and (optionally) - :call-jail-function with jail function call params, if request to jail needs - to be made as a result of suggestions update." + and returns new db with up-to date suggestions" [{:keys [chats current-chat-id] :as db}] (let [chat-text (str/trim (or (get-in chats [current-chat-id :input-text]) "")) requests (->> (commands-model/get-possible-requests db) @@ -73,7 +71,7 @@ (and dapp? (str/blank? chat-text)) (assoc-in [:chats current-chat-id :parameter-boxes :message] nil))] - {:db new-db})) + new-db)) (defn set-chat-input-text "Set input text for current-chat and updates suggestions relevant to current input. @@ -131,7 +129,7 @@ seq-params? (-> (input-model/selected-chat-command db current-chat-id) (get-in [:command :sequential-params]))] (if seq-params? - {:db (set-chat-seq-arg-input-text db arg)} + (set-chat-seq-arg-input-text db arg) (let [arg (str/replace arg (re-pattern const/arg-wrapping-char) "") command-name (first command) command-args (into [] (rest command)) @@ -155,7 +153,7 @@ (let [parameter-index (input-model/argument-position db)] (when (and command (> parameter-index -1)) (let [data (get-in db [:local-storage current-chat-id]) - bot-db (get bot-db (or bot current-chat-id)) + bot-db (get bot-db owner-id) path [(if (= :command type) :commands :responses) [name (if (= :command type) @@ -176,7 +174,7 @@ :from current-account-id :to to} (input-model/command-dependent-context-params current-chat-id command))}] - {:call-jail {:jail-id (or bot owner-id current-chat-id) + {:call-jail {:jail-id owner-id :path path :params params :callback-events-creator (fn [jail-response] @@ -214,9 +212,9 @@ (defn select-chat-input-command "Selects command + (optional) arguments as input for active chat" [{:keys [current-chat-id chat-ui-props] :as db} - {:keys [prefill prefill-bot-db sequential-params name] :as command} metadata prevent-auto-focus?] + {:keys [prefill prefill-bot-db sequential-params name owner-id] :as command} metadata prevent-auto-focus?] (let [db' (-> db - bots-events/clear-bot-db + (bots-events/clear-bot-db owner-id) clear-seq-arguments (model/set-chat-ui-props {:show-suggestions? false :show-emoji? false @@ -230,7 +228,8 @@ (input-model/join-command-args prefill))))) fx (assoc (load-chat-parameter-box db' command) :db db')] (cond-> fx - prefill-bot-db (update :db bots-events/update-bot-db {:db prefill-bot-db}) + prefill-bot-db (update :db bots-events/update-bot-db {:db prefill-bot-db + :bot owner-id}) (not (and sequential-params prevent-auto-focus?)) @@ -246,15 +245,18 @@ (defn set-contact-as-command-argument "Sets contact as command argument for active chat" - [db {:keys [bot-db-key contact arg-index]}] + [{:keys [current-chat-id] :as db} {:keys [bot-db-key contact arg-index]}] (let [name (str/replace (:name contact) (re-pattern const/arg-wrapping-char) "") - contact (select-keys contact [:address :whisper-identity :name :photo-path :dapp?])] - (-> (set-command-argument db arg-index name true) - (as-> fx - (merge fx (bots-events/set-in-bot-db - (:db fx) - {:path [:public (keyword bot-db-key)] - :value contact}))) + contact (select-keys contact [:address :whisper-identity :name :photo-path :dapp?]) + command-owner (-> db + (input-model/selected-chat-command current-chat-id) + :command + :owner-id)] + (-> db + (set-command-argument arg-index name true) + (bots-events/set-in-bot-db {:bot command-owner + :path [:public (keyword bot-db-key)] + :value contact}) (as-> fx (let [{:keys [current-chat-id] :as new-db} (:db fx) @@ -283,7 +285,7 @@ {:url (i18n/get-contact-translated chat-id :dapp-url dapp-url) :name (i18n/get-contact-translated chat-id :name name)})) owner-id (:owner-id command) - bot-db (get bot-db chat-id) + bot-db (get bot-db owner-id) params (merge (input-model/args->params content) {:bot-db bot-db :metadata metadata}) @@ -374,10 +376,10 @@ (fn [db [data]] (set-chat-input-metadata db data))) -(handlers/register-handler-fx +(handlers/register-handler-db :set-command-argument [re-frame/trim-v] - (fn [{:keys [db]} [[index arg move-to-next?]]] + (fn [db [[index arg move-to-next?]]] (set-command-argument db index arg move-to-next?))) (handlers/register-handler-fx @@ -393,9 +395,9 @@ (when-let [cmp-ref (get-in chat-ui-props [current-chat-id ref])] {::blur-rn-component cmp-ref}))) -(handlers/register-handler-fx +(handlers/register-handler-db :update-suggestions - (fn [{:keys [db]} _] + (fn [db _] (update-suggestions db))) (handlers/register-handler-fx @@ -443,18 +445,18 @@ [re-frame/trim-v] (fn [{{:keys [current-public-key current-chat-id] :accounts/keys [current-account-id] :as db} :db} [{:keys [command] :as command-message}]] - (-> db - clear-seq-arguments - (set-chat-input-metadata nil) - (set-chat-input-text nil) - (model/set-chat-ui-props {:sending-in-progress? false}) - update-suggestions - ;; TODO: refactor send-message.cljs to use atomic pure handlers and get rid of this dispatch - (assoc :dispatch [:check-commands-handlers! {:message (get-in db [:chats current-chat-id :input-text]) - :command command-message - :chat-id current-chat-id - :identity current-public-key - :address current-account-id}])))) + {:db (-> db + clear-seq-arguments + (set-chat-input-metadata nil) + (set-chat-input-text nil) + (model/set-chat-ui-props {:sending-in-progress? false}) + update-suggestions) + ;; TODO: refactor send-message.cljs to use atomic pure handlers and get rid of this dispatch + :dispatch [:check-commands-handlers! {:message (get-in db [:chats current-chat-id :input-text]) + :command command-message + :chat-id current-chat-id + :identity current-public-key + :address current-account-id}]})) (handlers/register-handler-fx ::check-command-type @@ -500,15 +502,15 @@ ;; no command detected, when not empty, proceed by sending text message without command processing (if (str/blank? input-text) {:db db} - (-> db - (set-chat-input-metadata nil) - (set-chat-input-text nil) - update-suggestions - ;; TODO: refactor send-message.cljs to use atomic pure handlers and get rid of this dispatch - (assoc :dispatch [:prepare-message {:message input-text - :chat-id current-chat-id - :identity current-public-key - :address (:accounts/current-account-id db)}]))))))) + {:db (-> db + (set-chat-input-metadata nil) + (set-chat-input-text nil) + update-suggestions) + ;; TODO: refactor send-message.cljs to use atomic pure handlers and get rid of this dispatch + :dispatch [:prepare-message {:message input-text + :chat-id current-chat-id + :identity current-public-key + :address (:accounts/current-account-id db)}]}))))) ;; TODO: remove this handler and leave only helper fn once all invocations are refactored (handlers/register-handler-db @@ -561,10 +563,10 @@ (let [input-text (get-in db [:chats current-chat-id :input-text]) command (input-model/selected-chat-command db current-chat-id input-text)] (if (get-in command [:command :sequential-params]) - (-> (set-command-argument db 0 "" false) - (update :db set-chat-seq-arg-input-text "") - (as-> fx - (merge fx (load-chat-parameter-box (:db fx) (:command command))))) + (-> db + (set-command-argument 0 "" false) + (set-chat-seq-arg-input-text "") + (load-chat-parameter-box (:command command))) (let [arg-pos (input-model/argument-position db)] (when (pos? arg-pos) (let [input-text (get-in db [:chats current-chat-id :input-text]) @@ -585,9 +587,9 @@ (fn [{:keys [db]} [params]] (set-contact-as-command-argument db params))) -(handlers/register-handler-fx +(handlers/register-handler-db :show-suggestions - (fn [{:keys [db]} _] + (fn [db _] (-> db (model/toggle-chat-ui-prop :show-suggestions?) (model/set-chat-ui-props {:validation-messages nil}) diff --git a/src/status_im/chat/events/receive_message.cljs b/src/status_im/chat/events/receive_message.cljs index b378e2c761..bfb0113751 100644 --- a/src/status_im/chat/events/receive_message.cljs +++ b/src/status_im/chat/events/receive_message.cljs @@ -11,27 +11,21 @@ [status-im.data-store.messages :as msg-store])) (re-frame/reg-cofx - :pop-up-chat? - (fn [cofx] - (assoc cofx :pop-up-chat? (fn [chat-id] - (or (not (chat-store/exists? chat-id)) - (chat-store/is-active? chat-id)))))) + :pop-up-chat? + (fn [cofx] + (assoc cofx :pop-up-chat? (fn [chat-id] + (or (not (chat-store/exists? chat-id)) + (chat-store/is-active? chat-id)))))) (re-frame/reg-cofx - :message-exists? - (fn [cofx] - (assoc cofx :message-exists? msg-store/exists?))) + :message-exists? + (fn [cofx] + (assoc cofx :message-exists? msg-store/exists?))) (re-frame/reg-cofx - :get-last-clock-value - (fn [cofx] - (assoc cofx :get-last-clock-value msg-store/get-last-clock-value))) - -(re-frame/reg-cofx - :current-timestamp - (fn [cofx] - ;; TODO (janherich) why is actual timestmap generation in random namespace ? - (assoc cofx :current-timestamp (random/timestamp)))) + :get-last-clock-value + (fn [cofx] + (assoc cofx :get-last-clock-value msg-store/get-last-clock-value))) (defn- get-current-identity [{:accounts/keys [accounts current-account-id]}] @@ -39,7 +33,7 @@ (defn add-message [{:keys [db message-exists? get-last-stored-message pop-up-chat? - get-last-clock-value current-timestamp random-id]} + get-last-clock-value now random-id]} {:keys [from group-id chat-id content-type message-id timestamp clock-value] :as message @@ -57,7 +51,7 @@ (get-last-stored-message chat-identifier) message) :chat-id chat-identifier - :timestamp (or timestamp current-timestamp) + :timestamp (or timestamp now) :clock-value (clocks/receive clock-value (get-last-clock-value chat-identifier)))] @@ -68,8 +62,7 @@ (assoc-in [:chats chat-identifier :last-message] message)) :dispatch-n [[:upsert-chat! {:chat-id chat-identifier :group-chat group-chat?}] - [:request-command-message-data enriched-message :short-preview] - [:update-suggestions]] + [:request-command-message-data enriched-message :short-preview]] :save-message (dissoc enriched-message :new?)} (get-in enriched-message [:content :command]) @@ -77,7 +70,7 @@ (= (:content-type enriched-message) const/content-type-command-request) (update :dispatch-n conj [:add-request chat-identifier enriched-message]) - + ;; TODO(janherich) this shouldn't be dispatch, but plain function call, refactor after adding requests is refactored true (update :dispatch-n conj [:update-suggestions]))) {:db db}))) @@ -85,8 +78,7 @@ (def ^:private receive-interceptors [(re-frame/inject-cofx :message-exists?) (re-frame/inject-cofx :get-last-stored-message) (re-frame/inject-cofx :pop-up-chat?) (re-frame/inject-cofx :get-last-clock-value) - (re-frame/inject-cofx :current-timestamp) (re-frame/inject-cofx :random-id) - re-frame/trim-v]) + (re-frame/inject-cofx :random-id) re-frame/trim-v]) (handlers/register-handler-fx :received-protocol-message! diff --git a/src/status_im/chat/handlers/send_message.cljs b/src/status_im/chat/handlers/send_message.cljs index 3c0588b57a..3a5884e417 100644 --- a/src/status_im/chat/handlers/send_message.cljs +++ b/src/status_im/chat/handlers/send_message.cljs @@ -218,15 +218,16 @@ (register-handler :received-bot-response (u/side-effect! - (fn [{:contacts/keys [contacts]} [_ {:keys [chat-id] :as params} {:keys [result] :as data}]] + (fn [{:contacts/keys [contacts]} [_ {:keys [chat-id] :as params} {:keys [result bot-id] :as data}]] (let [{:keys [returned context]} result {:keys [markup text-message err]} returned {:keys [log-messages update-db default-db]} context content (or err text-message)] (when update-db - (dispatch [:update-bot-db {:bot chat-id + (dispatch [:update-bot-db {:bot bot-id :db update-db}])) (dispatch [:suggestions-handler (assoc params + :bot-id bot-id :result data :default-db default-db)]) (doseq [message log-messages] diff --git a/src/status_im/chat/views/input/parameter_box.cljs b/src/status_im/chat/views/input/parameter_box.cljs index c63df7b589..7f813229ae 100644 --- a/src/status_im/chat/views/input/parameter_box.cljs +++ b/src/status_im/chat/views/input/parameter_box.cljs @@ -8,9 +8,9 @@ (defview parameter-box-container [] [{:keys [markup]} [:chat-parameter-box] - bot-db [:current-bot-db]] + bot-id-bot-db [:current-bot-db]] (when markup - (command-utils/generate-hiccup markup bot-db))) + (command-utils/generate-hiccup markup (first bot-id-bot-db) (second bot-id-bot-db)))) (defview parameter-box-view [] [show-parameter-box? [:show-parameter-box?] diff --git a/src/status_im/commands/handlers/jail.cljs b/src/status_im/commands/handlers/jail.cljs index 3ddaa35fbc..618ba3f849 100644 --- a/src/status_im/commands/handlers/jail.cljs +++ b/src/status_im/commands/handlers/jail.cljs @@ -35,7 +35,7 @@ (defn suggestions-handler! [{:keys [chats] :as db} - [{:keys [chat-id default-db command parameter-index result]}]] + [{:keys [chat-id bot-id default-db command parameter-index result]}]] (let [{:keys [markup height] :as returned} (get-in result [:result :returned]) contains-markup? (contains? returned :markup) current-input (get-in chats [chat-id :input-text]) @@ -47,36 +47,35 @@ (when (and contains-markup? path (not= (get-in db path) markup)) (dispatch [:set-in path returned]) (when default-db - (dispatch [:update-bot-db {:bot chat-id + (dispatch [:update-bot-db {:bot bot-id :db default-db}]))))) (defn suggestions-events-handler! - [{:keys [current-chat-id bot-db] :as db} [[n & data :as ev] val]] - (log/debug "Suggestion event: " n (first data) val) - (let [{:keys [dapp?]} (get-in db [:contacts/contacts current-chat-id])] - (case (keyword n) - :set-command-argument - (let [[index value move-to-next?] (first data)] - (dispatch [:set-command-argument [index value move-to-next?]])) - :set-value - (dispatch [:set-chat-input-text (first data)]) - :set - (let [opts {:bot current-chat-id - :path (mapv keyword data) - :value val}] - (dispatch [:set-in-bot-db opts])) - :set-command-argument-from-db - (let [[index arg move-to-next?] (first data) - path (keyword arg) - value (str (get-in bot-db [current-chat-id path]))] - (dispatch [:set-command-argument [index value move-to-next?]])) - :set-value-from-db - (let [path (keyword (first data)) - value (str (get-in bot-db [current-chat-id path]))] - (dispatch [:set-chat-input-text value])) - :focus-input - (dispatch [:chat-input-focus :input-ref]) - nil))) + [{:keys [bot-db] :as db} [bot-id [n & data :as ev] val]] + (log/debug "Suggestion event: " n (first data) val) + (case (keyword n) + :set-command-argument + (let [[index value move-to-next?] (first data)] + (dispatch [:set-command-argument [index value move-to-next?]])) + :set-value + (dispatch [:set-chat-input-text (first data)]) + :set + (let [opts {:bot bot-id + :path (mapv keyword data) + :value val}] + (dispatch [:set-in-bot-db opts])) + :set-command-argument-from-db + (let [[index arg move-to-next?] (first data) + path (keyword arg) + value (str (get-in bot-db [bot-id path]))] + (dispatch [:set-command-argument [index value move-to-next?]])) + :set-value-from-db + (let [path (keyword (first data)) + value (str (get-in bot-db [bot-id path]))] + (dispatch [:set-chat-input-text value])) + :focus-input + (dispatch [:chat-input-focus :input-ref]) + nil)) (defn print-error-message! [message] (fn [_ params] diff --git a/src/status_im/commands/utils.cljs b/src/status_im/commands/utils.cljs index 6dfa733612..265a0ef520 100644 --- a/src/status_im/commands/utils.cljs +++ b/src/status_im/commands/utils.cljs @@ -45,31 +45,30 @@ (def events #{:onPress :onValueChange :onSlidingComplete}) -(defn wrap-event [[_ event]] - (let [data (gensym)] - #(dispatch [:suggestions-event! (update event 0 keyword) %]))) +(defn wrap-event [[_ event] bot-id] + #(dispatch [:suggestions-event! bot-id (update event 0 keyword) %])) -(defn check-events [m] +(defn check-events [m bot-id] (let [ks (set (keys m)) evs (set/intersection ks events)] - (reduce #(update %1 %2 wrap-event) m evs))) + (reduce #(update %1 %2 wrap-event bot-id) m evs))) (defn generate-hiccup ([markup] - (generate-hiccup markup {})) - ([markup data] + (generate-hiccup markup nil {})) + ([markup bot-id bot-db] (w/prewalk (fn [el] (cond (and (vector? el) (= "subscribe" (first el))) (let [path (mapv keyword (second el))] - (get-in data path)) + (get-in bot-db path)) (and (vector? el) (string? (first el))) (-> el (update 0 get-element) - (update 1 check-events)) + (update 1 check-events bot-id)) :else el)) markup))) diff --git a/src/status_im/native_module/impl/module.cljs b/src/status_im/native_module/impl/module.cljs index 01445e8d17..41278dd5f7 100644 --- a/src/status_im/native_module/impl/module.cljs +++ b/src/status_im/native_module/impl/module.cljs @@ -120,9 +120,9 @@ (when status (call-module #(.discardTransaction status id)))) -(defn parse-jail [chat-id file callback] +(defn parse-jail [bot-id file callback] (when status - (call-module #(.parseJail status chat-id file callback)))) + (call-module #(.parseJail status bot-id file callback)))) (defn execute-call [{:keys [jail-id path params callback]}] (when status diff --git a/src/status_im/ui/screens/profile/events.cljs b/src/status_im/ui/screens/profile/events.cljs index 6840272378..8d1fcaec79 100644 --- a/src/status_im/ui/screens/profile/events.cljs +++ b/src/status_im/ui/screens/profile/events.cljs @@ -30,10 +30,11 @@ (handlers/register-handler-fx :profile/send-transaction [trim-v] - (fn [_ [chat-id]] - {:dispatch [:navigate-to :chat chat-id] - ;;TODO get rid of timeout - :dispatch-later [{:ms 100 :dispatch [:select-chat-input-command {:name "send"}]}]})) + (fn [{:keys [db]} [chat-id]] + (let [send-command (first (get-in db [:contacts/contacts "transactor-personal" :commands :send]))] + {:dispatch [:navigate-to :chat chat-id] + ;;TODO get rid of timeout + :dispatch-later [{:ms 100 :dispatch [:select-chat-input-command send-command]}]}))) (handlers/register-handler-fx :profile/send-message @@ -45,9 +46,10 @@ :my-profile/update-phone-number ;; Switch user to the console issuing the !phone command automatically to let him change his phone number. ;; We allow to change phone number only from console because this requires entering SMS verification code. - (fn [_ _] - {:dispatch-n [[:navigate-to :chat console-chat-id] - [:select-chat-input-command {:name "phone"}]]})) + (fn [{:keys [db]} _] + (let [phone-command (first (get-in db [:contacts/contacts "console" :responses :phone]))] + {:dispatch-n [[:navigate-to :chat console-chat-id] + [:select-chat-input-command phone-command]]}))) (defn get-current-account [{:keys [:accounts/current-account-id] :as db}] (get-in db [:accounts/accounts current-account-id])) diff --git a/src/status_im/ui/screens/wallet/request/events.cljs b/src/status_im/ui/screens/wallet/request/events.cljs index ff2f15231b..4018c027c1 100644 --- a/src/status_im/ui/screens/wallet/request/events.cljs +++ b/src/status_im/ui/screens/wallet/request/events.cljs @@ -4,23 +4,26 @@ [status-im.ui.screens.wallet.db :as wallet.db] [re-frame.core :as re-frame])) -(defn chat-loaded-callback [amount] +(defn chat-loaded-callback [request-command] (fn [] - (re-frame/dispatch [:select-chat-input-command {:name "request" :prefill [amount]}]) + (re-frame/dispatch [:select-chat-input-command request-command]) ;;TODO get rid of timeout (js/setTimeout #(re-frame/dispatch [:send-current-message]) 100))) (handlers/register-handler-fx :wallet-send-request - (fn [{{:wallet/keys [request-transaction]} :db} [_ {:keys [whisper-identity]}]] - {:dispatch-n [[:navigate-back] - [:navigate-to-clean :chat-list] - [:add-chat-loaded-callback whisper-identity (chat-loaded-callback (:amount request-transaction))] - [:start-chat whisper-identity]]})) + (fn [{{:wallet/keys [request-transaction] :as db} :db} [_ {:keys [whisper-identity]}]] + (let [request-command (first (get-in db [:contacts/contacts "transactor-personal" :commands :request]))] + {:dispatch-n [[:navigate-back] + [:navigate-to-clean :chat-list] + [:add-chat-loaded-callback whisper-identity (chat-loaded-callback + (assoc request-command + :prefill [(:amount request-transaction)]))] + [:start-chat whisper-identity]]}))) (handlers/register-handler-fx :wallet-validate-request-amount (fn [{{:wallet/keys [request-transaction] :as db} :db} _] (let [amount (:amount request-transaction) error (wallet.db/get-amount-validation-error amount)] - {:db (assoc-in db [:wallet/request-transaction :amount-error] error)}))) \ No newline at end of file + {:db (assoc-in db [:wallet/request-transaction :amount-error] error)}))) diff --git a/src/status_im/utils/utils.cljs b/src/status_im/utils/utils.cljs index 76b0951ad4..e55ce1071d 100644 --- a/src/status_im/utils/utils.cljs +++ b/src/status_im/utils/utils.cljs @@ -34,9 +34,9 @@ title content (clj->js - (vector (merge {:text (i18n/label :t/no)} - (when on-cancel {:onPress on-cancel})) - {:text (i18n/label :t/yes) :onPress on-accept}))))) + (vector (merge {:text (i18n/label :t/no)} + (when on-cancel {:onPress on-cancel})) + {:text (i18n/label :t/yes) :onPress on-accept}))))) (defn http-post ([action data on-success] @@ -125,3 +125,11 @@ (if (contains? m k) (apply update m k f args) m)) + +(defn map-values + "Efficiently apply function to all map values" + [m f] + (into {} + (map (fn [[k v]] + [k (f v)])) + m)) diff --git a/test/cljs/status_im/test/bots/events.cljs b/test/cljs/status_im/test/bots/events.cljs new file mode 100644 index 0000000000..9505bd4746 --- /dev/null +++ b/test/cljs/status_im/test/bots/events.cljs @@ -0,0 +1,50 @@ +(ns status-im.test.bots.events + (:require [cljs.test :refer-macros [deftest is testing]] + [status-im.bots.events :as bots-events])) + +(def ^:private initial-db + {:bot-db {} + :bot-subscriptions {} + :contacts/contacts + {"bot1" {:subscriptions + {:feeExplanation + {:subscriptions {:fee ["sliderValue"] + :tx ["transaction"]}}}} + "bot2" {:subscriptions + {:roundedValue + {:subscriptions {:amount ["input"]}}}} + "bot3" {:subscriptions + {:warning + {:subscriptions {:amount ["input"]}}}}}}) + +(deftest add-active-bot-subscriptions-test + (testing "That active bot subscriptions are correctly transformed and added to db" + (let [db (bots-events/add-active-bot-subscriptions initial-db #{"bot1" "bot3"})] + (is (= #{"bot1" "bot3"} (-> db :bot-subscriptions keys set))) + (is (= {[:sliderValue] {:feeExplanation {:fee [:sliderValue] + :tx [:transaction]}} + [:transaction] {:feeExplanation {:fee [:sliderValue] + :tx [:transaction]}}} + (-> db :bot-subscriptions (get "bot1"))))))) + +(defn- fake-subscription-call + [db {:keys [chat-id parameters]}] + (let [{:keys [name subscriptions]} parameters + simulated-jail-response {:result {:returned {:sub-call-arg-map subscriptions}}}] + (bots-events/calculated-subscription db {:bot chat-id + :path [name] + :result simulated-jail-response}))) + +(deftest set-in-bot-db-test + (let [{:keys [db call-jail-function-n]} (-> initial-db + (bots-events/add-active-bot-subscriptions #{"bot1" "bot2"}) + (bots-events/set-in-bot-db {:bot "bot1" + :path [:sliderValue] + :value 2})) + new-db (reduce fake-subscription-call db call-jail-function-n)] + (testing "That setting in value in bot-db correctly updates bot-db" + (is (= 2 (get-in new-db [:bot-db "bot1" :sliderValue])))) + (testing "That subscriptions are fired-off" + (is (= {:sub-call-arg-map {:fee 2 + :tx nil}} + (get-in new-db [:bot-db "bot1" :feeExplanation])))))) diff --git a/test/cljs/status_im/test/runner.cljs b/test/cljs/status_im/test/runner.cljs index 4e6b4a20e9..4680e5f1e9 100644 --- a/test/cljs/status_im/test/runner.cljs +++ b/test/cljs/status_im/test/runner.cljs @@ -6,6 +6,7 @@ [status-im.test.wallet.events] [status-im.test.wallet.transactions.subs] [status-im.test.profile.events] + [status-im.test.bots.events] [status-im.test.chat.models.input] [status-im.test.components.main-tabs] [status-im.test.i18n] @@ -35,6 +36,7 @@ ;;'status-im.test.contacts.events 'status-im.test.profile.events 'status-im.test.wallet.events + 'status-im.test.bots.events 'status-im.test.wallet.transactions.subs 'status-im.test.chat.models.input 'status-im.test.components.main-tabs diff --git a/test/cljs/status_im/test/utils/utils.cljs b/test/cljs/status_im/test/utils/utils.cljs index 90d33401cb..fa7fbdf0cd 100644 --- a/test/cljs/status_im/test/utils/utils.cljs +++ b/test/cljs/status_im/test/utils/utils.cljs @@ -36,3 +36,8 @@ (is (= {:a 1} (u/update-if-present {:a 0} :a inc))) (is (= {:a 2} (u/update-if-present {:a 0} :a + 2))) (is (= {:a 0} (u/update-if-present {:a 0} :b inc)))) + +(deftest map-values-test + (is (= {} (u/map-values {} inc))) + (is (= {:a 1} (u/map-values {:a 0} inc))) + (is (= {:a 1 :b 2} (u/map-values {:a 0 :b 1} inc))))