diff --git a/apps/explorer/lib/explorer/exchange_rates/exchange_rates.ex b/apps/explorer/lib/explorer/exchange_rates/exchange_rates.ex index bda2f4bbbf..217929af3c 100644 --- a/apps/explorer/lib/explorer/exchange_rates/exchange_rates.ex +++ b/apps/explorer/lib/explorer/exchange_rates/exchange_rates.ex @@ -31,7 +31,9 @@ defmodule Explorer.ExchangeRates do {symbol, token} end - :ets.insert(table_name(), records) + if store() == :ets do + :ets.insert(table_name(), records) + end {:noreply, state} end @@ -65,7 +67,9 @@ defmodule Explorer.ExchangeRates do write_concurrency: true ] - :ets.new(table_name(), table_opts) + if store() == :ets do + :ets.new(table_name(), table_opts) + end {:ok, %{}} end @@ -79,10 +83,20 @@ defmodule Explorer.ExchangeRates do """ @spec list :: [Token.t()] def list do - table_name() - |> :ets.tab2list() - |> Enum.map(fn {_, rate} -> rate end) - |> Enum.sort_by(fn %Token{symbol: symbol} -> symbol end) + list_from_store(store()) + end + + @doc """ + Returns a specific rate from the tracked tickers by symbol + """ + @spec lookup(String.t()) :: Token.t() + def lookup(symbol) do + if store() == :ets do + case :ets.lookup(table_name(), symbol) do + [{_key, token} | _] -> token + _ -> nil + end + end end @doc false @@ -105,4 +119,17 @@ defmodule Explorer.ExchangeRates do exchange_rates_source().fetch_exchange_rates() end) end + + defp list_from_store(:ets) do + table_name() + |> :ets.tab2list() + |> Enum.map(fn {_, rate} -> rate end) + |> Enum.sort_by(fn %Token{symbol: symbol} -> symbol end) + end + + defp list_from_store(_), do: [] + + defp store do + config(:store) || :ets + end end diff --git a/apps/explorer/lib/explorer/exchange_rates/token.ex b/apps/explorer/lib/explorer/exchange_rates/token.ex index eb4f577a1e..6830d5236b 100644 --- a/apps/explorer/lib/explorer/exchange_rates/token.ex +++ b/apps/explorer/lib/explorer/exchange_rates/token.ex @@ -29,4 +29,6 @@ defmodule Explorer.ExchangeRates.Token do } defstruct ~w(available_supply btc_value id last_updated market_cap_usd name symbol usd_value volume_24h_usd)a + + def null, do: %__MODULE__{} end diff --git a/apps/explorer/lib/explorer/market/market.ex b/apps/explorer/lib/explorer/market/market.ex index 1d2fcb8bc2..73ee59fb69 100644 --- a/apps/explorer/lib/explorer/market/market.ex +++ b/apps/explorer/lib/explorer/market/market.ex @@ -5,8 +5,17 @@ defmodule Explorer.Market do import Ecto.Query + alias Explorer.{ExchangeRates, Repo} + alias Explorer.ExchangeRates.Token alias Explorer.Market.MarketHistory - alias Explorer.Repo + + @doc """ + Get most recent exchange rate for the given symbol. + """ + @spec get_exchange_rate(String.t()) :: Token.t() + def get_exchange_rate(symbol) do + ExchangeRates.lookup(symbol) + end @doc """ Retrieves the history for the recent specified amount of days. diff --git a/apps/explorer/test/explorer/exchange_rates/exchange_rates_test.exs b/apps/explorer/test/explorer/exchange_rates/exchange_rates_test.exs index 427da15bb1..235a4be295 100644 --- a/apps/explorer/test/explorer/exchange_rates/exchange_rates_test.exs +++ b/apps/explorer/test/explorer/exchange_rates/exchange_rates_test.exs @@ -11,6 +11,16 @@ defmodule Explorer.ExchangeRatesTest do setup :verify_on_exit! + setup do + # Use TestSource mock and ets table for this test set + configuration = Application.get_env(:explorer, Explorer.ExchangeRates) + Application.put_env(:explorer, Explorer.ExchangeRates, source: TestSource) + + on_exit(fn -> + Application.put_env(:explorer, Explorer.ExchangeRates, configuration) + end) + end + test "start_link" do stub(TestSource, :fetch_exchange_rates, fn -> {:ok, [%Token{}]} end) set_mox_global() @@ -87,13 +97,26 @@ defmodule Explorer.ExchangeRatesTest do ExchangeRates.init([]) rates = [ - %Token{id: "z", symbol: "z"}, - %Token{id: "a", symbol: "a"} + %Token{symbol: "z"}, + %Token{symbol: "a"} ] expected_rates = Enum.reverse(rates) - for rate <- rates, do: :ets.insert(ExchangeRates.table_name(), {rate.id, rate}) + for rate <- rates, do: :ets.insert(ExchangeRates.table_name(), {rate.symbol, rate}) assert expected_rates == ExchangeRates.list() end + + test "lookup/1" do + ExchangeRates.init([]) + + z = %Token{symbol: "z"} + + rates = [z, %Token{symbol: "a"}] + + for rate <- rates, do: :ets.insert(ExchangeRates.table_name(), {rate.symbol, rate}) + + assert z == ExchangeRates.lookup("z") + assert nil == ExchangeRates.lookup("nope") + end end diff --git a/apps/explorer/test/support/factory.ex b/apps/explorer/test/support/factory.ex index 18df4ffdad..6acda32703 100644 --- a/apps/explorer/test/support/factory.ex +++ b/apps/explorer/test/support/factory.ex @@ -2,6 +2,7 @@ defmodule Explorer.Factory do use ExMachina.Ecto, repo: Explorer.Repo alias Explorer.Chain.{Address, Block, Hash, InternalTransaction, Log, Receipt, Transaction} + alias Explorer.Market.MarketHistory alias Explorer.Repo @dialyzer {:nowarn_function, fields_for: 1} @@ -71,6 +72,14 @@ defmodule Explorer.Factory do } end + def market_history_factory do + %MarketHistory{ + closing_price: Decimal.new(Enum.random(1..10_000) / 100), + opening_price: Decimal.new(Enum.random(1..10_000) / 100), + date: Date.utc_today() + } + end + def receipt_factory do %Receipt{ cumulative_gas_used: Enum.random(21_000..100_000), diff --git a/apps/explorer/test/support/fakes/no_op_source.ex b/apps/explorer/test/support/fakes/no_op_source.ex new file mode 100644 index 0000000000..15eedb6aca --- /dev/null +++ b/apps/explorer/test/support/fakes/no_op_source.ex @@ -0,0 +1,10 @@ +defmodule Explorer.ExchangeRates.Source.NoOpSource do + @moduledoc false + + alias Explorer.ExchangeRates.Source + + @behaviour Source + + @impl Source + def fetch_exchange_rates, do: {:ok, []} +end diff --git a/apps/explorer_web/assets/babelrc b/apps/explorer_web/assets/.babelrc similarity index 100% rename from apps/explorer_web/assets/babelrc rename to apps/explorer_web/assets/.babelrc diff --git a/apps/explorer_web/assets/css/app.scss b/apps/explorer_web/assets/css/app.scss index c2c25e6ad0..4247dc9803 100644 --- a/apps/explorer_web/assets/css/app.scss +++ b/apps/explorer_web/assets/css/app.scss @@ -32,3 +32,8 @@ $fa-font-path: "~@fortawesome/fontawesome-free/webfonts"; @import "components/sidebar"; @import "explorer/button"; @import "explorer/filter"; + +:export { + primary: $primary; + secondary: $secondary; +} diff --git a/apps/explorer_web/assets/css/components/_chain.scss b/apps/explorer_web/assets/css/components/_chain.scss index c61fd46a85..3b68d5f865 100644 --- a/apps/explorer_web/assets/css/components/_chain.scss +++ b/apps/explorer_web/assets/css/components/_chain.scss @@ -1,9 +1,5 @@ .chain { @extend %paper; - - display: flex; - justify-conntent: space-around; - align-items: flex-start; padding: explorer-size(0) 0; &__container { @@ -25,6 +21,43 @@ } } +.container__stats { + @extend %paper; + display: flex; + padding: 15px; + width: 100%; + font-size: 12px; + text-align: center; + flex-direction: row; + justify-content: space-around; + + img { + display: inline-block; + height: explorer-size(1); + margin-bottom: explorer-size(-2); + text-align: center; + } +} + +.graph__squares { + width: 12px; + height: 12px; + display: inline-block; + + &--price { + background-color: explorer-color("blue", "500"); + } + + &--mcap { + background-color: explorer-color("gray", "500"); + } +} + +.flex { + display: flex; + justify-content: space-between; +} + @media (min-width: $explorer-breakpoint-sm) { .chain { &__image { @@ -38,6 +71,23 @@ } @media (min-width: $explorer-breakpoint-md) { + + .container__stats { + width: 18%; + flex-direction: column; + align-content: space-between; + + img { + display: inline-block; + height: explorer-size(1); + margin-bottom: explorer-size(-2); + text-align: center; + } + + div { + flex-grow: 1; + } + } .chain { &__image { height: explorer-size(1); diff --git a/apps/explorer_web/assets/js/app.js b/apps/explorer_web/assets/js/app.js index 361c7539a2..2073c9ac07 100644 --- a/apps/explorer_web/assets/js/app.js +++ b/apps/explorer_web/assets/js/app.js @@ -20,3 +20,4 @@ import 'bootstrap' // import socket from "./socket" import './lib/sidebar' +import './lib/market_history_chart' diff --git a/apps/explorer_web/assets/js/lib/market_history_chart.js b/apps/explorer_web/assets/js/lib/market_history_chart.js new file mode 100644 index 0000000000..bdcdcca9c5 --- /dev/null +++ b/apps/explorer_web/assets/js/lib/market_history_chart.js @@ -0,0 +1,100 @@ +import $ from 'jquery' +import Chart from 'chart.js' +import humps from 'humps' +import moment from 'moment' +import numeral from 'numeral' +import sassVariables from '../../css/app.scss' + +function formatPrice (price) { + return '$' + price.toFixed(2) +} + +function formatMarketCap (marketCap) { + return numeral(marketCap).format('($0,0a)') +} + +function createMarketHistoryChart (ctx) { + const currentExchangeRate = ctx.dataset.current_exchange_rate + const availableSupply = ctx.dataset.available_supply + const marketHistoryData = humps.camelizeKeys(JSON.parse(ctx.dataset.market_history_data)) + const today = moment().format('YYYY-MM-DD') + const currentMarketHistoryData = marketHistoryData.map(({date, closingPrice}) => ({ + date, + closingPrice: date === today ? currentExchangeRate : closingPrice + })) + + return new Chart(ctx, { + type: 'line', + responsive: true, + data: { + datasets: [{ + label: 'Price', + yAxisID: 'price', + data: currentMarketHistoryData.map(({ date, closingPrice }) => ({x: date, y: closingPrice})), + fill: false, + pointRadius: 0, + backgroundColor: sassVariables.primary, + borderColor: sassVariables.primary, + lineTension: 0 + }, { + label: 'Market Cap', + yAxisID: 'marketCap', + data: currentMarketHistoryData.map(({ date, closingPrice }) => ({x: date, y: closingPrice * availableSupply})), + fill: false, + pointRadius: 0.5, + backgroundColor: sassVariables.secondary, + borderColor: sassVariables.secondary, + lineTension: 0 + }] + }, + options: { + legend: { + display: false + }, + scales: { + xAxes: [{ + type: 'time', + time: { + unit: 'week', + displayFormats: { + week: 'MMM D' + } + } + }], + yAxes: [{ + id: 'price', + ticks: { + beginAtZero: true, + callback: (value, index, values) => formatPrice(value), + maxTicksLimit: 6 + } + }, { + id: 'marketCap', + position: 'right', + ticks: { + callback: (value, index, values) => formatMarketCap(value), + maxTicksLimit: 6 + } + }] + }, + tooltips: { + mode: 'index', + intersect: false, + callbacks: { + label: ({datasetIndex, yLabel}, {datasets}) => { + const label = datasets[datasetIndex].label + if (datasets[datasetIndex].label === 'Price') { + return `${label}: ${formatPrice(yLabel)}` + } else if (datasets[datasetIndex].label === 'Market Cap') { + return `${label}: ${formatMarketCap(yLabel)}` + } else { + return yLabel + } + } + } + } + } + }) +} + +$('[data-chart="marketHistoryChart"]').each((i, ctx) => createMarketHistoryChart(ctx)) diff --git a/apps/explorer_web/assets/package-lock.json b/apps/explorer_web/assets/package-lock.json index a852ce9f6f..8594fd4d37 100644 --- a/apps/explorer_web/assets/package-lock.json +++ b/apps/explorer_web/assets/package-lock.json @@ -1673,6 +1673,39 @@ "integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=", "dev": true }, + "chart.js": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-2.7.2.tgz", + "integrity": "sha512-90wl3V9xRZ8tnMvMlpcW+0Yg13BelsGS9P9t0ClaDxv/hdypHDr/YAGf+728m11P5ljwyB0ZHfPKCapZFqSqYA==", + "requires": { + "chartjs-color": "2.2.0", + "moment": "2.22.1" + } + }, + "chartjs-color": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/chartjs-color/-/chartjs-color-2.2.0.tgz", + "integrity": "sha1-hKL7dVeH7YXDndbdjHsdiEKbrq4=", + "requires": { + "chartjs-color-string": "0.5.0", + "color-convert": "0.5.3" + }, + "dependencies": { + "color-convert": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-0.5.3.tgz", + "integrity": "sha1-vbbGnOZg+t/+CwAHzER+G59ygr0=" + } + } + }, + "chartjs-color-string": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/chartjs-color-string/-/chartjs-color-string-0.5.0.tgz", + "integrity": "sha512-amWNvCOXlOUYxZVDSa0YOab5K/lmEhbFNKI55PWc4mlv28BDzA7zaoQTGxSBgJMHIW+hGX8YUrvw/FH4LyhwSQ==", + "requires": { + "color-name": "1.1.3" + } + }, "chokidar": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.0.3.tgz", @@ -2004,8 +2037,7 @@ "color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" }, "color-string": { "version": "0.3.0", @@ -4719,6 +4751,11 @@ "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=", "dev": true }, + "humps": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/humps/-/humps-2.0.1.tgz", + "integrity": "sha1-3QLqYIG9BWjcXQcxhEY5V7qe+ao=" + }, "iconv-lite": { "version": "0.4.19", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz", @@ -6427,6 +6464,11 @@ "minimist": "0.0.8" } }, + "moment": { + "version": "2.22.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.22.1.tgz", + "integrity": "sha512-shJkRTSebXvsVqk56I+lkb2latjBs8I+pc2TzWc545y2iFnSjm7Wg0QMh+ZWcdSLQyGEau5jI8ocnmkyTgr9YQ==" + }, "move-concurrently": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", @@ -6737,6 +6779,11 @@ "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", "dev": true }, + "numeral": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/numeral/-/numeral-2.0.6.tgz", + "integrity": "sha1-StCAk21EPCVhrtnyGX7//iX05QY=" + }, "oauth-sign": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", diff --git a/apps/explorer_web/assets/package.json b/apps/explorer_web/assets/package.json index 49d3cb2056..5c4101013a 100644 --- a/apps/explorer_web/assets/package.json +++ b/apps/explorer_web/assets/package.json @@ -20,7 +20,11 @@ "dependencies": { "@fortawesome/fontawesome-free": "^5.1.0-4", "bootstrap": "^4.1.0", + "chart.js": "^2.7.2", + "humps": "^2.0.1", "jquery": "^3.3.1", + "moment": "^2.22.1", + "numeral": "^2.0.6", "phoenix": "file:../../../deps/phoenix", "phoenix_html": "file:../../../deps/phoenix_html", "popper.js": "^1.14.3" diff --git a/apps/explorer_web/lib/explorer_web/controllers/chain_controller.ex b/apps/explorer_web/lib/explorer_web/controllers/chain_controller.ex index 8cccf77cbf..af50789687 100644 --- a/apps/explorer_web/lib/explorer_web/controllers/chain_controller.ex +++ b/apps/explorer_web/lib/explorer_web/controllers/chain_controller.ex @@ -2,10 +2,18 @@ defmodule ExplorerWeb.ChainController do use ExplorerWeb, :controller alias Explorer.Chain.{Address, Block, Statistics, Transaction} + alias Explorer.ExchangeRates.Token + alias Explorer.Market alias ExplorerWeb.Chain def show(conn, _params) do - render(conn, "show.html", chain: Statistics.fetch()) + render( + conn, + "show.html", + chain: Statistics.fetch(), + market_history_data: Market.fetch_recent_history(30), + exchange_rate: Market.get_exchange_rate(coin()) || Token.null() + ) end def search(conn, %{"q" => query}) do @@ -21,6 +29,10 @@ defmodule ExplorerWeb.ChainController do end end + defp coin do + Application.get_env(:explorer, :coin) + end + defp redirect_search_results(conn, %Address{} = item) do redirect(conn, to: address_path(conn, :show, Gettext.get_locale(), item)) end diff --git a/apps/explorer_web/lib/explorer_web/templates/chain/show.html.eex b/apps/explorer_web/lib/explorer_web/templates/chain/show.html.eex index dd0c5bbfcb..2ab2e7d570 100644 --- a/apps/explorer_web/lib/explorer_web/templates/chain/show.html.eex +++ b/apps/explorer_web/lib/explorer_web/templates/chain/show.html.eex @@ -1,50 +1,38 @@
-
-
- " /> -
<%= gettext("Skipped") %>
-
<%= @chain.skipped_blocks |> Cldr.Number.to_string! %>
-
-
- " /> -
<%= gettext("Lag") %>
-
<%= @chain.lag |> Timex.format_duration(:humanized) %>
-
-
- " /> -
<%= gettext("BPM") %>
-
<%= @chain.block_velocity |> Cldr.Number.to_string! %>
-
-
- " /> -
<%= gettext("TPM") %>
-
<%= @chain.transaction_velocity |> Cldr.Number.to_string! %>
-
-
-
-
+
+
" />
<%= gettext("Block") %>
#<%= @chain.number %>
-
- " /> +
+ " />
<%= gettext("Last Block") %>
<%= @chain.timestamp |> Timex.from_now() %>
-
- " /> -
<%= gettext("Average Block Time") %>
-
- <%= @chain.average_time |> Timex.format_duration(:humanized) %> -
+
+ " /> +
<%= gettext("Avg Block Time") %>
+ <%= @chain.average_time |> Timex.format_duration(:humanized) %>
-
- " /> -
<%= gettext("Transactions") %>
-
- <%= gettext("%{count} per day", count: Cldr.Number.to_string!(@chain.transaction_count)) %> +
+
+ +
+
+
+ <%= gettext "Price" %>
+ $<%= format_exchange_rate(@exchange_rate) %> <%= gettext "USD" %> +
+
+
+ <%= gettext "Market Cap" %>
+ $<%= format_market_cap(@exchange_rate) %> <%= gettext "USD" %> +
+
+ <%= gettext "24h Volume" %>
+ $<%= format_volume_24h(@exchange_rate) %> <%= gettext "USD" %>
diff --git a/apps/explorer_web/lib/explorer_web/views/chain_view.ex b/apps/explorer_web/lib/explorer_web/views/chain_view.ex index a8f253f504..42d081905c 100644 --- a/apps/explorer_web/lib/explorer_web/views/chain_view.ex +++ b/apps/explorer_web/lib/explorer_web/views/chain_view.ex @@ -1,3 +1,32 @@ defmodule ExplorerWeb.ChainView do use ExplorerWeb, :view + + alias Explorer.ExchangeRates.Token + + def encode_market_history_data(market_history_data) do + market_history_data + |> Enum.map(fn day -> Map.take(day, [:closing_price, :date]) end) + |> Jason.encode() + |> case do + {:ok, data} -> data + _ -> [] + end + end + + def format_exchange_rate(%Token{usd_value: nil}), do: nil + + def format_exchange_rate(%Token{usd_value: usd_value}) do + Cldr.Number.to_string!(usd_value, fractional_digits: 6) + end + + def format_volume_24h(%Token{volume_24h_usd: volume_24h}) do + format_number(volume_24h) + end + + def format_market_cap(%Token{market_cap_usd: market_cap}) do + format_number(market_cap) + end + + defp format_number(nil), do: nil + defp format_number(number), do: Cldr.Number.to_string!(number) end diff --git a/apps/explorer_web/priv/gettext/default.pot b/apps/explorer_web/priv/gettext/default.pot index b3f7e8801e..e950c3918e 100644 --- a/apps/explorer_web/priv/gettext/default.pot +++ b/apps/explorer_web/priv/gettext/default.pot @@ -2,8 +2,8 @@ #: lib/explorer_web/templates/address_transaction/index.html.eex:69 #: lib/explorer_web/templates/block/index.html.eex:30 #: lib/explorer_web/templates/block_transaction/index.html.eex:99 -#: lib/explorer_web/templates/chain/show.html.eex:71 -#: lib/explorer_web/templates/chain/show.html.eex:110 +#: lib/explorer_web/templates/chain/show.html.eex:59 +#: lib/explorer_web/templates/chain/show.html.eex:98 #: lib/explorer_web/templates/transaction/index.html.eex:36 #: lib/explorer_web/templates/transaction/overview.html.eex:37 msgid "Age" @@ -12,13 +12,13 @@ msgstr "" #: lib/explorer_web/templates/address_internal_transaction/index.html.eex:64 #: lib/explorer_web/templates/address_transaction/index.html.eex:68 #: lib/explorer_web/templates/block_transaction/index.html.eex:98 -#: lib/explorer_web/templates/chain/show.html.eex:28 -#: lib/explorer_web/templates/chain/show.html.eex:109 +#: lib/explorer_web/templates/chain/show.html.eex:6 +#: lib/explorer_web/templates/chain/show.html.eex:97 #: lib/explorer_web/templates/transaction/index.html.eex:35 msgid "Block" msgstr "" -#: lib/explorer_web/templates/chain/show.html.eex:58 +#: lib/explorer_web/templates/chain/show.html.eex:46 #: lib/explorer_web/templates/layout/app.html.eex:25 msgid "Blocks" msgstr "" @@ -29,21 +29,21 @@ msgstr "" #: lib/explorer_web/templates/block/index.html.eex:32 #: lib/explorer_web/templates/block_transaction/index.html.eex:60 -#: lib/explorer_web/templates/chain/show.html.eex:73 +#: lib/explorer_web/templates/chain/show.html.eex:61 msgid "Gas Used" msgstr "" #: lib/explorer_web/templates/address_transaction/index.html.eex:67 #: lib/explorer_web/templates/block_transaction/index.html.eex:22 #: lib/explorer_web/templates/block_transaction/index.html.eex:97 -#: lib/explorer_web/templates/chain/show.html.eex:108 +#: lib/explorer_web/templates/chain/show.html.eex:96 #: lib/explorer_web/templates/pending_transaction/index.html.eex:34 #: lib/explorer_web/templates/transaction/index.html.eex:34 msgid "Hash" msgstr "" #: lib/explorer_web/templates/block/index.html.eex:29 -#: lib/explorer_web/templates/chain/show.html.eex:70 +#: lib/explorer_web/templates/chain/show.html.eex:58 msgid "Height" msgstr "" @@ -56,9 +56,8 @@ msgstr "" #: lib/explorer_web/templates/block/index.html.eex:31 #: lib/explorer_web/templates/block_transaction/index.html.eex:16 #: lib/explorer_web/templates/block_transaction/index.html.eex:84 -#: lib/explorer_web/templates/chain/show.html.eex:45 -#: lib/explorer_web/templates/chain/show.html.eex:72 -#: lib/explorer_web/templates/chain/show.html.eex:99 +#: lib/explorer_web/templates/chain/show.html.eex:60 +#: lib/explorer_web/templates/chain/show.html.eex:87 #: lib/explorer_web/templates/layout/app.html.eex:31 #: lib/explorer_web/templates/pending_transaction/index.html.eex:12 #: lib/explorer_web/templates/transaction/index.html.eex:12 @@ -68,7 +67,7 @@ msgstr "" #: lib/explorer_web/templates/address_internal_transaction/index.html.eex:68 #: lib/explorer_web/templates/address_transaction/index.html.eex:72 #: lib/explorer_web/templates/block_transaction/index.html.eex:102 -#: lib/explorer_web/templates/chain/show.html.eex:111 +#: lib/explorer_web/templates/chain/show.html.eex:99 #: lib/explorer_web/templates/pending_transaction/index.html.eex:38 #: lib/explorer_web/templates/transaction/index.html.eex:39 #: lib/explorer_web/templates/transaction/overview.html.eex:43 @@ -288,7 +287,7 @@ msgstr "" msgid "Lag" msgstr "" -#: lib/explorer_web/templates/chain/show.html.eex:33 +#: lib/explorer_web/templates/chain/show.html.eex:11 msgid "Last Block" msgstr "" @@ -401,3 +400,25 @@ msgstr "" #: lib/explorer_web/templates/address_internal_transaction/index.html.eex:63 msgid "Parent Tx Hash" msgstr "" + +#: lib/explorer_web/templates/chain/show.html.eex:34 +msgid "24h Volume" +msgstr "" + +#: lib/explorer_web/templates/chain/show.html.eex:16 +msgid "Avg Block Time" +msgstr "" + +#: lib/explorer_web/templates/chain/show.html.eex:30 +msgid "Market Cap" +msgstr "" + +#: lib/explorer_web/templates/chain/show.html.eex:25 +msgid "Price" +msgstr "" + +#: lib/explorer_web/templates/chain/show.html.eex:26 +#: lib/explorer_web/templates/chain/show.html.eex:31 +#: lib/explorer_web/templates/chain/show.html.eex:35 +msgid "USD" +msgstr "" diff --git a/apps/explorer_web/priv/gettext/en/LC_MESSAGES/default.po b/apps/explorer_web/priv/gettext/en/LC_MESSAGES/default.po index 0d7fe3604e..e7226f0391 100644 --- a/apps/explorer_web/priv/gettext/en/LC_MESSAGES/default.po +++ b/apps/explorer_web/priv/gettext/en/LC_MESSAGES/default.po @@ -14,8 +14,8 @@ msgstr "" #: lib/explorer_web/templates/address_transaction/index.html.eex:69 #: lib/explorer_web/templates/block/index.html.eex:30 #: lib/explorer_web/templates/block_transaction/index.html.eex:99 -#: lib/explorer_web/templates/chain/show.html.eex:71 -#: lib/explorer_web/templates/chain/show.html.eex:110 +#: lib/explorer_web/templates/chain/show.html.eex:59 +#: lib/explorer_web/templates/chain/show.html.eex:98 #: lib/explorer_web/templates/transaction/index.html.eex:36 #: lib/explorer_web/templates/transaction/overview.html.eex:37 msgid "Age" @@ -24,13 +24,13 @@ msgstr "Age" #: lib/explorer_web/templates/address_internal_transaction/index.html.eex:64 #: lib/explorer_web/templates/address_transaction/index.html.eex:68 #: lib/explorer_web/templates/block_transaction/index.html.eex:98 -#: lib/explorer_web/templates/chain/show.html.eex:28 -#: lib/explorer_web/templates/chain/show.html.eex:109 +#: lib/explorer_web/templates/chain/show.html.eex:6 +#: lib/explorer_web/templates/chain/show.html.eex:97 #: lib/explorer_web/templates/transaction/index.html.eex:35 msgid "Block" msgstr "Block" -#: lib/explorer_web/templates/chain/show.html.eex:58 +#: lib/explorer_web/templates/chain/show.html.eex:46 #: lib/explorer_web/templates/layout/app.html.eex:25 msgid "Blocks" msgstr "Blocks" @@ -41,21 +41,21 @@ msgstr "%{year} POA Network Ltd. All rights reserved" #: lib/explorer_web/templates/block/index.html.eex:32 #: lib/explorer_web/templates/block_transaction/index.html.eex:60 -#: lib/explorer_web/templates/chain/show.html.eex:73 +#: lib/explorer_web/templates/chain/show.html.eex:61 msgid "Gas Used" msgstr "Gas Used" #: lib/explorer_web/templates/address_transaction/index.html.eex:67 #: lib/explorer_web/templates/block_transaction/index.html.eex:22 #: lib/explorer_web/templates/block_transaction/index.html.eex:97 -#: lib/explorer_web/templates/chain/show.html.eex:108 +#: lib/explorer_web/templates/chain/show.html.eex:96 #: lib/explorer_web/templates/pending_transaction/index.html.eex:34 #: lib/explorer_web/templates/transaction/index.html.eex:34 msgid "Hash" msgstr "Hash" #: lib/explorer_web/templates/block/index.html.eex:29 -#: lib/explorer_web/templates/chain/show.html.eex:70 +#: lib/explorer_web/templates/chain/show.html.eex:58 msgid "Height" msgstr "Height" @@ -68,9 +68,8 @@ msgstr "POA Network Explorer" #: lib/explorer_web/templates/block/index.html.eex:31 #: lib/explorer_web/templates/block_transaction/index.html.eex:16 #: lib/explorer_web/templates/block_transaction/index.html.eex:84 -#: lib/explorer_web/templates/chain/show.html.eex:45 -#: lib/explorer_web/templates/chain/show.html.eex:72 -#: lib/explorer_web/templates/chain/show.html.eex:99 +#: lib/explorer_web/templates/chain/show.html.eex:60 +#: lib/explorer_web/templates/chain/show.html.eex:87 #: lib/explorer_web/templates/layout/app.html.eex:31 #: lib/explorer_web/templates/pending_transaction/index.html.eex:12 #: lib/explorer_web/templates/transaction/index.html.eex:12 @@ -80,7 +79,7 @@ msgstr "Transactions" #: lib/explorer_web/templates/address_internal_transaction/index.html.eex:68 #: lib/explorer_web/templates/address_transaction/index.html.eex:72 #: lib/explorer_web/templates/block_transaction/index.html.eex:102 -#: lib/explorer_web/templates/chain/show.html.eex:111 +#: lib/explorer_web/templates/chain/show.html.eex:99 #: lib/explorer_web/templates/pending_transaction/index.html.eex:38 #: lib/explorer_web/templates/transaction/index.html.eex:39 #: lib/explorer_web/templates/transaction/overview.html.eex:43 @@ -300,7 +299,7 @@ msgstr "" msgid "Lag" msgstr "" -#: lib/explorer_web/templates/chain/show.html.eex:33 +#: lib/explorer_web/templates/chain/show.html.eex:11 msgid "Last Block" msgstr "" @@ -413,3 +412,25 @@ msgstr "" #: lib/explorer_web/templates/address_internal_transaction/index.html.eex:63 msgid "Parent Tx Hash" msgstr "" + +#: lib/explorer_web/templates/chain/show.html.eex:34 +msgid "24h Volume" +msgstr "" + +#: lib/explorer_web/templates/chain/show.html.eex:16 +msgid "Avg Block Time" +msgstr "" + +#: lib/explorer_web/templates/chain/show.html.eex:30 +msgid "Market Cap" +msgstr "" + +#: lib/explorer_web/templates/chain/show.html.eex:25 +msgid "Price" +msgstr "" + +#: lib/explorer_web/templates/chain/show.html.eex:26 +#: lib/explorer_web/templates/chain/show.html.eex:31 +#: lib/explorer_web/templates/chain/show.html.eex:35 +msgid "USD" +msgstr "" diff --git a/apps/explorer_web/test/explorer_web/controllers/chain_controller_test.exs b/apps/explorer_web/test/explorer_web/controllers/chain_controller_test.exs index ed90f61c23..f35b7d8843 100644 --- a/apps/explorer_web/test/explorer_web/controllers/chain_controller_test.exs +++ b/apps/explorer_web/test/explorer_web/controllers/chain_controller_test.exs @@ -56,6 +56,16 @@ defmodule ExplorerWeb.ChainControllerTest do assert(List.first(conn.assigns.chain.transactions).hash == transaction.hash) end + + test "returns market history data", %{conn: conn} do + today = Date.utc_today() + for day <- -40..0, do: insert(:market_history, date: Date.add(today, day)) + + conn = get(conn, "/en") + + assert Map.has_key?(conn.assigns, :market_history_data) + assert length(conn.assigns.market_history_data) == 30 + end end describe "GET q/2" do diff --git a/config/test.exs b/config/test.exs index 27bf64ea42..3c5bc99626 100644 --- a/config/test.exs +++ b/config/test.exs @@ -3,4 +3,6 @@ use Mix.Config # Print only warnings and errors during test config :logger, level: :warn -config :explorer, Explorer.ExchangeRates, source: Explorer.ExchangeRates.Source.TestSource +config :explorer, Explorer.ExchangeRates, + source: Explorer.ExchangeRates.Source.NoOpSource, + store: :none