New component Selector > Filter (#14650)

This commit is contained in:
Icaro Motta 2022-12-28 12:21:15 -03:00 committed by GitHub
parent 6280a6c4d5
commit 915b8ebd9a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 434 additions and 207 deletions

View File

@ -19,6 +19,10 @@
:respect-bl] :respect-bl]
:fn-map :fn-map
{"reg-sub" :arg1-pair {"reg-sub" :arg1-pair
"h/describe" :arg1-body
"h/test" :arg1-body
"global.describe" :arg1-body
"global.test" :arg1-body
"list-comp" :binding "list-comp" :binding
"defview" :arg1-body "defview" :arg1-body
"letsubs" :binding "letsubs" :binding

View File

@ -399,13 +399,15 @@ src
├── react_native ├── react_native
│ ├── gesture.cljs │ ├── gesture.cljs
│ └── platform.cljs │ └── platform.cljs
├── status_im ├── status_im/
├── status_im2
│ ├── common │ ├── common
│ │ └── components │ │ └── components
│ │ └── bottom_sheet.cljs │ │ └── bottom_sheet.cljs
│ ├── contexts/ │ ├── contexts/
│ ├── setup/ │ ├── setup/
│ └── subs/ │ └── subs/
├── test_helpers/
└── utils.cljs └── utils.cljs
``` ```
@ -414,17 +416,23 @@ src
- `src/quo2/`: The component library for Status Mobile. - `src/quo2/`: The component library for Status Mobile.
- `src/react_native/`: Contains only low-level constructs to help React Native - `src/react_native/`: Contains only low-level constructs to help React Native
work in tandem with Clojure(Script). work in tandem with Clojure(Script).
- `src/status_im/common/`: Directories named `common` can appear at any level of - `src/status_im2/`: Directory where we try to be as strict as possible about
the directory tree. Just like directories named `utils`, their directory our guidelines and where we prefer to write code for the new, redesigned
mobile app.
- `src/status_im/`: Directory containing what we call "old code", not yet
migrated to new guidelines for the new mobile app.
- `src/status_im2/common/`: Directories named `common` can appear at any level
of the directory tree. Just like directories named `utils`, their directory
nesting level communicates their applicable limits. nesting level communicates their applicable limits.
- `src/status_im/common/components/`: Contains reusable components that are not - `src/status_im2/common/components/`: Contains reusable components that are not
part of the design system (quo2). part of the design system (quo2).
- `src/status_im/contexts/`: Contains [bounded contexts](#glossary), like - `src/status_im2/contexts/`: Contains [bounded contexts](#glossary), like
`browser/`, `messaging/`, etc. As much as possible, _bounded contexts_ should `browser/`, `messaging/`, etc. As much as possible, _bounded contexts_ should
not directly require each other's namespaces. not directly require each other's namespaces.
- `src/status_im/setup/`: Contains namespaces that are mostly used to initialize - `src/status_im2/setup/`: Contains namespaces that are mostly used to
the application, configure test runners, etc. In general, such namespaces initialize the application, configure test runners, etc. In general, such
should not be required from the outside. namespaces should not be required from the outside.
- `src/test_helpers/`: Reusable utilities for writing all kinds of tests.
- `src/status_im/subs/`: All subscriptions should live inside it. - `src/status_im/subs/`: All subscriptions should live inside it.
Directories named `utils/` can appear at any level of the directory tree. The Directories named `utils/` can appear at any level of the directory tree. The
@ -485,18 +493,26 @@ src
[Unit tests](#glossary) should be created alongside their respective source [Unit tests](#glossary) should be created alongside their respective source
implementation. We prefer them colocated with the source and not like most implementation. We prefer them colocated with the source and not like most
Clojure (JVM) codebases which mirror the sources in a top-level test directory. Clojure (JVM) codebases which mirror the sources in a top-level test directory.
Component tests should be created in a separate directory `__tests__`. Example:
``` ```
├── models ├── models
│ ├── message.cljs │ ├── message.cljs
│ └── message_test.cljs │ └── message_test.cljs
├── __tests__
│ └── input_bla_test.cljs
├── models.cljs ├── models.cljs
└── models_test.cljs └── models_test.cljs
``` ```
Component tests should be created in a separate directory `__tests__`, colocated
with the source. When the entire component implementation is isolated under a
single directory, create a test file named `component_spec.cljs` instead.
```
└── filter
├── component_spec.cljs
├── style.cljs
└── view.cljs
```
There's no hard rule on how integration test namespaces should be split, but There's no hard rule on how integration test namespaces should be split, but
we're at least striving to define them under appropriate bounded contexts that we're at least striving to define them under appropriate bounded contexts that
mirror the source code. mirror the source code.

View File

@ -19,6 +19,7 @@
;; routing ;; routing
[bidi "2.1.6"] [bidi "2.1.6"]
;; test dependencies ;; test dependencies
[camel-snake-kebab "0.4.3"]
[day8.re-frame/test "0.1.5"] [day8.re-frame/test "0.1.5"]
[com.taoensso/tufte "2.1.0"]] [com.taoensso/tufte "2.1.0"]]

View File

@ -8,10 +8,10 @@
(rtl/render (reagent/as-element [banner/banner opts]))) (rtl/render (reagent/as-element [banner/banner opts])))
(js/global.test "basic render of banner component" (js/global.test "basic render of banner component"
(fn [] (fn []
(render-banner {:pins-count "5" (render-banner {:pins-count "5"
:latest-pin-text "this message"}) :latest-pin-text "this message"})
(-> (js/expect (rtl/screen.getByText "this message")) (-> (js/expect (rtl/screen.getByText "this message"))
(.toBeTruthy)) (.toBeTruthy))
(-> (js/expect (rtl/screen.getByText "5")) (-> (js/expect (rtl/screen.getByText "5"))
(.toBeTruthy)))) (.toBeTruthy))))

View File

@ -8,21 +8,21 @@
(rtl/render (reagent/as-element [button/button options label])))) (rtl/render (reagent/as-element [button/button options label]))))
(js/global.test "default render of button component" (js/global.test "default render of button component"
(fn [] (fn []
(render-button {:accessibility-label "test-button"} "") (render-button {:accessibility-label "test-button"} "")
(-> (js/expect (rtl/screen.getByLabelText "test-button")) (-> (js/expect (rtl/screen.getByLabelText "test-button"))
(.toBeTruthy)))) (.toBeTruthy))))
(js/global.test "button renders with a label" (js/global.test "button renders with a label"
(fn [] (fn []
(render-button {} "test-label") (render-button {} "test-label")
(-> (js/expect (rtl/screen.getByText "test-label")) (-> (js/expect (rtl/screen.getByText "test-label"))
(.toBeTruthy)))) (.toBeTruthy))))
(js/global.test "button on-press works" (js/global.test "button on-press works"
(let [event (js/jest.fn)] (let [event (js/jest.fn)]
(fn [] (fn []
(render-button {:on-press event} "test-label") (render-button {:on-press event} "test-label")
(rtl/fireEvent.press (rtl/screen.getByText "test-label")) (rtl/fireEvent.press (rtl/screen.getByText "test-label"))
(-> (js/expect event) (-> (js/expect event)
(.toHaveBeenCalledTimes 1))))) (.toHaveBeenCalledTimes 1)))))

View File

@ -10,25 +10,25 @@
(rtl/render (reagent/as-element [counter/counter opts value])))) (rtl/render (reagent/as-element [counter/counter opts value]))))
(js/global.test "default render of counter component" (js/global.test "default render of counter component"
(fn [] (fn []
(render-counter) (render-counter)
(-> (js/expect (rtl/screen.getByTestId "counter-component")) (-> (js/expect (rtl/screen.getByTestId "counter-component"))
(.toBeTruthy)))) (.toBeTruthy))))
(js/global.test "renders counter with a string value" (js/global.test "renders counter with a string value"
(fn [] (fn []
(render-counter {} "1") (render-counter {} "1")
(-> (js/expect (rtl/screen.getByText "1")) (-> (js/expect (rtl/screen.getByText "1"))
(.toBeTruthy)))) (.toBeTruthy))))
(js/global.test "renders counter with an integer value" (js/global.test "renders counter with an integer value"
(fn [] (fn []
(render-counter {} 1) (render-counter {} 1)
(-> (js/expect (rtl/screen.getByText "1")) (-> (js/expect (rtl/screen.getByText "1"))
(.toBeTruthy)))) (.toBeTruthy))))
(js/global.test "renders counter with value 99+ when the value is greater than 99" (js/global.test "renders counter with value 99+ when the value is greater than 99"
(fn [] (fn []
(render-counter {} "100") (render-counter {} "100")
(-> (js/expect (rtl/screen.getByText "99+")) (-> (js/expect (rtl/screen.getByText "99+"))
(.toBeTruthy)))) (.toBeTruthy))))

View File

@ -10,36 +10,36 @@
(rtl/render (reagent/as-element [divider-label/divider-label opts])))) (rtl/render (reagent/as-element [divider-label/divider-label opts]))))
(js/global.test "default render of divider-label component" (js/global.test "default render of divider-label component"
(fn [] (fn []
(render-divider-label) (render-divider-label)
(-> (js/expect (rtl/screen.getByLabelText "divider-label")) (-> (js/expect (rtl/screen.getByLabelText "divider-label"))
(.toBeTruthy)))) (.toBeTruthy))))
(js/global.test "render divider-label component with a label" (js/global.test "render divider-label component with a label"
(fn [] (fn []
(render-divider-label {:label :hello}) (render-divider-label {:label :hello})
(-> (js/expect (rtl/screen.getByText "hello")) (-> (js/expect (rtl/screen.getByText "hello"))
(.toBeTruthy)))) (.toBeTruthy))))
(js/global.test "render divider-label component with a counter-value" (js/global.test "render divider-label component with a counter-value"
(fn [] (fn []
(render-divider-label {:label :hello (render-divider-label {:label :hello
:counter-value "1"}) :counter-value "1"})
(-> (js/expect (rtl/screen.getByText "1")) (-> (js/expect (rtl/screen.getByText "1"))
(.toBeTruthy)))) (.toBeTruthy))))
(js/global.test "divider-label chevron icon renders to the left when set" (js/global.test "divider-label chevron icon renders to the left when set"
(fn [] (fn []
(render-divider-label {:label :hello (render-divider-label {:label :hello
:counter-value "1" :counter-value "1"
:chevron-position :left}) :chevron-position :left})
(-> (js/expect (rtl/screen.getByTestId "divider-label-icon-left")) (-> (js/expect (rtl/screen.getByTestId "divider-label-icon-left"))
(.toBeTruthy)))) (.toBeTruthy))))
(js/global.test "divider-label chevron icon renders to the right when set" (js/global.test "divider-label chevron icon renders to the right when set"
(fn [] (fn []
(render-divider-label {:label :hello (render-divider-label {:label :hello
:counter-value "1" :counter-value "1"
:chevron-position :right}) :chevron-position :right})
(-> (js/expect (rtl/screen.getByTestId "divider-label-icon-right")) (-> (js/expect (rtl/screen.getByTestId "divider-label-icon-right"))
(.toBeTruthy)))) (.toBeTruthy))))

View File

@ -8,46 +8,46 @@
(rtl/render (reagent/as-element [action-drawer/action-drawer options])))) (rtl/render (reagent/as-element [action-drawer/action-drawer options]))))
(js/global.test "action-drawer renders with elements label displaying" (js/global.test "action-drawer renders with elements label displaying"
(fn [] (fn []
(render-action-drawer [[{:icon :i/friend (render-action-drawer [[{:icon :i/friend
:label "a sample label"}]]) :label "a sample label"}]])
(-> (js/expect (rtl/screen.getByText "a sample label")) (-> (js/expect (rtl/screen.getByText "a sample label"))
(.toBeTruthy)))) (.toBeTruthy))))
(js/global.test "action-drawer renders with elements sub-label displaying" (js/global.test "action-drawer renders with elements sub-label displaying"
(fn [] (fn []
(render-action-drawer [[{:icon :i/friend (render-action-drawer [[{:icon :i/friend
:label "a sample label" :label "a sample label"
:sub-label "a sample sub label"}]]) :sub-label "a sample sub label"}]])
(-> (js/expect (rtl/screen.getByText "a sample sub label")) (-> (js/expect (rtl/screen.getByText "a sample sub label"))
(.toBeTruthy)))) (.toBeTruthy))))
(js/global.test "action-drawer on click action works on element" (js/global.test "action-drawer on click action works on element"
(let [event (js/jest.fn)] (let [event (js/jest.fn)]
(fn [] (fn []
(render-action-drawer [[{:icon :i/friend (render-action-drawer [[{:icon :i/friend
:label "a sample label" :label "a sample label"
:on-press event}]]) :on-press event}]])
(rtl/fireEvent.press (rtl/screen.getByText "a sample label")) (rtl/fireEvent.press (rtl/screen.getByText "a sample label"))
(-> (js/expect event) (-> (js/expect event)
(.toHaveBeenCalled))))) (.toHaveBeenCalled)))))
(js/global.test "action-drawer renders two icons when set" (js/global.test "action-drawer renders two icons when set"
(fn [] (fn []
(render-action-drawer [[{:icon :i/friend (render-action-drawer [[{:icon :i/friend
:label "a sample label" :label "a sample label"
:right-icon :i/friend :right-icon :i/friend
:accessibility-label :first-element}]]) :accessibility-label :first-element}]])
(-> (js/expect (rtl/screen.getByLabelText "right-icon-for-action")) (-> (js/expect (rtl/screen.getByLabelText "right-icon-for-action"))
(.toBeTruthy)) (.toBeTruthy))
(-> (js/expect (rtl/screen.queryByLabelText "left-icon-for-action")) (-> (js/expect (rtl/screen.queryByLabelText "left-icon-for-action"))
(.toBeTruthy)))) (.toBeTruthy))))
(js/global.test "action-drawer renders a divider when the add-divider? prop is true" (js/global.test "action-drawer renders a divider when the add-divider? prop is true"
(fn [] (fn []
(render-action-drawer [[{:icon :i/friend (render-action-drawer [[{:icon :i/friend
:label "a sample label" :label "a sample label"
:add-divider? true :add-divider? true
:accessibility-label :first-element}]]) :accessibility-label :first-element}]])
(-> (js/expect (rtl/screen.getAllByLabelText "divider")) (-> (js/expect (rtl/screen.getAllByLabelText "divider"))
(.toBeTruthy)))) (.toBeTruthy))))

View File

@ -8,7 +8,7 @@
(rtl/render (reagent/as-element [text/text options value])))) (rtl/render (reagent/as-element [text/text options value]))))
(js/global.test "text renders with text" (js/global.test "text renders with text"
(fn [] (fn []
(render-text {} "hello") (render-text {} "hello")
(-> (js/expect (rtl/screen.getByText "hello")) (-> (js/expect (rtl/screen.getByText "hello"))
(.toBeTruthy)))) (.toBeTruthy))))

View File

@ -28,57 +28,57 @@
(rtl/render (reagent/as-element [selectors/radio opts])))) (rtl/render (reagent/as-element [selectors/radio opts]))))
(js/global.test "default render of toggle component" (js/global.test "default render of toggle component"
(fn [] (fn []
(render-toggle) (render-toggle)
(-> (js/expect (rtl/screen.getByTestId "toggle-component")) (-> (js/expect (rtl/screen.getByTestId "toggle-component"))
(.toBeTruthy)))) (.toBeTruthy))))
(js/global.test "toggle component on change is working" (js/global.test "toggle component on change is working"
(let [mock-fn (js/jest.fn)] (let [mock-fn (js/jest.fn)]
(fn [] (fn []
(render-toggle {:on-change mock-fn}) (render-toggle {:on-change mock-fn})
(rtl/fireEvent.press (rtl/screen.getByTestId "toggle-component")) (rtl/fireEvent.press (rtl/screen.getByTestId "toggle-component"))
(-> (js/expect mock-fn) (-> (js/expect mock-fn)
(.toHaveBeenCalledTimes 1))))) (.toHaveBeenCalledTimes 1)))))
(js/global.test "default render of radio component" (js/global.test "default render of radio component"
(fn [] (fn []
(render-radio) (render-radio)
(-> (js/expect (rtl/screen.getByTestId "radio-component")) (-> (js/expect (rtl/screen.getByTestId "radio-component"))
(.toBeTruthy)))) (.toBeTruthy))))
(js/global.test "radio component on change is working" (js/global.test "radio component on change is working"
(let [mock-fn (js/jest.fn)] (let [mock-fn (js/jest.fn)]
(fn [] (fn []
(render-radio {:on-change mock-fn}) (render-radio {:on-change mock-fn})
(rtl/fireEvent.press (rtl/screen.getByTestId "radio-component")) (rtl/fireEvent.press (rtl/screen.getByTestId "radio-component"))
(-> (js/expect mock-fn) (-> (js/expect mock-fn)
(.toHaveBeenCalledTimes 1))))) (.toHaveBeenCalledTimes 1)))))
(js/global.test "default render of checkbox component" (js/global.test "default render of checkbox component"
(fn [] (fn []
(render-checkbox) (render-checkbox)
(-> (js/expect (rtl/screen.getByTestId "checkbox-component")) (-> (js/expect (rtl/screen.getByTestId "checkbox-component"))
(.toBeTruthy)))) (.toBeTruthy))))
(js/global.test "checkbox component on change is working" (js/global.test "checkbox component on change is working"
(let [mock-fn (js/jest.fn)] (let [mock-fn (js/jest.fn)]
(fn [] (fn []
(render-checkbox {:on-change mock-fn}) (render-checkbox {:on-change mock-fn})
(rtl/fireEvent.press (rtl/screen.getByTestId "checkbox-component")) (rtl/fireEvent.press (rtl/screen.getByTestId "checkbox-component"))
(-> (js/expect mock-fn) (-> (js/expect mock-fn)
(.toHaveBeenCalledTimes 1))))) (.toHaveBeenCalledTimes 1)))))
(js/global.test "default render of checkbox-prefill component" (js/global.test "default render of checkbox-prefill component"
(fn [] (fn []
(render-checkbox-prefill) (render-checkbox-prefill)
(-> (js/expect (rtl/screen.getByTestId "checkbox-prefill-component")) (-> (js/expect (rtl/screen.getByTestId "checkbox-prefill-component"))
(.toBeTruthy)))) (.toBeTruthy))))
(js/global.test "checkbox-prefill component on change is working" (js/global.test "checkbox-prefill component on change is working"
(let [mock-fn (js/jest.fn)] (let [mock-fn (js/jest.fn)]
(fn [] (fn []
(render-checkbox-prefill {:on-change mock-fn}) (render-checkbox-prefill {:on-change mock-fn})
(rtl/fireEvent.press (rtl/screen.getByTestId "checkbox-prefill-component")) (rtl/fireEvent.press (rtl/screen.getByTestId "checkbox-prefill-component"))
(-> (js/expect mock-fn) (-> (js/expect mock-fn)
(.toHaveBeenCalledTimes 1))))) (.toHaveBeenCalledTimes 1)))))

View File

@ -1,32 +0,0 @@
(ns quo2.components.selectors.disclaimer
(:require [quo2.components.markdown.text :as text]
[quo2.components.selectors.selectors :as selectors]
[quo2.foundations.colors :as colors]
[react-native.core :as rn]))
(defn disclaimer
[{:keys [on-change accessibility-label container-style]} label]
[rn/view
{:style
(merge
container-style
{:flex 1
:flex-direction :row
:background-color (colors/theme-colors
colors/neutral-5
colors/neutral-80-opa-40)
:padding 11
:align-self :stretch
:border-radius 12
:border-width 1
:border-color (colors/theme-colors
colors/neutral-20
colors/neutral-70)})}
[selectors/checkbox
{:accessibility-label accessibility-label
:on-change on-change}]
[text/text
{:size :paragraph-2
:style {:margin-left 8}}
label]])

View File

@ -0,0 +1,16 @@
(ns quo2.components.selectors.disclaimer.style
(:require [quo2.foundations.colors :as colors]))
(defn container
[]
{:flex 1
:flex-direction :row
:background-color (colors/theme-colors colors/neutral-5 colors/neutral-80-opa-40)
:padding 11
:align-self :stretch
:border-radius 12
:border-width 1
:border-color (colors/theme-colors colors/neutral-20 colors/neutral-70)})
(def text
{:margin-left 8})

View File

@ -0,0 +1,17 @@
(ns quo2.components.selectors.disclaimer.view
(:require [quo2.components.markdown.text :as text]
[quo2.components.selectors.disclaimer.style :as style]
[quo2.components.selectors.selectors :as selectors]
[react-native.core :as rn]))
(defn view
[{:keys [on-change accessibility-label container-style]} label]
[rn/view
{:style (merge container-style (style/container))}
[selectors/checkbox
{:accessibility-label accessibility-label
:on-change on-change}]
[text/text
{:size :paragraph-2
:style style/text}
label]])

View File

@ -0,0 +1,16 @@
(ns quo2.components.selectors.filter.component-spec
(:require [quo2.components.selectors.filter.view :as quo]
[test-helpers.component :as h]))
(h/describe "selector filter component"
(h/test "renders component"
(h/render [quo/view])
(-> (js/expect (h/get-by-label-text :selector-filter))
(.toBeTruthy)))
(h/test "calls custom event handler when on-press-out is triggered"
(let [on-press-out-mock (js/jest.fn)]
(h/render [quo/view {:on-press-out on-press-out-mock}])
(h/fire-event :press-out (h/get-by-label-text :selector-filter))
(-> (js/expect on-press-out-mock)
(.toHaveBeenCalledTimes 1)))))

View File

@ -0,0 +1,60 @@
(ns quo2.components.selectors.filter.style
(:require [quo2.foundations.colors :as colors]))
(def container-default
{:width 32
:height 32
:border-radius 10
:align-items :center
:justify-content :center
:padding 6})
(defn container-border-color
[pressed? blur? override-theme]
(let [dark? (= :dark override-theme)]
(cond
(and (not pressed?) (not dark?) (not blur?))
colors/neutral-20
(and (not pressed?) dark? (not blur?))
colors/neutral-80
(and pressed? (not dark?) blur?)
colors/neutral-80-opa-20
(or (and pressed? (not dark?) (not blur?))
(and (not pressed?) (not dark?) blur?))
colors/neutral-80-opa-10
(or (and pressed? dark? (not blur?))
(and (not pressed?) dark? blur?)
(and pressed? dark? blur?))
colors/white-opa-10
:else
nil)))
(defn container-background-color
[pressed? override-theme]
(when pressed?
(if (= :dark override-theme)
colors/primary-60
colors/primary-50)))
(defn container-outer
[pressed? override-theme]
(merge container-default
{:background-color (container-background-color pressed? override-theme)}))
(defn container-inner
[pressed? blur? override-theme]
(merge container-default
{:border-width 1
:border-color (container-border-color pressed? blur? override-theme)}))
(defn icon-color
[pressed? override-theme]
(if (and (not pressed?)
(= :light override-theme))
colors/neutral-100
colors/white))

View File

@ -0,0 +1,23 @@
(ns quo2.components.selectors.filter.view
(:require [quo2.components.icon :as icon]
[quo2.components.selectors.filter.style :as style]
[quo2.theme :as theme]
[react-native.core :as rn]
[reagent.core :as reagent]))
(defn view
[initial-props]
(let [pressed? (reagent/atom (:pressed? initial-props))]
(fn [{:keys [blur? override-theme on-press-out]
:or {override-theme (theme/get-theme)}}]
[rn/touchable-without-feedback
{:accessibility-label :selector-filter
:on-press-out (fn []
(swap! pressed? not)
(when on-press-out
(on-press-out @pressed?)))}
[rn/view {:style (style/container-outer @pressed? override-theme)}
[rn/view {:style (style/container-inner @pressed? blur? override-theme)}
[icon/icon :i/unread
{:color (style/icon-color @pressed? override-theme)
:size 20}]]]])))

View File

@ -1,4 +1,5 @@
(ns quo2.core (ns quo2.core
(:refer-clojure :exclude [filter])
(:require (:require
quo2.components.avatars.account-avatar quo2.components.avatars.account-avatar
quo2.components.avatars.channel-avatar quo2.components.avatars.channel-avatar
@ -41,7 +42,8 @@
quo2.components.notifications.notification-dot quo2.components.notifications.notification-dot
quo2.components.notifications.toast quo2.components.notifications.toast
quo2.components.reactions.reaction quo2.components.reactions.reaction
quo2.components.selectors.disclaimer quo2.components.selectors.disclaimer.view
quo2.components.selectors.filter.view
quo2.components.selectors.selectors quo2.components.selectors.selectors
quo2.components.separator quo2.components.separator
quo2.components.settings.privacy-option quo2.components.settings.privacy-option
@ -77,8 +79,9 @@
(def floating-shell-button quo2.components.navigation.floating-shell-button/floating-shell-button) (def floating-shell-button quo2.components.navigation.floating-shell-button/floating-shell-button)
(def status-tag quo2.components.tags.status-tags/status-tag) (def status-tag quo2.components.tags.status-tags/status-tag)
(def page-nav quo2.components.navigation.page-nav/page-nav) (def page-nav quo2.components.navigation.page-nav/page-nav)
(def disclaimer quo2.components.selectors.disclaimer/disclaimer) (def disclaimer quo2.components.selectors.disclaimer.view/view)
(def checkbox quo2.components.selectors.selectors/checkbox) (def checkbox quo2.components.selectors.selectors/checkbox)
(def filter quo2.components.selectors.filter.view/view)
(def skeleton quo2.components.loaders.skeleton/skeleton) (def skeleton quo2.components.loaders.skeleton/skeleton)
(def author quo2.components.messages.author.view/author) (def author quo2.components.messages.author.view/author)

View File

@ -1,9 +1,9 @@
(ns quo2.core-spec (ns quo2.core-spec
(:require (:require [quo2.components.banners.--tests--.banner-component-spec]
[quo2.components.banners.--tests--.banner-component-spec] [quo2.components.buttons.--tests--.buttons-component-spec]
[quo2.components.buttons.--tests--.buttons-component-spec] [quo2.components.counter.--tests--.counter-component-spec]
[quo2.components.counter.--tests--.counter-component-spec] [quo2.components.dividers.--tests--.divider-label-component-spec]
[quo2.components.dividers.--tests--.divider-label-component-spec] [quo2.components.drawers.--tests--.action-drawers-component-spec]
[quo2.components.drawers.--tests--.action-drawers-component-spec] [quo2.components.markdown.--tests--.text-component-spec]
[quo2.components.markdown.--tests--.text-component-spec] [quo2.components.selectors.--tests--.selectors-component-spec]
[quo2.components.selectors.--tests--.selectors-component-spec])) [quo2.components.selectors.filter.component-spec]))

View File

@ -15,18 +15,14 @@
(defn filter-selector-read-toggle (defn filter-selector-read-toggle
[] []
(let [unread-filter-enabled? (rf/sub [:activity-center/filter-status-unread-enabled?])] (let [unread-filter-enabled? (rf/sub [:activity-center/filter-status-unread-enabled?])]
;; TODO(@ilmotta): Replace the button by a Filter Selector. [quo/filter
;; https://github.com/status-im/status-mobile/issues/14355 {:pressed? unread-filter-enabled?
[quo/button :blur? true
{:icon true
:type (if unread-filter-enabled? :primary :blur-bg-outline)
:size 32
:override-theme :dark :override-theme :dark
:on-press #(rf/dispatch [:activity-center.notifications/fetch-first-page :on-press-out #(rf/dispatch [:activity-center.notifications/fetch-first-page
{:filter-status (if unread-filter-enabled? {:filter-status (if unread-filter-enabled?
:all :all
:unread)}])} :unread)}])}]))
:i/unread]))
(defn empty-tab (defn empty-tab
[] []

View File

@ -1,4 +1,5 @@
(ns status-im2.contexts.quo-preview.main (ns status-im2.contexts.quo-preview.main
(:refer-clojure :exclude [filter])
(:require (:require
[quo2.components.buttons.button :as quo2-button] [quo2.components.buttons.button :as quo2-button]
[quo2.components.markdown.text :as quo2-text] [quo2.components.markdown.text :as quo2-text]
@ -47,6 +48,7 @@
[status-im2.contexts.quo-preview.reactions.react :as react] [status-im2.contexts.quo-preview.reactions.react :as react]
[status-im2.contexts.quo-preview.record-audio.record-audio :as record-audio] [status-im2.contexts.quo-preview.record-audio.record-audio :as record-audio]
[status-im2.contexts.quo-preview.selectors.disclaimer :as disclaimer] [status-im2.contexts.quo-preview.selectors.disclaimer :as disclaimer]
[status-im2.contexts.quo-preview.selectors.filter :as filter]
[status-im2.contexts.quo-preview.selectors.selectors :as selectors] [status-im2.contexts.quo-preview.selectors.selectors :as selectors]
[status-im2.contexts.quo-preview.settings.privacy-option :as privacy-option] [status-im2.contexts.quo-preview.settings.privacy-option :as privacy-option]
[status-im2.contexts.quo-preview.switcher.switcher-cards :as switcher-cards] [status-im2.contexts.quo-preview.switcher.switcher-cards :as switcher-cards]
@ -184,6 +186,9 @@
:selectors [{:name :disclaimer :selectors [{:name :disclaimer
:insets {:top false} :insets {:top false}
:component disclaimer/preview-disclaimer} :component disclaimer/preview-disclaimer}
{:name :filter
:insets {:top false}
:component filter/preview}
{:name :selectors {:name :selectors
:insets {:top false} :insets {:top false}
:component selectors/preview-selectors}] :component selectors/preview-selectors}]

View File

@ -1,6 +1,6 @@
(ns status-im2.contexts.quo-preview.selectors.disclaimer (ns status-im2.contexts.quo-preview.selectors.disclaimer
(:require [quo2.components.buttons.button :as button] (:require [quo2.components.buttons.button :as button]
[quo2.components.selectors.disclaimer :as quo2] [quo2.components.selectors.disclaimer.view :as quo]
[quo2.foundations.colors :as colors] [quo2.foundations.colors :as colors]
[react-native.core :as rn] [react-native.core :as rn]
[reagent.core :as reagent])) [reagent.core :as reagent]))
@ -16,7 +16,7 @@
[rn/view [rn/view
{:padding-vertical 60 {:padding-vertical 60
:align-items :center} :align-items :center}
[quo2/disclaimer [quo/view
{:container-style {:margin-bottom 40} {:container-style {:margin-bottom 40}
:on-change #(swap! checked? not)} :on-change #(swap! checked? not)}
"I agree with the community rules"] "I agree with the community rules"]

View File

@ -0,0 +1,56 @@
(ns status-im2.contexts.quo-preview.selectors.filter
(:require [quo2.components.selectors.filter.view :as quo]
[quo2.foundations.colors :as colors]
[quo2.theme :as theme]
[react-native.core :as rn]
[reagent.core :as reagent]
[status-im2.contexts.quo-preview.preview :as preview]))
(def descriptor
[{:label "Theme"
:key :override-theme
:type :select
:options [{:key :dark
:value "Dark"}
{:key :light
:value "Light"}]}
{:label "Blur?"
:key :blur?
:type :boolean}])
(defn cool-preview
[]
(let [state (reagent/atom {:override-theme (theme/get-theme)
:blur? false})]
(fn []
[rn/view
{:style {:margin-bottom 50
:padding-vertical 16
:padding-horizontal 20}}
[preview/customizer state descriptor]
[rn/view
{:style {:padding-vertical 60
:align-items :center}}
[rn/view
{:style {:width "100%"
:height 250
:align-items :center
:justify-content :center
:border-radius 20
:background-color (cond (= :dark (:override-theme @state))
colors/neutral-95
(= :light (:override-theme @state))
colors/white)}}
[quo/view @state]]]])))
(defn preview
[]
[rn/view
{:style {:background-color (colors/theme-colors colors/white colors/neutral-90)
:flex 1}}
[rn/flat-list
{:style {:flex 1}
:keyboardShouldPersistTaps :always
:header [cool-preview]
:key-fn str}]])

View File

@ -1,11 +1,14 @@
(ns status-im2.setup.db (ns status-im2.setup.db
(:require [react-native.core :as rn] ;; TODO (14/11/22 flexsurfer move to status-im2 namespace (:require [react-native.core :as rn] ;; TODO (14/11/22 flexsurfer move to status-im2 namespace
[status-im.fleet.core :as fleet] [status-im.fleet.core :as fleet]
[status-im.wallet.db :as wallet.db])) [status-im.wallet.db :as wallet.db]
[status-im2.contexts.activity-center.events :as activity-center]))
;; initial state of app-db ;; initial state of app-db
(def app-db (def app-db
{:contacts/contacts {} {:activity-center {:filter {:status (:filter-status activity-center/defaults)
:type (:filter-type activity-center/defaults)}}
:contacts/contacts {}
:pairing/installations {} :pairing/installations {}
:group/selected-contacts #{} :group/selected-contacts #{}
:chats {} :chats {}

View File

@ -0,0 +1,17 @@
(ns test-helpers.component (:refer-clojure :exclude [test]))
(defmacro describe
[description & body]
`(js/global.describe
~description
(fn []
~@body
;; We need to return 'undefined', otherwise Jest gives a
;; warning: "Describe callback must not return a value".
js/undefined)))
(defmacro test
[description & body]
`(js/global.test
~description
(fn [] ~@body)))

View File

@ -0,0 +1,26 @@
(ns test-helpers.component
"Helpers for writing component tests using React Native Testing Library."
(:require-macros test-helpers.component)
(:require ["@testing-library/react-native" :as rtl]
[camel-snake-kebab.core :as camel-snake-kebab]
[reagent.core :as reagent]))
(defn render
[component]
(rtl/render (reagent/as-element component)))
(defn fire-event
[event-name element]
(rtl/fireEvent element (camel-snake-kebab/->camelCaseString event-name)))
(defn debug
[element]
(rtl/screen.debug element))
(defn get-by-test-id
[test-id]
(rtl/screen.getByTestId (name test-id)))
(defn get-by-label-text
[label]
(rtl/screen.getByLabelText (name label)))