Skip to content

Commit

Permalink
Initialize Account Dashboard Page (#1811)
Browse files Browse the repository at this point in the history
Co-authored-by: vutuanlinh2k2 <[email protected]>
  • Loading branch information
AtelyPham and vutuanlinh2k2 authored Nov 2, 2023
1 parent 4b6435c commit 04cb272
Show file tree
Hide file tree
Showing 92 changed files with 2,103 additions and 962 deletions.
4 changes: 2 additions & 2 deletions apps/bridge-dapp/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import * as Sentry from '@sentry/react';
import { AppEvent, WebbProvider } from '@webb-tools/api-provider-environment';
import { WebbUIProvider } from '@webb-tools/webb-ui-components';
import { FC } from 'react';
import BridgeRoutes from './routes';
import AppRoutes from './routes';

// Singleton app event instance
export const appEvent = new AppEvent();
Expand All @@ -11,7 +11,7 @@ const App: FC = () => {
return (
<WebbUIProvider hasErrorBoudary>
<WebbProvider appEvent={appEvent} applicationName={'Webb DApp'}>
<BridgeRoutes />
<AppRoutes />
</WebbProvider>
</WebbUIProvider>
);
Expand Down
95 changes: 95 additions & 0 deletions apps/bridge-dapp/src/components/Header/ActiveChainDropdown.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import { DropdownMenuTrigger as DropdownButton } from '@radix-ui/react-dropdown-menu';
import { useWebContext } from '@webb-tools/api-provider-environment/webb-context/webb-context';
import type { ChainConfig } from '@webb-tools/dapp-config/chains/chain-config.interface';
import getChainFromConfig from '@webb-tools/dapp-config/utils/getChainFromConfig';
import { WebbError, WebbErrorCodes } from '@webb-tools/dapp-types/WebbError';
import { ChainIcon } from '@webb-tools/icons/ChainIcon';
import { calculateTypedChainId } from '@webb-tools/sdk-core/typed-chain-id';
import {
Dropdown,
DropdownBody,
} from '@webb-tools/webb-ui-components/components/Dropdown';
import { MenuItem } from '@webb-tools/webb-ui-components/components/MenuItem';
import { ScrollArea } from '@webb-tools/webb-ui-components/components/ScrollArea';
import ChainButtonCmp from '@webb-tools/webb-ui-components/components/buttons/ChainButton';
import { useWebbUI } from '@webb-tools/webb-ui-components/hooks/useWebbUI';
import { useCallback, useMemo } from 'react';
import useChainsFromRoute from '../../hooks/useChainsFromRoute';
import { useConnectWallet } from '../../hooks/useConnectWallet';

const ActiveChainDropdown = () => {
const { activeChain, activeWallet, apiConfig, switchChain, loading } =
useWebContext();
const { toggleModal } = useConnectWallet();
const { srcTypedChainId } = useChainsFromRoute();
const { notificationApi } = useWebbUI();

const chain = useMemo(() => {
if (activeChain) {
return activeChain;
}

// Default to the chain from route if no active chain
if (typeof srcTypedChainId === 'number' && activeChain !== null) {
return apiConfig.chains[srcTypedChainId];
}
}, [activeChain, apiConfig.chains, srcTypedChainId]);

const selectableChains = useMemo(
() => apiConfig.getSupportedChains({ withEnv: true }),
[apiConfig]
);

const handleSelectChain = useCallback(
async (chainCfg: ChainConfig) => {
const chain = getChainFromConfig(chainCfg);

if (!activeWallet || !chain.wallets.includes(activeWallet.id)) {
toggleModal(true, calculateTypedChainId(chain.chainType, chain.id));
} else {
const api = await switchChain(chain, activeWallet);
if (!api) {
notificationApi.addToQueue({
variant: 'error',
message: WebbError.getErrorMessage(WebbErrorCodes.SwitchChainFailed)
.message,
});
}
}
},
[activeWallet, notificationApi, switchChain, toggleModal]
);

return (
<Dropdown>
<DropdownButton asChild disabled={loading}>
<ChainButtonCmp
chain={chain}
status="success"
placeholder={activeChain === null ? 'Unsupported Chain' : undefined}
textClassname="hidden lg:!block"
/>
</DropdownButton>
<DropdownBody className="mt-2">
<ScrollArea className="h-[var(--dropdown-height)]">
<ul>
{selectableChains.map((chain) => {
return (
<li key={`${chain.chainType}-${chain.id}`}>
<MenuItem
startIcon={<ChainIcon size="lg" name={chain.name} />}
onSelect={() => handleSelectChain(chain)}
>
{chain.name}
</MenuItem>
</li>
);
})}
</ul>
</ScrollArea>
</DropdownBody>
</Dropdown>
);
};

export default ActiveChainDropdown;
37 changes: 0 additions & 37 deletions apps/bridge-dapp/src/components/Header/ChainButton.tsx

This file was deleted.

27 changes: 16 additions & 11 deletions apps/bridge-dapp/src/components/Header/Header.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useWebContext } from '@webb-tools/api-provider-environment';
import { ContrastTwoLine, WebbLogoIcon } from '@webb-tools/icons';
import { WebbLogoIcon } from '@webb-tools/icons';
import {
Breadcrumbs,
BreadcrumbsItem,
Expand All @@ -23,21 +23,22 @@ import {
WEBB_MKT_URL,
} from '@webb-tools/webb-ui-components/constants';
import {
type ComponentProps,
type FC,
useCallback,
useEffect,
useState,
useMemo,
useState,
type ComponentProps,
type FC,
} from 'react';
import { NavLink, useLocation } from 'react-router-dom';
import sidebarProps from '../../constants/sidebar';
import { BREADCRUMBS_RECORD } from '../../constants/breadcrumb';
import useChainsFromRoute from '../../hooks/useChainsFromRoute';
import { useConnectWallet } from '../../hooks/useConnectWallet';
import useSidebarProps from '../../hooks/useSidebarProps';
import ActiveChainDropdown from './ActiveChainDropdown';
import TxProgressDropdown from './TxProgressDropdown';
import { WalletDropdown } from './WalletDropdown';
import { HeaderProps } from './types';
import ChainButton from './ChainButton';

/**
* The statistic `Header` for `Layout` container
Expand All @@ -55,17 +56,21 @@ export const Header: FC<HeaderProps> = () => {

const items = location.pathname.split('/').filter((item) => item !== '');

const sidebarProps = useSidebarProps();

const breadcrumbItems = useMemo(
() =>
items.map((item, index) => {
const preCfgBreadcrumb = BREADCRUMBS_RECORD[item];

return (
<NavLink key={index} to={'/'}>
<NavLink key={index} to={item}>
<BreadcrumbsItem
isLast={index === items.length - 1}
icon={index === 0 ? <ContrastTwoLine size="lg" /> : undefined}
icon={preCfgBreadcrumb?.Icon}
className="capitalize"
>
{index === 0 ? `Hubble ${item}` : item.split('-').join(' ')}
{preCfgBreadcrumb?.label ?? item.split('-').join(' ')}
</BreadcrumbsItem>
</NavLink>
);
Expand Down Expand Up @@ -98,7 +103,7 @@ export const Header: FC<HeaderProps> = () => {
<TxProgressDropdown />

<div className="flex items-center space-x-2">
<ChainButton />
<ActiveChainDropdown />
{isConnecting || loading || !activeWallet || !activeAccount ? (
isMobile ? (
<ConnectWalletMobileButton />
Expand All @@ -109,7 +114,7 @@ export const Header: FC<HeaderProps> = () => {
onClick={() =>
toggleModal(true, srcTypedChainId ?? undefined)
}
className="flex justify-center items-center px-6"
className="flex items-center justify-center px-6"
>
Connect
</Button>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,15 @@ import { getExplorerURI } from '@webb-tools/api-provider-environment/transaction
import { useWebContext } from '@webb-tools/api-provider-environment/webb-context';
import TxProgressor from '@webb-tools/webb-ui-components/components/TxProgressor';
import type { TxInfo } from '@webb-tools/webb-ui-components/components/TxProgressor/types';
import type { ButtonProps } from '@webb-tools/webb-ui-components/components/buttons/types';
import type { TransactionItemStatus } from '@webb-tools/webb-ui-components/containers/TransactionProgressCard/types';
import type { FC } from 'react';
import { NOTE_ACCOUNT_PATH } from '../../../constants/paths';

const TxItem: FC<{ tx: Transaction<unknown> }> = ({ tx }) => {
const TxItem: FC<{ tx: Transaction<unknown>; isOnAccountPage?: boolean }> = ({
tx,
isOnAccountPage,
}) => {
const { activeApi, apiConfig, txQueue } = useWebContext();
const { api } = txQueue;

Expand Down Expand Up @@ -48,12 +53,17 @@ const TxItem: FC<{ tx: Transaction<unknown> }> = ({ tx }) => {

const externalUrl = getExternalUrl(blockExplorer, activeApi?.type, tx.txHash);

const btnProps = {
onClick: () => {
api.dismissTransaction(tx.id);
},
children: 'Dismiss',
};
const btnProps = isOnAccountPage
? ({
onClick: () => {
api.dismissTransaction(tx.id);
},
children: 'Dismiss',
} satisfies ButtonProps)
: ({
href: `/#/${NOTE_ACCOUNT_PATH}`,
children: 'View Account',
} satisfies ButtonProps);

return (
<TxProgressor.Root key={tx.id}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,14 @@ import LoadingPill from '@webb-tools/webb-ui-components/components/buttons/Loadi
import type { LoadingPillStatus } from '@webb-tools/webb-ui-components/components/buttons/types';
import type { TransactionItemStatus } from '@webb-tools/webb-ui-components/containers/TransactionProgressCard';
import { useEffect, useMemo, useState } from 'react';
import { useLocation } from 'react-router';
import { NOTE_ACCOUNT_PATH } from '../../../constants/paths';
import useCurrentTx from '../../../hooks/useCurrentTx';
import TxItem from './TxItem';

const TxProgressDropdown = () => {
const { txQueue: txQueue_ } = useWebContext();
const { pathname } = useLocation();

const { txQueue, currentTxId } = txQueue_;

Expand All @@ -25,6 +28,11 @@ const TxProgressDropdown = () => {

const currentTx = useCurrentTx(sortedTxQueue, currentTxId, { latest: true });

const isOnAccountPage = useMemo(
() => pathname.includes(`/${NOTE_ACCOUNT_PATH}`),
[pathname]
);

useEffect(() => {
if (!currentTx) {
return;
Expand Down Expand Up @@ -56,7 +64,9 @@ const TxProgressDropdown = () => {
className="mt-4 -ml-14 max-h-80 w-[30rem] overflow-scroll overflow-x-hidden"
>
{sortedTxQueue.map((tx) => {
return <TxItem key={tx.id} tx={tx} />;
return (
<TxItem key={tx.id} tx={tx} isOnAccountPage={isOnAccountPage} />
);
})}
</DropdownBody>
</Dropdown>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import { useWebContext } from '@webb-tools/api-provider-environment/webb-context';
import { useMemo } from 'react';
import cx from 'classnames';
import { IconWithTooltip } from '@webb-tools/webb-ui-components/components/IconWithTooltip';
import { Avatar } from '@webb-tools/webb-ui-components/components/Avatar';
import { KeyValueWithButton } from '@webb-tools/webb-ui-components/components/KeyValueWithButton';
import { InformationLine } from '@webb-tools/icons/InformationLine';
import { Typography } from '@webb-tools/webb-ui-components/typography/Typography';
import cx from 'classnames';
import { useMemo } from 'react';
import { NOTE_ACCOUNT_DOCS_URL } from '../../../constants/links';
import NoteAccountAvatarWithKey from '../../NoteAccountAvatarWithKey';

const NoteAccountKey = () => {
const { noteManager } = useWebContext();
Expand All @@ -28,21 +26,11 @@ const NoteAccountKey = () => {
)}
>
{keyPairStr ? (
<>
<IconWithTooltip
icon={<Avatar value={keyPairStr} theme="ethereum" />}
content="Note account"
/>

<KeyValueWithButton
className="mt-0.5"
label="Public Key:"
keyValue={keyPairStr}
size="sm"
labelVariant="body1"
valueVariant="body1"
/>
</>
<NoteAccountAvatarWithKey
keyValue={keyPairStr}
label="Public Key:"
iconTooltipContent="Note account public key"
/>
) : (
<>
<div className="p-1 !text-inherit">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,11 +93,11 @@ export const WalletDropdown: FC<{ account: Account; wallet: WalletConfig }> = ({
<WalletButton
wallet={wallet}
address={account.address}
addressClassname="hidden lg:block"
addressClassname="hidden lg:!block"
/>
</DropdownTrigger>

<DropdownBody className="mt-6 w-[480px] p-4 space-y-4 dark:bg-mono-160">
<DropdownBody className="mt-2 w-[480px] p-4 space-y-4 dark:bg-mono-160">
<div className="flex items-center justify-between">
<div className="flex space-x-2">
{wallet.Logo}
Expand Down
23 changes: 23 additions & 0 deletions apps/bridge-dapp/src/components/HiddenValue.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import useHiddenValue from '../hooks/useHiddenValue';

function HiddenValue(props: {
/** The children must be a string */
children: string;

/** Number of star to display. @default to children.length */
numberOfStars?: number;
}) {
const { numberOfStars } = props;

const [isHidden] = useHiddenValue();

if (isHidden) {
return Array.from({ length: numberOfStars ?? props.children.length })
.map(() => '*')
.join('');
}

return props.children;
}

export default HiddenValue;
Loading

0 comments on commit 04cb272

Please sign in to comment.