Skip to content

Commit

Permalink
EVM Staking - Breadcrumbs & Header chips (#1781)
Browse files Browse the repository at this point in the history
  • Loading branch information
devpavan04 authored Oct 19, 2023
1 parent 2b2b4e0 commit 4ea6a42
Show file tree
Hide file tree
Showing 19 changed files with 231 additions and 15 deletions.
13 changes: 12 additions & 1 deletion apps/tangle-dapp/app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
import { Typography } from '@webb-tools/webb-ui-components';
import { HeaderChipsContainer } from '../containers/HeaderChipsContainer';

export default async function Index() {
return <div></div>;
return (
<div className="flex items-center justify-between">
<Typography variant="h4" fw="bold">
Staking Overview
</Typography>

<HeaderChipsContainer />
</div>
);
}
59 changes: 59 additions & 0 deletions apps/tangle-dapp/components/Breadcrumbs/Breadcrumbs.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
'use client';

import { FundsLine } from '@webb-tools/icons';
import {
Breadcrumbs as BreadcrumbsCmp,
BreadcrumbsItem,
} from '@webb-tools/webb-ui-components';
import cx from 'classnames';
import Link from 'next/link';
import { usePathname, useRouter } from 'next/navigation';
import { type FC, useMemo, useEffect } from 'react';
import { BreadcrumbType } from './types';
import { getIconSizeInPixel } from '@webb-tools/icons/utils';

const Breadcrumbs: FC = () => {
const router = useRouter();
const pathname = usePathname();

const breadCrumbs = useMemo<BreadcrumbType[]>(() => {
const md = getIconSizeInPixel('md');
const lg = getIconSizeInPixel('lg');

return [
{
label: 'EVM Staking',
isLast: true,
icon: (
<FundsLine
className={`w-[${md}] h-[${md}] lg:w-[${lg}] lg:h-[${lg}]`}
/>
),
href: '/',
},
];
}, []);

return (
<BreadcrumbsCmp>
{breadCrumbs.map((breadcrumb, index) => (
/**
* Data on the client-side needs to be up-to-date when the user navigates to a page
* Therefore, do not need to prefetch routes in breadcrumb items
*/
<Link key={index} href={breadcrumb.href} prefetch={false}>
<BreadcrumbsItem
icon={breadcrumb.icon}
className={cx('whitespace-nowrap', breadcrumb.className)}
textClassName="!text-[12px] lg:!text-[16px] normal-case"
isLast={breadcrumb.isLast}
>
{breadcrumb.label}
</BreadcrumbsItem>
</Link>
))}
</BreadcrumbsCmp>
);
};

export default Breadcrumbs;
1 change: 1 addition & 0 deletions apps/tangle-dapp/components/Breadcrumbs/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as Breadcrumbs } from './Breadcrumbs';
7 changes: 7 additions & 0 deletions apps/tangle-dapp/components/Breadcrumbs/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export type BreadcrumbType = {
label: string;
isLast: boolean;
icon: JSX.Element;
href: string;
className?: string;
};
52 changes: 52 additions & 0 deletions apps/tangle-dapp/components/HeaderChip/HeaderChip.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { Suspense, type FC, useMemo } from 'react';
import {
Chip,
Tooltip,
TooltipBody,
TooltipTrigger,
Typography,
SkeletonLoader,
} from '@webb-tools/webb-ui-components';
import { HeaderChipItemProps } from './types';

export const HeaderChip: FC<HeaderChipItemProps> = ({
Icon,
label,
hasTooltip = false,
tooltipContent,
dataFetcher,
}: HeaderChipItemProps) => {
const mainContent = useMemo(
() => (
<Chip color="blue">
<Icon size="lg" className="stroke-blue-90 dark:stroke-blue-30" />
{label}:{' '}
<Suspense fallback={<SkeletonLoader className="w-[100px]" />}>
<HeaderChipValue dataFetcher={dataFetcher} />
</Suspense>
</Chip>
),
[Icon, label, dataFetcher]
);

if (hasTooltip && tooltipContent) {
return (
<Tooltip>
<TooltipTrigger>{mainContent}</TooltipTrigger>
<TooltipBody>
<Typography variant="body2">{tooltipContent}</Typography>
</TooltipBody>
</Tooltip>
);
}

return mainContent;
};

const HeaderChipValue = async ({
dataFetcher,
}: Pick<HeaderChipItemProps, 'dataFetcher'>) => {
const value = await dataFetcher();

return <>{value}</>;
};
1 change: 1 addition & 0 deletions apps/tangle-dapp/components/HeaderChip/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './HeaderChip';
9 changes: 9 additions & 0 deletions apps/tangle-dapp/components/HeaderChip/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { type IconBase } from '@webb-tools/icons/types';

export interface HeaderChipItemProps {
Icon: (props: IconBase) => JSX.Element;
label: string;
hasTooltip?: boolean;
tooltipContent?: string;
dataFetcher: () => Promise<number | undefined>;
}
4 changes: 3 additions & 1 deletion apps/tangle-dapp/components/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
export * from './sideBar';
export * from './Sidebar';
export * from './Breadcrumbs';
export * from './HeaderChip';
1 change: 1 addition & 0 deletions apps/tangle-dapp/constants/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './polkadot';
16 changes: 16 additions & 0 deletions apps/tangle-dapp/constants/polkadot.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { ApiPromise, WsProvider } from '@polkadot/api';
import { TANGLE_RPC_ENDPOINT } from '@webb-tools/webb-ui-components/constants';

export const getPolkadotApi = async (
endpoint: string = TANGLE_RPC_ENDPOINT
): Promise<ApiPromise | undefined> => {
try {
const wsProvider = new WsProvider(endpoint);
const apiPromise = await ApiPromise.create({ provider: wsProvider });

return apiPromise;
} catch (e) {
console.error(e);
return undefined;
}
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { BlockIcon } from '@webb-tools/icons';
import { HeaderChip } from '../../components';
import { getEra, getSession } from '../../data';

export const HeaderChipsContainer = () => {
return (
<div className="items-center hidden gap-2 md:flex lg:gap-4">
<HeaderChip Icon={BlockIcon} label="ERA" dataFetcher={getEra} />

<HeaderChip Icon={BlockIcon} label="Session" dataFetcher={getSession} />
</div>
);
};
1 change: 1 addition & 0 deletions apps/tangle-dapp/containers/HeaderChipsContainer/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './HeaderChipsContainer';
22 changes: 11 additions & 11 deletions apps/tangle-dapp/containers/Layout/Layout.tsx
Original file line number Diff line number Diff line change
@@ -1,32 +1,32 @@
import React, { type PropsWithChildren, type FC } from 'react';
import { Footer } from '@webb-tools/webb-ui-components';
import { getSideBarStateFromCookie } from '@webb-tools/webb-ui-components/next-utils';
import { SideBar, SideBarMenu } from '../../components';
import { SideBar, SideBarMenu, Breadcrumbs } from '../../components';

const Layout: FC<PropsWithChildren> = ({ children }) => {
const isSideBarInitiallyExpanded = getSideBarStateFromCookie();

return (
<>
<SideBar isExpandedAtDefault={isSideBarInitiallyExpanded} />
<main className="flex flex-col justify-between flex-1 h-full px-3 overflow-y-auto md:px-5 lg:px-10">
<div className="flex-[1]">
{/* Header */}
<div className="flex items-center justify-between pt-6 pb-4">
<div className="flex items-center gap-2">

<main className="flex flex-col justify-between flex-1 h-full overflow-y-auto max-w-[1448px] m-auto px-10">
<div className="flex flex-col justify-between">
<div className="flex items-center justify-between py-6 mb-10">
<div className="flex items-center space-x-4 lg:space-x-0">
<SideBarMenu />
{/* Breadcrumbs will go here! */}

<Breadcrumbs />
</div>

{/* Wallet connection will go here! */}
{/* Wallet Connection */}
<div></div>
</div>

{/* Body */}
{children}
</div>

{/* Footer */}
<Footer isMinimal className="py-12 mx-0 max-w-none" />
<Footer isMinimal className="py-8" />
</main>
</>
);
Expand Down
18 changes: 18 additions & 0 deletions apps/tangle-dapp/data/HeaderChips/getEra.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { getPolkadotApi } from '../../constants';

export const getEra = async (): Promise<number> => {
const api = await getPolkadotApi();

if (!api) return NaN;

try {
let activeEra = await api.query.staking.activeEra();
activeEra = JSON.parse(JSON.stringify(activeEra)).index;

return Number(activeEra.toString());
} catch (e: any) {
console.error(e);

return 0;
}
};
18 changes: 18 additions & 0 deletions apps/tangle-dapp/data/HeaderChips/getSession.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { getPolkadotApi } from '../../constants';

export const getSession = async (): Promise<number> => {
const api = await getPolkadotApi();

if (!api) return NaN;

try {
const currentDKGPublicKey: any = await api.query.dkg.dkgPublicKey();
const currentSessionNumber = currentDKGPublicKey[0];

return Number(currentSessionNumber.toString());
} catch (e: any) {
console.error(e);

return 0;
}
};
2 changes: 2 additions & 0 deletions apps/tangle-dapp/data/HeaderChips/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './getEra';
export * from './getSession';
1 change: 1 addition & 0 deletions apps/tangle-dapp/data/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './HeaderChips';
8 changes: 6 additions & 2 deletions libs/webb-ui-components/src/constants/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,10 @@ export const DKG_STATS_KEYS_URL = `${DKG_STATS_URL}/#/keys`;
export const DKG_STATS_AUTHORITIES_URL = `${DKG_STATS_URL}/#/authorities`;
export const DKG_STATS_PROPOSALS_URL = `${DKG_STATS_URL}/#/proposals`;

export const TANGLE_RPC_ENDPOINT = 'wss://rpc-archive.tangle.tools';
export const SUBQUERY_ENDPOINT =
'https://standalone-subql.tangle.tools/graphql';

export const WEBB_DOC_ROUTES_RECORD = {
concepts: {
'anchor-system': {
Expand Down Expand Up @@ -203,8 +207,8 @@ export const webbNetworks: webbNetworksType[] = [
name: 'Tangle Standalone',
networkType: 'testnet',
networkNodeType: 'standalone',
subqueryEndpoint: 'https://standalone-subql.tangle.tools/graphql',
polkadotEndpoint: 'wss://rpc-archive.tangle.tools',
subqueryEndpoint: SUBQUERY_ENDPOINT,
polkadotEndpoint: TANGLE_RPC_ENDPOINT,
polkadotExplorer: TANGLE_STANDALONE_EXPLORER_URL,
avatar: '',
},
Expand Down

0 comments on commit 4ea6a42

Please sign in to comment.