diff --git a/explorer/src/components/Copyable.tsx b/explorer/src/components/Copyable.tsx
index 74863ee6ac..a0cd571948 100644
--- a/explorer/src/components/Copyable.tsx
+++ b/explorer/src/components/Copyable.tsx
@@ -31,7 +31,7 @@ function Copyable({ bottom, text, children }: CopyableProps) {
return (
setState("copy")}
onMouseOut={() => state === "copy" && setState("hide")}
diff --git a/explorer/src/components/InfoTooltip.tsx b/explorer/src/components/InfoTooltip.tsx
new file mode 100644
index 0000000000..5eb5e1d845
--- /dev/null
+++ b/explorer/src/components/InfoTooltip.tsx
@@ -0,0 +1,40 @@
+import React, { useState, ReactNode } from "react";
+
+type Props = {
+ text: string;
+ children: ReactNode;
+ bottom?: boolean;
+ right?: boolean;
+};
+
+type State = "hide" | "show";
+
+function Popover({ state, bottom, right, text }: { state: State; bottom?: boolean, right?: boolean, text: string }) {
+ if (state === "hide") return null;
+ return (
+
+ );
+}
+
+function InfoTooltip({ bottom, right, text, children }: Props) {
+ const [state, setState] = useState
("hide");
+
+ return (
+ setState("show")}
+ onMouseOut={() => setState("hide")}
+ >
+
+ {children}
+
+
+
+
+ );
+}
+
+export default InfoTooltip;
diff --git a/explorer/src/components/TransactionDetails.tsx b/explorer/src/components/TransactionDetails.tsx
index 03751b12b4..f40fd2a2c5 100644
--- a/explorer/src/components/TransactionDetails.tsx
+++ b/explorer/src/components/TransactionDetails.tsx
@@ -25,6 +25,7 @@ import ErrorCard from "./common/ErrorCard";
import LoadingCard from "./common/LoadingCard";
import TableCardBody from "./common/TableCardBody";
import { displayTimestamp } from "utils/date";
+import InfoTooltip from "components/InfoTooltip";
type Props = { signature: TransactionSignature };
export default function TransactionDetails({ signature }: Props) {
@@ -146,12 +147,16 @@ function StatusCard({ signature }: Props) {
{renderResult()} |
- {info.timestamp && (
-
- Timestamp |
- {displayTimestamp(info.timestamp)} |
-
- )}
+
+ Timestamp |
+
+ {info.timestamp !== "unavailable" ? displayTimestamp(info.timestamp) : (
+
+ Unavailable
+
+ )}
+ |
+
Confirmations |
diff --git a/explorer/src/providers/transactions/index.tsx b/explorer/src/providers/transactions/index.tsx
index f70efa2758..4c157e4b16 100644
--- a/explorer/src/providers/transactions/index.tsx
+++ b/explorer/src/providers/transactions/index.tsx
@@ -26,10 +26,12 @@ export enum FetchStatus {
export type Confirmations = number | "max";
+export type Timestamp = number | "unavailable";
+
export interface TransactionStatusInfo {
slot: number;
result: SignatureResult;
- timestamp: number | null;
+ timestamp: Timestamp;
confirmations: Confirmations;
}
@@ -236,7 +238,20 @@ export async function fetchTransactionStatus(
});
if (value !== null) {
- let timestamp = await connection.getBlockTime(value.slot);
+ let blockTime = await connection.getBlockTime(value.slot);
+
+ let timestamp: Timestamp;
+ if (blockTime !== null) {
+ timestamp = blockTime;
+ } else {
+ const epochInfo = await connection.getEpochInfo();
+ if (value.slot < epochInfo.absoluteSlot - epochInfo.slotsInEpoch) {
+ timestamp = "unavailable";
+ } else {
+ throw new Error("Unable to fetch timestamp");
+ }
+ }
+
let confirmations: Confirmations;
if (typeof value.confirmations === "number") {
confirmations = value.confirmations;
diff --git a/explorer/src/scss/_solana.scss b/explorer/src/scss/_solana.scss
index c6f0889f97..9c34f6930f 100644
--- a/explorer/src/scss/_solana.scss
+++ b/explorer/src/scss/_solana.scss
@@ -10,15 +10,19 @@ code {
color: $black;
}
-.copyable {
+.popover-container {
position: relative;
- display: inline;
- cursor: pointer;
.popover {
&.bs-popover-top {
background-color: $dark;
- top: -4rem;
+ top: auto;
+ bottom: 1.5rem;
+ }
+
+ &.right {
+ left: auto;
+ right: 0;
}
&.bs-popover-bottom {
@@ -30,6 +34,10 @@ code {
color: white;
}
+ .arrow.right {
+ right: 1rem;
+ }
+
.arrow::after {
border-top-color: $dark;
border-bottom-color: $dark;
@@ -45,7 +53,7 @@ code {
display: block;
}
-.modal .close {
+.c-pointer {
cursor: pointer;
}