Implement about tab on collectible page (#18269)

* add basics

* finalize component

* fix lint issues

* move color to props

* move variants to props

* change file structure

* working

* finalize loader

* fix lint issues

* fix style issues

* add tabs structure

* add basics

* draft codes

* draft

* make codes work after rebase

* fix lint issues

* remove Permissions tab

* revert codes

* finalize code

* fix lint issues

* revert podfile.lock

* create new reg-sub for traits and chain-id

* add real title and description for about tab

* resolve comments

* fix overview tab

* add tests

* resolve comments

---------

Co-authored-by: Jamie Caprani <jamiecaprani@gmail.com>
This commit is contained in:
mmilad75 2024-01-10 18:47:07 +03:30 committed by GitHub
parent 433be1daef
commit da03989c88
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 319 additions and 151 deletions

View File

@ -8,7 +8,7 @@
[react-native.linear-gradient :as linear-gradient]))
(defn- view-internal
[{:keys [address theme on-press icon title customization-color]}]
[{:keys [address theme on-press icon title customization-color container-style]}]
[rn/pressable
{:accessibility-label :link-card
:on-press on-press}
@ -17,7 +17,7 @@
(properties/gradient-end-color theme customization-color)]
:start {:x 0 :y 1}
:end {:x 1 :y 1}
:style (style/container theme)}
:style (merge (style/container theme) container-style)}
[rn/view {:style style/icon-container}
[social/view
{:accessibility-label :social-icon

View File

@ -43,29 +43,3 @@
(def opensea-button
{:flex 1
:margin-left 6})
(def info-container
{:flex-direction :row
:margin-horizontal 20
:margin-top 8
:margin-bottom 12})
(def account
{:margin-right 6
:flex 1})
(def network
{:margin-left 6
:flex 1})
(def traits-title-container
{:margin-left 20
:margin-top 8})
(def traits-item
{:margin 6
:flex 1})
(def traits-container
{:margin-horizontal 14
:margin-vertical 12})

View File

@ -0,0 +1,27 @@
(ns status-im.contexts.wallet.collectible.tabs.about.style)
(def title
{:padding-horizontal 20
:padding-top 8
:padding-bottom 4})
(def description
{:padding-horizontal 20
:padding-top 4
:padding-bottom 12})
(def section-label
{:margin-horizontal 20
:margin-top 12})
(def link-cards-container
{:margin-horizontal 20
:margin-top 12
:flex-direction :row
:justify-content :space-between
:flex-wrap :wrap})
(defn link-card
[item-width]
{:margin-bottom 16
:width item-width})

View File

@ -0,0 +1,36 @@
(ns status-im.contexts.wallet.collectible.tabs.about.view
(:require [quo.core :as quo]
[quo.theme]
[react-native.core :as rn]
[status-im.contexts.wallet.collectible.tabs.about.style :as style]
[status-im.contexts.wallet.temp :as temp]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(def ^:private link-card-space 28)
(defn- view-internal
[]
(let [window-width (rf/sub [:dimensions/window-width])
item-width (- (/ window-width 2) link-card-space)
{:keys [collectible-data]} (rf/sub [:wallet/last-collectible-details])
link-card-container-style (style/link-card item-width)]
[:<>
[rn/view {:style style/title}
[quo/text
{:size :heading-2
:weight :semi-bold}
(:name collectible-data)]]
[rn/view {:style style/description}
[quo/text
{:size :paragraph-2}
(:description collectible-data)]]
[quo/section-label
{:container-style style/section-label
:section (i18n/label :t/on-the-web)}]
[rn/view {:style style/link-cards-container}
(for [item (:cards temp/collectible-about)]
^{:key (:title item)}
[quo/link-card (assoc item :container-style link-card-container-style)])]]))
(def view (quo.theme/with-theme view-internal))

View File

@ -0,0 +1,17 @@
(ns status-im.contexts.wallet.collectible.tabs.activity.view
(:require [quo.core :as quo]
[react-native.core :as rn]
[status-im.contexts.wallet.temp :as temp]))
(defn activity-item
[item]
[:<>
[quo/divider-date (:timestamp item)]
[quo/wallet-activity item]])
(defn view
[]
[rn/flat-list
{:data temp/collectible-activities
:style {:flex 1}
:render-fn activity-item}])

View File

@ -0,0 +1,27 @@
(ns status-im.contexts.wallet.collectible.tabs.overview.style)
(def info-container
{:flex-direction :row
:margin-horizontal 20
:margin-top 8
:margin-bottom 12})
(def account
{:margin-right 6
:flex 1})
(def network
{:margin-left 6
:flex 1})
(def traits-title-container
{:margin-left 20
:margin-top 8})
(def traits-item
{:margin 6
:flex 1})
(def traits-container
{:margin-horizontal 14
:margin-vertical 12})

View File

@ -0,0 +1,72 @@
(ns status-im.contexts.wallet.collectible.tabs.overview.view
(:require
[clojure.string :as string]
[quo.core :as quo]
[quo.foundations.resources :as quo.resources]
[quo.theme]
[react-native.core :as rn]
[status-im.contexts.wallet.collectible.tabs.overview.style :as style]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(defn- trait-item
[{:keys [trait-type value]}]
[quo/data-item
{:subtitle-type :default
:card? true
:status :default
:size :default
:title trait-type
:subtitle value
:container-style style/traits-item}])
(defn- traits-section
[]
(let [traits (rf/sub [:wallet/last-collectible-details-traits])]
(when (pos? (count traits))
[rn/view
[quo/section-label
{:section (i18n/label :t/traits)
:container-style style/traits-title-container}]
[rn/flat-list
{:render-fn trait-item
:data traits
:key :collectibles-list
:key-fn :id
:num-columns 2
:content-container-style style/traits-container}]])))
(defn- info
[]
(let [chain-id (rf/sub [:wallet/last-collectible-details-chain-id])
{:keys [network-name]} (rf/sub [:wallet/network-details-by-chain-id chain-id])
subtitle (string/capitalize (name (or network-name "")))
{:keys [name emoji color]} (rf/sub [:wallet/last-collectible-details-owner])]
[rn/view {:style style/info-container}
[rn/view {:style style/account}
[quo/data-item
{:card? true
:status :default
:size :default
:title (i18n/label :t/account-title)
:subtitle name
:emoji emoji
:subtitle-type :account
:customization-color color}]]
[rn/view {:style style/network}
[quo/data-item
{:subtitle-type :network
:card? true
:status :default
:size :default
:title (i18n/label :t/network)
:network-image (quo.resources/get-network network-name)
:subtitle subtitle}]]]))
(defn- view-internal
[]
[:<>
[info]
[traits-section]])
(def view (quo.theme/with-theme view-internal))

View File

@ -0,0 +1,15 @@
(ns status-im.contexts.wallet.collectible.tabs.view
(:require [quo.theme]
[status-im.contexts.wallet.collectible.tabs.about.view :as about]
[status-im.contexts.wallet.collectible.tabs.activity.view :as activity]
[status-im.contexts.wallet.collectible.tabs.overview.view :as overview]))
(defn- view-internal
[{:keys [selected-tab]}]
(case selected-tab
:overview [overview/view]
:about [about/view]
:activity [activity/view]
nil))
(def view (quo.theme/with-theme view-internal))

View File

@ -1,14 +1,12 @@
(ns status-im.contexts.wallet.collectible.view
(:require
[clojure.string :as string]
[quo.core :as quo]
[quo.foundations.resources :as quo.resources]
[quo.theme :as quo.theme]
[react-native.core :as rn]
[reagent.core :as reagent]
[status-im.common.scroll-page.view :as scroll-page]
[status-im.contexts.wallet.collectible.style :as style]
[status-im.contexts.wallet.temp :as temp]
[status-im.contexts.wallet.collectible.tabs.view :as tabs]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
@ -42,105 +40,17 @@
:icon-left :i/opensea}
(i18n/label :t/opensea)]])
(def activity-tabs-data
(def tabs-data
[{:id :overview
:label (i18n/label :t/overview)
:accessibility-label :overview-tab}
{:id :activity
:label (i18n/label :t/activity)
:accessibility-label :activity-tab}
{:id :permissions
:label (i18n/label :t/permissions)
:accessibility-label :permissions-tab}
{:id :about
:label (i18n/label :t/about)
:accessibility-label :about-tab}])
(defn traits-section
[traits]
(when (pos? (count traits))
[rn/view
[quo/section-label
{:section (i18n/label :t/traits)
:container-style style/traits-title-container}]
[rn/flat-list
{:render-fn (fn [{:keys [trait-type value]}]
[quo/data-item
{:card? true
:status :default
:size :default
:title trait-type
:subtitle value
:subtitle-type :default
:container-style style/traits-item}])
:data traits
:key :collectibles-list
:key-fn :id
:num-columns 2
:content-container-style style/traits-container}]]))
(defn activity-item
[item]
[:<>
[quo/divider-date (:timestamp item)]
[quo/wallet-activity item]])
(defn activity-section
[]
[rn/flat-list
{:data temp/collectible-activities
:style {:flex 1}
:render-fn activity-item}])
(defn info
[chain-id]
(let [network (rf/sub [:wallet/network-details-by-chain-id
chain-id])
network-keyword (get network :network-name)
network-name (when network-keyword
(string/capitalize (name network-keyword)))]
[rn/view
{:style style/info-container}
[rn/view {:style style/account}
[quo/data-item
{:card? true
:status :default
:size :default
:title (i18n/label :t/account-title)
:subtitle "Collectibles vault"
:subtitle-type :account
:emoji "🎮"
:customization-color :yellow}]]
[rn/view {:style style/network}
[quo/data-item
{:card? true
:status :default
:size :default
:title (i18n/label :t/network)
:network-image (quo.resources/get-network network-keyword)
:subtitle network-name
:subtitle-type :network}]]]))
(defn tabs
[_]
(let [selected-tab (reagent/atom (:id (first activity-tabs-data)))]
(fn [{:keys [traits chain-id] :as _props}]
[:<>
[quo/tabs
{:size 32
:style style/tabs
:scrollable? true
:default-active @selected-tab
:data activity-tabs-data
:on-change #(reset! selected-tab %)}]
(condp = @selected-tab
:overview [:<>
[info chain-id]
[traits-section traits]]
:activity [activity-section]
nil)])))
(defn collectible-actions-sheet
[]
[quo/action-drawer
@ -162,35 +72,41 @@
(defn view-internal
[{:keys [theme] :as _props}]
(let [collectible (rf/sub [:wallet/last-collectible-details])
{:keys [collectible-data preview-url
collection-data]} collectible
{traits :traits
collectible-name :name} collectible-data
{collection-image :image-url
collection-name :name} collection-data
chain-id (rf/sub [:wallet/last-collectible-chain-id])]
[scroll-page/scroll-page
{:navigate-back? true
:height 148
:page-nav-props {:type :title-description
:title collectible-name
:description collection-name
:right-side [{:icon-name :i/options
:on-press #(rf/dispatch
[:show-bottom-sheet
{:content collectible-actions-sheet
:theme theme}])}]
:picture preview-url}}
[rn/view {:style style/container}
[rn/view {:style style/preview-container}
[rn/image
{:source preview-url
:style style/preview}]]
[header collectible-name collection-name collection-image]
[cta-buttons]
[tabs
{:traits traits
:chain-id chain-id}]]]))
(let [selected-tab (reagent/atom :overview)
on-tab-change #(reset! selected-tab %)]
(fn []
(let [collectible (rf/sub [:wallet/last-collectible-details])
{:keys [collectible-data preview-url
collection-data]} collectible
{collection-image :image-url
collection-name :name} collection-data
{collectible-name :name} collectible-data]
[scroll-page/scroll-page
{:navigate-back? true
:height 148
:page-nav-props {:type :title-description
:title collectible-name
:description collection-name
:right-side [{:icon-name :i/options
:on-press #(rf/dispatch
[:show-bottom-sheet
{:content collectible-actions-sheet
:theme theme}])}]
:picture preview-url}}
[rn/view {:style style/container}
[rn/view {:style style/preview-container}
[rn/image
{:source preview-url
:style style/preview}]]
[header collectible-name collection-name collection-image]
[cta-buttons]
[quo/tabs
{:size 32
:style style/tabs
:scrollable? true
:default-active @selected-tab
:on-change on-tab-change
:data tabs-data}]
[tabs/view {:selected-tab @selected-tab}]]]))))
(def view (quo.theme/with-theme view-internal))

View File

@ -105,3 +105,20 @@
:type :network
:network-logo (quo.resources/get-network :ethereum)
:network-name "Mainnet"}}])
(def collectible-about
{:cards [{:title "BAYC"
:icon :social/link
:address "boredapeyachtclub"
:customization-color :social/link
:on-press #(js/alert "pressed")}
{:title "Twitter"
:icon :social/twitter
:address "@BoredApeYC"
:customization-color :social/twitter
:on-press #(js/alert "pressed")}
{:title "Opensea"
:icon :social/opensea
:address "Bored Ape Yacht Club"
:customization-color :social/opensea
:on-press #(js/alert "pressed")}]})

View File

@ -38,7 +38,22 @@
(assoc last-collectible :preview-url (preview-url (:collectible-data last-collectible))))))
(re-frame/reg-sub
:wallet/last-collectible-chain-id
:wallet/last-collectible-details-chain-id
:<- [:wallet/last-collectible-details]
(fn [collectible]
(get-in collectible [:id :contract-id :chain-id])))
(re-frame/reg-sub
:wallet/last-collectible-details-traits
:<- [:wallet/last-collectible-details]
(fn [collectible]
(get-in collectible [:collectible-data :traits])))
(re-frame/reg-sub
:wallet/last-collectible-details-owner
:<- [:wallet/last-collectible-details]
:<- [:wallet]
(fn [[collectible wallet]]
(let [address (:address (first (:ownership collectible)))
account (get-in wallet [:accounts address])]
account)))

View File

@ -0,0 +1,50 @@
(ns status-im.subs.wallet.collectibles-test
(:require
[cljs.test :refer [is testing]]
[re-frame.db :as rf-db]
status-im.subs.root
status-im.subs.wallet.collectibles
[test-helpers.unit :as h]
[utils.re-frame :as rf]))
(def ^:private traits
[{:trait-type "Background"
:value "Gradient 5"
:display-type ""
:max-value ""}
{:trait-type "Skin"
:value "Pale"
:display-type ""
:max-value ""}
{:trait-type "Clothes"
:value "Naked"
:display-type ""
:max-value ""}])
(def ^:private collectible-owner-wallet
{:last-collectible-details {:ownership [{:address "0x1"}]}
:accounts {"0x1" {:name "account 1"
:color "army"}}})
(h/deftest-sub :wallet/last-collectible-details-chain-id
[sub-name]
(testing "correct chain-id of the last collectible should be returned"
(swap! rf-db/app-db assoc-in [:wallet :last-collectible-details :id :contract-id :chain-id] "1")
(let [result (rf/sub [sub-name])]
(is (= "1" result)))))
(h/deftest-sub :wallet/last-collectible-details-traits
[sub-name]
(testing "correct traits of the last collectible should be returned"
(swap! rf-db/app-db assoc-in [:wallet :last-collectible-details :collectible-data :traits] traits)
(let [result (rf/sub [sub-name])]
(is (= traits result)))))
(h/deftest-sub :wallet/last-collectible-details-owner
[sub-name]
(testing "correct owner of the last collectible should be returned"
(swap! rf-db/app-db assoc-in [:wallet] collectible-owner-wallet)
(let [result (rf/sub [sub-name])]
(is (= {:name "account 1"
:color "army"}
result)))))

View File

@ -2449,6 +2449,8 @@
"copy-all-details": "Copy all details",
"share-details": "Share details",
"what-are-you-waiting-for": "What are you waiting for?",
"no-relevant-tokens": "No relevant tokens",
"on-the-web": "On the web",
"sending-with-elipsis": "Sending...",
"transaction-confirmed": "Transaction confirmed!",
"transacation-finalised": "Transaction finalised!",