1d721dc748
Co-authored-by: Dariusz Majcherczyk <dariusz.majcherczyk@gmail.com>
229 lines
6.6 KiB
TypeScript
229 lines
6.6 KiB
TypeScript
import { useState } from 'react';
|
|
import CopyToClipboard from 'react-copy-to-clipboard';
|
|
import { truncateByChars } from '@vegaprotocol/utils';
|
|
import {
|
|
VegaIcon,
|
|
VegaIconNames,
|
|
TradingButton as Button,
|
|
Intent,
|
|
TradingDropdown,
|
|
TradingDropdownTrigger,
|
|
TradingDropdownContent,
|
|
TradingDropdownRadioGroup,
|
|
TradingDropdownSeparator,
|
|
TradingDropdownItem,
|
|
TradingDropdownRadioItem,
|
|
TradingDropdownItemIndicator,
|
|
Tooltip,
|
|
} from '@vegaprotocol/ui-toolkit';
|
|
import { isBrowserWalletInstalled, type Key } from '@vegaprotocol/wallet';
|
|
import { useDialogStore, useVegaWallet } from '@vegaprotocol/wallet-react';
|
|
import { useCopyTimeout } from '@vegaprotocol/react-helpers';
|
|
import classNames from 'classnames';
|
|
import { ViewType, useSidebar } from '../sidebar';
|
|
import { useGetCurrentRouteId } from '../../lib/hooks/use-get-current-route-id';
|
|
import { useT } from '../../lib/use-t';
|
|
import { usePartyProfilesQuery } from './__generated__/PartyProfiles';
|
|
import { useProfileDialogStore } from '../../stores/profile-dialog-store';
|
|
|
|
export const VegaWalletConnectButton = ({
|
|
intent = Intent.None,
|
|
onClick,
|
|
}: {
|
|
intent?: Intent;
|
|
onClick?: () => void;
|
|
}) => {
|
|
const t = useT();
|
|
const [dropdownOpen, setDropdownOpen] = useState(false);
|
|
const openVegaWalletDialog = useDialogStore((store) => store.open);
|
|
const currentRouteId = useGetCurrentRouteId();
|
|
const setViews = useSidebar((store) => store.setViews);
|
|
const {
|
|
status,
|
|
pubKeys,
|
|
pubKey,
|
|
selectPubKey,
|
|
disconnect,
|
|
refreshKeys,
|
|
isReadOnly,
|
|
} = useVegaWallet();
|
|
|
|
const walletInstalled = isBrowserWalletInstalled();
|
|
|
|
const activeKey = pubKeys?.find((pk) => pk.publicKey === pubKey);
|
|
|
|
if (status === 'connected') {
|
|
return (
|
|
<TradingDropdown
|
|
open={dropdownOpen}
|
|
trigger={
|
|
<TradingDropdownTrigger
|
|
data-testid="manage-vega-wallet"
|
|
onClick={() => {
|
|
refreshKeys();
|
|
setDropdownOpen((x) => !x);
|
|
}}
|
|
>
|
|
<Button
|
|
size="small"
|
|
icon={<VegaIcon name={VegaIconNames.CHEVRON_DOWN} size={14} />}
|
|
>
|
|
{activeKey ? (
|
|
<>
|
|
{activeKey && (
|
|
<span className="uppercase">
|
|
{activeKey.name ? activeKey.name : t('Unnamed key')}
|
|
</span>
|
|
)}
|
|
</>
|
|
) : (
|
|
<>{'Select key'}</>
|
|
)}
|
|
</Button>
|
|
</TradingDropdownTrigger>
|
|
}
|
|
>
|
|
<TradingDropdownContent
|
|
onInteractOutside={() => setDropdownOpen(false)}
|
|
sideOffset={12}
|
|
side="bottom"
|
|
align="end"
|
|
onEscapeKeyDown={() => setDropdownOpen(false)}
|
|
>
|
|
<div className="min-w-[340px]" data-testid="keypair-list">
|
|
<KeypairRadioGroup
|
|
pubKey={pubKey}
|
|
pubKeys={pubKeys}
|
|
activeKey={activeKey?.publicKey}
|
|
onSelect={selectPubKey}
|
|
/>
|
|
<TradingDropdownSeparator />
|
|
{!isReadOnly && (
|
|
<TradingDropdownItem
|
|
data-testid="wallet-transfer"
|
|
onClick={() => {
|
|
setViews({ type: ViewType.Transfer }, currentRouteId);
|
|
setDropdownOpen(false);
|
|
}}
|
|
>
|
|
{t('Transfer')}
|
|
</TradingDropdownItem>
|
|
)}
|
|
<TradingDropdownItem data-testid="disconnect" onClick={disconnect}>
|
|
{t('Disconnect')}
|
|
</TradingDropdownItem>
|
|
</div>
|
|
</TradingDropdownContent>
|
|
</TradingDropdown>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<Button
|
|
data-testid="connect-vega-wallet"
|
|
onClick={() => {
|
|
onClick?.();
|
|
openVegaWalletDialog();
|
|
}}
|
|
size="small"
|
|
intent={intent}
|
|
icon={<VegaIcon name={VegaIconNames.ARROW_RIGHT} size={14} />}
|
|
>
|
|
<span className="whitespace-nowrap uppercase">
|
|
{walletInstalled ? t('Connect') : t('Get started')}
|
|
</span>
|
|
</Button>
|
|
);
|
|
};
|
|
|
|
const KeypairRadioGroup = ({
|
|
pubKey,
|
|
pubKeys,
|
|
activeKey,
|
|
onSelect,
|
|
}: {
|
|
pubKey: string | undefined;
|
|
pubKeys: Key[];
|
|
activeKey: string | undefined;
|
|
onSelect: (pubKey: string) => void;
|
|
}) => {
|
|
const { data } = usePartyProfilesQuery({
|
|
variables: { partyIds: pubKeys.map((pk) => pk.publicKey) },
|
|
skip: pubKeys.length <= 0,
|
|
fetchPolicy: 'cache-and-network',
|
|
});
|
|
|
|
return (
|
|
<TradingDropdownRadioGroup value={pubKey} onValueChange={onSelect}>
|
|
{pubKeys.map((pk) => {
|
|
const profile = data?.partiesProfilesConnection?.edges.find(
|
|
(e) => e.node.partyId === pk.publicKey
|
|
);
|
|
return (
|
|
<KeypairItem
|
|
key={pk.publicKey}
|
|
pk={pk}
|
|
isActive={activeKey === pk.publicKey}
|
|
alias={profile?.node.alias}
|
|
/>
|
|
);
|
|
})}
|
|
</TradingDropdownRadioGroup>
|
|
);
|
|
};
|
|
|
|
const KeypairItem = ({
|
|
pk,
|
|
isActive,
|
|
alias,
|
|
}: {
|
|
pk: Key;
|
|
alias: string | undefined;
|
|
isActive: boolean;
|
|
}) => {
|
|
const t = useT();
|
|
const [copied, setCopied] = useCopyTimeout();
|
|
const setOpen = useProfileDialogStore((store) => store.setOpen);
|
|
|
|
return (
|
|
<TradingDropdownRadioItem value={pk.publicKey}>
|
|
<div>
|
|
<div className="flex items-center gap-2">
|
|
<span>{pk.name ? pk.name : t('Unnamed key')}</span>
|
|
{' | '}
|
|
<span className="font-mono">
|
|
{truncateByChars(pk.publicKey, 3, 3)}
|
|
</span>
|
|
<CopyToClipboard text={pk.publicKey} onCopy={() => setCopied(true)}>
|
|
<button
|
|
data-testid="copy-vega-public-key"
|
|
className="relative -top-px"
|
|
onClick={(e) => e.stopPropagation()}
|
|
>
|
|
<span className="sr-only">{t('Copy')}</span>
|
|
<VegaIcon name={VegaIconNames.COPY} />
|
|
</button>
|
|
</CopyToClipboard>
|
|
{copied && <span className="text-xs">{t('Copied')}</span>}
|
|
</div>
|
|
<div
|
|
className={classNames('flex-1 mr-2 text-secondary text-sm')}
|
|
data-testid={`key-${pk.publicKey}`}
|
|
>
|
|
<Tooltip description={t('Public facing key alias. Click to edit')}>
|
|
<button
|
|
data-testid="alias"
|
|
onClick={() => setOpen(pk.publicKey)}
|
|
className="flex items-center gap-1"
|
|
>
|
|
{alias ? alias : t('No alias')}
|
|
{isActive && <VegaIcon name={VegaIconNames.EDIT} />}
|
|
</button>
|
|
</Tooltip>
|
|
</div>
|
|
</div>
|
|
<TradingDropdownItemIndicator />
|
|
</TradingDropdownRadioItem>
|
|
);
|
|
};
|