Skip to content

Commit

Permalink
feat: query param base impl (#153)
Browse files Browse the repository at this point in the history
* feat: query param base impl

* feat: moving fetching logic to context

* feat: using page before rendering if is diff from default

* chore: changing number upon change of page with state update

* chore: upon going back update url with queryParam
  • Loading branch information
wainola authored Feb 20, 2024
1 parent 03d1a97 commit aa60682
Show file tree
Hide file tree
Showing 12 changed files with 9,805 additions and 6,782 deletions.
14 changes: 13 additions & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
require("@rushstack/eslint-patch/modern-module-resolution");

module.exports = {
extends: "@chainsafe"
extends: "@chainsafe" ,
rules: {
"@typescript-eslint/explicit-function-return-type": "off",
},
"overrides": [
{
// enable the rule specifically for TypeScript files
"files": ["*.ts"],
"rules": {
"@typescript-eslint/explicit-function-return-type": "error",
},
},
],
}
2 changes: 0 additions & 2 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import CssBaseline from "@mui/material/CssBaseline"
import { ThemeProvider } from "@mui/material/styles"
import { Routes, Route, BrowserRouter as Router } from "react-router-dom"
import { Alert } from "@mui/material"
import { ExplorerPage, DetailView } from "./pages"
import { SygmaTheme } from "./themes/SygmaTheme"
import { ExplorerProvider } from "./context"
Expand All @@ -13,7 +12,6 @@ export const ROUTE_LINKS = {
}

function App(): JSX.Element {
// ADD HERE SHARED CONFIG SUPPORT
return (
<ThemeProvider theme={SygmaTheme}>
<CssBaseline />
Expand Down
14 changes: 5 additions & 9 deletions src/components/ExplorerTable/ExplorerTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React from "react"
import { Table, TableHead, TableCell, TableBody, TableRow, CircularProgress } from "@mui/material"
import clsx from "clsx"
import { Link } from "react-router-dom"
import { EvmBridgeConfig, ResourceTypes, SharedConfigDomain, Transfer } from "../../types"
import { EvmBridgeConfig, ExplorerContextState, ResourceTypes, SharedConfigDomain, Transfer } from "../../types"
import {
getDisplayedStatuses,
shortenAddress,
Expand All @@ -23,11 +23,7 @@ type ExplorerTable = {
active: boolean
setActive: (state: boolean) => void
chains: Array<EvmBridgeConfig>
state: {
transfers: Transfer[]
loading: "none" | "loading" | "done"
error: undefined | string
}
state: ExplorerContextState
sharedConfig: SharedConfigDomain[] | []
}

Expand Down Expand Up @@ -66,7 +62,7 @@ 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 }}>
<Link className={classes.hashAnchorLink} to={`/transfer/${deposit?.txHash!}`} state={{ id: id, page: state.queryParams.page }}>
{txHash}
</Link>
) : (
Expand Down Expand Up @@ -144,8 +140,8 @@ const ExplorerTable: React.FC<ExplorerTable> = ({ state, sharedConfig }: Explore
<TableCell sx={{ borderTopRightRadius: "12px !important" }}>Value</TableCell>
</TableRow>
</TableHead>
{state.loading === "done" && <TableBody>{renderTransferList(state.transfers)}</TableBody>}
{state.loading === "loading" && (
{state.isLoading === "done" && <TableBody>{renderTransferList(state.transfers)}</TableBody>}
{state.isLoading === "loading" && (
<TableBody>
<TableRow>
<TableCell colSpan={8} align="center">
Expand Down
119 changes: 52 additions & 67 deletions src/context/ExplorerContext.tsx
Original file line number Diff line number Diff line change
@@ -1,93 +1,78 @@
import React, { useEffect } from "react";
import {
ExplorerContextState,
ExplorerContext as ExplorerContextType,
ExplorerState,
PaginationParams,
SharedConfig,
SharedConfigDomain,
} from "../types";
import { getAccount, getChainId } from "./connection";
import { routes } from "./data";
import { reducer } from "./reducer";

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

const ExplorerProvider = ({
children,
}: {
children: React.ReactNode | React.ReactNode[];
}) => {

// TO BE DEFINED
const loadMore = (options: PaginationParams) => null;
import React, { useEffect } from "react"

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

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

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

const ExplorerProvider = ({ children }: { children: React.ReactNode | React.ReactNode[] }) => {
const explorerPageContextState: ExplorerContextState = {
queryParams: {
page: 1, //by default
page: 1,
limit: 10,
},
isLoading: false,
isLoading: "none",
transfers: [],
error: false,
error: undefined,
chains: [],
transferDetails: undefined,
pillColorStatus: undefined,
account: undefined,
};
}

const [explorerContextState, explorerContextDispatcher] = React.useReducer(
reducer,
explorerPageContextState,
);
const [explorerContextState, explorerContextDispatcher] = React.useReducer(reducer, explorerPageContextState)

const [chainId, setChainId] = React.useState<number | undefined>(undefined);
const [account, setAccount] = React.useState<string | undefined>(undefined);
const [explorerUrls, setExplorerUrls] = React.useState<
[] | ExplorerState["explorerUrls"]
>([]);
const [chainId, setChainId] = React.useState<number | undefined>(undefined)
const [account, setAccount] = React.useState<string | undefined>(undefined)
const [explorerUrls, setExplorerUrls] = React.useState<[] | ExplorerState["explorerUrls"]>([])

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

const getSharedConfig = async (): Promise<void> => {
const reponse = await fetch(import.meta.env.VITE_SHARED_CONFIG_URL);
const domainsData = (await reponse.json()) as SharedConfig;
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));
};
setSharedConfig(domainsData.domains)
localStorage.setItem("sharedConfig", JSON.stringify(domainsData))
}

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

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

useEffect(() => {
if (window.ethereum !== undefined) {
window.ethereum!.on("chainChanged", (chainId: unknown) => {
setChainId(Number(chainId as string));
});
window.ethereum.on("chainChanged", (chainId: unknown) => {
setChainId(Number(chainId as string))
})

window.ethereum!.on("accountsChanged", (accounts: unknown) => {
setAccount((accounts as Array<string>)[0] as string);
});
window.ethereum.on("accountsChanged", (accounts: unknown) => {
setAccount((accounts as Array<string>)[0])
})
}

getSharedConfig();

setExplorerUrls(JSON.parse(import.meta.env.VITE_EXPLORER_URLS));
void getSharedConfig()

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

return () => {
if (window.ethereum !== undefined) {
window.ethereum!.removeAllListeners("chainChanged");
window.ethereum!.removeAllListeners("accountsChanged");
window.ethereum.removeAllListeners("chainChanged")
window.ethereum.removeAllListeners("accountsChanged")
}
};
}, []);
}
}, [])

return (
<ExplorerCtx.Provider
value={{
loadMore,
explorerContextState,
explorerContextDispatcher,
getAccount,
Expand All @@ -102,17 +87,17 @@ const ExplorerProvider = ({
>
{children}
</ExplorerCtx.Provider>
);
};
)
}

const useExplorer = () => {
const context = React.useContext(ExplorerCtx);
const context = React.useContext(ExplorerCtx)

if (context === undefined) {
throw new Error("useExplorer must be used within a ExplorerProvider");
throw new Error("useExplorer must be used within a ExplorerProvider")
}

return context;
};
return context
}

export { ExplorerProvider, useExplorer };
export { ExplorerProvider, useExplorer }
20 changes: 20 additions & 0 deletions src/context/reducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,26 @@ export function reducer(state: ExplorerContextState, action: Actions): ExplorerC
account: action.payload,
}
}
case "fetch_transfers":
return {
...state,
transfers: action.payload,
}
case "loading_done":
return {
...state,
isLoading: "done",
}
case "loading_transfers":
return {
...state,
isLoading: "loading",
}
case "fetch_transfer_error":
return {
...state,
error: action.payload,
}
default:
return state
}
Expand Down
48 changes: 48 additions & 0 deletions src/context/useGetTransferData.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { useEffect } from "react"
import { Actions, ExplorerContextState, Routes } from "../types"
import { sanitizeTransferData } from "../utils/Helpers"

export function useGetTransferData(routes: Routes, dispatcher: React.Dispatch<Actions>, state: ExplorerContextState, page: number): void {
const pageToUse = page !== 0 && page !== state.queryParams.page ? page : state.queryParams.page

const fetchTransfers = async (): Promise<void> => {
dispatcher({
type: "loading_transfers",
})

try {
const transfers = await routes.transfers(`${pageToUse}`, `${state.queryParams.limit}`)
const sanitizedTransfers = sanitizeTransferData(transfers)

dispatcher({
type: "fetch_transfers",
payload: sanitizedTransfers,
})

dispatcher({
type: "loading_done",
})
} catch (e) {
dispatcher({
type: "fetch_transfer_error",
payload: "Error fetching all the transfers",
})
}
}

useEffect(() => {
void fetchTransfers()
}, [state.queryParams])

useEffect(() => {
if (pageToUse !== state.queryParams.page) {
dispatcher({
type: "set_query_params",
payload: {
page: pageToUse,
limit: state.queryParams.limit,
},
})
}
}, [page])
}
8 changes: 4 additions & 4 deletions src/pages/DetailView/DetailView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export default function DetailView() {

const { classes } = useStyles()

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

const initState: DetailViewState = {
transferDetails: null,
Expand All @@ -52,9 +52,9 @@ export default function DetailView() {

useClipboard(state, dispatcher)

useFetchTransfer(routes, sharedConfig, setSharedConfig, transferId, dispatcher)
useFetchTransfer(routes, sharedConfig, setSharedConfig, data, dispatcher)

useUpdateInterval(state, dispatcher, transferId, routes)
useUpdateInterval(state, dispatcher, data, routes)

// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
const renderTransferDetails = (transfer: Transfer | null) => {
Expand Down Expand Up @@ -218,7 +218,7 @@ export default function DetailView() {
<section className={classes.sectionContainer}>
<span className={classes.backIcon}>
<Link
to="/"
to={`/?page=${data.page}`}
style={{
color: "black",
textDecoration: "none",
Expand Down
Loading

0 comments on commit aa60682

Please sign in to comment.