Skip to content

Commit

Permalink
feat: direct link (#161)
Browse files Browse the repository at this point in the history
* feat: fetching detail view by transaction hash and not transfer id

* feat: remove old code, new way of fetching shared config, updates on renders

* chore: update package.json file

* chore: removing log
  • Loading branch information
wainola authored Feb 28, 2024
1 parent 2056a92 commit e6fa560
Show file tree
Hide file tree
Showing 14 changed files with 142 additions and 95 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"date-fns": "^2.30.0",
"dayjs": "^1.11.7",
"ethers": "^6.3.0",
"history": "^5.3.0",
"react": "17.0.2",
"react-dom": "17.0.2",
"react-router-dom": "^6.14.2",
Expand Down
6 changes: 5 additions & 1 deletion src/components/ExplorerTable/ExplorerTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,11 @@ const ExplorerTable: React.FC<ExplorerTable> = ({ state, sharedConfig }: Explore
<TableRow className={classes.row} key={transfer.id}>
<TableCell className={clsx(classes.row, classes.dataRow, classes.cellRow)}>
{txHash !== undefined ? (
<Link className={classes.hashAnchorLink} to={`/transfer/${deposit?.txHash!}`} state={{ id: id, page: state.queryParams.page }}>
<Link
className={classes.hashAnchorLink}
to={`/transfer/${deposit?.txHash!}`}
state={{ id: id, page: state.queryParams.page, txHash: deposit?.txHash }}
>
{txHash}
</Link>
) : (
Expand Down
20 changes: 5 additions & 15 deletions src/context/ExplorerContext.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import React, { useEffect } from "react"

import type { ExplorerContextState, ExplorerContext as ExplorerContextType, ExplorerState, SharedConfig, SharedConfigDomain } from "../types"
import type { ExplorerContextState, ExplorerContext as ExplorerContextType, ExplorerState } from "../types"

import { getAccount, getChainId } from "./connection"
import { routes } from "./data"
import { reducer } from "./reducer"
import { useGetTransferData } from "./useGetTransferData"
import { useGetSharedConfig } from "./useGetSharedConfig"

const ExplorerCtx = React.createContext<ExplorerContextType | undefined>(undefined)

Expand All @@ -22,6 +23,7 @@ const ExplorerProvider = ({ children }: { children: React.ReactNode | React.Reac
transferDetails: undefined,
pillColorStatus: undefined,
account: undefined,
sharedConfig: [],
}

const [explorerContextState, explorerContextDispatcher] = React.useReducer(reducer, explorerPageContextState)
Expand All @@ -30,20 +32,12 @@ const ExplorerProvider = ({ children }: { children: React.ReactNode | React.Reac
const [account, setAccount] = React.useState<string | undefined>(undefined)
const [explorerUrls, setExplorerUrls] = React.useState<[] | ExplorerState["explorerUrls"]>([])

const [sharedConfig, setSharedConfig] = React.useState<SharedConfigDomain[] | []>([])

const getSharedConfig = async (): Promise<void> => {
const reponse = await fetch(import.meta.env.VITE_SHARED_CONFIG_URL as string)
const domainsData = (await reponse.json()) as SharedConfig

setSharedConfig(domainsData.domains)
localStorage.setItem("sharedConfig", JSON.stringify(domainsData))
}

const { search } = window.location
const urlParams = new URLSearchParams(search)
const page = urlParams.get("page")

useGetSharedConfig(explorerContextDispatcher)

useGetTransferData(routes(), explorerContextDispatcher, explorerContextState, Number(page))

useEffect(() => {
Expand All @@ -57,8 +51,6 @@ const ExplorerProvider = ({ children }: { children: React.ReactNode | React.Reac
})
}

void getSharedConfig()

// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
setExplorerUrls(JSON.parse(import.meta.env.VITE_EXPLORER_URLS))

Expand All @@ -80,8 +72,6 @@ const ExplorerProvider = ({ children }: { children: React.ReactNode | React.Reac
chainId,
account,
routes: routes(),
sharedConfig,
setSharedConfig,
explorerUrls,
}}
>
Expand Down
7 changes: 7 additions & 0 deletions src/context/data/data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ export const fetchTransfer = async (url: string): Promise<Transfer> => {
return transfer
}

export const fetchTransferByTxHash = async (url: string): Promise<Transfer | Transfer[]> => {
const response = await fetch(url)
const data = (await response.json()) as Transfer | Transfer[]
return data
}

export const routes = (): Routes => {
const { VITE_INDEXER_URL } = import.meta.env

Expand All @@ -23,5 +29,6 @@ export const routes = (): Routes => {
transfer: async (id: string) => await fetchTransfer(`${indexerUrl}/transfers/${id}`),
transferBySender: async (sender: string, page: string, limit: string) =>
await fetchTransfers(`${indexerUrl}/sender/${sender}/transfers?limit=${limit}&page=${page}`),
transferByTransactionHash: async (txHash: string) => await fetchTransferByTxHash(`${indexerUrl}/transfers/txHash/${txHash}`),
}
}
5 changes: 5 additions & 0 deletions src/context/reducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ export function reducer(state: ExplorerContextState, action: Actions): ExplorerC
...state,
error: action.payload,
}
case "fetch_shared_config":
return {
...state,
sharedConfig: action.payload,
}
default:
return state
}
Expand Down
18 changes: 18 additions & 0 deletions src/context/useGetSharedConfig.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { useEffect } from "react"
import { Actions, SharedConfig } from "../types"

export function useGetSharedConfig(explorerContextDispatcher: React.Dispatch<Actions>): void {
const getSharedConfig = async (): Promise<void> => {
const reponse = await fetch(import.meta.env.VITE_SHARED_CONFIG_URL as string)
const domainsData = (await reponse.json()) as SharedConfig

explorerContextDispatcher({
type: "fetch_shared_config",
payload: domainsData.domains,
})
}

useEffect(() => {
void getSharedConfig()
}, [])
}
36 changes: 25 additions & 11 deletions src/pages/DetailView/DetailView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,18 @@ import useUpdateInterval from "./hooks/useUpdateInterval"

dayjs.extend(localizedFormat)

export type LocationT = {
state: { id: string; page: number; txHash: string }
}

export default function DetailView() {
const explorerContext = useExplorer()

const { sharedConfig, setSharedConfig, explorerUrls, routes } = explorerContext
const { explorerUrls, routes, explorerContextState } = explorerContext

const { classes } = useStyles()

const { state: data } = useLocation() as { state: { id: string; page: number } }
const { state: data } = useLocation() as LocationT

const initState: DetailViewState = {
transferDetails: null,
Expand All @@ -46,20 +50,22 @@ export default function DetailView() {
clipboardMessageT2: "Copy to clipboard",
delay: 5000,
fetchingStatus: "idle",
isLoading: "none",
fallbackPage: 1,
}

const [state, dispatcher] = useReducer(reducer, initState)

useClipboard(state, dispatcher)

useFetchTransfer(routes, sharedConfig, setSharedConfig, data, dispatcher)
useFetchTransfer(routes, data?.txHash, dispatcher)

useUpdateInterval(state, dispatcher, data, routes)
useUpdateInterval(state, dispatcher, data?.txHash, routes)

// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
const renderTransferDetails = (transfer: Transfer | null) => {
const fromDomainInfo = getDomainData(transfer?.fromDomainId!, sharedConfig)
const toDomainInfo = getDomainData(transfer?.toDomainId!, sharedConfig)
const fromDomainInfo = getDomainData(transfer?.fromDomainId!, explorerContextState.sharedConfig)
const toDomainInfo = getDomainData(transfer?.toDomainId!, explorerContextState.sharedConfig)

const { resource, usdValue } = transfer as Transfer

Expand Down Expand Up @@ -207,18 +213,19 @@ export default function DetailView() {
<span className={classes.detailsInnerContentTitle}>Fees:</span>
<span className={classes.detailsInnerContent}>{getFormatedFee(transfer?.fee!, fromDomainInfo!)}</span>
</div>
{Array.isArray(state.transferDetails) && <br />}
</Container>
)
}

return (
<Container>
<Box className={classes.boxContainer}>
{state.transferStatus !== "none" ? (
{state.isLoading === "done" && explorerContextState.sharedConfig.length && (
<section className={classes.sectionContainer}>
<span className={classes.backIcon}>
<Link
to={`/?page=${data.page}`}
to={`/?page=${data?.page || state.fallbackPage}`}
style={{
color: "black",
textDecoration: "none",
Expand All @@ -233,10 +240,17 @@ export default function DetailView() {
<Typography variant="h4" sx={{ fontSize: "24px" }}>
Transaction Detail
</Typography>
<Container className={classes.transferDetailsContainer}>{renderTransferDetails(state.transferDetails)}</Container>
<Container className={classes.transferDetailsContainer}>
{Array.isArray(state.transferDetails)
? state.transferDetails.map(transfer => renderTransferDetails(transfer))
: renderTransferDetails(state.transferDetails)}
</Container>
</section>
) : (
<CircularProgress />
)}
{state.isLoading === "loading" && (
<Container className={classes.circularProgress}>
<CircularProgress />
</Container>
)}
</Box>
</Container>
Expand Down
79 changes: 24 additions & 55 deletions src/pages/DetailView/hooks/useFetchTransfer.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,28 @@
import { useEffect } from "react"
import { useParams } from "react-router-dom"
import history from "history/browser"
import { sanitizeTransferData } from "../../../utils/Helpers"
import { Routes, SharedConfig, SharedConfigDomain, Transfer } from "../../../types"
import { Routes, Transfer } from "../../../types"
import { DetailViewActions } from "../reducer"

export default function useFetchTransfer(
routes: Routes,
sharedConfig: SharedConfigDomain[] | [],
setSharedConfig: React.Dispatch<React.SetStateAction<SharedConfigDomain[] | []>>,
transferId: { id: string } | null,
dispatcher: React.Dispatch<DetailViewActions>,
): void {
const fetchTransfer = async (): Promise<void> => {
const transfer = await routes.transfer(transferId!.id)
const sanitizedTransfer = sanitizeTransferData([transfer])
export default function useFetchTransfer(routes: Routes, txHash: string, dispatcher: React.Dispatch<DetailViewActions>): void {
const fetchTransfer = async (txHashFallback?: string): Promise<void> => {
dispatcher({
type: "fetch_transfer",
})

let transfer: Transfer | Transfer[]

if (txHashFallback) {
transfer = await routes.transferByTransactionHash(txHashFallback)
} else {
transfer = await routes.transferByTransactionHash(txHash)
}

const sanitizedTransfer = Array.isArray(transfer) ? sanitizeTransferData([...transfer]) : sanitizeTransferData([transfer])

dispatcher({
type: "set_transfer_details",
payload: sanitizedTransfer[0],
payload: sanitizedTransfer,
})

dispatcher({
Expand All @@ -31,50 +36,14 @@ export default function useFetchTransfer(
})
}

// fallback when you are opening the detail view on new tab
const params = useParams()

const getTransfersFromLocalStorage = (): void => {
const transfers = localStorage.getItem("transfers")
const { txHash } = params
const parsedTransfers = JSON.parse(transfers!) as Transfer[]
const transfer = parsedTransfers.find(transfer => transfer.deposit?.txHash === txHash)

if (transfer) {
dispatcher({
type: "set_transfer_details",
payload: transfer,
})

dispatcher({
type: "set_transfer_status",
payload: "completed",
})

dispatcher({
type: "update_fetching_status",
payload: "fetching",
})
}
}

const getSharedConfigFromLocalStorage = (): void => {
const sharedConfig = localStorage.getItem("sharedConfig")
const parsedSharedConfig = JSON.parse(sharedConfig!) as SharedConfig

setSharedConfig(parsedSharedConfig.domains)
}

useEffect(() => {
if (transferId !== null) {
if (txHash !== undefined) {
void fetchTransfer()
} else {
getTransfersFromLocalStorage()
}

// fallback because ExplorerState is new coming to a new tab
if (sharedConfig.length === 0) {
getSharedConfigFromLocalStorage()
const { pathname } = history.location
const txHashFallback = pathname.split("/").filter(Boolean)[1]
history.replace(history.location.pathname, { txHash, page: 1, id: "" })
void fetchTransfer(txHashFallback)
}
}, [])
}, [txHash])
}
18 changes: 13 additions & 5 deletions src/pages/DetailView/hooks/useUpdateInterval.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,30 @@ import { Routes } from "../../../types"
export default function useUpdateInterval(
state: DetailViewState,
dispatcher: React.Dispatch<DetailViewActions>,
transferId: { id: string } | null,
txHash: string,
routes: Routes,
): void {
const fetchUpdatedTransfer = async (): Promise<void> => {
const transfer = await routes.transfer(transferId!.id)
const sanitizedTransfer = sanitizeTransferData([transfer])
dispatcher({
type: "fetch_transfer",
})

const transfer = await routes.transferByTransactionHash(txHash)
const sanitizedTransfer = Array.isArray(transfer) ? sanitizeTransferData([...transfer]) : sanitizeTransferData([transfer])

dispatcher({
type: "set_transfer_details",
payload: sanitizedTransfer[0],
payload: sanitizedTransfer,
})
}

useInterval(
() => {
if (state.transferDetails?.status !== "executed") {
const isExecuted = Array.isArray(state.transferDetails)
? state.transferDetails.every(transfer => transfer.status === "executed")
: state.transferDetails?.status === "executed"

if (!isExecuted) {
void fetchUpdatedTransfer()
} else {
dispatcher({
Expand Down
Loading

0 comments on commit e6fa560

Please sign in to comment.