diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/address_internal_transaction_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/address_internal_transaction_controller.ex
index 36c32740e7..08be14a9fc 100644
--- a/apps/block_scout_web/lib/block_scout_web/controllers/address_internal_transaction_controller.ex
+++ b/apps/block_scout_web/lib/block_scout_web/controllers/address_internal_transaction_controller.ex
@@ -8,10 +8,12 @@ defmodule BlockScoutWeb.AddressInternalTransactionController do
import BlockScoutWeb.AddressController, only: [transaction_count: 1, validation_count: 1]
import BlockScoutWeb.Chain, only: [current_filter: 1, paging_options: 1, next_page_params: 3, split_list_by_page: 1]
+ alias BlockScoutWeb.InternalTransactionView
alias Explorer.{Chain, Market}
alias Explorer.ExchangeRates.Token
+ alias Phoenix.View
- def index(conn, %{"address_id" => address_hash_string} = params) do
+ def index(conn, %{"address_id" => address_hash_string, "type" => "JSON"} = params) do
with {:ok, address_hash} <- Chain.string_to_address_hash(address_hash_string),
{:ok, address} <- Chain.hash_to_address(address_hash) do
full_options =
@@ -28,14 +30,45 @@ defmodule BlockScoutWeb.AddressInternalTransactionController do
internal_transactions_plus_one = Chain.address_to_internal_transactions(address, full_options)
{internal_transactions, next_page} = split_list_by_page(internal_transactions_plus_one)
+ next_page_path =
+ case next_page_params(next_page, internal_transactions, params) do
+ nil ->
+ nil
+
+ next_page_params ->
+ address_internal_transaction_path(conn, :index, address_hash, Map.delete(next_page_params, "type"))
+ end
+
+ internal_transactions_json =
+ Enum.map(internal_transactions, fn internal_transaction ->
+ View.render_to_string(
+ InternalTransactionView,
+ "_tile.html",
+ current_address: address,
+ internal_transaction: internal_transaction
+ )
+ end)
+
+ json(conn, %{items: internal_transactions_json, next_page_path: next_page_path})
+ else
+ :error ->
+ not_found(conn)
+
+ {:error, :not_found} ->
+ not_found(conn)
+ end
+ end
+
+ def index(conn, %{"address_id" => address_hash_string} = params) do
+ with {:ok, address_hash} <- Chain.string_to_address_hash(address_hash_string),
+ {:ok, address} <- Chain.hash_to_address(address_hash) do
render(
conn,
"index.html",
address: address,
- next_page_params: next_page_params(next_page, internal_transactions, params),
+ current_path: current_path(conn),
exchange_rate: Market.get_exchange_rate(Explorer.coin()) || Token.null(),
filter: params["filter"],
- internal_transactions: internal_transactions,
transaction_count: transaction_count(address),
validation_count: validation_count(address)
)
diff --git a/apps/block_scout_web/lib/block_scout_web/templates/address_internal_transaction/index.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/address_internal_transaction/index.html.eex
index e866c4ae19..2883e278f2 100644
--- a/apps/block_scout_web/lib/block_scout_web/templates/address_internal_transaction/index.html.eex
+++ b/apps/block_scout_web/lib/block_scout_web/templates/address_internal_transaction/index.html.eex
@@ -7,7 +7,7 @@
<%= render BlockScoutWeb.AddressView, "_tabs.html", assigns %>
-
+
+
<%= gettext "Internal Transactions" %>
- <%= if Enum.count(@internal_transactions) > 0 do %>
-
- <%= for internal_transaction <- @internal_transactions do %>
- <%= render BlockScoutWeb.InternalTransactionView, "_tile.html", current_address: @address, internal_transaction: internal_transaction %>
- <% end %>
-
- <% else %>
+
+
<%= gettext "There are no internal transactions for this address." %>
- <% end %>
-
- <%= if @next_page_params do %>
- <%= link(
- gettext("Older"),
- class: "button button-secondary button-sm float-right mt-3",
- to: address_internal_transaction_path(
- @conn,
- :index,
- @address,
- @next_page_params
- )
- ) %>
- <% end %>
+
+
+
+
+
+
+ <%= gettext("Loading") %>...
+
+
+
+ <%= gettext("Older") %>
+
+
+
+
+
+
+ <%= gettext("Loading") %>...
diff --git a/apps/block_scout_web/test/block_scout_web/controllers/address_internal_transaction_controller_test.exs b/apps/block_scout_web/test/block_scout_web/controllers/address_internal_transaction_controller_test.exs
index 19d03d9cdd..398501294a 100644
--- a/apps/block_scout_web/test/block_scout_web/controllers/address_internal_transaction_controller_test.exs
+++ b/apps/block_scout_web/test/block_scout_web/controllers/address_internal_transaction_controller_test.exs
@@ -1,7 +1,8 @@
defmodule BlockScoutWeb.AddressInternalTransactionControllerTest do
use BlockScoutWeb.ConnCase
- import BlockScoutWeb.Router.Helpers, only: [address_internal_transaction_path: 3]
+ import BlockScoutWeb.Router.Helpers,
+ only: [address_internal_transaction_path: 3, address_internal_transaction_path: 4]
alias Explorer.Chain.{Block, InternalTransaction, Transaction}
alias Explorer.ExchangeRates.Token
@@ -21,6 +22,14 @@ defmodule BlockScoutWeb.AddressInternalTransactionControllerTest do
assert html_response(conn, 404)
end
+ test "includes USD exchange rate value for address in assigns", %{conn: conn} do
+ address = insert(:address)
+
+ conn = get(conn, address_internal_transaction_path(BlockScoutWeb.Endpoint, :index, address.hash))
+
+ assert %Token{} = conn.assigns.exchange_rate
+ end
+
test "returns internal transactions for the address", %{conn: conn} do
address = insert(:address)
@@ -47,29 +56,17 @@ defmodule BlockScoutWeb.AddressInternalTransactionControllerTest do
transaction_index: transaction.index
)
- path = address_internal_transaction_path(conn, :index, address)
+ path = address_internal_transaction_path(conn, :index, address, %{"type" => "JSON"})
conn = get(conn, path)
- actual_internal_transaction_primary_keys =
- Enum.map(conn.assigns.internal_transactions, &{&1.transaction_hash, &1.index})
-
- assert Enum.member?(
- actual_internal_transaction_primary_keys,
- {from_internal_transaction.transaction_hash, from_internal_transaction.index}
- )
+ internal_transaction_tiles = json_response(conn, 200)["items"]
- assert Enum.member?(
- actual_internal_transaction_primary_keys,
- {to_internal_transaction.transaction_hash, to_internal_transaction.index}
- )
- end
-
- test "includes USD exchange rate value for address in assigns", %{conn: conn} do
- address = insert(:address)
-
- conn = get(conn, address_internal_transaction_path(BlockScoutWeb.Endpoint, :index, address.hash))
-
- assert %Token{} = conn.assigns.exchange_rate
+ assert Enum.all?([from_internal_transaction, to_internal_transaction], fn internal_transaction ->
+ Enum.any?(internal_transaction_tiles, fn tile ->
+ String.contains?(tile, to_string(internal_transaction.transaction_hash)) &&
+ String.contains?(tile, "data-internal-transaction-index=\"#{internal_transaction.index}\"")
+ end)
+ end)
end
test "returns next page of results based on last seen internal transaction", %{conn: conn} do
@@ -105,7 +102,6 @@ defmodule BlockScoutWeb.AddressInternalTransactionControllerTest do
transaction_index: transaction_1.index
)
end)
- |> Enum.map(&"#{&1.transaction_hash}.#{&1.index}")
transaction_2_hashes =
1..20
@@ -119,7 +115,6 @@ defmodule BlockScoutWeb.AddressInternalTransactionControllerTest do
transaction_index: transaction_2.index
)
end)
- |> Enum.map(&"#{&1.transaction_hash}.#{&1.index}")
transaction_3_hashes =
1..10
@@ -133,9 +128,8 @@ defmodule BlockScoutWeb.AddressInternalTransactionControllerTest do
transaction_index: transaction_3.index
)
end)
- |> Enum.map(&"#{&1.transaction_hash}.#{&1.index}")
- second_page_hashes = transaction_1_hashes ++ transaction_2_hashes ++ transaction_3_hashes
+ second_page = transaction_1_hashes ++ transaction_2_hashes ++ transaction_3_hashes
%InternalTransaction{index: index} =
insert(
@@ -151,15 +145,18 @@ defmodule BlockScoutWeb.AddressInternalTransactionControllerTest do
get(conn, address_internal_transaction_path(BlockScoutWeb.Endpoint, :index, address.hash), %{
"block_number" => Integer.to_string(b_block.number),
"transaction_index" => Integer.to_string(transaction_3.index),
- "index" => Integer.to_string(index)
+ "index" => Integer.to_string(index),
+ "type" => "JSON"
})
- actual_hashes =
- conn.assigns.internal_transactions
- |> Enum.map(&"#{&1.transaction_hash}.#{&1.index}")
- |> Enum.reverse()
+ internal_transaction_tiles = json_response(conn, 200)["items"]
- assert second_page_hashes == actual_hashes
+ assert Enum.all?(second_page, fn internal_transaction ->
+ Enum.any?(internal_transaction_tiles, fn tile ->
+ String.contains?(tile, to_string(internal_transaction.transaction_hash)) &&
+ String.contains?(tile, "data-internal-transaction-index=\"#{internal_transaction.index}\"")
+ end)
+ end)
end
test "next_page_params exist if not on last page", %{conn: conn} do
@@ -184,10 +181,17 @@ defmodule BlockScoutWeb.AddressInternalTransactionControllerTest do
)
end)
- conn = get(conn, address_internal_transaction_path(BlockScoutWeb.Endpoint, :index, address.hash))
+ conn =
+ get(conn, address_internal_transaction_path(BlockScoutWeb.Endpoint, :index, address.hash, %{"type" => "JSON"}))
+
+ expected_response =
+ address_internal_transaction_path(BlockScoutWeb.Endpoint, :index, address.hash, %{
+ "block_number" => number,
+ "index" => 11,
+ "transaction_index" => transaction_index
+ })
- assert %{"block_number" => ^number, "index" => 11, "transaction_index" => ^transaction_index} =
- conn.assigns.next_page_params
+ assert expected_response == json_response(conn, 200)["next_page_path"]
end
test "next_page_params are empty if on last page", %{conn: conn} do
@@ -208,9 +212,10 @@ defmodule BlockScoutWeb.AddressInternalTransactionControllerTest do
)
end)
- conn = get(conn, address_internal_transaction_path(BlockScoutWeb.Endpoint, :index, address.hash))
+ conn =
+ get(conn, address_internal_transaction_path(BlockScoutWeb.Endpoint, :index, address.hash, %{"type" => "JSON"}))
- refute conn.assigns.next_page_params
+ assert %{"next_page_path" => nil} = json_response(conn, 200)
end
end
end