diff --git a/.changeset/slow-roses-hide.md b/.changeset/slow-roses-hide.md
new file mode 100644
index 000000000..ecce31ba1
--- /dev/null
+++ b/.changeset/slow-roses-hide.md
@@ -0,0 +1,5 @@
+---
+'explorer': minor
+---
+
+Added previous and next block navigation to blocks page.
diff --git a/apps/explorer-e2e/src/specs/block.spec.ts b/apps/explorer-e2e/src/specs/block.spec.ts
index c1e746a0e..ca5ad1622 100644
--- a/apps/explorer-e2e/src/specs/block.spec.ts
+++ b/apps/explorer-e2e/src/specs/block.spec.ts
@@ -28,10 +28,22 @@ test('block can be directly navigated to by height', async ({ page }) => {
await expect(page.getByText(TEST_BLOCK_1.display.title).nth(0)).toBeVisible()
})
-test('block can be directly navigated to by id', async ({ page }) => {
+test('block can navigate to previous block', async ({ page }) => {
await explorerApp.goTo('/block/' + TEST_BLOCK_1.id)
+ await page.getByTestId('explorer-block-prevBlock').click()
- await expect(page.getByText(TEST_BLOCK_1.display.title).nth(0)).toBeVisible()
+ await expect(
+ page.getByText((Number(TEST_BLOCK_1.height) - 1).toLocaleString())
+ ).toBeVisible()
+})
+
+test('block can navigate to nextblock', async ({ page }) => {
+ await explorerApp.goTo('/block/' + TEST_BLOCK_1.id)
+ await page.getByTestId('explorer-block-nextBlock').click()
+
+ await expect(
+ page.getByText((Number(TEST_BLOCK_1.height) + 1).toLocaleString())
+ ).toBeVisible()
})
test('block can click through to a transaction', async ({ page }) => {
diff --git a/apps/explorer/app/block/[id]/page.tsx b/apps/explorer/app/block/[id]/page.tsx
index 52dde558b..bcb6b3436 100644
--- a/apps/explorer/app/block/[id]/page.tsx
+++ b/apps/explorer/app/block/[id]/page.tsx
@@ -37,31 +37,33 @@ export default async function Page({ params }) {
// Check if the incoming id is referencing height.
if (!isNaN(Number(params?.id))) {
- // If it is, we need the block ID.
-
- // Grab the tip at this height.
- const [tipInfo, tipInfoError] = await to(
+ // If it is, we need the block ID at that height.
+ const [tipAtHeightInfo, tipAtHeightInfoError] = await to(
explored.consensusTipByHeight({ params: { height: params?.id } })
)
+ if (tipAtHeightInfoError) throw tipAtHeightInfoError
+ if (!tipAtHeightInfo) throw notFound()
- if (tipInfoError) throw tipInfoError
- if (!tipInfo) throw notFound()
-
- id = tipInfo.id
+ id = tipAtHeightInfo.id
} else {
- // If it is not the height, it is referencing the ID. No call necessary.
+ // If it is not the height, assume we're referencing ID. No call necessary.
id = params?.id
}
- // Get the block using the id from the previous request.
- const [block, blockError] = await to(explored.blockByID({ params: { id } }))
+ // Get the block using the id from the previous sequence. Also grab the
+ // currentTip for next block navigation handling.
+ const [[block, blockError], [currentTipInfo, currentTipInfoError]] =
+ await Promise.all([
+ to(explored.blockByID({ params: { id } })),
+ to(explored.consensusTip()),
+ ])
- if (blockError) {
- throw blockError
- }
- if (!block) {
- return notFound()
- }
+ if (blockError) throw blockError
+ if (currentTipInfoError) throw currentTipInfoError
+ if (!block) return notFound()
+ if (!currentTipInfo) throw notFound()
- return