mirror of
https://github.com/status-im/status-react.git
synced 2025-02-07 08:34:26 +00:00
Redirect user to Activity Center to manage pending contact requests (#14610)
This commit is contained in:
parent
d9e8fea14b
commit
a8d392e4de
@ -24,6 +24,7 @@
|
||||
"letsubs" :binding
|
||||
"testing" :arg1-body
|
||||
"deftest-sub" :arg1-body
|
||||
"wait-for" :arg1-body
|
||||
"with-deps-check" :arg1-body
|
||||
"ns" [:arg1-body
|
||||
{:list {:respect-nl? false}
|
||||
|
@ -4,18 +4,23 @@
|
||||
[react-native.core :as rn]))
|
||||
|
||||
(defn info-count
|
||||
[count style]
|
||||
(when (> count 0)
|
||||
[rn/view
|
||||
{:style (merge {:width 16
|
||||
:height 16
|
||||
:position :absolute
|
||||
:right 22
|
||||
:border-radius 6
|
||||
:justify-content :center
|
||||
:align-items :center
|
||||
:background-color (colors/theme-colors colors/primary-50 colors/primary-60)}
|
||||
style)}
|
||||
[rn/text
|
||||
{:style (merge typography/font-medium typography/label {:color colors/white :text-align :center})}
|
||||
count]]))
|
||||
([count]
|
||||
(info-count {} count))
|
||||
([props count]
|
||||
(when (> count 0)
|
||||
[rn/view
|
||||
(merge props
|
||||
{:style (merge {:width 16
|
||||
:height 16
|
||||
:position :absolute
|
||||
:right 22
|
||||
:border-radius 6
|
||||
:justify-content :center
|
||||
:align-items :center
|
||||
:background-color (colors/theme-colors colors/primary-50 colors/primary-60)}
|
||||
(:style props))})
|
||||
[rn/text
|
||||
{:style (merge typography/font-medium
|
||||
typography/label
|
||||
{:color colors/white :text-align :center})}
|
||||
count]])))
|
||||
|
@ -15,16 +15,17 @@
|
||||
(defn indicator
|
||||
[]
|
||||
[rn/view
|
||||
{:position :absolute
|
||||
:z-index 1
|
||||
:right -2
|
||||
:top -2
|
||||
:width 10
|
||||
:height 10
|
||||
:border-radius 5
|
||||
:justify-content :center
|
||||
:align-items :center
|
||||
:background-color (colors/theme-colors colors/neutral-5 colors/neutral-95)}
|
||||
{:accessibility-label :notification-dot
|
||||
:style {:position :absolute
|
||||
:z-index 1
|
||||
:right -2
|
||||
:top -2
|
||||
:width 10
|
||||
:height 10
|
||||
:border-radius 5
|
||||
:justify-content :center
|
||||
:align-items :center
|
||||
:background-color (colors/theme-colors colors/neutral-5 colors/neutral-95)}}
|
||||
[notification-dot]])
|
||||
|
||||
(defn tabs
|
||||
|
@ -43,6 +43,10 @@
|
||||
(and added (not was-added))
|
||||
(conj [:start-profile-chat public-key])
|
||||
|
||||
(and (not (:has-added-us contact))
|
||||
(= constants/contact-request-state-none (:contact-request-state contact)))
|
||||
(conj [:activity-center/remove-pending-contact-request (:public-key contact)])
|
||||
|
||||
(and was-added (not added))
|
||||
(conj nil)
|
||||
|
||||
|
@ -55,3 +55,34 @@
|
||||
{'cljs.test/testing `testing-subscription
|
||||
'testing `testing-subscription}
|
||||
body)))))))
|
||||
|
||||
(defmacro use-log-fixture
|
||||
"Register log fixture which allows inspecting all calls to `taoensso.timbre/log`.
|
||||
|
||||
Usage: Simply call this macro once per test namespace, and use the
|
||||
`status-im.test-helpers/logs` atom to deref the collection of all logs for the
|
||||
test under execution.
|
||||
|
||||
In Clojure(Script), we can rely on fixtures for each `cljs.deftest`, but not
|
||||
for individual `cljs.testing` macro calls. So keep that in mind when testing
|
||||
for log messages."
|
||||
[]
|
||||
`(cljs.test/use-fixtures
|
||||
:each
|
||||
{:before status-im.test-helpers/log-fixture-before
|
||||
:after status-im.test-helpers/log-fixture-after}))
|
||||
|
||||
(defmacro run-test-sync
|
||||
"Wrap around `re-frame.test/run-test-sync` to make it work with our aliased
|
||||
function `utils.re-frame/dispatch`.
|
||||
|
||||
This macro is a must, because the original implementation uses `with-redefs`
|
||||
pointing to the original re-frame `dispatch` function, but our event handlers
|
||||
are dispatching using our aliased function.
|
||||
|
||||
If tests run using the original `run-test-sync`, then all bets are off, and
|
||||
tests start to behave erratically."
|
||||
[& body]
|
||||
`(day8.re-frame.test/run-test-sync
|
||||
(with-redefs [utils.re-frame/dispatch re-frame.core/dispatch]
|
||||
~@body)))
|
||||
|
@ -89,20 +89,6 @@
|
||||
(and original-on-success on-success)
|
||||
(original-on-success (on-success fx-map)))))))
|
||||
|
||||
(defn using-log-test-appender
|
||||
"Rebinds `taoensso.timbre/*config*` to use a custom test appender that persists
|
||||
all `taoensso.timbre/log` call arguments. `f` is called with the atom
|
||||
reference so that tests can de-reference it and verify log messages and their
|
||||
respective levels."
|
||||
[f]
|
||||
(let [logs (atom [])]
|
||||
(binding [log/*config* (assoc-in log/*config*
|
||||
[:appenders :test]
|
||||
{:enabled? true
|
||||
:fn (fn [{:keys [vargs level]}]
|
||||
(swap! logs conj {:args vargs :level level}))})]
|
||||
(f logs))))
|
||||
|
||||
(defn restore-app-db
|
||||
"Saves current app DB, calls `f` and restores the original app DB.
|
||||
|
||||
@ -114,3 +100,39 @@
|
||||
(f)
|
||||
(finally
|
||||
(reset! rf-db/app-db original-db)))))
|
||||
|
||||
;;;; Log fixture
|
||||
|
||||
(def ^:private original-log-config
|
||||
(atom nil))
|
||||
|
||||
(def logs
|
||||
"The collection of all logs registered by `test-log-appender`. Tests can
|
||||
de-reference it and verify log messages and their respective levels."
|
||||
(atom []))
|
||||
|
||||
(defn- test-log-appender
|
||||
"Custom log appender that persists all `taoensso.timbre/log` call arguments."
|
||||
[{:keys [vargs level]}]
|
||||
(swap! logs conj {:args vargs :level level}))
|
||||
|
||||
#_{:clj-kondo/ignore [:unused-private-var]}
|
||||
(defn- log-fixture-before
|
||||
[]
|
||||
#_{:clj-kondo/ignore [:unresolved-var]}
|
||||
(reset! original-log-config log/*config*)
|
||||
|
||||
;; We reset the logs *before* running tests instead of *after* because: 1.
|
||||
;; It's just as reliable; 2. It helps when using the REPL, because we can
|
||||
;; easily inspect `logs` after a test has finished.
|
||||
(reset! logs [])
|
||||
|
||||
(log/swap-config! assoc-in
|
||||
[:appenders :test]
|
||||
{:enabled? true
|
||||
:fn test-log-appender}))
|
||||
|
||||
#_{:clj-kondo/ignore [:unused-private-var]}
|
||||
(defn- log-fixture-after
|
||||
[]
|
||||
(log/set-config! @original-log-config))
|
||||
|
@ -1,94 +0,0 @@
|
||||
(ns status-im.ui2.screens.chat.components.received-cr-item
|
||||
(:require [clojure.string :as string]
|
||||
[quo2.components.avatars.user-avatar :as user-avatar]
|
||||
[quo2.components.notifications.notification-dot :refer [notification-dot]]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[quo2.foundations.typography :as typography]
|
||||
[react-native.core :as rn]
|
||||
[status-im.i18n.i18n :as i18n]
|
||||
[status-im.utils.datetime :as time]
|
||||
[status-im.utils.handlers :refer [<sub >evt]]
|
||||
[status-im.utils.utils :as utils.utils]))
|
||||
|
||||
(defn received-cr-item
|
||||
[{:keys [chat-id message timestamp read]}]
|
||||
(let [no-ens-name (string/blank? (get-in message [:content :ens-name]))
|
||||
display-name (first (<sub [:contacts/contact-two-names-by-identity chat-id]))]
|
||||
[rn/view
|
||||
{:style {:flex-direction :row
|
||||
:padding-top 8
|
||||
:margin-top 4
|
||||
:padding-bottom 12
|
||||
:flex 1}}
|
||||
(when-not read
|
||||
[notification-dot {:right 32 :top 16}])
|
||||
[user-avatar/user-avatar
|
||||
{:full-name display-name
|
||||
:status-indicator? true
|
||||
:online? true
|
||||
:size :small
|
||||
:ring? false}]
|
||||
[rn/view {:style {:margin-horizontal 8}}
|
||||
[rn/view {:style {:flex-direction :row}}
|
||||
[rn/text
|
||||
{:style (merge typography/font-semi-bold
|
||||
typography/paragraph-1
|
||||
{:color (colors/theme-colors colors/neutral-100 colors/white)
|
||||
:margin-right 8})} display-name]
|
||||
(when no-ens-name
|
||||
[rn/text
|
||||
{:style (merge typography/font-regular
|
||||
typography/label
|
||||
{:color (colors/theme-colors colors/neutral-50 colors/neutral-40)
|
||||
:margin-top 4})}
|
||||
(str (utils.utils/get-shortened-address chat-id) " · ")])
|
||||
[rn/text
|
||||
{:style (merge typography/font-regular
|
||||
typography/label
|
||||
{:color (colors/theme-colors colors/neutral-50 colors/neutral-40)
|
||||
:margin-top 4})}
|
||||
(time/to-short-str timestamp)]]
|
||||
[rn/view
|
||||
{:style {:border-radius 12
|
||||
:margin-top 10
|
||||
:padding-horizontal 12
|
||||
:padding-vertical 8
|
||||
:border-width 1
|
||||
:border-color (colors/theme-colors colors/neutral-20 colors/neutral-70)}}
|
||||
[rn/text
|
||||
{:style (merge typography/font-regular
|
||||
typography/paragraph-1
|
||||
{:color (colors/theme-colors colors/neutral-100 colors/white)})}
|
||||
(:text (:content message))]]
|
||||
[rn/view
|
||||
{:style {:margin-top 12
|
||||
:flex-direction :row}}
|
||||
[rn/touchable-opacity
|
||||
{:accessibility-label :decline-cr
|
||||
:on-press #(>evt [:contact-requests.ui/decline-request (:message-id message)])
|
||||
:active-opacity 1
|
||||
:style {:background-color (colors/theme-colors colors/danger-50
|
||||
colors/danger-60)
|
||||
:justify-content :center
|
||||
:align-items :center
|
||||
:align-self :flex-start
|
||||
:border-radius 8
|
||||
:padding-vertical 4
|
||||
:padding-horizontal 8}}
|
||||
[rn/text {:style (merge typography/font-medium typography/paragraph-2 {:color colors/white})}
|
||||
(i18n/label :t/decline)]]
|
||||
[rn/touchable-opacity
|
||||
{:accessibility-label :accept-cr
|
||||
:on-press #(>evt [:contact-requests.ui/accept-request (:message-id message)])
|
||||
:active-opacity 1
|
||||
:style {:background-color (colors/theme-colors colors/success-50
|
||||
colors/success-60)
|
||||
:justify-content :center
|
||||
:align-items :center
|
||||
:align-self :flex-start
|
||||
:border-radius 8
|
||||
:padding-vertical 4
|
||||
:padding-horizontal 8
|
||||
:margin-left 8}}
|
||||
[rn/text {:style (merge typography/font-medium typography/paragraph-2 {:color colors/white})}
|
||||
(i18n/label :t/accept)]]]]]))
|
@ -62,8 +62,7 @@
|
||||
:height (/ window-width 3)
|
||||
:background-color (colors/theme-colors colors/white-opa-40 colors/neutral-80-opa-40)})
|
||||
|
||||
(defn image-count
|
||||
[]
|
||||
(def image-count
|
||||
{:width 24
|
||||
:height 24
|
||||
:border-radius 8
|
||||
|
@ -56,7 +56,8 @@
|
||||
(when (some #{item} @selected)
|
||||
[rn/view {:style (style/overlay window-width)}])
|
||||
(when (some #{item} @selected)
|
||||
[info-count/info-count (+ (utils/first-index #(= item %) @selected) 1) (style/image-count)])])
|
||||
[info-count/info-count {:style style/image-count}
|
||||
(inc (utils/first-index #(= item %) @selected))])])
|
||||
|
||||
(defn photo-selector
|
||||
[chat-id]
|
||||
|
@ -1,9 +1,8 @@
|
||||
(ns status-im2.contexts.activity-center.events
|
||||
(:require [re-frame.core :as rf]
|
||||
[status-im.data-store.activities :as data-store.activities]
|
||||
[status-im.utils.fx :as fx]
|
||||
(:require [status-im.data-store.activities :as data-store.activities]
|
||||
[status-im2.contexts.activity-center.notification-types :as types]
|
||||
[taoensso.timbre :as log]))
|
||||
[taoensso.timbre :as log]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(def defaults
|
||||
{:filter-status :unread
|
||||
@ -15,20 +14,26 @@
|
||||
|
||||
;;;; Navigation
|
||||
|
||||
(fx/defn open-activity-center
|
||||
(rf/defn open-activity-center
|
||||
{:events [:activity-center/open]}
|
||||
[_]
|
||||
(rf/dispatch [:show-popover
|
||||
{:view :activity-center
|
||||
:style {:margin 0}
|
||||
:disable-touchable-overlay? true
|
||||
:blur-view? true
|
||||
:blur-view-props {:blur-amount 20
|
||||
:blur-type :dark}}]))
|
||||
[{:keys [db]} {:keys [filter-type filter-status]}]
|
||||
{:db (cond-> db
|
||||
filter-status
|
||||
(assoc-in [:activity-center :filter :status] filter-status)
|
||||
|
||||
filter-type
|
||||
(assoc-in [:activity-center :filter :type] filter-type))
|
||||
:dispatch [:show-popover
|
||||
{:view :activity-center
|
||||
:style {:margin 0}
|
||||
:disable-touchable-overlay? true
|
||||
:blur-view? true
|
||||
:blur-view-props {:blur-amount 20
|
||||
:blur-type :dark}}]})
|
||||
|
||||
;;;; Misc
|
||||
|
||||
(fx/defn process-notification-failure
|
||||
(rf/defn process-notification-failure
|
||||
{:events [:activity-center/process-notification-failure]}
|
||||
[_ notification-id action error]
|
||||
(log/warn (str "Failed to " action)
|
||||
@ -68,7 +73,7 @@
|
||||
db-notifications
|
||||
new-notifications))
|
||||
|
||||
(fx/defn notifications-reconcile
|
||||
(rf/defn notifications-reconcile
|
||||
{:events [:activity-center.notifications/reconcile]}
|
||||
[{:keys [db]} new-notifications]
|
||||
(when (seq new-notifications)
|
||||
@ -77,7 +82,7 @@
|
||||
update-notifications
|
||||
new-notifications)}))
|
||||
|
||||
(fx/defn notifications-reconcile-from-response
|
||||
(rf/defn notifications-reconcile-from-response
|
||||
{:events [:activity-center/reconcile-notifications-from-response]}
|
||||
[cofx response]
|
||||
(->> response
|
||||
@ -85,6 +90,28 @@
|
||||
(map data-store.activities/<-rpc)
|
||||
(notifications-reconcile cofx)))
|
||||
|
||||
(defn- remove-pending-contact-request
|
||||
[notifications contact-id]
|
||||
(remove #(= contact-id (:author %))
|
||||
notifications))
|
||||
|
||||
(rf/defn notifications-remove-pending-contact-request
|
||||
{:events [:activity-center/remove-pending-contact-request]}
|
||||
[{:keys [db]} contact-id]
|
||||
{:db (-> db
|
||||
(update-in [:activity-center :notifications types/no-type :all :data]
|
||||
remove-pending-contact-request
|
||||
contact-id)
|
||||
(update-in [:activity-center :notifications types/no-type :unread :data]
|
||||
remove-pending-contact-request
|
||||
contact-id)
|
||||
(update-in [:activity-center :notifications types/contact-request :all :data]
|
||||
remove-pending-contact-request
|
||||
contact-id)
|
||||
(update-in [:activity-center :notifications types/contact-request :unread :data]
|
||||
remove-pending-contact-request
|
||||
contact-id))})
|
||||
|
||||
;;;; Mark notifications as read
|
||||
|
||||
(defn- get-notification
|
||||
@ -98,7 +125,7 @@
|
||||
(filter #(= notification-id (:id %)))
|
||||
first))
|
||||
|
||||
(fx/defn mark-as-read
|
||||
(rf/defn mark-as-read
|
||||
{:events [:activity-center.notifications/mark-as-read]}
|
||||
[{:keys [db]} notification-id]
|
||||
(when-let [notification (get-notification db notification-id)]
|
||||
@ -111,14 +138,14 @@
|
||||
:notification/mark-as-read
|
||||
%])}]}))
|
||||
|
||||
(fx/defn mark-as-read-success
|
||||
(rf/defn mark-as-read-success
|
||||
{:events [:activity-center.notifications/mark-as-read-success]}
|
||||
[cofx notification]
|
||||
(notifications-reconcile cofx [(assoc notification :read true)]))
|
||||
|
||||
;;;; Contact verification
|
||||
|
||||
(fx/defn contact-verification-decline
|
||||
(rf/defn contact-verification-decline
|
||||
{:events [:activity-center.contact-verification/decline]}
|
||||
[_ notification-id]
|
||||
{:json-rpc/call [{:method "wakuext_declineContactVerificationRequest"
|
||||
@ -130,7 +157,7 @@
|
||||
:contact-verification/decline
|
||||
%])}]})
|
||||
|
||||
(fx/defn contact-verification-reply
|
||||
(rf/defn contact-verification-reply
|
||||
{:events [:activity-center.contact-verification/reply]}
|
||||
[_ notification-id reply]
|
||||
{:json-rpc/call [{:method "wakuext_acceptContactVerificationRequest"
|
||||
@ -142,7 +169,7 @@
|
||||
:contact-verification/reply
|
||||
%])}]})
|
||||
|
||||
(fx/defn contact-verification-mark-as-trusted
|
||||
(rf/defn contact-verification-mark-as-trusted
|
||||
{:events [:activity-center.contact-verification/mark-as-trusted]}
|
||||
[_ notification-id]
|
||||
{:json-rpc/call [{:method "wakuext_verifiedTrusted"
|
||||
@ -154,7 +181,7 @@
|
||||
:contact-verification/mark-as-trusted
|
||||
%])}]})
|
||||
|
||||
(fx/defn contact-verification-mark-as-untrustworthy
|
||||
(rf/defn contact-verification-mark-as-untrustworthy
|
||||
{:events [:activity-center.contact-verification/mark-as-untrustworthy]}
|
||||
[_ notification-id]
|
||||
{:json-rpc/call [{:method "wakuext_verifiedUntrustworthy"
|
||||
@ -186,7 +213,7 @@
|
||||
:all status-all
|
||||
99))
|
||||
|
||||
(fx/defn notifications-fetch
|
||||
(rf/defn notifications-fetch
|
||||
[{:keys [db]} {:keys [cursor per-page filter-type filter-status reset-data?]}]
|
||||
(when-not (get-in db [:activity-center :notifications filter-type filter-status :loading?])
|
||||
(let [per-page (or per-page (defaults :notifications-per-page))]
|
||||
@ -200,7 +227,7 @@
|
||||
:on-error #(rf/dispatch [:activity-center.notifications/fetch-error
|
||||
filter-type filter-status %])}]})))
|
||||
|
||||
(fx/defn notifications-fetch-first-page
|
||||
(rf/defn notifications-fetch-first-page
|
||||
{:events [:activity-center.notifications/fetch-first-page]}
|
||||
[{:keys [db] :as cofx} {:keys [filter-type filter-status]}]
|
||||
(let [filter-type (or filter-type
|
||||
@ -211,7 +238,7 @@
|
||||
(get-in db
|
||||
[:activity-center :filter :status]
|
||||
(defaults :filter-status)))]
|
||||
(fx/merge cofx
|
||||
(rf/merge cofx
|
||||
{:db (-> db
|
||||
(assoc-in [:activity-center :filter :type] filter-type)
|
||||
(assoc-in [:activity-center :filter :status] filter-status))}
|
||||
@ -220,7 +247,7 @@
|
||||
:filter-status filter-status
|
||||
:reset-data? true}))))
|
||||
|
||||
(fx/defn notifications-fetch-next-page
|
||||
(rf/defn notifications-fetch-next-page
|
||||
{:events [:activity-center.notifications/fetch-next-page]}
|
||||
[{:keys [db] :as cofx}]
|
||||
(let [{:keys [type status]} (get-in db [:activity-center :filter])
|
||||
@ -232,7 +259,7 @@
|
||||
:filter-status status
|
||||
:reset-data? false}))))
|
||||
|
||||
(fx/defn notifications-fetch-success
|
||||
(rf/defn notifications-fetch-success
|
||||
{:events [:activity-center.notifications/fetch-success]}
|
||||
[{:keys [db]}
|
||||
filter-type
|
||||
@ -248,7 +275,7 @@
|
||||
(constantly processed)
|
||||
#(concat %1 processed))))}))
|
||||
|
||||
(fx/defn notifications-fetch-unread-contact-requests
|
||||
(rf/defn notifications-fetch-unread-contact-requests
|
||||
"Unread contact requests are, in practical terms, the same as pending contact
|
||||
requests in the new Activity Center, because pending contact requests are
|
||||
always marked as unread, and once the user declines/accepts the request, they
|
||||
@ -265,7 +292,7 @@
|
||||
:per-page 20
|
||||
:reset-data? true}))
|
||||
|
||||
(fx/defn notifications-fetch-unread-count
|
||||
(rf/defn notifications-fetch-unread-count
|
||||
{:events [:activity-center.notifications/fetch-unread-count]}
|
||||
[_]
|
||||
{:json-rpc/call [{:method "wakuext_unreadActivityCenterNotificationsCount"
|
||||
@ -274,12 +301,12 @@
|
||||
%])
|
||||
:on-error #()}]})
|
||||
|
||||
(fx/defn notifications-fetch-unread-count-success
|
||||
(rf/defn notifications-fetch-unread-count-success
|
||||
{:events [:activity-center.notifications/fetch-unread-count-success]}
|
||||
[{:keys [db]} result]
|
||||
{:db (assoc-in db [:activity-center :unread-count] result)})
|
||||
|
||||
(fx/defn notifications-fetch-error
|
||||
(rf/defn notifications-fetch-error
|
||||
{:events [:activity-center.notifications/fetch-error]}
|
||||
[{:keys [db]} filter-type filter-status error]
|
||||
(log/warn "Failed to load Activity Center notifications" error)
|
||||
|
@ -1,12 +1,13 @@
|
||||
(ns status-im2.contexts.activity-center.events-test
|
||||
(:require [cljs.test :refer [deftest is testing]]
|
||||
[day8.re-frame.test :as rf-test]
|
||||
[re-frame.core :as rf]
|
||||
[status-im.constants :as constants]
|
||||
status-im.events
|
||||
[status-im.test-helpers :as h]
|
||||
[status-im2.contexts.activity-center.events :as activity-center]
|
||||
[status-im2.contexts.activity-center.notification-types :as types]))
|
||||
[status-im2.contexts.activity-center.notification-types :as types]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(h/use-log-fixture)
|
||||
|
||||
(def notification-id "0x1")
|
||||
|
||||
@ -17,27 +18,57 @@
|
||||
|
||||
(defn test-log-on-failure
|
||||
[{:keys [before-test notification-id event action]}]
|
||||
(rf-test/run-test-sync
|
||||
(h/run-test-sync
|
||||
(setup)
|
||||
(h/using-log-test-appender
|
||||
(fn [logs]
|
||||
(when before-test
|
||||
(before-test))
|
||||
(h/stub-fx-with-callbacks :json-rpc/call :on-error (constantly :fake-error))
|
||||
(when before-test
|
||||
(before-test))
|
||||
(h/stub-fx-with-callbacks :json-rpc/call :on-error (constantly :fake-error))
|
||||
|
||||
(rf/dispatch event)
|
||||
(rf/dispatch event)
|
||||
|
||||
(is (= {:args [(str "Failed to " action)
|
||||
{:notification-id notification-id
|
||||
:error :fake-error}]
|
||||
:level :warn}
|
||||
(last @logs)))))))
|
||||
(is (= {:args [(str "Failed to " action)
|
||||
{:notification-id notification-id
|
||||
:error :fake-error}]
|
||||
:level :warn}
|
||||
(last @h/logs)))))
|
||||
|
||||
;;;; Misc
|
||||
|
||||
(deftest open-activity-center-test
|
||||
(testing "opens the activity center with filters enabled"
|
||||
(h/run-test-sync
|
||||
(let [spy-queue (atom [])]
|
||||
(setup)
|
||||
(h/spy-fx spy-queue :show-popover)
|
||||
|
||||
(rf/dispatch [:activity-center/open
|
||||
{:filter-type types/contact-request
|
||||
:filter-status :unread}])
|
||||
|
||||
(is (= {:status :unread
|
||||
:type types/contact-request}
|
||||
(get-in (h/db) [:activity-center :filter])))
|
||||
(is (= [{:id :show-popover :args nil}]
|
||||
@spy-queue)))))
|
||||
|
||||
(testing "opens the activity center without custom filters"
|
||||
(h/run-test-sync
|
||||
(let [spy-queue (atom [])
|
||||
existing-filters {:status :all}]
|
||||
(setup)
|
||||
(h/spy-fx spy-queue :show-popover)
|
||||
(rf/dispatch [:test/assoc-in [:activity-center :filter] existing-filters])
|
||||
|
||||
(rf/dispatch [:activity-center/open])
|
||||
|
||||
(is (= existing-filters
|
||||
(get-in (h/db) [:activity-center :filter])))
|
||||
(is (= [{:id :show-popover :args nil}]
|
||||
@spy-queue))))))
|
||||
|
||||
(deftest mark-as-read-test
|
||||
(testing "does nothing if the notification ID cannot be found in the app db"
|
||||
(rf-test/run-test-sync
|
||||
(h/run-test-sync
|
||||
(setup)
|
||||
(let [spy-queue (atom [])]
|
||||
(h/spy-fx spy-queue :json-rpc/call)
|
||||
@ -58,7 +89,7 @@
|
||||
(is (= notifications (get-in (h/db) [:activity-center :notifications])))))))
|
||||
|
||||
(testing "marks notifications as read and updates app db"
|
||||
(rf-test/run-test-sync
|
||||
(h/run-test-sync
|
||||
(setup)
|
||||
(let [notif-1 {:id "0x1" :read true :type types/one-to-one-chat}
|
||||
notif-2 {:id "0x2" :read false :type types/one-to-one-chat}
|
||||
@ -156,7 +187,7 @@
|
||||
|
||||
(defn test-contact-verification-event
|
||||
[{:keys [event expected-rpc-call]}]
|
||||
(rf-test/run-test-sync
|
||||
(h/run-test-sync
|
||||
(setup)
|
||||
(let [spy-queue (atom [])]
|
||||
(h/stub-fx-with-callbacks :json-rpc/call
|
||||
@ -231,7 +262,7 @@
|
||||
|
||||
(deftest notifications-reconcile-test
|
||||
(testing "does nothing when there are no new notifications"
|
||||
(rf-test/run-test-sync
|
||||
(h/run-test-sync
|
||||
(setup)
|
||||
(let [notifications {types/one-to-one-chat
|
||||
{:all {:cursor ""
|
||||
@ -257,7 +288,7 @@
|
||||
(is (= notifications (get-in (h/db) [:activity-center :notifications]))))))
|
||||
|
||||
(testing "removes dismissed or accepted notifications"
|
||||
(rf-test/run-test-sync
|
||||
(h/run-test-sync
|
||||
(setup)
|
||||
(let [notif-1 {:id "0x1" :read true :type types/one-to-one-chat}
|
||||
notif-2 {:id "0x2" :read false :type types/one-to-one-chat}
|
||||
@ -290,7 +321,7 @@
|
||||
(get-in (h/db) [:activity-center :notifications]))))))
|
||||
|
||||
(testing "replaces old notifications with newly arrived ones"
|
||||
(rf-test/run-test-sync
|
||||
(h/run-test-sync
|
||||
(setup)
|
||||
(let [notif-1 {:id "0x1" :read true :type types/one-to-one-chat}
|
||||
notif-4 {:id "0x4" :read false :type types/private-group-chat}
|
||||
@ -320,7 +351,7 @@
|
||||
(get-in (h/db) [:activity-center :notifications]))))))
|
||||
|
||||
(testing "reconciles notifications that switched their read/unread status"
|
||||
(rf-test/run-test-sync
|
||||
(h/run-test-sync
|
||||
(setup)
|
||||
(let [notif-1 {:id "0x1" :read true :type types/one-to-one-chat}
|
||||
new-notif-1 (assoc notif-1 :read false)]
|
||||
@ -342,7 +373,7 @@
|
||||
;; Sorting by timestamp and ID is compatible with what the backend does when
|
||||
;; returning paginated results.
|
||||
(testing "sorts notifications by timestamp and id in descending order"
|
||||
(rf-test/run-test-sync
|
||||
(h/run-test-sync
|
||||
(setup)
|
||||
(let [notif-1 {:id "0x1" :read true :type types/one-to-one-chat :timestamp 1}
|
||||
notif-2 {:id "0x2" :read true :type types/one-to-one-chat :timestamp 1}
|
||||
@ -366,11 +397,41 @@
|
||||
:unread {:cursor "" :data [notif-5 new-notif-4 notif-3]}}}
|
||||
(get-in (h/db) [:activity-center :notifications])))))))
|
||||
|
||||
(deftest remove-pending-contact-request-test
|
||||
(testing "removes notification from all related filter types and status"
|
||||
(h/run-test-sync
|
||||
(setup)
|
||||
(let [contact-pub-key "0x99"
|
||||
notif-1 {:id "0x1" :read true :type types/contact-request}
|
||||
notif-2 {:id "0x2" :read false :type types/contact-request :author contact-pub-key}
|
||||
notif-3 {:id "0x3" :read false :type types/private-group-chat}
|
||||
notifications {types/contact-request
|
||||
{:all {:cursor "" :data [notif-2 notif-1]}
|
||||
:unread {:cursor "" :data [notif-2]}}
|
||||
types/private-group-chat
|
||||
{:unread {:cursor "" :data [notif-3]}}
|
||||
types/no-type
|
||||
{:all {:cursor "" :data [notif-3 notif-2 notif-1]}
|
||||
:unread {:cursor "" :data [notif-2 notif-3]}}}]
|
||||
(rf/dispatch [:test/assoc-in [:activity-center :notifications] notifications])
|
||||
|
||||
(rf/dispatch [:activity-center/remove-pending-contact-request contact-pub-key])
|
||||
|
||||
(is (= {types/contact-request
|
||||
{:all {:cursor "" :data [notif-1]}
|
||||
:unread {:cursor "" :data []}}
|
||||
types/private-group-chat
|
||||
{:unread {:cursor "" :data [notif-3]}}
|
||||
types/no-type
|
||||
{:all {:cursor "" :data [notif-3 notif-1]}
|
||||
:unread {:cursor "" :data [notif-3]}}}
|
||||
(get-in (h/db) [:activity-center :notifications])))))))
|
||||
|
||||
;;;; Notifications fetching and pagination
|
||||
|
||||
(deftest notifications-fetch-test
|
||||
(testing "fetches first page"
|
||||
(rf-test/run-test-sync
|
||||
(h/run-test-sync
|
||||
(setup)
|
||||
(let [spy-queue (atom [])]
|
||||
(h/stub-fx-with-callbacks
|
||||
@ -405,7 +466,7 @@
|
||||
(get-in (h/db) [:activity-center :notifications]))))))
|
||||
|
||||
(testing "does not fetch next page when pagination cursor reached the end"
|
||||
(rf-test/run-test-sync
|
||||
(h/run-test-sync
|
||||
(setup)
|
||||
(let [spy-queue (atom [])]
|
||||
(h/spy-fx spy-queue :json-rpc/call)
|
||||
@ -425,7 +486,7 @@
|
||||
;; about updating the cursor value, but we have to make sure the next page is
|
||||
;; only fetched if the current cursor is valid.
|
||||
(testing "does not fetch next page when cursor is nil"
|
||||
(rf-test/run-test-sync
|
||||
(h/run-test-sync
|
||||
(setup)
|
||||
(let [spy-queue (atom [])]
|
||||
(h/spy-fx spy-queue :json-rpc/call)
|
||||
@ -442,7 +503,7 @@
|
||||
(is (= [] @spy-queue)))))
|
||||
|
||||
(testing "fetches next page when pagination cursor is not empty"
|
||||
(rf-test/run-test-sync
|
||||
(h/run-test-sync
|
||||
(setup)
|
||||
(let [spy-queue (atom [])]
|
||||
(h/stub-fx-with-callbacks
|
||||
@ -480,7 +541,7 @@
|
||||
(get-in (h/db) [:activity-center :notifications]))))))
|
||||
|
||||
(testing "does not fetch next page while it is still loading"
|
||||
(rf-test/run-test-sync
|
||||
(h/run-test-sync
|
||||
(setup)
|
||||
(let [spy-queue (atom [])]
|
||||
(h/spy-fx spy-queue :json-rpc/call)
|
||||
@ -499,7 +560,7 @@
|
||||
(is (= [] @spy-queue)))))
|
||||
|
||||
(testing "resets loading flag after an error"
|
||||
(rf-test/run-test-sync
|
||||
(h/run-test-sync
|
||||
(setup)
|
||||
(let [spy-queue (atom [])]
|
||||
(h/stub-fx-with-callbacks :json-rpc/call :on-error (constantly :fake-error))
|
||||
@ -542,7 +603,7 @@
|
||||
|
||||
(deftest notifications-fetch-unread-count-test
|
||||
(testing "fetches total notification count and store in db"
|
||||
(rf-test/run-test-sync
|
||||
(h/run-test-sync
|
||||
(setup)
|
||||
(let [spy-queue (atom [])]
|
||||
(h/stub-fx-with-callbacks :json-rpc/call :on-success (constantly 9))
|
||||
|
@ -138,6 +138,7 @@
|
||||
(get-in last-message [:content :text])]
|
||||
[render-subheader (get-in last-message [:content :parsed-text])])]
|
||||
(if (> unviewed-mentions-count 0)
|
||||
[quo/info-count unviewed-mentions-count {:top 16}]
|
||||
[quo/info-count {:style {:top 16}}
|
||||
unviewed-mentions-count]
|
||||
(when (> unviewed-messages-count 0)
|
||||
[rn/view {:style (style/count-container)}]))]))
|
||||
|
@ -17,13 +17,3 @@
|
||||
:border-radius 16
|
||||
:border-width 1
|
||||
:border-color (colors/theme-colors colors/neutral-20 colors/neutral-80)})
|
||||
|
||||
(defn contact-requests-sheet
|
||||
[]
|
||||
{:background-color (colors/theme-colors colors/neutral-10 colors/neutral-80)
|
||||
:width 32
|
||||
:height 32
|
||||
:border-radius 10
|
||||
:justify-content :center
|
||||
:align-items :center
|
||||
:margin-bottom 24})
|
||||
|
@ -4,37 +4,10 @@
|
||||
[quo2.core :as quo]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[react-native.core :as rn]
|
||||
[reagent.core :as reagent] ;; TODO move to status-im2
|
||||
[status-im.ui2.screens.chat.components.received-cr-item :as received-cr-item]
|
||||
[status-im2.contexts.activity-center.notification-types :as notification-types]
|
||||
[status-im2.contexts.chat.home.contact-request.style :as style]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn contact-requests-sheet
|
||||
[received-requests]
|
||||
(let [selected-requests-tab (reagent/atom :received)]
|
||||
(fn []
|
||||
(let [sent-requests []]
|
||||
[rn/view {:style {:margin-left 20}}
|
||||
[rn/touchable-opacity
|
||||
{:on-press #(rf/dispatch [:bottom-sheet/hide])
|
||||
:style (style/contact-requests-sheet)}
|
||||
[quo/icon :i/close]]
|
||||
[rn/text {:size :heading-1 :weight :semi-bold}
|
||||
(i18n/label :t/pending-requests)]
|
||||
[quo/tabs
|
||||
{:style {:margin-top 12 :margin-bottom 20}
|
||||
:size 32
|
||||
:on-change #(reset! selected-requests-tab %)
|
||||
:default-active :received
|
||||
:data [{:id :received
|
||||
:label (i18n/label :t/received)}
|
||||
{:id :sent
|
||||
:label (i18n/label :t/sent)}]}]
|
||||
[rn/flat-list
|
||||
{:key-fn :chat-id
|
||||
:data (if (= @selected-requests-tab :received) received-requests sent-requests)
|
||||
:render-fn received-cr-item/received-cr-item}]]))))
|
||||
|
||||
(defn get-display-name
|
||||
[{:keys [chat-id message]}]
|
||||
(let [name (first (rf/sub [:contacts/contact-two-names-by-identity chat-id]))
|
||||
@ -62,11 +35,13 @@
|
||||
(defn contact-requests
|
||||
[requests]
|
||||
[rn/touchable-opacity
|
||||
{:active-opacity 1
|
||||
:on-press (fn []
|
||||
(rf/dispatch [:bottom-sheet/show-sheet
|
||||
{:content (fn [] [contact-requests-sheet requests])}]))
|
||||
:style style/contact-requests}
|
||||
{:active-opacity 1
|
||||
:accessibility-label :open-activity-center-contact-requests
|
||||
:on-press (fn []
|
||||
(rf/dispatch [:activity-center/open
|
||||
{:filter-status :unread
|
||||
:filter-type notification-types/contact-request}]))
|
||||
:style style/contact-requests}
|
||||
[rn/view {:style (style/contact-requests-icon)}
|
||||
[quo/icon :i/pending-user {:color (colors/theme-colors colors/neutral-50 colors/neutral-40)}]]
|
||||
[rn/view {:style {:margin-left 8}}
|
||||
@ -75,4 +50,5 @@
|
||||
{:size :paragraph-2
|
||||
:style {:color (colors/theme-colors colors/neutral-50 colors/neutral-40)}}
|
||||
(requests-summary requests)]]
|
||||
[quo/info-count (count requests)]])
|
||||
[quo/info-count {:accessibility-label :pending-contact-requests-count}
|
||||
(count requests)]])
|
||||
|
@ -52,12 +52,13 @@
|
||||
(defn contacts
|
||||
[contact-requests]
|
||||
(let [items (rf/sub [:contacts/active-sections])]
|
||||
(if (empty? items)
|
||||
(if (and (empty? items) (empty? contact-requests))
|
||||
[welcome-blank-contacts]
|
||||
[:<>
|
||||
(when (pos? (count contact-requests))
|
||||
(when (seq contact-requests)
|
||||
[contact-request/contact-requests contact-requests])
|
||||
[contact-list/contact-list {:icon :options}]])))
|
||||
(when (seq items)
|
||||
[contact-list/contact-list {:icon :options}])])))
|
||||
|
||||
(defn tabs
|
||||
[]
|
||||
@ -75,13 +76,16 @@
|
||||
:size 32
|
||||
:on-change #(reset! selected-tab %)
|
||||
:default-active @selected-tab
|
||||
:data [{:id :recent
|
||||
:label (i18n/label :t/recent)}
|
||||
{:id :groups
|
||||
:label (i18n/label :t/groups)}
|
||||
{:id :contacts
|
||||
:label (i18n/label :t/contacts)
|
||||
:notification-dot? (pos? (count contact-requests))}]}]
|
||||
:data [{:id :recent
|
||||
:label (i18n/label :t/recent)
|
||||
:accessibility-label :tab-recent}
|
||||
{:id :groups
|
||||
:label (i18n/label :t/groups)
|
||||
:accessibility-label :tab-groups}
|
||||
{:id :contacts
|
||||
:label (i18n/label :t/contacts)
|
||||
:accessibility-label :tab-contacts
|
||||
:notification-dot? (pos? (count contact-requests))}]}]
|
||||
(if (= @selected-tab :contacts)
|
||||
[contacts contact-requests]
|
||||
[chats @selected-tab])]))))
|
||||
|
Loading…
x
Reference in New Issue
Block a user