Skip to content

Commit

Permalink
feat(ui-ux): display preferred label and customize wallet list order (#…
Browse files Browse the repository at this point in the history
…350)

* add prefer and custom wallet order

* revert checking for build

* refactor to use wallet[] for orders

* refactor to use order

* remove redundant sort
  • Loading branch information
JoshuaC817 authored Aug 23, 2024
1 parent aef8953 commit 9b44b29
Show file tree
Hide file tree
Showing 5 changed files with 168 additions and 67 deletions.
3 changes: 3 additions & 0 deletions packages/ord-connect/src/SampleApp.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
Network,
OrdConnectProvider,
useOrdConnect,
Wallet,
} from "./providers/OrdConnectProvider";
import { OrdConnectKit, useSign } from "./index";

Expand Down Expand Up @@ -117,6 +118,8 @@ export function SampleApp() {
<OrdConnectProvider initialNetwork={Network.TESTNET}>
<OrdConnectKit
onViewProfile={() => console.log("View profile clicked")}

Check warning on line 120 in packages/ord-connect/src/SampleApp.tsx

View workflow job for this annotation

GitHub Actions / Lint - Typescript and ESLint

Unexpected console statement
preferredWallet={Wallet.XVERSE}
walletsOrder={[Wallet.XVERSE, Wallet.MAGICEDEN, Wallet.OKX]}
/>
<TestControls />
</OrdConnectProvider>
Expand Down
10 changes: 9 additions & 1 deletion packages/ord-connect/src/components/OrdConnectKit.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { ReactNode } from "react";

import useHasMounted from "../hooks/useHasMounted";
import { useOrdConnect } from "../providers/OrdConnectProvider";
import { useOrdConnect, Wallet } from "../providers/OrdConnectProvider";

import { PostConnectButton } from "./PostConnectButton";
import { PreConnectButton } from "./PreConnectButton";
Expand All @@ -15,6 +15,8 @@ export interface OrdConnectKitProp {
onChangeWalletClick?: () => void;
onDisconnectWalletClick?: () => void;
renderAvatar?: (address: string, size: "large" | "small") => ReactNode;
preferredWallet?: Wallet;
walletsOrder?: Wallet[];
}

/**
Expand All @@ -27,6 +29,8 @@ export interface OrdConnectKitProp {
* @param {Function} [props.onViewProfile] - Callback function to handle clicking view wallet profile.
* @param {Function} [props.onChangeWalletClick] - Callback function to handle clicking change wallet.
* @param {Function} [props.onDisconnectWalletClick] - Callback function to handle clicking disconnect wallet.
* @param {Wallet} [props.preferredWallet] - Displays "Preferred" label beside desired wallet.
* @param {Wallet[]} [props.walletsOrder] - Customize wallets display order in select wallet pop up.
* @returns {JSX.Element} OrdConnectKit React component.
*/
export function OrdConnectKit({
Expand All @@ -35,6 +39,8 @@ export function OrdConnectKit({
onChangeWalletClick,
onDisconnectWalletClick,
renderAvatar,
preferredWallet,
walletsOrder,
}: OrdConnectKitProp) {
const {
address,
Expand Down Expand Up @@ -80,6 +86,8 @@ export function OrdConnectKit({
isOpen={isModalOpen}
closeModal={closeModal}
renderAvatar={renderAvatar}
preferredWallet={preferredWallet}
walletsOrder={walletsOrder}
/>
) : null}
</>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const WALLET_TO_NAME: Record<Wallet, string> = {
[Wallet.OKX]: "OKX",
} as const;

interface WalletButtonProp {
export interface WalletButtonProp {
wallet: Wallet;
subtitle: string;
onConnect: () => Promise<boolean>;
Expand All @@ -23,6 +23,7 @@ interface WalletButtonProp {
isDisabled?: boolean;
isMobileDevice?: boolean;
renderAvatar?: (address: string, size: "large" | "small") => ReactNode;
isPreferred?: boolean;
}

export function WalletButton({
Expand All @@ -34,6 +35,7 @@ export function WalletButton({
isDisabled,
isMobileDevice,
renderAvatar,
isPreferred,
}: WalletButtonProp) {
const { wallet: _connectedWallet, address: _connectedAddress } =
useOrdConnect();
Expand Down Expand Up @@ -67,6 +69,9 @@ export function WalletButton({
}
}, [onConnect, setErrorMessage]);

const hasConnectedWallet =
connectedWallet === wallet && connectedAddress.ordinals;

return (
<button
type="button"
Expand Down Expand Up @@ -102,6 +107,11 @@ export function WalletButton({
</span>
</div>
) : null}

{!hasConnectedWallet && isPreferred ? (
<span className="preferred-label">Preferred</span>
) : null}

{loading ? (
<img
src={LoadingIcon}
Expand Down
199 changes: 134 additions & 65 deletions packages/ord-connect/src/components/SelectWalletModal/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
import { Fragment, ReactNode, useCallback, useEffect, useState } from "react";
import {
Fragment,
ReactNode,
useCallback,
useEffect,
useMemo,
useState,
} from "react";
import { Dialog, Transition } from "@headlessui/react";
import {
BrowserWalletNotInstalledError,
Expand All @@ -24,12 +31,19 @@ import {
import { isMobileUserAgent } from "../../utils/mobile-detector";
import { waitForUnisatExtensionReady } from "../../utils/unisat";

import { WalletButton } from "./WalletButton";
import { WalletButton, WalletButtonProp } from "./WalletButton";

interface WalletListItemProp extends WalletButtonProp {
isAvailable: boolean;
order: number;
}

interface SelectWalletModalProp {
isOpen: boolean;
closeModal: () => void;
renderAvatar?: (address: string, size: "large" | "small") => ReactNode;
preferredWallet?: Wallet;
walletsOrder?: Wallet[];
}

const WALLET_CHROME_EXTENSION_URL: Record<Wallet, string> = {
Expand All @@ -44,6 +58,8 @@ export function SelectWalletModal({
isOpen,
closeModal,
renderAvatar,
preferredWallet,
walletsOrder,
}: SelectWalletModalProp) {
const {
updateAddress,
Expand Down Expand Up @@ -396,6 +412,94 @@ export function SelectWalletModal({
};
}, [wallet, onConnectUnisatWallet, disconnectWallet]);

Check warning on line 413 in packages/ord-connect/src/components/SelectWalletModal/index.tsx

View workflow job for this annotation

GitHub Actions / Lint - Typescript and ESLint

React Hook useEffect has missing dependencies: 'address', 'format', and 'publicKey'. Either include them or remove the dependency array

Check warning on line 413 in packages/ord-connect/src/components/SelectWalletModal/index.tsx

View workflow job for this annotation

GitHub Actions / Build (Apps & Packages)

React Hook useEffect has missing dependencies: 'address', 'format', and 'publicKey'. Either include them or remove the dependency array

Check warning on line 413 in packages/ord-connect/src/components/SelectWalletModal/index.tsx

View workflow job for this annotation

GitHub Actions / NPM

React Hook useEffect has missing dependencies: 'address', 'format', and 'publicKey'. Either include them or remove the dependency array

const orderedWalletList = useMemo<WalletListItemProp[]>(() => {
const walletList: WalletListItemProp[] = [
{
wallet: Wallet.OKX,
subtitle: "Available on OKX app",
onConnect: onConnectOKXWallet,
icon: OKXWalletIcon,
setErrorMessage,
isMobileDevice: isMobile,
renderAvatar,
isAvailable: !isMobile || (isMobile && network === Network.MAINNET),
order: 20,
},
{
wallet: Wallet.UNISAT,
subtitle: "Coming soon on mobile browsing",
onConnect: onConnectUnisatWallet,
icon: UnisatWalletIcon,
setErrorMessage,
isMobileDevice: isMobile,
renderAvatar,
isAvailable: !isMobile,
order: 21,
},
{
wallet: Wallet.XVERSE,
subtitle: "Available on Xverse app",
onConnect: onConnectXverseWallet,
icon: XverseWalletIcon,
setErrorMessage,
isMobileDevice: isMobile,
renderAvatar,
isAvailable: true,
order: 22,
},
{
wallet: Wallet.MAGICEDEN,
subtitle: "Coming soon on mobile browsing",
onConnect: onConnectMagicEdenWallet,
icon: MagicEdenWalletIcon,
setErrorMessage,
isDisabled: isMobile,
isMobileDevice: isMobile,
renderAvatar,
isAvailable: !isMobile,
order: 23,
},
{
wallet: Wallet.LEATHER,
subtitle: "Coming soon on mobile browsing",
onConnect: onConnectLeatherWallet,
icon: LeatherWalletIcon,
setErrorMessage,
isDisabled: isMobile,
isMobileDevice: isMobile,
renderAvatar,
isAvailable: !isMobile,
order: 24,
},
];

if (!walletsOrder) {
return walletList;
}

const updatedList = walletList.map((walletItem) => {
const foundIndex = walletsOrder.findIndex(
(data) => data === walletItem.wallet,
);
if (foundIndex >= 0) {
return { ...walletItem, order: foundIndex };
}
return walletItem;
});

return updatedList.sort((a, b) => a.order - b.order);
}, [
walletsOrder,
isMobile,
network,
onConnectLeatherWallet,
onConnectMagicEdenWallet,
onConnectOKXWallet,
onConnectUnisatWallet,
onConnectXverseWallet,
renderAvatar,
]);

return (
<Transition appear show={isOpen} as={Fragment}>
<Dialog
Expand Down Expand Up @@ -442,69 +546,34 @@ export function SelectWalletModal({

<section className="panel-content-container">
<section className="panel-content-inner-container">
{!isMobile || (isMobile && network === Network.MAINNET) ? (
<>
<WalletButton
wallet={Wallet.OKX}
subtitle="Available on OKX app"
onConnect={onConnectOKXWallet}
icon={OKXWalletIcon}
setErrorMessage={setErrorMessage}
isMobileDevice={isMobile}
renderAvatar={renderAvatar}
/>
<hr className="horizontal-separator" />
</>
) : null}
{!isMobile && ( // TODO: remove this once unisat supported on mobile devices
<>
<WalletButton
wallet={Wallet.UNISAT}
subtitle="Coming soon on mobile browsing"
onConnect={onConnectUnisatWallet}
icon={UnisatWalletIcon}
setErrorMessage={setErrorMessage}
isDisabled={isMobile} // disable unisat on mobile until it is supported
isMobileDevice={isMobile}
renderAvatar={renderAvatar}
/>
<hr className="horizontal-separator" />
</>
)}
<WalletButton
wallet={Wallet.XVERSE}
subtitle="Available on Xverse app"
onConnect={onConnectXverseWallet}
icon={XverseWalletIcon}
setErrorMessage={setErrorMessage}
isMobileDevice={isMobile}
renderAvatar={renderAvatar}
/>
{!isMobile && (
<>
<hr className="horizontal-separator" />
<WalletButton
wallet={Wallet.MAGICEDEN}
subtitle="Coming soon on mobile browsing"
onConnect={onConnectMagicEdenWallet}
icon={MagicEdenWalletIcon}
setErrorMessage={setErrorMessage}
isDisabled={isMobile}
isMobileDevice={isMobile}
renderAvatar={renderAvatar}
/>
<hr className="horizontal-separator" />
<WalletButton
wallet={Wallet.LEATHER}
subtitle="Coming soon on mobile browsing"
onConnect={onConnectLeatherWallet}
icon={LeatherWalletIcon}
setErrorMessage={setErrorMessage}
isDisabled={isMobile}
isMobileDevice={isMobile}
renderAvatar={renderAvatar}
/>
</>
{orderedWalletList.map(
(walletItem: WalletListItemProp, index: number) => {
if (!walletItem.isAvailable) {
return null;
}

const isLastItem =
index === orderedWalletList.length - 1;
return (
<>
<WalletButton
wallet={walletItem.wallet}
subtitle={walletItem.subtitle}
onConnect={walletItem.onConnect}
icon={walletItem.icon}
setErrorMessage={walletItem.setErrorMessage}
isMobileDevice={walletItem.isMobileDevice}
renderAvatar={walletItem.renderAvatar}
isPreferred={
preferredWallet === walletItem.wallet
}
/>
{!isLastItem && (
<hr className="horizontal-separator" />
)}
</>
);
},
)}
</section>
<p className="error-message">{errorMessage}</p>
Expand Down
11 changes: 11 additions & 0 deletions packages/ord-connect/src/components/SelectWalletModal/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -283,3 +283,14 @@
font-size: 14px;
line-height: 20px;
}

.ord-connect-wallet-modal .preferred-label {
padding: 4px 12px 4px 12px;
color: #000000b2;
background-color: #ffbf18;
font-size: 12px;
line-height: 14px;
font-weight: 400;
border-radius: 100px;
margin-right: 10px;
}

0 comments on commit 9b44b29

Please sign in to comment.