diff --git a/src/status_im/chat/models/loading.cljs b/src/status_im/chat/models/loading.cljs index b5b89761a5..d395755ba3 100644 --- a/src/status_im/chat/models/loading.cljs +++ b/src/status_im/chat/models/loading.cljs @@ -178,7 +178,7 @@ (when (or first-request cursor) (merge {:db (assoc-in db [:pagination-info chat-id :loading-messages?] true)} - {:utils/dispatch-later [{:ms 100 :dispatch [:load-more-reactions cursor chat-id]}]} + {:utils/dispatch-later [{:ms 100 :dispatch [:reactions/load-more cursor chat-id]}]} (data-store.messages/messages-by-chat-id-rpc chat-id cursor diff --git a/src/status_im/chat/models/reactions.cljs b/src/status_im/chat/models/reactions.cljs deleted file mode 100644 index 9382566484..0000000000 --- a/src/status_im/chat/models/reactions.cljs +++ /dev/null @@ -1,116 +0,0 @@ -(ns status-im.chat.models.reactions - (:require - [re-frame.core :as re-frame] - [status-im.data-store.reactions :as data-store.reactions] - [status-im2.constants :as constants] - [taoensso.timbre :as log] - [utils.re-frame :as rf] - [utils.transforms :as transforms])) - -(defn update-reaction - [acc retracted chat-id message-id emoji-id emoji-reaction-id reaction] - ;; NOTE(Ferossgp): For a better performance, better to not keep in db all retracted reactions - ;; retraction will always come after the reaction so there shouldn't be a conflict - (if retracted - (update-in acc [chat-id message-id emoji-id] dissoc emoji-reaction-id) - (assoc-in acc [chat-id message-id emoji-id emoji-reaction-id] reaction))) - -(defn process-reactions - [_] - (fn [reactions new-reactions] - ;; TODO(Ferossgp): handling own reaction in subscription could be expensive, - ;; for better performance we can here separate own reaction into 2 maps - (reduce - (fn [acc - {:keys [chat-id message-id emoji-id emoji-reaction-id retracted] - :as reaction}] - (update-reaction acc retracted chat-id message-id emoji-id emoji-reaction-id reaction)) - reactions - new-reactions))) - -(defn- earlier-than-deleted-at? - [{:keys [db]} {:keys [chat-id clock-value]}] - (let [{:keys [deleted-at-clock-value]} - (get-in db [:chats chat-id])] - (>= deleted-at-clock-value clock-value))) - -(rf/defn receive-signal - [{:keys [db] :as cofx} reactions] - (let [reactions (filter (partial earlier-than-deleted-at? cofx) reactions)] - {:db (update db :reactions (process-reactions (:chats db)) reactions)})) - -(rf/defn load-more-reactions - {:events [:load-more-reactions]} - [{:keys [db]} cursor chat-id] - (when-let [session-id (get-in db [:pagination-info chat-id :messages-initialized?])] - (data-store.reactions/reactions-by-chat-id-rpc - chat-id - cursor - constants/default-number-of-messages - #(re-frame/dispatch [::reactions-loaded chat-id session-id %]) - #(log/error "failed loading reactions" chat-id %)))) - -(rf/defn reactions-loaded - {:events [::reactions-loaded]} - [{db :db} - chat-id - session-id - reactions] - (when-not (and (get-in db [:pagination-info chat-id :messages-initialized?]) - (not= session-id - (get-in db [:pagination-info chat-id :messages-initialized?]))) - (let [reactions-w-chat-id (map #(assoc % :chat-id chat-id) reactions)] - {:db (update db :reactions (process-reactions (:chats db)) reactions-w-chat-id)}))) - -(defn message-reactions - [current-public-key reactions] - (reduce - (fn [acc [emoji-id reactions]] - (if (pos? (count reactions)) - (let [own (first (filter (fn [[_ {:keys [from]}]] - (= from current-public-key)) - reactions))] - (conj acc - {:emoji-id emoji-id - :own (boolean (seq own)) - :emoji-reaction-id (:emoji-reaction-id (second own)) - :quantity (count reactions)})) - acc)) - [] - reactions)) - -(defn- <-rpc - [{compressed-key :compressedKey - emoji-id :emojiId - :keys [from]}] - {:compressed-key compressed-key - :emoji-id emoji-id - :from from}) - -(defn- format-response - [response] - (->> (transforms/js->clj response) - (map <-rpc) - (group-by :emoji-id))) - -(rf/defn save-emoji-reaction-details - {:events [:chat/save-emoji-reaction-details]} - [{:keys [db]} reaction-authors] - {:db (assoc db :chat/reactions-authors reaction-authors)}) - -(rf/defn clear-emoji-reaction-details - {:events [:chat/clear-emoji-reaction-author-details]} - [{:keys [db]}] - {:db (dissoc db :chat/reactions-authors)}) - -(rf/defn emoji-reactions-by-message-id - {:events [:chat.ui/emoji-reactions-by-message-id]} - [{:keys [db]} {:keys [message-id on-success]}] - {:db (dissoc db :chat/reactions-authors) - :json-rpc/call [{:method "wakuext_emojiReactionsByChatIDMessageID" - :params [(:current-chat-id db) message-id] - :js-response true - :on-error #(log/error "failed to fetch emoji reaction by message-id: " - {:message-id message-id :error %}) - :on-success #(when on-success - (on-success (format-response %)))}]}) diff --git a/src/status_im/data_store/reactions.cljs b/src/status_im/data_store/reactions.cljs deleted file mode 100644 index c3855335ee..0000000000 --- a/src/status_im/data_store/reactions.cljs +++ /dev/null @@ -1,34 +0,0 @@ -(ns status-im.data-store.reactions - (:require - [clojure.set :as set])) - -(defn ->rpc - [message] - (-> message - (set/rename-keys {:message-id :messageId - :emoji-id :emojiId - :chat-id :localChatId - :message-type :messageType - :emoji-reaction-id :id}))) - -(defn <-rpc - [message] - (-> message - (dissoc :chat_id) - (set/rename-keys {:messageId :message-id - :localChatId :chat-id - :emojiId :emoji-id - :messageType :message-type - :id :emoji-reaction-id}))) - -(defn reactions-by-chat-id-rpc - [chat-id - cursor - limit - on-success - on-error] - {:json-rpc/call [{:method "wakuext_emojiReactionsByChatID" - :params [chat-id cursor limit] - :on-success (fn [result] - (on-success (map <-rpc result))) - :on-error on-error}]}) diff --git a/src/status_im2/contexts/chat/events.cljs b/src/status_im2/contexts/chat/events.cljs index d97d00c840..3dddcebb2f 100644 --- a/src/status_im2/contexts/chat/events.cljs +++ b/src/status_im2/contexts/chat/events.cljs @@ -12,6 +12,7 @@ [status-im2.contexts.chat.composer.link-preview.events :as link-preview] status-im2.contexts.chat.effects status-im2.contexts.chat.lightbox.events + status-im2.contexts.chat.messages.content.reactions.events [status-im2.contexts.chat.messages.delete-message-for-me.events :as delete-for-me] [status-im2.contexts.chat.messages.delete-message.events :as delete-message] [status-im2.contexts.chat.messages.list.state :as chat.state] diff --git a/src/status_im2/contexts/chat/messages/content/reactions/events.cljs b/src/status_im2/contexts/chat/messages/content/reactions/events.cljs new file mode 100644 index 0000000000..62ee564847 --- /dev/null +++ b/src/status_im2/contexts/chat/messages/content/reactions/events.cljs @@ -0,0 +1,106 @@ +(ns status-im2.contexts.chat.messages.content.reactions.events + (:require [clojure.set :as set] + [status-im2.constants :as constants] + [taoensso.timbre :as log] + [utils.re-frame :as rf])) + +(defn update-reaction + [acc retracted chat-id message-id emoji-id emoji-reaction-id reaction] + ;; NOTE: For a better performance, better to not keep in db all retracted reactions + ;; retraction will always come after the reaction so there shouldn't be a conflict + (if retracted + (update-in acc [chat-id message-id emoji-id] dissoc emoji-reaction-id) + (assoc-in acc [chat-id message-id emoji-id emoji-reaction-id] reaction))) + +(defn process-reactions + [_] + (fn [reactions new-reactions] + ;; NOTE: handling own reaction in subscription could be expensive, + ;; for better performance we can here separate own reaction into 2 maps + (reduce + (fn [acc + {:keys [chat-id message-id emoji-id emoji-reaction-id retracted] + :as reaction}] + (update-reaction acc retracted chat-id message-id emoji-id emoji-reaction-id reaction)) + reactions + new-reactions))) + +(defn- earlier-than-deleted-at? + [{:keys [db]} {:keys [chat-id clock-value]}] + (let [{:keys [deleted-at-clock-value]} + (get-in db [:chats chat-id])] + (>= deleted-at-clock-value clock-value))) + +(rf/defn receive-signal + [{:keys [db] :as cofx} reactions] + (let [reactions (filter (partial earlier-than-deleted-at? cofx) reactions)] + {:db (update db :reactions (process-reactions (:chats db)) reactions)})) + +(defn <-rpc + [message] + (-> message + (dissoc :chat_id) + (set/rename-keys {:messageId :message-id + :localChatId :chat-id + :emojiId :emoji-id + :messageType :message-type + :id :emoji-reaction-id}))) + +(rf/reg-event-fx :reactions/load-more + (fn [{:keys [db]} [cursor chat-id]] + (when-let [session-id (get-in db [:pagination-info chat-id :messages-initialized?])] + {:json-rpc/call [{:method "wakuext_emojiReactionsByChatID" + :params [chat-id cursor constants/default-number-of-messages] + :on-success #(rf/dispatch [:reactions/loaded chat-id session-id (map <-rpc %)]) + :on-error #(log/error "failed loading reactions" chat-id %)}]}))) + +(rf/reg-event-fx :reactions/loaded + (fn [{db :db} [chat-id session-id reactions]] + (when-not (and (get-in db [:pagination-info chat-id :messages-initialized?]) + (not= session-id + (get-in db [:pagination-info chat-id :messages-initialized?]))) + (let [reactions-w-chat-id (map #(assoc % :chat-id chat-id) reactions)] + {:db (update db :reactions (process-reactions (:chats db)) reactions-w-chat-id)})))) + +(defn- format-authors-response + [response] + (->> response + (map (fn [item] + {:compressed-key (:compressedKey item) + :emoji-id (:emojiId item) + :from (:from item)})) + (group-by :emoji-id))) + +(rf/reg-event-fx :reactions/get-authors-by-message-id + (fn [{:keys [db]} [{:keys [message-id on-success]}]] + {:db (dissoc db :reactions/authors) + :json-rpc/call [{:method "wakuext_emojiReactionsByChatIDMessageID" + :params [(:current-chat-id db) message-id] + :on-error #(log/error "failed to fetch emoji reaction by message-id: " + {:message-id message-id :error %}) + :on-success #(when on-success + (on-success (format-authors-response %)))}]})) + +(rf/reg-event-fx :reactions/save-authors + (fn [{:keys [db]} [reaction-authors]] + {:db (assoc db :reactions/authors reaction-authors)})) + +(rf/reg-event-fx :reactions/clear-authors + (fn [{:keys [db]}] + {:db (dissoc db :reactions/authors)})) + +(rf/reg-event-fx :reactions/send-emoji-reaction + (fn [{{:keys [current-chat-id]} :db} [{:keys [message-id emoji-id]}]] + {:json-rpc/call [{:method "wakuext_sendEmojiReaction" + :params [current-chat-id message-id emoji-id] + :js-response true + :on-success #(rf/dispatch [:sanitize-messages-and-process-response %]) + :on-error #(log/error "failed to send a reaction" %)}]})) + +(rf/reg-event-fx :reactions/send-emoji-reaction-retraction + (fn [_ [emoji-reaction-id]] + {:json-rpc/call [{:method "wakuext_sendEmojiReactionRetraction" + :params [emoji-reaction-id] + :js-response true + :on-success #(rf/dispatch [:sanitize-messages-and-process-response %]) + :on-error #(log/error "failed to send a reaction retraction" %)}]})) diff --git a/src/status_im2/contexts/chat/messages/content/reactions/view.cljs b/src/status_im2/contexts/chat/messages/content/reactions/view.cljs index e64789ac5c..95f385f038 100644 --- a/src/status_im2/contexts/chat/messages/content/reactions/view.cljs +++ b/src/status_im2/contexts/chat/messages/content/reactions/view.cljs @@ -2,6 +2,7 @@ (:require [quo.core :as quo] [quo.theme :as quo.theme] + [react-native.core :as rn] [status-im2.constants :as constants] [status-im2.contexts.chat.messages.drawers.view :as drawers] [utils.re-frame :as rf])) @@ -17,23 +18,21 @@ (defn- on-long-press [{:keys [message-id emoji-id user-message-content reactions-order theme]}] (rf/dispatch - [:chat.ui/emoji-reactions-by-message-id + [:reactions/get-authors-by-message-id {:message-id message-id :on-success (fn [response] - (rf/dispatch [:chat/save-emoji-reaction-details + (rf/dispatch [:reactions/save-authors {:reaction-authors-list response :selected-reaction emoji-id}]) (rf/dispatch [:dismiss-keyboard]) (rf/dispatch [:show-bottom-sheet - {:on-close (fn [] - (rf/dispatch - [:chat/clear-emoji-reaction-author-details])) - :content (fn [] - [drawers/reaction-authors - {:reactions-order reactions-order - :theme theme}]) - :selected-item (fn [] - user-message-content) + {:on-close #(rf/dispatch + [:reactions/clear-authors]) + :content (fn [] + [drawers/reaction-authors + {:reactions-order reactions-order + :theme theme}]) + :selected-item (fn [] user-message-content) :padding-bottom-override 0}]))}])) (defn- on-press-add @@ -56,7 +55,7 @@ (defn- view-internal [{:keys [message-id chat-id pinned-by theme]} user-message-content] (let [reactions (rf/sub [:chats/message-reactions message-id chat-id])] - [:<> + [rn/view {:border-color :red :border-width 1} (when (seq reactions) [quo/react {:container-style {:margin-left 44 diff --git a/src/status_im2/contexts/chat/messages/drawers/view.cljs b/src/status_im2/contexts/chat/messages/drawers/view.cljs index 1ee71beb22..c50f3eb3fd 100644 --- a/src/status_im2/contexts/chat/messages/drawers/view.cljs +++ b/src/status_im2/contexts/chat/messages/drawers/view.cljs @@ -71,7 +71,7 @@ (defn reaction-authors [{:keys [reactions-order theme]}] (let [{:keys [reaction-authors-list - selected-reaction]} (rf/sub [:chat/reactions-authors]) + selected-reaction]} (rf/sub [:reactions/authors]) selected-tab (reagent/atom (or selected-reaction (first (keys reaction-authors-list))))] (fn [] diff --git a/src/status_im2/contexts/chat/messages/transport/events.cljs b/src/status_im2/contexts/chat/messages/transport/events.cljs index c0780c4957..af462c4591 100644 --- a/src/status_im2/contexts/chat/messages/transport/events.cljs +++ b/src/status_im2/contexts/chat/messages/transport/events.cljs @@ -4,12 +4,10 @@ [clojure.string :as string] [status-im.browser.core :as browser] [status-im.chat.models.message :as models.message] - [status-im.chat.models.reactions :as models.reactions] [status-im.communities.core :as models.communities] [status-im.data-store.activities :as data-store.activities] [status-im.data-store.chats :as data-store.chats] [status-im.data-store.invitations :as data-store.invitations] - [status-im.data-store.reactions :as data-store.reactions] [status-im.group-chats.core :as models.group] [status-im.multiaccounts.update.core :as update.core] [status-im.pairing.core :as models.pairing] @@ -18,6 +16,7 @@ [status-im.wallet.core :as wallet] [status-im2.constants :as constants] [status-im2.contexts.chat.events :as chat.events] + [status-im2.contexts.chat.messages.content.reactions.events :as reactions] [status-im2.contexts.chat.messages.pin.events :as messages.pin] [status-im2.contexts.contacts.events :as models.contact] [status-im2.contexts.shell.activity-center.events :as activity-center] @@ -139,7 +138,7 @@ (js-delete response-js "emojiReactions") (rf/merge cofx (process-next response-js sync-handler) - (models.reactions/receive-signal (map data-store.reactions/<-rpc reactions)))) + (reactions/receive-signal (map reactions/<-rpc reactions)))) (seq invitations) (let [invitations (types/js->clj invitations)] @@ -386,21 +385,3 @@ :on-error #(do (log/warn "failed to send a message" %) (js/alert (str "failed to send a message: " %)))}]}) - -(rf/defn send-emoji-reaction - {:events [:reactions/send-emoji-reaction]} - [{{:keys [current-chat-id]} :db} {:keys [message-id emoji-id]}] - {:json-rpc/call [{:method "wakuext_sendEmojiReaction" - :params [current-chat-id message-id emoji-id] - :js-response true - :on-success #(rf/dispatch [:sanitize-messages-and-process-response %]) - :on-error #(log/error "failed to send a reaction" %)}]}) - -(rf/defn send-retract-emoji-reaction - {:events [:reactions/send-emoji-reaction-retraction]} - [_ emoji-reaction-id] - {:json-rpc/call [{:method "wakuext_sendEmojiReactionRetraction" - :params [emoji-reaction-id] - :js-response true - :on-success #(rf/dispatch [:sanitize-messages-and-process-response %]) - :on-error #(log/error "failed to send a reaction retraction" %)}]}) diff --git a/src/status_im2/subs/messages.cljs b/src/status_im2/subs/messages.cljs index 1485882315..985e837096 100644 --- a/src/status_im2/subs/messages.cljs +++ b/src/status_im2/subs/messages.cljs @@ -1,7 +1,6 @@ (ns status-im2.subs.messages (:require [re-frame.core :as re-frame] - [status-im.chat.models.reactions :as models.reactions] [status-im2.constants :as constants] [status-im2.contexts.chat.messages.list.events :as models.message-list] [status-im2.contexts.chat.messages.resolver.message-resolver :as resolver] @@ -177,9 +176,21 @@ :<- [:multiaccount/public-key] :<- [:messages/reactions] (fn [[current-public-key reactions] [_ message-id chat-id]] - (models.reactions/message-reactions - current-public-key - (get-in reactions [chat-id message-id])))) + (let [reactions (get-in reactions [chat-id message-id])] + (reduce + (fn [acc [emoji-id reactions]] + (if (pos? (count reactions)) + (let [own (first (filter (fn [[_ {:keys [from]}]] + (= from current-public-key)) + reactions))] + (conj acc + {:emoji-id emoji-id + :own (boolean (seq own)) + :emoji-reaction-id (:emoji-reaction-id (second own)) + :quantity (count reactions)})) + acc)) + [] + reactions)))) (re-frame/reg-sub :chats/all-loaded? diff --git a/src/status_im2/subs/root.cljs b/src/status_im2/subs/root.cljs index 19100c2f7a..ca6cbfd0d3 100644 --- a/src/status_im2/subs/root.cljs +++ b/src/status_im2/subs/root.cljs @@ -99,7 +99,7 @@ (reg-root-key-sub :chat/inputs-with-mentions :chat/inputs-with-mentions) (reg-root-key-sub :chats-home-list :chats-home-list) (reg-root-key-sub :chats/recording? :chats/recording?) -(reg-root-key-sub :chat/reactions-authors :chat/reactions-authors) +(reg-root-key-sub :reactions/authors :reactions/authors) ;;chat images lightbox (reg-root-key-sub :lightbox/exit-signal :lightbox/exit-signal)