diff --git a/.zprintrc b/.zprintrc index 059d1998a2..1f938b862a 100644 --- a/.zprintrc +++ b/.zprintrc @@ -19,6 +19,10 @@ :respect-bl] :fn-map {"reg-sub" :arg1-pair + "h/describe" :arg1-body + "h/test" :arg1-body + "global.describe" :arg1-body + "global.test" :arg1-body "list-comp" :binding "defview" :arg1-body "letsubs" :binding diff --git a/doc/new-guidelines.md b/doc/new-guidelines.md index ac504d50b9..a1c5af182c 100644 --- a/doc/new-guidelines.md +++ b/doc/new-guidelines.md @@ -399,13 +399,15 @@ src ├── react_native │ ├── gesture.cljs │ └── platform.cljs -├── status_im +├── status_im/ +├── status_im2 │ ├── common │ │ └── components │ │ └── bottom_sheet.cljs │ ├── contexts/ │ ├── setup/ │ └── subs/ +├── test_helpers/ └── utils.cljs ``` @@ -414,17 +416,23 @@ src - `src/quo2/`: The component library for Status Mobile. - `src/react_native/`: Contains only low-level constructs to help React Native work in tandem with Clojure(Script). -- `src/status_im/common/`: Directories named `common` can appear at any level of - the directory tree. Just like directories named `utils`, their directory +- `src/status_im2/`: Directory where we try to be as strict as possible about + 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. -- `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). -- `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 not directly require each other's namespaces. -- `src/status_im/setup/`: Contains namespaces that are mostly used to initialize - the application, configure test runners, etc. In general, such namespaces - should not be required from the outside. +- `src/status_im2/setup/`: Contains namespaces that are mostly used to + initialize the application, configure test runners, etc. In general, such + 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. 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 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. -Component tests should be created in a separate directory `__tests__`. Example: ``` ├── models │ ├── message.cljs │ └── message_test.cljs -├── __tests__ -│ └── input_bla_test.cljs ├── models.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 we're at least striving to define them under appropriate bounded contexts that mirror the source code. diff --git a/shadow-cljs.edn b/shadow-cljs.edn index f494982cde..46fb82729a 100644 --- a/shadow-cljs.edn +++ b/shadow-cljs.edn @@ -19,6 +19,7 @@ ;; routing [bidi "2.1.6"] ;; test dependencies + [camel-snake-kebab "0.4.3"] [day8.re-frame/test "0.1.5"] [com.taoensso/tufte "2.1.0"]] diff --git a/src/quo2/components/banners/__tests__/banner_component_spec.cljs b/src/quo2/components/banners/__tests__/banner_component_spec.cljs index d0eaf2bb2a..c3084021df 100644 --- a/src/quo2/components/banners/__tests__/banner_component_spec.cljs +++ b/src/quo2/components/banners/__tests__/banner_component_spec.cljs @@ -8,10 +8,10 @@ (rtl/render (reagent/as-element [banner/banner opts]))) (js/global.test "basic render of banner component" - (fn [] - (render-banner {:pins-count "5" - :latest-pin-text "this message"}) - (-> (js/expect (rtl/screen.getByText "this message")) - (.toBeTruthy)) - (-> (js/expect (rtl/screen.getByText "5")) - (.toBeTruthy)))) + (fn [] + (render-banner {:pins-count "5" + :latest-pin-text "this message"}) + (-> (js/expect (rtl/screen.getByText "this message")) + (.toBeTruthy)) + (-> (js/expect (rtl/screen.getByText "5")) + (.toBeTruthy)))) diff --git a/src/quo2/components/buttons/__tests__/buttons_component_spec.cljs b/src/quo2/components/buttons/__tests__/buttons_component_spec.cljs index abfefdc9af..3408e3ef63 100644 --- a/src/quo2/components/buttons/__tests__/buttons_component_spec.cljs +++ b/src/quo2/components/buttons/__tests__/buttons_component_spec.cljs @@ -8,21 +8,21 @@ (rtl/render (reagent/as-element [button/button options label])))) (js/global.test "default render of button component" - (fn [] - (render-button {:accessibility-label "test-button"} "") - (-> (js/expect (rtl/screen.getByLabelText "test-button")) - (.toBeTruthy)))) + (fn [] + (render-button {:accessibility-label "test-button"} "") + (-> (js/expect (rtl/screen.getByLabelText "test-button")) + (.toBeTruthy)))) (js/global.test "button renders with a label" - (fn [] - (render-button {} "test-label") - (-> (js/expect (rtl/screen.getByText "test-label")) - (.toBeTruthy)))) + (fn [] + (render-button {} "test-label") + (-> (js/expect (rtl/screen.getByText "test-label")) + (.toBeTruthy)))) (js/global.test "button on-press works" - (let [event (js/jest.fn)] - (fn [] - (render-button {:on-press event} "test-label") - (rtl/fireEvent.press (rtl/screen.getByText "test-label")) - (-> (js/expect event) - (.toHaveBeenCalledTimes 1))))) + (let [event (js/jest.fn)] + (fn [] + (render-button {:on-press event} "test-label") + (rtl/fireEvent.press (rtl/screen.getByText "test-label")) + (-> (js/expect event) + (.toHaveBeenCalledTimes 1))))) diff --git a/src/quo2/components/counter/__tests__/counter_component_spec.cljs b/src/quo2/components/counter/__tests__/counter_component_spec.cljs index 2d06142a51..105705148d 100644 --- a/src/quo2/components/counter/__tests__/counter_component_spec.cljs +++ b/src/quo2/components/counter/__tests__/counter_component_spec.cljs @@ -10,25 +10,25 @@ (rtl/render (reagent/as-element [counter/counter opts value])))) (js/global.test "default render of counter component" - (fn [] - (render-counter) - (-> (js/expect (rtl/screen.getByTestId "counter-component")) - (.toBeTruthy)))) + (fn [] + (render-counter) + (-> (js/expect (rtl/screen.getByTestId "counter-component")) + (.toBeTruthy)))) (js/global.test "renders counter with a string value" - (fn [] - (render-counter {} "1") - (-> (js/expect (rtl/screen.getByText "1")) - (.toBeTruthy)))) + (fn [] + (render-counter {} "1") + (-> (js/expect (rtl/screen.getByText "1")) + (.toBeTruthy)))) (js/global.test "renders counter with an integer value" - (fn [] - (render-counter {} 1) - (-> (js/expect (rtl/screen.getByText "1")) - (.toBeTruthy)))) + (fn [] + (render-counter {} 1) + (-> (js/expect (rtl/screen.getByText "1")) + (.toBeTruthy)))) (js/global.test "renders counter with value 99+ when the value is greater than 99" - (fn [] - (render-counter {} "100") - (-> (js/expect (rtl/screen.getByText "99+")) - (.toBeTruthy)))) \ No newline at end of file + (fn [] + (render-counter {} "100") + (-> (js/expect (rtl/screen.getByText "99+")) + (.toBeTruthy)))) \ No newline at end of file diff --git a/src/quo2/components/dividers/__tests__/divider_label_component_spec.cljs b/src/quo2/components/dividers/__tests__/divider_label_component_spec.cljs index 4bbf66b09a..19c7d92938 100644 --- a/src/quo2/components/dividers/__tests__/divider_label_component_spec.cljs +++ b/src/quo2/components/dividers/__tests__/divider_label_component_spec.cljs @@ -10,36 +10,36 @@ (rtl/render (reagent/as-element [divider-label/divider-label opts])))) (js/global.test "default render of divider-label component" - (fn [] - (render-divider-label) - (-> (js/expect (rtl/screen.getByLabelText "divider-label")) - (.toBeTruthy)))) + (fn [] + (render-divider-label) + (-> (js/expect (rtl/screen.getByLabelText "divider-label")) + (.toBeTruthy)))) (js/global.test "render divider-label component with a label" - (fn [] - (render-divider-label {:label :hello}) - (-> (js/expect (rtl/screen.getByText "hello")) - (.toBeTruthy)))) + (fn [] + (render-divider-label {:label :hello}) + (-> (js/expect (rtl/screen.getByText "hello")) + (.toBeTruthy)))) (js/global.test "render divider-label component with a counter-value" - (fn [] - (render-divider-label {:label :hello - :counter-value "1"}) - (-> (js/expect (rtl/screen.getByText "1")) - (.toBeTruthy)))) + (fn [] + (render-divider-label {:label :hello + :counter-value "1"}) + (-> (js/expect (rtl/screen.getByText "1")) + (.toBeTruthy)))) (js/global.test "divider-label chevron icon renders to the left when set" - (fn [] - (render-divider-label {:label :hello - :counter-value "1" - :chevron-position :left}) - (-> (js/expect (rtl/screen.getByTestId "divider-label-icon-left")) - (.toBeTruthy)))) + (fn [] + (render-divider-label {:label :hello + :counter-value "1" + :chevron-position :left}) + (-> (js/expect (rtl/screen.getByTestId "divider-label-icon-left")) + (.toBeTruthy)))) (js/global.test "divider-label chevron icon renders to the right when set" - (fn [] - (render-divider-label {:label :hello - :counter-value "1" - :chevron-position :right}) - (-> (js/expect (rtl/screen.getByTestId "divider-label-icon-right")) - (.toBeTruthy)))) + (fn [] + (render-divider-label {:label :hello + :counter-value "1" + :chevron-position :right}) + (-> (js/expect (rtl/screen.getByTestId "divider-label-icon-right")) + (.toBeTruthy)))) diff --git a/src/quo2/components/drawers/__tests__/action_drawers_component_spec.cljs b/src/quo2/components/drawers/__tests__/action_drawers_component_spec.cljs index 311a926a7e..c22c56172a 100644 --- a/src/quo2/components/drawers/__tests__/action_drawers_component_spec.cljs +++ b/src/quo2/components/drawers/__tests__/action_drawers_component_spec.cljs @@ -8,46 +8,46 @@ (rtl/render (reagent/as-element [action-drawer/action-drawer options])))) (js/global.test "action-drawer renders with elements label displaying" - (fn [] - (render-action-drawer [[{:icon :i/friend - :label "a sample label"}]]) - (-> (js/expect (rtl/screen.getByText "a sample label")) - (.toBeTruthy)))) + (fn [] + (render-action-drawer [[{:icon :i/friend + :label "a sample label"}]]) + (-> (js/expect (rtl/screen.getByText "a sample label")) + (.toBeTruthy)))) (js/global.test "action-drawer renders with elements sub-label displaying" - (fn [] - (render-action-drawer [[{:icon :i/friend - :label "a sample label" - :sub-label "a sample sub label"}]]) - (-> (js/expect (rtl/screen.getByText "a sample sub label")) - (.toBeTruthy)))) + (fn [] + (render-action-drawer [[{:icon :i/friend + :label "a sample label" + :sub-label "a sample sub label"}]]) + (-> (js/expect (rtl/screen.getByText "a sample sub label")) + (.toBeTruthy)))) (js/global.test "action-drawer on click action works on element" - (let [event (js/jest.fn)] - (fn [] - (render-action-drawer [[{:icon :i/friend - :label "a sample label" - :on-press event}]]) - (rtl/fireEvent.press (rtl/screen.getByText "a sample label")) - (-> (js/expect event) - (.toHaveBeenCalled))))) + (let [event (js/jest.fn)] + (fn [] + (render-action-drawer [[{:icon :i/friend + :label "a sample label" + :on-press event}]]) + (rtl/fireEvent.press (rtl/screen.getByText "a sample label")) + (-> (js/expect event) + (.toHaveBeenCalled))))) (js/global.test "action-drawer renders two icons when set" - (fn [] - (render-action-drawer [[{:icon :i/friend - :label "a sample label" - :right-icon :i/friend - :accessibility-label :first-element}]]) - (-> (js/expect (rtl/screen.getByLabelText "right-icon-for-action")) - (.toBeTruthy)) - (-> (js/expect (rtl/screen.queryByLabelText "left-icon-for-action")) - (.toBeTruthy)))) + (fn [] + (render-action-drawer [[{:icon :i/friend + :label "a sample label" + :right-icon :i/friend + :accessibility-label :first-element}]]) + (-> (js/expect (rtl/screen.getByLabelText "right-icon-for-action")) + (.toBeTruthy)) + (-> (js/expect (rtl/screen.queryByLabelText "left-icon-for-action")) + (.toBeTruthy)))) (js/global.test "action-drawer renders a divider when the add-divider? prop is true" - (fn [] - (render-action-drawer [[{:icon :i/friend - :label "a sample label" - :add-divider? true - :accessibility-label :first-element}]]) - (-> (js/expect (rtl/screen.getAllByLabelText "divider")) - (.toBeTruthy)))) \ No newline at end of file + (fn [] + (render-action-drawer [[{:icon :i/friend + :label "a sample label" + :add-divider? true + :accessibility-label :first-element}]]) + (-> (js/expect (rtl/screen.getAllByLabelText "divider")) + (.toBeTruthy)))) \ No newline at end of file diff --git a/src/quo2/components/markdown/__tests__/text_component_spec.cljs b/src/quo2/components/markdown/__tests__/text_component_spec.cljs index 231cfdd0b2..74bd9ef69f 100644 --- a/src/quo2/components/markdown/__tests__/text_component_spec.cljs +++ b/src/quo2/components/markdown/__tests__/text_component_spec.cljs @@ -8,7 +8,7 @@ (rtl/render (reagent/as-element [text/text options value])))) (js/global.test "text renders with text" - (fn [] - (render-text {} "hello") - (-> (js/expect (rtl/screen.getByText "hello")) - (.toBeTruthy)))) + (fn [] + (render-text {} "hello") + (-> (js/expect (rtl/screen.getByText "hello")) + (.toBeTruthy)))) diff --git a/src/quo2/components/selectors/__tests__/selectors_component_spec.cljs b/src/quo2/components/selectors/__tests__/selectors_component_spec.cljs index 3a62db31c5..c74424cfc7 100644 --- a/src/quo2/components/selectors/__tests__/selectors_component_spec.cljs +++ b/src/quo2/components/selectors/__tests__/selectors_component_spec.cljs @@ -28,57 +28,57 @@ (rtl/render (reagent/as-element [selectors/radio opts])))) (js/global.test "default render of toggle component" - (fn [] - (render-toggle) - (-> (js/expect (rtl/screen.getByTestId "toggle-component")) - (.toBeTruthy)))) + (fn [] + (render-toggle) + (-> (js/expect (rtl/screen.getByTestId "toggle-component")) + (.toBeTruthy)))) (js/global.test "toggle component on change is working" - (let [mock-fn (js/jest.fn)] - (fn [] - (render-toggle {:on-change mock-fn}) - (rtl/fireEvent.press (rtl/screen.getByTestId "toggle-component")) - (-> (js/expect mock-fn) - (.toHaveBeenCalledTimes 1))))) + (let [mock-fn (js/jest.fn)] + (fn [] + (render-toggle {:on-change mock-fn}) + (rtl/fireEvent.press (rtl/screen.getByTestId "toggle-component")) + (-> (js/expect mock-fn) + (.toHaveBeenCalledTimes 1))))) (js/global.test "default render of radio component" - (fn [] - (render-radio) - (-> (js/expect (rtl/screen.getByTestId "radio-component")) - (.toBeTruthy)))) + (fn [] + (render-radio) + (-> (js/expect (rtl/screen.getByTestId "radio-component")) + (.toBeTruthy)))) (js/global.test "radio component on change is working" - (let [mock-fn (js/jest.fn)] - (fn [] - (render-radio {:on-change mock-fn}) - (rtl/fireEvent.press (rtl/screen.getByTestId "radio-component")) - (-> (js/expect mock-fn) - (.toHaveBeenCalledTimes 1))))) + (let [mock-fn (js/jest.fn)] + (fn [] + (render-radio {:on-change mock-fn}) + (rtl/fireEvent.press (rtl/screen.getByTestId "radio-component")) + (-> (js/expect mock-fn) + (.toHaveBeenCalledTimes 1))))) (js/global.test "default render of checkbox component" - (fn [] - (render-checkbox) - (-> (js/expect (rtl/screen.getByTestId "checkbox-component")) - (.toBeTruthy)))) + (fn [] + (render-checkbox) + (-> (js/expect (rtl/screen.getByTestId "checkbox-component")) + (.toBeTruthy)))) (js/global.test "checkbox component on change is working" - (let [mock-fn (js/jest.fn)] - (fn [] - (render-checkbox {:on-change mock-fn}) - (rtl/fireEvent.press (rtl/screen.getByTestId "checkbox-component")) - (-> (js/expect mock-fn) - (.toHaveBeenCalledTimes 1))))) + (let [mock-fn (js/jest.fn)] + (fn [] + (render-checkbox {:on-change mock-fn}) + (rtl/fireEvent.press (rtl/screen.getByTestId "checkbox-component")) + (-> (js/expect mock-fn) + (.toHaveBeenCalledTimes 1))))) (js/global.test "default render of checkbox-prefill component" - (fn [] - (render-checkbox-prefill) - (-> (js/expect (rtl/screen.getByTestId "checkbox-prefill-component")) - (.toBeTruthy)))) + (fn [] + (render-checkbox-prefill) + (-> (js/expect (rtl/screen.getByTestId "checkbox-prefill-component")) + (.toBeTruthy)))) (js/global.test "checkbox-prefill component on change is working" - (let [mock-fn (js/jest.fn)] - (fn [] - (render-checkbox-prefill {:on-change mock-fn}) - (rtl/fireEvent.press (rtl/screen.getByTestId "checkbox-prefill-component")) - (-> (js/expect mock-fn) - (.toHaveBeenCalledTimes 1))))) \ No newline at end of file + (let [mock-fn (js/jest.fn)] + (fn [] + (render-checkbox-prefill {:on-change mock-fn}) + (rtl/fireEvent.press (rtl/screen.getByTestId "checkbox-prefill-component")) + (-> (js/expect mock-fn) + (.toHaveBeenCalledTimes 1))))) \ No newline at end of file diff --git a/src/quo2/components/selectors/disclaimer.cljs b/src/quo2/components/selectors/disclaimer.cljs deleted file mode 100644 index d5e80f1b5a..0000000000 --- a/src/quo2/components/selectors/disclaimer.cljs +++ /dev/null @@ -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]]) - diff --git a/src/quo2/components/selectors/disclaimer/style.cljs b/src/quo2/components/selectors/disclaimer/style.cljs new file mode 100644 index 0000000000..1cbc9d691d --- /dev/null +++ b/src/quo2/components/selectors/disclaimer/style.cljs @@ -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}) diff --git a/src/quo2/components/selectors/disclaimer/view.cljs b/src/quo2/components/selectors/disclaimer/view.cljs new file mode 100644 index 0000000000..eb8584e189 --- /dev/null +++ b/src/quo2/components/selectors/disclaimer/view.cljs @@ -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]]) diff --git a/src/quo2/components/selectors/filter/component_spec.cljs b/src/quo2/components/selectors/filter/component_spec.cljs new file mode 100644 index 0000000000..c924112031 --- /dev/null +++ b/src/quo2/components/selectors/filter/component_spec.cljs @@ -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))))) diff --git a/src/quo2/components/selectors/filter/style.cljs b/src/quo2/components/selectors/filter/style.cljs new file mode 100644 index 0000000000..e380c53a41 --- /dev/null +++ b/src/quo2/components/selectors/filter/style.cljs @@ -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)) diff --git a/src/quo2/components/selectors/filter/view.cljs b/src/quo2/components/selectors/filter/view.cljs new file mode 100644 index 0000000000..e51c133425 --- /dev/null +++ b/src/quo2/components/selectors/filter/view.cljs @@ -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}]]]]))) diff --git a/src/quo2/core.cljs b/src/quo2/core.cljs index 917b82d2b1..e65c4b4c24 100644 --- a/src/quo2/core.cljs +++ b/src/quo2/core.cljs @@ -1,4 +1,5 @@ (ns quo2.core + (:refer-clojure :exclude [filter]) (:require quo2.components.avatars.account-avatar quo2.components.avatars.channel-avatar @@ -41,7 +42,8 @@ quo2.components.notifications.notification-dot quo2.components.notifications.toast quo2.components.reactions.reaction - quo2.components.selectors.disclaimer + quo2.components.selectors.disclaimer.view + quo2.components.selectors.filter.view quo2.components.selectors.selectors quo2.components.separator quo2.components.settings.privacy-option @@ -77,8 +79,9 @@ (def floating-shell-button quo2.components.navigation.floating-shell-button/floating-shell-button) (def status-tag quo2.components.tags.status-tags/status-tag) (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 filter quo2.components.selectors.filter.view/view) (def skeleton quo2.components.loaders.skeleton/skeleton) (def author quo2.components.messages.author.view/author) diff --git a/src/quo2/core_spec.cljs b/src/quo2/core_spec.cljs index 492e7a335f..7b1068b247 100644 --- a/src/quo2/core_spec.cljs +++ b/src/quo2/core_spec.cljs @@ -1,9 +1,9 @@ (ns quo2.core-spec - (:require - [quo2.components.banners.--tests--.banner-component-spec] - [quo2.components.buttons.--tests--.buttons-component-spec] - [quo2.components.counter.--tests--.counter-component-spec] - [quo2.components.dividers.--tests--.divider-label-component-spec] - [quo2.components.drawers.--tests--.action-drawers-component-spec] - [quo2.components.markdown.--tests--.text-component-spec] - [quo2.components.selectors.--tests--.selectors-component-spec])) + (:require [quo2.components.banners.--tests--.banner-component-spec] + [quo2.components.buttons.--tests--.buttons-component-spec] + [quo2.components.counter.--tests--.counter-component-spec] + [quo2.components.dividers.--tests--.divider-label-component-spec] + [quo2.components.drawers.--tests--.action-drawers-component-spec] + [quo2.components.markdown.--tests--.text-component-spec] + [quo2.components.selectors.--tests--.selectors-component-spec] + [quo2.components.selectors.filter.component-spec])) diff --git a/src/status_im2/contexts/activity_center/view.cljs b/src/status_im2/contexts/activity_center/view.cljs index ea1604f025..2b0e2790cd 100644 --- a/src/status_im2/contexts/activity_center/view.cljs +++ b/src/status_im2/contexts/activity_center/view.cljs @@ -15,18 +15,14 @@ (defn filter-selector-read-toggle [] (let [unread-filter-enabled? (rf/sub [:activity-center/filter-status-unread-enabled?])] - ;; TODO(@ilmotta): Replace the button by a Filter Selector. - ;; https://github.com/status-im/status-mobile/issues/14355 - [quo/button - {:icon true - :type (if unread-filter-enabled? :primary :blur-bg-outline) - :size 32 + [quo/filter + {:pressed? unread-filter-enabled? + :blur? true :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? :all - :unread)}])} - :i/unread])) + :unread)}])}])) (defn empty-tab [] diff --git a/src/status_im2/contexts/quo_preview/main.cljs b/src/status_im2/contexts/quo_preview/main.cljs index b7edf0e3b1..28f1138059 100644 --- a/src/status_im2/contexts/quo_preview/main.cljs +++ b/src/status_im2/contexts/quo_preview/main.cljs @@ -1,4 +1,5 @@ (ns status-im2.contexts.quo-preview.main + (:refer-clojure :exclude [filter]) (:require [quo2.components.buttons.button :as quo2-button] [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.record-audio.record-audio :as record-audio] [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.settings.privacy-option :as privacy-option] [status-im2.contexts.quo-preview.switcher.switcher-cards :as switcher-cards] @@ -184,6 +186,9 @@ :selectors [{:name :disclaimer :insets {:top false} :component disclaimer/preview-disclaimer} + {:name :filter + :insets {:top false} + :component filter/preview} {:name :selectors :insets {:top false} :component selectors/preview-selectors}] diff --git a/src/status_im2/contexts/quo_preview/selectors/disclaimer.cljs b/src/status_im2/contexts/quo_preview/selectors/disclaimer.cljs index 2d755c0c62..a7ca7c2cd9 100644 --- a/src/status_im2/contexts/quo_preview/selectors/disclaimer.cljs +++ b/src/status_im2/contexts/quo_preview/selectors/disclaimer.cljs @@ -1,6 +1,6 @@ (ns status-im2.contexts.quo-preview.selectors.disclaimer (: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] [react-native.core :as rn] [reagent.core :as reagent])) @@ -16,7 +16,7 @@ [rn/view {:padding-vertical 60 :align-items :center} - [quo2/disclaimer + [quo/view {:container-style {:margin-bottom 40} :on-change #(swap! checked? not)} "I agree with the community rules"] diff --git a/src/status_im2/contexts/quo_preview/selectors/filter.cljs b/src/status_im2/contexts/quo_preview/selectors/filter.cljs new file mode 100644 index 0000000000..196dd9cb92 --- /dev/null +++ b/src/status_im2/contexts/quo_preview/selectors/filter.cljs @@ -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}]]) diff --git a/src/status_im2/setup/db.cljs b/src/status_im2/setup/db.cljs index fc55a1dc4a..8148927991 100644 --- a/src/status_im2/setup/db.cljs +++ b/src/status_im2/setup/db.cljs @@ -1,11 +1,14 @@ (ns status-im2.setup.db (:require [react-native.core :as rn] ;; TODO (14/11/22 flexsurfer move to status-im2 namespace [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 (def app-db - {:contacts/contacts {} + {:activity-center {:filter {:status (:filter-status activity-center/defaults) + :type (:filter-type activity-center/defaults)}} + :contacts/contacts {} :pairing/installations {} :group/selected-contacts #{} :chats {} diff --git a/src/test_helpers/component.clj b/src/test_helpers/component.clj new file mode 100644 index 0000000000..8eca2fea05 --- /dev/null +++ b/src/test_helpers/component.clj @@ -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))) diff --git a/src/test_helpers/component.cljs b/src/test_helpers/component.cljs new file mode 100644 index 0000000000..d189035fe3 --- /dev/null +++ b/src/test_helpers/component.cljs @@ -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)))