From 5e31fcdacca81a3609f9dd51d05638d72f913506 Mon Sep 17 00:00:00 2001 From: Eric Dvorsak Date: Tue, 12 Sep 2017 04:03:59 +0200 Subject: [PATCH] add transaction details screen --- src/status_im/translations/en.cljs | 66 ++++++----- src/status_im/ui/screens/subs.cljs | 4 + src/status_im/ui/screens/views.cljs | 3 +- src/status_im/ui/screens/wallet/events.cljs | 8 +- .../ui/screens/wallet/main/views.cljs | 2 +- src/status_im/ui/screens/wallet/subs.cljs | 21 ++-- .../screens/wallet/transactions/styles.cljs | 83 +++++++++++++- .../ui/screens/wallet/transactions/subs.cljs | 67 +++++++++-- .../ui/screens/wallet/transactions/views.cljs | 104 +++++++++++++++--- src/status_im/utils/datetime.cljs | 6 + src/status_im/utils/transactions.cljs | 50 +++++---- 11 files changed, 329 insertions(+), 85 deletions(-) diff --git a/src/status_im/translations/en.cljs b/src/status_im/translations/en.cljs index 1ae8e71250..63bb5e0c94 100644 --- a/src/status_im/translations/en.cljs +++ b/src/status_im/translations/en.cljs @@ -2,7 +2,7 @@ (def translations { - ;common + ;;common :members-title "Members" :not-implemented "!not implemented" :chat-name "Chat name" @@ -20,7 +20,7 @@ :camera-access-error "To grant the required camera permission, please, go to your system settings and make sure that Status > Camera is selected." :photos-access-error "To grant the required photos permission, please, go to your system settings and make sure that Status > Photos is selected." - ;drawer + ;;drawer :invite-friends "Invite friends" :faq "FAQ" :switch-users "Switch users" @@ -28,7 +28,7 @@ :view-all "View all" :current-network "Current network" - ;chat + ;;chat :is-typing "is typing" :and-you "and you" :search-chat "Search chat" @@ -48,11 +48,11 @@ :faucet-success "Faucet request has been received" :faucet-error "Faucet request error" - ;sync + ;;sync :sync-in-progress "Syncing..." :sync-synced "In sync" - ;messages + ;;messages :status-sending "Sending" :status-pending "Pending" :status-sent "Sent" @@ -61,7 +61,7 @@ :status-delivered "Delivered" :status-failed "Failed" - ;datetime + ;;datetime :datetime-ago-format "{{number}} {{time-intervals}} {{ago}}" :datetime-second {:one "second" :other "seconds"} @@ -76,7 +76,7 @@ :datetime-yesterday "yesterday" :datetime-today "today" - ;profile + ;;profile :profile "Profile" :edit-profile "Edit profile" :report-user "REPORT USER" @@ -116,7 +116,7 @@ :browsing-open-in-web-browser "Open in web browser" :browsing-cancel "Cancel" - ;sign-up + ;;sign-up :contacts-syncronized "Your contacts have been synchronized" :confirmation-code (str "Thanks! We've sent you a text message with a confirmation " "code. Please provide that code to confirm your phone number") @@ -135,13 +135,13 @@ :move-to-internal-failure-message "We need to move some important files from external to internal storage. To do this, we need your permission. We won't be using external storage in future versions." :debug-enabled "Debug server has been launched! You can now execute *status-dev-cli scan* to find the server from your computer on the same network." - ;phone types + ;;phone types :phone-e164 "International 1" :phone-international "International 2" :phone-national "National" :phone-significant "Significant" - ;chats + ;;chats :chats "Chats" :new-chat "New chat" :delete-chat "Delete chat" @@ -153,7 +153,7 @@ :topic-format "Wrong format [a-z0-9\\-]+" :public-group-topic "Topic" - ;discover + ;;discover :discover "Discover" :none "None" :search-tags "Type your search tags here" @@ -162,10 +162,10 @@ :no-statuses-discovered "No statuses discovered" :no-statuses-found "No statuses found" - ;settings + ;;settings :settings "Settings" - ;contacts + ;;contacts :contacts "Contacts" :new-contact "New contact" :delete-contact "Delete contact" @@ -183,7 +183,7 @@ :enter-address "Enter address" :more "more" - ;group-settings + ;;group-settings :remove "Remove" :save "Save" :delete "Delete" @@ -200,7 +200,7 @@ :green "Green" :red "Red" - ;commands + ;;commands :money-command-description "Send money" :location-command-description "Send location" :phone-command-description "Send phone number" @@ -216,7 +216,7 @@ :chat-send-eth-to "{{amount}} ETH to {{chat-name}}" :chat-send-eth-from "{{amount}} ETH from {{chat-name}}" - ;location command + ;;location command :your-current-location "Your current location" :places-nearby "Places nearby" :search-results "Search results" @@ -226,7 +226,7 @@ :sharing-copy-to-clipboard-address "Copy the Address" :sharing-copy-to-clipboard-coordinates "Copy coordinates" - ;new-group + ;;new-group :group-chat-name "Chat name" :empty-group-chat-name "Please enter a name" :illegal-group-chat-name "Please select another name" @@ -241,11 +241,11 @@ :contact-s {:one "contact" :other "contacts"} - ;participants + ;;participants :add-participants "Add Participants" :remove-participants "Remove Participants" - ;protocol + ;;protocol :received-invitation "received chat invitation" :removed-from-chat "removed you from group chat" :left "left" @@ -253,7 +253,7 @@ :removed "removed" :You "You" - ;new-contact + ;;new-contact :add-new-contact "Add new contact" :import-qr "Import" :scan-qr "Scan QR" @@ -267,7 +267,7 @@ :can-not-add-yourself "You can't add yourself" :unknown-address "Unknown address" - ;login + ;;login :connect "Connect" :address "Address" :password "Password" @@ -276,7 +276,7 @@ :sign-in "Sign in" :wrong-password "Wrong password" - ;recover + ;;recover :recover-from-passphrase "Recover from passphrase" :recover-explain "Please enter the passphrase for your password to recover access" :passphrase "Passphrase" @@ -285,21 +285,21 @@ :enter-valid-password "Please enter a password" :twelve-words-in-correct-order "12 words in correct order" - ;accounts + ;;accounts :recover-access "Recover access" :add-account "Add account" :create-new-account "Create new account" - ;wallet-qr-code + ;;wallet-qr-code :done "Done" - ;validation + ;;validation :invalid-phone "Invalid phone number" :amount "Amount" :not-enough-eth (str "Not enough ETH on balance " "({{balance}} ETH)") - ;transactions + ;;transactions :confirm "Confirm" :confirm-transactions {:one "Confirm transaction" :other "Confirm {{count}} transactions" @@ -324,8 +324,19 @@ :data "Data" :got-it "Got it" :contract-creation "Contract Creation" + :block "Block" + :hash "Hash" + :gas-limit "Gas limit" + :gas-price "Gas price" + :gas-used "Gas Used" + :cost-fee "Cost/Fee" + :nonce "Nonce" + :confirmations "confirmations" + :confirmations-helper-text "If you want to be sure your transaction will not be compromise wait until it gets at least 10 blocks confirmations" + :copy-transaction-hash "Copy transaction hash" + :open-on-etherscan "Open on Etherscan" - ;:webview + ;;webview :web-view-error "oops, error" ;;testfairy warning @@ -350,6 +361,7 @@ :share "Share" :currency "Currency" :transactions "Transactions" + :transaction-details "Transaction details" :transactions-sign "Sign" :transactions-sign-all "Sign all" :transactions-sign-all-text "Sign the transaction by entering your password.\nMake sure that the words above match your secret signing phrase" diff --git a/src/status_im/ui/screens/subs.cljs b/src/status_im/ui/screens/subs.cljs index 150fe0b593..ef14fce565 100644 --- a/src/status_im/ui/screens/subs.cljs +++ b/src/status_im/ui/screens/subs.cljs @@ -42,3 +42,7 @@ (or search-mode? (and (= view-id :chat-list) chats-edit-mode?) (and (= view-id :contact-list) contacts-edit-mode?)))) + +(reg-sub :network + (fn [db] + (:network db))) diff --git a/src/status_im/ui/screens/views.cljs b/src/status_im/ui/screens/views.cljs index 1056abd995..a7164145d3 100644 --- a/src/status_im/ui/screens/views.cljs +++ b/src/status_im/ui/screens/views.cljs @@ -66,6 +66,8 @@ :wallet-list wallet-list-screen :wallet-send-transaction send-transaction :wallet-request-transaction request-transaction + :wallet-transactions wallet-transactions/transactions + :wallet-transaction-details wallet-transactions/transaction-details :discover-search-results discover-search-results :new-chat new-chat :new-group new-group @@ -106,7 +108,6 @@ :transaction-details transaction-details :confirmation-success confirmation-success :contact-list-modal contact-list-modal - :wallet-transactions wallet-transactions/transactions :wallet-transactions-filter wallet-transactions/filter-history :wallet-transactions-sign-all wallet-transactions/sign-all (throw (str "Unknown modal view: " modal-view)))] diff --git a/src/status_im/ui/screens/wallet/events.cljs b/src/status_im/ui/screens/wallet/events.cljs index 017e654903..202b09ff53 100644 --- a/src/status_im/ui/screens/wallet/events.cljs +++ b/src/status_im/ui/screens/wallet/events.cljs @@ -129,4 +129,10 @@ (log/debug "Unable to get prices: " err) (-> db (assoc-error-message :prices-update err) - (assoc :prices-loading? false)))) \ No newline at end of file + (assoc :prices-loading? false)))) + +(handlers/register-handler-fx + :show-transaction-details + (fn [{:keys [db]} [_ hash]] + {:db (assoc-in db [:wallet :current-transaction] hash) + :dispatch [:navigate-to :wallet-transaction-details]})) diff --git a/src/status_im/ui/screens/wallet/main/views.cljs b/src/status_im/ui/screens/wallet/main/views.cljs index 40f520b089..21c73c01b4 100644 --- a/src/status_im/ui/screens/wallet/main/views.cljs +++ b/src/status_im/ui/screens/wallet/main/views.cljs @@ -33,7 +33,7 @@ (def transaction-history-action {:icon :icons/transaction-history :icon-opts (merge {:color :white :style {:viewBox "-108 65.9 24 24"}} wallet.styles/toolbar-icon) - :handler #(rf/dispatch [:navigate-to-modal :wallet-transactions])}) + :handler #(rf/dispatch [:navigate-to :wallet-transactions])}) (defn toolbar-view [] [toolbar/toolbar2 {:style wallet.styles/toolbar} diff --git a/src/status_im/ui/screens/wallet/subs.cljs b/src/status_im/ui/screens/wallet/subs.cljs index 4e56333ec2..2802b90ce4 100644 --- a/src/status_im/ui/screens/wallet/subs.cljs +++ b/src/status_im/ui/screens/wallet/subs.cljs @@ -2,9 +2,14 @@ (:require [re-frame.core :refer [reg-sub subscribe]] [status-im.utils.money :as money])) -(reg-sub :balance +(reg-sub :wallet (fn [db] - (get-in db [:wallet :balance]))) + (:wallet db))) + +(reg-sub :balance + :<- [:wallet] + (fn [wallet] + (:balance wallet))) (reg-sub :price (fn [db] @@ -15,9 +20,10 @@ (get-in db [:prices :last-day]))) (reg-sub :wallet/error-message? - (fn [db] - (or (get-in db [:wallet :errors :balance-update]) - (get-in db [:wallet :errors :prices-update])))) + :<- [:wallet] + (fn [wallet] + (or (get-in wallet [:errors :balance-update]) + (get-in wallet [:errors :prices-update])))) (reg-sub :eth-balance :<- [:balance] @@ -51,5 +57,6 @@ (:prices-loading? db))) (reg-sub :wallet/balance-loading? - (fn [db] - (get-in db [:wallet :balance-loading?]))) + :<- [:wallet] + (fn [wallet] + (:balance-loading? wallet))) diff --git a/src/status_im/ui/screens/wallet/transactions/styles.cljs b/src/status_im/ui/screens/wallet/transactions/styles.cljs index 104648087e..7ea0316608 100644 --- a/src/status_im/ui/screens/wallet/transactions/styles.cljs +++ b/src/status_im/ui/screens/wallet/transactions/styles.cljs @@ -15,7 +15,9 @@ :padding-right 10 :font-size 13}) -(def main-section styles/flex) +(def main-section + {:flex 1 + :background-color styles/color-white}) (def tabs {:border-bottom-width 1 @@ -29,7 +31,7 @@ {:color styles/color-gray7}) (def empty-text - {:text-align :center + {:text-align :center :margin-top 22 :margin-horizontal 92}) @@ -88,3 +90,80 @@ :height 40 :border-radius 32 :background-color color}) + +;; transaction details + +(def transaction-details-row + {:flex-direction :row + :margin-vertical 5}) + +(def transaction-details-item-label + {:flex 1 + :margin-right 10 + :color styles/color-gray4 + :font-size 14}) + +(def transaction-details-item-value-wrapper + {:flex 5}) + +(def transaction-details-item-value + {:font-size 14 + :color styles/color-black}) + +(def transaction-details-item-extra-value + {:font-size 14 + :color styles/color-gray4}) + +(def transaction-details-header + {:margin-horizontal 16 + :margin-top 10 + :flex-direction :row}) + +(def transaction-details-header-icon + {:margin-vertical 7}) + +(def transaction-details-header-infos + {:flex 1 + :flex-direction :column + :margin-left 12 + :margin-vertical 7}) + +(def transaction-details-header-value + {:font-size 16 + :color styles/color-black}) + +(def transaction-details-header-date + {:font-size 14 + :color styles/color-gray4}) + +(def transaction-details-block + {:margin-horizontal 16}) + +(def progress-bar + {:flex-direction :row + :margin-vertical 10 + :height 2}) + +(defn progress-bar-done [done] + {:flex done + :background-color styles/color-blue2}) + +(defn progress-bar-todo [todo] + {:flex todo + :background-color styles/color-blue2 + :opacity 0.30}) + +(def transaction-details-confirmations-count + {:color styles/color-black + :font-size 15 + :margin-vertical 2}) + +(def transaction-details-confirmations-helper-text + {:color styles/color-gray4 + :font-size 14 + :margin-vertical 2}) + +(def transaction-details-separator + {:background-color styles/color-light-gray3 + :height 1 + :margin-vertical 10}) diff --git a/src/status_im/ui/screens/wallet/transactions/subs.cljs b/src/status_im/ui/screens/wallet/transactions/subs.cljs index 60ffdd0e05..ff24ab88f1 100644 --- a/src/status_im/ui/screens/wallet/transactions/subs.cljs +++ b/src/status_im/ui/screens/wallet/transactions/subs.cljs @@ -1,26 +1,36 @@ (ns status-im.ui.screens.wallet.transactions.subs (:require [re-frame.core :refer [reg-sub subscribe]] - [status-im.utils.datetime :as datetime])) + [status-im.utils.datetime :as datetime] + [status-im.utils.money :as money] + [status-im.utils.transactions :as transactions])) (reg-sub :wallet.transactions/transactions-loading? - (fn [db] - (get-in db [:wallet :transactions-loading?]))) + :<- [:wallet] + (fn [wallet] + (:transactions-loading? wallet))) (reg-sub :wallet.transactions/error-message? - (fn [db] - (get-in db [:wallet :errors :transactions-update]))) + :<- [:wallet] + (fn [wallet] + (get-in wallet [:errors :transactions-update]))) (reg-sub :wallet.transactions/transactions - (fn [db] - (group-by :type (get-in db [:wallet :transactions])))) + :<- [:wallet] + (fn [wallet] + (:transactions wallet))) + +(reg-sub :wallet.transactions/grouped-transactions + :<- [:wallet.transactions/transactions] + (fn [transactions] + (group-by :type (vals transactions)))) (reg-sub :wallet.transactions/unsigned-transactions - :<- [:wallet.transactions/transactions] + :<- [:wallet.transactions/grouped-transactions] (fn [transactions] (:unsigned transactions))) (reg-sub :wallet.transactions/postponed-transactions-list - :<- [:wallet.transactions/transactions] + :<- [:wallet.transactions/grouped-transactions] (fn [{:keys [postponed]}] (when postponed {:title "Postponed" @@ -28,7 +38,7 @@ :data postponed}))) (reg-sub :wallet.transactions/pending-transactions-list - :<- [:wallet.transactions/transactions] + :<- [:wallet.transactions/grouped-transactions] (fn [{:keys [pending]}] (when pending {:title "Pending" @@ -36,7 +46,7 @@ :data pending}))) (reg-sub :wallet.transactions/completed-transactions-list - :<- [:wallet.transactions/transactions] + :<- [:wallet.transactions/grouped-transactions] (fn [{:keys [inbound outbound]}] (->> (into inbound outbound) (group-by #(datetime/timestamp->date-key (:timestamp %))) @@ -57,3 +67,38 @@ postponed (into postponed) pending (into pending) completed (into completed)))) + +(reg-sub :wallet.transactions/current-transaction + :<- [:wallet] + (fn [wallet] + (:current-transaction wallet))) + +(reg-sub :wallet.transactions/transaction-details + :<- [:wallet.transactions/transactions] + :<- [:wallet.transactions/current-transaction] + :<- [:network] + (fn [[transactions current-transaction network]] + (let [{:keys [gas-used gas-price hash timestamp type] :as transaction} (get transactions current-transaction)] + (merge transaction + {:cost (money/wei->ether (money/fee-value gas-used gas-price)) + :gas-price-eth (str (.toFixed (money/wei->ether gas-price)) " ETH") + :date (datetime/timestamp->long-date timestamp) + :url (transactions/get-transaction-details-url network hash)} + ;; TODO (yenda) proper wallet logic when wallet switching is impletmented + (if (= type :inbound) + {:to-wallet "Main wallet"} + {:from-wallet "Main wallet"}))))) + +(reg-sub :wallet.transactions.details/confirmations + :<- [:wallet.transactions/transaction-details] + (fn [transaction-details] + ;;TODO (yenda) this field should be calculated based on the current-block and the block of the transaction + (:confirmations transaction-details))) + +(reg-sub :wallet.transactions.details/confirmations-progress + :<- [:wallet.transactions.details/confirmations] + (fn [confirmations] + (let [max-confirmations 10] + (if (>= confirmations max-confirmations) + 100 + (* 100 (/ confirmations max-confirmations)))))) diff --git a/src/status_im/ui/screens/wallet/transactions/views.cljs b/src/status_im/ui/screens/wallet/transactions/views.cljs index 6275c4524c..670f63ec23 100644 --- a/src/status_im/ui/screens/wallet/transactions/views.cljs +++ b/src/status_im/ui/screens/wallet/transactions/views.cljs @@ -8,6 +8,7 @@ [status-im.components.status-bar :as status-bar] [status-im.components.styles :as styles] [status-im.components.tabs.views :as tabs] + [status-im.components.toolbar-new.actions :as actions] [status-im.components.toolbar-new.view :as toolbar] [status-im.i18n :as i18n] [status-im.ui.screens.wallet.transactions.styles :as transactions.styles] @@ -15,6 +16,9 @@ [status-im.utils.utils :as utils]) (:require-macros [status-im.utils.views :refer [defview letsubs]])) +(defn- show-not-implemented! [] + (utils/show-popup "TODO" "Not implemented yet!")) + (defn on-sign-transaction [m] ;; TODO(yenda) implement @@ -50,6 +54,7 @@ [button/primary-button {:text (i18n/label :t/transactions-sign) :on-press #(on-sign-transaction m)}] [button/secondary-button {:text (i18n/label :t/delete) :on-press #(on-delete-transaction m)}]]) +(defn- inbound? [type] (= "inbound" type)) (defn- unsigned? [type] (= "unsigned" type)) (defn- transaction-icon [k background-color color] @@ -57,25 +62,28 @@ :icon-opts {:color color} :style (transactions.styles/transaction-icon-background background-color)}) -(defn- transaction-type->icon [s] - (case s - "unsigned" (transaction-icon :icons/dots-horizontal styles/color-gray4-transparent styles/color-gray7) - "inbound" (transaction-icon :icons/arrow-left styles/color-green-3-light styles/color-green-3) - "outbound" (transaction-icon :icons/arrow-right styles/color-blue4-transparent styles/color-blue4) - ("postponed" "pending") (transaction-icon :icons/arrow-right styles/color-gray4-transparent styles/color-gray7) - (throw (str "Unknown transaction type: " s)))) +(defn- transaction-type->icon [k] + (case k + :unsigned (transaction-icon :icons/dots-horizontal styles/color-gray4-transparent styles/color-gray7) + :inbound (transaction-icon :icons/arrow-left styles/color-green-3-light styles/color-green-3) + :outbound (transaction-icon :icons/arrow-right styles/color-blue4-transparent styles/color-blue4) + (:postponed :pending) (transaction-icon :icons/arrow-right styles/color-gray4-transparent styles/color-gray7) + (throw (str "Unknown transaction type: " k)))) -(defn render-transaction [{:keys [to from type value symbol] :as m}] +(defn render-transaction [{:keys [hash to from type value symbol] :as m}] [list/item - [list/item-icon (transaction-type->icon type)] + [list/item-icon (transaction-type->icon (keyword type))] [list/item-content (str value " " symbol) - (if to - (str (i18n/label :t/to) " " to) - (str (i18n/label :t/from) " " from)) + (if (inbound? type) + (str (i18n/label :t/from) " " from) + (str (i18n/label :t/to) " " to)) (when (unsigned? type) [action-buttons m])] - [list/item-icon {:icon :icons/forward :icon-opts transactions.styles/forward}]]) + [react/touchable-highlight {:on-press #(re-frame/dispatch [:show-transaction-details hash])} + [react/view + [list/item-icon {:icon :icons/forward + :icon-opts transactions.styles/forward}]]]]) ;; TODO(yenda) hook with re-frame (defn- empty-text [s] [react/text {:style transactions.styles/empty-text} s]) @@ -135,13 +143,13 @@ (defn- item-tokens [{:keys [symbol label checked?]}] [list/item - [list/item-icon (transaction-type->icon "pending")] ;; TODO(jeluard) add proper token data + [list/item-icon (transaction-type->icon :pending)] ;; TODO(jeluard) add proper token data [list/item-content label symbol] [checkbox/checkbox {:checked? true #_checked?}]]) (defn- item-type [{:keys [id label checked?]}] [list/item - [list/item-icon (transaction-type->icon id)] + [list/item-icon (transaction-type->icon (keyword id))] [list/item-content label] [checkbox/checkbox checked?]]) @@ -189,6 +197,70 @@ default-view (get-in tabs [0 :view-id]) view-id (reagent/atom default-view)] [react/view {:style styles/flex} - [status-bar/status-bar {:type :modal-white}] + [status-bar/status-bar] [toolbar-view view-id unsigned-transactions] [main-section view-id tabs]])) + +(defn transaction-details-header [{:keys [value date type]}] + [react/view {:style transactions.styles/transaction-details-header} + [react/view {:style transactions.styles/transaction-details-header-icon} + [list/item-icon (transaction-type->icon type)]] + [react/view {:style transactions.styles/transaction-details-header-infos} + [react/text {:style transactions.styles/transaction-details-header-value} (str value " ETH")] + [react/text {:style transactions.styles/transaction-details-header-date} date]]]) + +(defn progress-bar [progress] + [react/view {:style transactions.styles/progress-bar} + [react/view {:style (transactions.styles/progress-bar-done progress)}] + [react/view {:style (transactions.styles/progress-bar-todo (- 100 progress))}]]) + +(defn transaction-details-confirmations [confirmations confirmations-progress] + [react/view {:style transactions.styles/transaction-details-block} + [progress-bar confirmations-progress] + [react/text {:style transactions.styles/transaction-details-confirmations-count} + (str confirmations " " (i18n/label :t/confirmations))] + [react/text {:style transactions.styles/transaction-details-confirmations-helper-text} + (i18n/label :t/confirmations-helper-text)]]) + +(defn transaction-details-list-row + ([label value] + (transaction-details-list-row label value nil)) + ([label value extra-value] + [react/view {:style transactions.styles/transaction-details-row} + [react/text {:style transactions.styles/transaction-details-item-label} (i18n/label label)] + [react/view {:style transactions.styles/transaction-details-item-value-wrapper} + [react/text {:style transactions.styles/transaction-details-item-value} (str value)] + [react/text {:style transactions.styles/transaction-details-item-extra-value} (str extra-value)]]])) + +(defn transaction-details-list [{:keys [block hash from from-wallet to to-wallet gas-limit gas-price-eth gas-used cost nonce data]}] + [react/view {:style transactions.styles/transaction-details-block} + [transaction-details-list-row :t/block block] + [transaction-details-list-row :t/hash hash] + [transaction-details-list-row :t/from (or from-wallet from) (when from-wallet from)] + [transaction-details-list-row :t/to (or to-wallet to) (when to-wallet to)] + [transaction-details-list-row :t/gas-limit gas-limit] + [transaction-details-list-row :t/gas-price gas-price-eth] + [transaction-details-list-row :t/gas-used gas-used] + [transaction-details-list-row :t/cost-fee (str cost " ETH")] + [transaction-details-list-row :t/nonce nonce] + [transaction-details-list-row :t/data data]]) + +(defn details-action [hash url] + [(actions/opts [{:text (i18n/label :t/copy-transaction-hash) :value #(react/copy-to-clipboard hash)} + {:text (i18n/label :t/open-on-etherscan) :value #(.openURL react/linking url)}])]) + +(defview transaction-details [] + (letsubs [{:keys [hash url] :as transaction-details} [:wallet.transactions/transaction-details] + confirmations [:wallet.transactions.details/confirmations] + confirmations-progress [:wallet.transactions.details/confirmations-progress]] + [react/view {:style styles/flex} + [status-bar/status-bar] + [toolbar/toolbar2 {} + toolbar/default-nav-back + [toolbar/content-title (i18n/label :t/transaction-details)] + [toolbar/actions (details-action hash url)]] + [react/scroll-view + [transaction-details-header transaction-details] + [transaction-details-confirmations confirmations confirmations-progress] + [react/view {:style transactions.styles/transaction-details-separator}] + [transaction-details-list transaction-details]]])) diff --git a/src/status_im/utils/datetime.cljs b/src/status_im/utils/datetime.cljs index 765a073184..84bc8ce937 100644 --- a/src/status_im/utils/datetime.cljs +++ b/src/status_im/utils/datetime.cljs @@ -44,6 +44,12 @@ from-long (plus time-zone-offset))))) +(defn timestamp->long-date [ms] + (keyword (unparse (formatter "MMM DD YYYY HH:mm:ss") + (-> ms + from-long + (plus time-zone-offset))))) + (defn day-relative [ms] (when (pos? ms) (to-short-str ms #(label :t/datetime-today)))) diff --git a/src/status_im/utils/transactions.cljs b/src/status_im/utils/transactions.cljs index 7a52c2af83..b8db2f177d 100644 --- a/src/status_im/utils/transactions.cljs +++ b/src/status_im/utils/transactions.cljs @@ -3,33 +3,45 @@ [status-im.utils.types :as types] [status-im.utils.money :as money])) +(defn get-network-subdomain [network] + (case network + "testnet" "ropsten" + "mainnet" "api")) + +(defn get-transaction-details-url [network hash] + (let [network-subdomain (get-network-subdomain network)] + (str "https://" network-subdomain ".etherscan.io/tx/" hash))) + (defn get-transaction-url [network account] - (let [network (case network - "testnet" "ropsten" - "mainnet" "api")] - (str "https://" network ".etherscan.io/api?module=account&action=txlist&address=0x" + (let [network-subdomain (get-network-subdomain network)] + (str "https://" network-subdomain ".etherscan.io/api?module=account&action=txlist&address=0x" account "&startblock=0&endblock=99999999&sort=desc&apikey=YourApiKeyToken?q=json"))) -(defn format-transaction [account {:keys [value to from timeStamp]}] - (let [transaction {:value (money/wei->ether value) - ;; timestamp is in seconds, we convert it in ms - :timestamp (str timeStamp "000") - :symbol "ETH"} - inbound? (= (str "0x" account) to)] - (if inbound? - (assoc transaction - :from from - :type :inbound) - (assoc transaction - :to to - :type :outbound)))) +(defn format-transaction [account {:keys [value timeStamp blockNumber hash from to gas gasPrice gasUsed nonce confirmations input]}] + (let [inbound? (= (str "0x" account) to)] + {:value (money/wei->ether value) + ;; timestamp is in seconds, we convert it in ms + :timestamp (str timeStamp "000") + :symbol "ETH" + :type (if inbound? :inbound :outbound) + :block blockNumber + :hash hash + :from from + :to to + :gas-limit gas + :gas-price gasPrice + :gas-used gasUsed + :nonce nonce + :confirmations confirmations + :data input})) (defn format-transactions-response [response account] (->> response types/json->clj :result - (map (partial format-transaction account)) - (sort-by :timestamp))) + (reduce (fn [transactions {:keys [hash] :as transaction}] + (assoc transactions hash (format-transaction account transaction))) + {}))) (defn get-transactions [network account on-success on-error] (utils/http-get (get-transaction-url network account)