Commit 90d38a52 authored by tom's avatar tom

basic link builder and its usage for tx as an example

parent 9dad0728
import { compile } from 'path-to-regexp';
import { ROUTES } from './routes';
import type { RouteName } from './routes';
export function link(routeName: RouteName, urlParams?: Record<string, string | undefined>, queryParams?: Record<string, string>): string {
const route = ROUTES[routeName];
if (!route) {
return '';
}
const toPath = compile(route.pattern, { encode: encodeURIComponent, validate: false });
const path = toPath(urlParams);
const url = new URL(path, window.location.origin);
queryParams && Object.entries(queryParams).forEach(([ key, value ]) => {
url.searchParams.append(key, value);
});
return url.toString();
}
export interface Route {
pattern: string;
}
export type RouteName = keyof typeof ROUTES;
export const ROUTES = {
tx: {
pattern: '/:network_type/:network_sub_type/tx/:id/:tab?',
},
};
// !!! for development purpose only !!!
// don't wanna strict ROUTES to type "Record<string, Route>"
// otherwise we lose benefit of using "keyof typeof ROUTES" for possible route names (it will be any string then)
// but we still want typescript to tell us if routes follow its interface
// so we do this simple type-checking here
//
// another option is to create common enum with all possible route names and use it across the project
// but it is a little bit overwhelming as it seems right now
function checkRoutes(route: Record<string, Route>) {
return route;
}
if (process.env.NODE_ENV === 'development') {
checkRoutes(ROUTES);
}
import { useRouter } from 'next/router';
import React from 'react';
import { link } from 'lib/link/link';
type LinkBuilderParams = Parameters<typeof link>;
export default function useLink() {
const router = useRouter();
const networkType = router.query.network_type;
const networkSubType = router.query.network_sub_type;
return React.useCallback((...args: LinkBuilderParams) => {
if (typeof networkType !== 'string' || typeof networkSubType !== 'string') {
return '';
}
return link(args[0], { network_type: networkType, network_sub_type: networkSubType, ...args[1] }, args[2]);
}, [ networkType, networkSubType ]);
}
type ArrayElement<ArrayType extends Array<unknown>> =
ArrayType extends Array<(infer ElementType)> ? ElementType : never;
export default ArrayElement;
...@@ -8,7 +8,7 @@ import { ...@@ -8,7 +8,7 @@ import {
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import React from 'react'; import React from 'react';
import useBasePath from 'lib/hooks/useBasePath'; import useLink from 'lib/link/useLink';
import Page from 'ui/shared/Page'; import Page from 'ui/shared/Page';
import PageHeader from 'ui/shared/PageHeader'; import PageHeader from 'ui/shared/PageHeader';
import TxDetails from 'ui/tx/TxDetails'; import TxDetails from 'ui/tx/TxDetails';
...@@ -17,17 +17,17 @@ import TxLogs from 'ui/tx/TxLogs'; ...@@ -17,17 +17,17 @@ import TxLogs from 'ui/tx/TxLogs';
interface Tab { interface Tab {
type: 'details' | 'internal_txn' | 'logs' | 'raw_trace' | 'state'; type: 'details' | 'internal_txn' | 'logs' | 'raw_trace' | 'state';
path: string;
name: string; name: string;
path?: string;
component?: React.ReactNode; component?: React.ReactNode;
} }
const TABS: Array<Tab> = [ const TABS: Array<Tab> = [
{ type: 'details', path: '', name: 'Details', component: <TxDetails/> }, { type: 'details', name: 'Details', component: <TxDetails/> },
{ type: 'internal_txn', path: '/internal-transactions', name: 'Internal txn', component: <TxInternals/> }, { type: 'internal_txn', path: 'internal-transactions', name: 'Internal txn', component: <TxInternals/> },
{ type: 'logs', path: '/logs', name: 'Logs', component: <TxLogs/> }, { type: 'logs', path: 'logs', name: 'Logs', component: <TxLogs/> },
{ type: 'state', path: '/state', name: 'State' }, { type: 'state', path: 'state', name: 'State' },
{ type: 'raw_trace', path: '/raw-trace', name: 'Raw trace' }, { type: 'raw_trace', path: 'raw-trace', name: 'Raw trace' },
]; ];
export interface Props { export interface Props {
...@@ -37,14 +37,14 @@ export interface Props { ...@@ -37,14 +37,14 @@ export interface Props {
const TransactionPageContent = ({ tab }: Props) => { const TransactionPageContent = ({ tab }: Props) => {
const [ , setActiveTab ] = React.useState<Tab['type']>(tab); const [ , setActiveTab ] = React.useState<Tab['type']>(tab);
const router = useRouter(); const router = useRouter();
const basePath = useBasePath(); const link = useLink();
const handleTabChange = React.useCallback((index: number) => { const handleTabChange = React.useCallback((index: number) => {
const nextTab = TABS[index]; const nextTab = TABS[index];
setActiveTab(nextTab.type); setActiveTab(nextTab.type);
const newUrl = basePath + '/tx/' + router.query.id + nextTab.path; const newUrl = link('tx', { id: router.query.id as string, tab: nextTab.path });
window.history.replaceState(history.state, '', newUrl); window.history.replaceState(history.state, '', newUrl);
}, [ setActiveTab, basePath, router ]); }, [ setActiveTab, link, router.query.id ]);
const defaultIndex = TABS.map(({ type }) => type).indexOf(tab); const defaultIndex = TABS.map(({ type }) => type).indexOf(tab);
......
...@@ -4497,6 +4497,11 @@ path-parse@^1.0.6, path-parse@^1.0.7: ...@@ -4497,6 +4497,11 @@ path-parse@^1.0.6, path-parse@^1.0.7:
resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
path-to-regexp@^6.2.1:
version "6.2.1"
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-6.2.1.tgz#d54934d6798eb9e5ef14e7af7962c945906918e5"
integrity sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw==
path-type@^4.0.0: path-type@^4.0.0:
version "4.0.0" version "4.0.0"
resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment