Redirect user to Activity Center to manage pending contact requests (#14610)

This commit is contained in:
Icaro Motta 2022-12-23 11:30:46 -03:00 committed by GitHub
parent d9e8fea14b
commit a8d392e4de
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 281 additions and 252 deletions

View File

@ -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}

View File

@ -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]])))

View File

@ -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

View File

@ -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)

View File

@ -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)))

View File

@ -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))

View File

@ -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)]]]]]))

View File

@ -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

View File

@ -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]

View File

@ -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)

View File

@ -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))

View File

@ -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)}]))]))

View File

@ -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})

View File

@ -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)]])

View File

@ -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])]))))