Skip to content

Commit

Permalink
Make the issuer's address copyable similar to vault address and memo …
Browse files Browse the repository at this point in the history
…(Spacewalk)

* extract ClickablePublicKey component from PublicKey

* extract CopyablePublicKey component from PublicKey

* refactor PublicKey component

* lint css classes CloseButton

* update component name from CopyableAddress to CopyablePublicKey
  • Loading branch information
Sharqiewicz committed Sep 6, 2024
1 parent 92533dc commit 6d823aa
Show file tree
Hide file tree
Showing 14 changed files with 182 additions and 194 deletions.
2 changes: 1 addition & 1 deletion src/components/CloseButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export const CloseButton = (props: ButtonProps) => (
color="ghost"
size="sm"
shape="circle"
className="text-xl font-thin !leading-5 w-[2.25rem] h-[2.25rem]"
className="h-[2.25rem] w-[2.25rem] text-xl font-thin !leading-5"
style={{ color: 'var(--secondary)' }}
type="button"
{...props}
Expand Down
32 changes: 32 additions & 0 deletions src/components/PublicKey/ClickablePublicKey/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { CSSProperties } from 'preact/compat';
import { Button } from 'react-daisyui';
import { FormatPublicKeyVariant, PublicKey } from '..';

export interface ClickablePublicKeyProps {
publicKey: string;
variant?: FormatPublicKeyVariant;
inline?: boolean;
style?: CSSProperties;
className?: string;
icon?: JSX.Element;
onClick?: () => void;
wrap?: boolean;
}

export const ClickablePublicKey = (props: ClickablePublicKeyProps) => (
<Button
className="m-0 h-1 rounded p-1"
style={props.inline ? { height: 'inherit', minHeight: '0', padding: 0 } : {}}
color="ghost"
type="button"
onClick={props.onClick}
>
{props.icon ? (
<>
{props.icon}
&nbsp;
</>
) : null}
<PublicKey {...props} />
</Button>
);
21 changes: 21 additions & 0 deletions src/components/PublicKey/CopyablePublicKey/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { ClickablePublicKey, ClickablePublicKeyProps } from '../ClickablePublicKey';
import { useClipboard } from '../../../hooks/useClipboard';
import CopyIcon from '../../../assets/CopyIcon';

interface CopyablePublicKeyProps extends ClickablePublicKeyProps {
onClick?: () => void;
publicKey: string;
}

export const CopyablePublicKey = ({ onClick, publicKey, ...props }: CopyablePublicKeyProps) => {
const clipboard = useClipboard();

const handleClick = () => {
onClick && onClick();
clipboard.copyToClipboard(publicKey);
};

return (
<ClickablePublicKey {...{ ...props, publicKey }} onClick={handleClick} icon={<CopyIcon className="w-4 h-4" />} />
);
};
121 changes: 28 additions & 93 deletions src/components/PublicKey/index.tsx
Original file line number Diff line number Diff line change
@@ -1,120 +1,55 @@
import { CSSProperties, memo, useCallback } from 'preact/compat';
import { Button } from 'react-daisyui';
import CopyIcon from '../../assets/CopyIcon';
import { useClipboard } from '../../hooks/useClipboard';
import { CSSProperties } from 'preact/compat';

type Variant = 'full' | 'short' | 'shorter' | 'hexa';
export type FormatPublicKeyVariant = 'full' | 'short' | 'shorter' | 'hexa';

function getDigitCounts(variant?: Variant) {
if (variant === 'short') {
return {
leading: 6,
trailing: 6,
};
} else if (variant === 'hexa') {
return {
leading: 10,
trailing: 10,
};
} else {
return {
leading: 4,
trailing: 4,
};
}
const digitCounts: Record<FormatPublicKeyVariant, { leading: number; trailing: number }> = {
full: { leading: 4, trailing: 4 },
shorter: { leading: 4, trailing: 4 },
short: { leading: 6, trailing: 6 },
hexa: { leading: 10, trailing: 10 },
};

function getDigitCounts(variant: FormatPublicKeyVariant = 'full') {
return digitCounts[variant];
}

export function shortenName(name: string, intendedLength: number) {
if (name.length <= intendedLength) {
return name;
} else {
return (
name.substr(0, intendedLength - 3).trim() +
'…' +
name
.substr(intendedLength - 3)
.substr(-3)
.trim()
);
}
return (
name.substring(0, intendedLength - 3).trim() +
'…' +
name
.substring(intendedLength - 3)
.slice(-3)
.trim()
);
}

interface PublicKeyProps {
publicKey: string;
variant?: Variant;
variant?: FormatPublicKeyVariant;
style?: CSSProperties;
className?: string;
showRaw?: boolean;
}

// tslint:disable-next-line no-shadowed-variable
export const PublicKey = memo(function PublicKey(props: PublicKeyProps) {
const { variant = 'full', className } = props;
const digits = getDigitCounts(props.variant);
export function PublicKey({ publicKey, variant = 'full', style, className }: PublicKeyProps) {
const digits = getDigitCounts(variant);

const style: CSSProperties = {
const spanStyle: CSSProperties = {
userSelect: 'text',
WebkitUserSelect: 'text',
whiteSpace: variant !== 'full' ? 'pre' : undefined,
...props.style,
...style,
};

return (
<span style={style} className={className}>
{props.variant === 'full' || !props.variant
? props.publicKey
: props.publicKey.substr(0, digits.leading) + '…' + props.publicKey.substr(-digits.trailing)}
<span style={spanStyle} className={className}>
{variant === 'full'
? publicKey
: publicKey.substring(0, digits.leading) + '…' + publicKey.substring(publicKey.length - digits.trailing)}
</span>
);
});

interface AddressProps {
publicKey: string;
variant?: Variant;
inline?: boolean;
style?: CSSProperties;
className?: string;
icon?: JSX.Element;
onClick?: () => void;
wrap?: boolean;
}

// tslint:disable-next-line no-shadowed-variable
export const ClickableAddress = memo(function ClickableAddress(props: AddressProps) {
return (
<Button
className="h-1 p-1 m-0 rounded"
style={props.inline ? { height: 'inherit', minHeight: '0', padding: 0 } : {}}
color="ghost"
type="button"
onClick={props.onClick}
>
{props.icon ? (
<>
{props.icon}
&nbsp;
</>
) : null}
<PublicKey {...props} />
</Button>
);
});

interface CopyableAddressProps extends AddressProps {
onClick?: () => void;
}

// tslint:disable-next-line no-shadowed-variable
export const CopyableAddress = memo(function CopyableAddress(props: CopyableAddressProps) {
const { onClick } = props;
const clipboard = useClipboard();

const handleClick = useCallback(() => {
if (onClick) {
onClick();
}
clipboard.copyToClipboard(props.publicKey);
}, [clipboard, onClick, props.publicKey]);

return <ClickableAddress {...props} onClick={handleClick} icon={<CopyIcon className="w-4 h-4" />} />;
});
14 changes: 7 additions & 7 deletions src/components/Wallet/modals/DisconnectModal/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { getAddressForFormat } from '../../../../helpers/addressFormatter';
import { useNodeInfoState } from '../../../../NodeInfoProvider';
import { useAccountBalance } from '../../../../shared/useAccountBalance';
import { useGlobalState } from '../../../../GlobalStateProvider';
import { CopyableAddress } from '../../../PublicKey';
import { CopyablePublicKey } from '../../../PublicKey/CopyablePublicKey';
import { Skeleton } from '../../../Skeleton';

interface WalletButtonProps {
Expand All @@ -23,18 +23,18 @@ const WalletButton = ({ wallet, query, balance, tokenSymbol, walletAccount }: Wa
<Button
size="sm"
color="ghost"
className="text-sm border-base-300 border-1 bg-base-200 min-h-[2.1rem] h-auto px-5 sm:px-3 overflow-hidden ellipsis max-w36 sm:max-w-fit"
className="border-1 ellipsis max-w36 h-auto min-h-[2.1rem] overflow-hidden border-base-300 bg-base-200 px-5 text-sm sm:max-w-fit sm:px-3"
title={wallet?.title}
type="button"
>
{query.isLoading ? (
<Skeleton className="bg-[rgba(0,0,0,.06)] px-2 py-1 mr-2 hidden sm:flex">10000.00 TKN</Skeleton>
<Skeleton className="mr-2 hidden bg-[rgba(0,0,0,.06)] px-2 py-1 sm:flex">10000.00 TKN</Skeleton>
) : (
<span className="items-center bg-[rgba(0,0,0,.06)] px-2 py-0.5 mr-2 rounded-lg hidden sm:flex">
<span className="mr-2 hidden items-center rounded-lg bg-[rgba(0,0,0,.06)] px-2 py-0.5 sm:flex">
{balance} {tokenSymbol}
</span>
)}
<p className="hidden sm:block truncate">{walletAccount?.name}</p>
<p className="hidden truncate sm:block">{walletAccount?.name}</p>
<img src={wallet?.logo?.src || ''} className="w-[20px] sm:ml-2" alt={wallet?.logo?.alt || ''} />
</Button>
);
Expand All @@ -56,10 +56,10 @@ const WalletDropdownMenu = ({
tokenSymbol,
removeWalletAccount,
}: WalletDropdownMenuProps) => (
<Dropdown.Menu className="text-center border border-base-300 bg-base-200 shadow-lg min-w-[240px] p-3 mt-2 right-0">
<Dropdown.Menu className="right-0 mt-2 min-w-[240px] border border-base-300 bg-base-200 p-3 text-center shadow-lg">
<div className="text-sm text-neutral-400">{walletAccount?.name}</div>
<div className="text-neutral-500">
<CopyableAddress
<CopyablePublicKey
publicKey={ss58Format ? getAddressForFormat(address, ss58Format) : address}
variant="short"
inline={true}
Expand Down
18 changes: 9 additions & 9 deletions src/pages/spacewalk/bridge/Issue/ConfirmationDialog.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useMemo } from 'preact/compat';
import { useMemo } from 'preact/hooks';
import { Button, Divider } from 'react-daisyui';

import { CopyableAddress, PublicKey } from '../../../../components/PublicKey';
import { CopyablePublicKey } from '../../../../components/PublicKey/CopyablePublicKey';
import TransferCountdown from '../../../../components/TransferCountdown';
import { convertCurrencyToStellarAsset, deriveShortenedRequestId } from '../../../../helpers/spacewalk';
import { convertRawHexKeyToPublicKey } from '../../../../helpers/stellar';
Expand Down Expand Up @@ -67,17 +67,17 @@ export function ConfirmationDialog(props: ConfirmationDialogProps): JSX.Element
<div className="text-xl">
Send {totalAmount} {asset?.getCode()}
</div>
<div className="text-sm">
<div className="flex items-center justify-center text-sm">
{asset && asset.getIssuer() && (
<>
issued by <PublicKey variant="short" publicKey={asset?.getIssuer()} />
<p>issued by</p> <CopyablePublicKey variant="short" publicKey={asset?.getIssuer()} />
</>
)}
</div>
<div className="text mt-4">With the text memo</div>
{issueRequest && <CopyableAddress variant="short" publicKey={expectedStellarMemo} />}
<div className="text mt-4">In a single transaction to</div>
<CopyableAddress variant="short" publicKey={destination} />
<div className="mt-4 text">With the text memo</div>
{issueRequest && <CopyablePublicKey variant="short" publicKey={expectedStellarMemo} />}
<div className="mt-4 text">In a single transaction to</div>
<CopyablePublicKey variant="short" publicKey={destination} />

<StellarUriScheme transactionURIScheme={transactionURIScheme} />

Expand All @@ -93,7 +93,7 @@ export function ConfirmationDialog(props: ConfirmationDialogProps): JSX.Element
)}
</div>

<div className="text-sm mt-4">Note:</div>
<div className="mt-4 text-sm">Note:</div>
<ul className="text-sm list-disc list-inside">
<li className="mt-1">
Stellar transactions require memos for accurate processing. Failure to include the transaction memo may
Expand Down
12 changes: 6 additions & 6 deletions src/pages/spacewalk/bridge/Redeem/ConfirmationDialog.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { Button } from 'react-daisyui';
import { useNavigate } from 'react-router-dom';
import { useMemo } from 'preact/hooks';
import { useGlobalState } from '../../../../GlobalStateProvider';
import { PublicKey } from '../../../../components/PublicKey';
import { convertCurrencyToStellarAsset } from '../../../../helpers/spacewalk';
import { RichRedeemRequest } from '../../../../hooks/spacewalk/useRedeemPallet';
import { nativeStellarToDecimal } from '../../../../shared/parseNumbers/metric';
import { Dialog } from '../../../../components/Dialog';
import { useMemo } from 'preact/hooks';
import { PENDULUM_SUPPORT_CHAT_URL } from '../../../../shared/constants';
import { PAGES_PATHS } from '../../../../app';

Expand All @@ -33,14 +33,14 @@ export function ConfirmationDialog(props: ConfirmationDialogProps): JSX.Element
You will receive {totalAmount} {asset?.getCode()}
</div>
{asset && asset.getIssuer() && (
<>
issued by <PublicKey variant="short" publicKey={asset?.getIssuer()} />
</>
<div className="flex items-center justify-center text-sm">
<div>issued by</div> <PublicKey variant="short" publicKey={asset?.getIssuer()} />
</div>
)}
<div className="text-sm mt-4">Your request is being processed</div>
<div className="mt-4 text-sm">Your request is being processed</div>
</div>
<div className="mt-6">
<div className="text-sm mt-2 text-center">
<div className="mt-2 text-sm text-center">
This typically takes only a few minutes. Contact
<a href={PENDULUM_SUPPORT_CHAT_URL} target="_blank" rel="noreferrer" className="mx-1 text-primary">
support
Expand Down
Loading

0 comments on commit 6d823aa

Please sign in to comment.