Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Transfer Module - Part 2 #1131

Merged
merged 7 commits into from
Sep 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions apps/namadillo/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"private": true,
"dependencies": {
"@anomaorg/namada-indexer-client": "0.0.23",
"@chain-registry/client": "^1.48.80",
"@cosmjs/encoding": "^0.32.3",
"@tailwindcss/container-queries": "^0.1.1",
"@tanstack/query-core": "^5.40.0",
Expand Down
18 changes: 13 additions & 5 deletions apps/namadillo/src/App/Common/SelectModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,39 @@ import { Modal } from "@namada/components";
import clsx from "clsx";
import React from "react";
import { IoClose } from "react-icons/io5";
import { twMerge } from "tailwind-merge";
import { ModalTransition } from "./ModalTransition";

type SelectModalProps = {
children: React.ReactNode;
title: React.ReactNode;
onClose: () => void;
};
} & React.ComponentPropsWithoutRef<"div">;

export const SelectModal = ({
children,
title,
onClose,
className,
...props
}: SelectModalProps): JSX.Element => {
return (
<Modal onClose={onClose}>
<ModalTransition>
<div
className={clsx(
"px-3 pt-2 pb-6 bg-rblack max-w-[400px] min-h-[120px] w-screen rounded-xl border border-neutral-700"
className={twMerge(
clsx(
"px-8 pt-3 pb-6 bg-rblack max-w-[480px] min-h-[120px]",
"w-screen rounded-xl border border-neutral-700"
),
className
)}
{...props}
>
<header className="flex w-full justify-center items-center relative mb-4 text-light leading-8">
<header className="flex w-full justify-center items-center relative mb-6 text-light leading-8">
{title}
<i
className="cursor-pointer text-white absolute right-0 text-xl p-1.5 hover:text-yellow z-50"
className="cursor-pointer text-white absolute -right-2.5 text-xl p-1.5 hover:text-yellow z-50"
onClick={onClose}
>
<IoClose />
Expand Down
40 changes: 20 additions & 20 deletions apps/namadillo/src/App/Common/TabSelector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,25 +18,25 @@ export const TabSelector = ({
onChange,
}: TabSelectorProps): JSX.Element => {
return (
<nav>
<ul className="flex">
{items.map((item) => (
<li key={item.id} className="w-full">
<button
onClick={() => onChange(item)}
className={twMerge(
clsx(
"border border-current text-current rounded-sm bg-black opacity-70",
{ "border border-current opacity-100": item.id === active },
item.className
)
)}
>
{item.text}
</button>
</li>
))}
</ul>
</nav>
<ul className="flex">
{items.map((item) => (
<li key={item.id} className="w-full">
<button
type="button"
onClick={() => onChange(item)}
className={twMerge(
clsx(
"w-full text-current rounded-sm bg-black opacity-50 py-1",
"hover:opacity-80 transition-opacity duration-200",
{ "border border-current opacity-100": item.id === active },
item.className
)
)}
>
{item.text}
</button>
</li>
))}
</ul>
);
};
31 changes: 31 additions & 0 deletions apps/namadillo/src/App/Transfer/AssetCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { Asset } from "@chain-registry/types";
import clsx from "clsx";

type AssetCardProps = {
asset: Asset;
};

export const AssetCard = ({ asset }: AssetCardProps): JSX.Element => {
const image = asset.logo_URIs?.svg || asset.logo_URIs?.png;
return (
<span
className={clsx(
"grid grid-cols-[40px_auto] gap-6 w-full px-4 py-2.5 items-center"
)}
>
{image ?
<img
src={image}
alt={asset.name + ` logo`}
className="w-full aspect-square"
/>
: <img
className="bg-neutral-800 rounded-full aspect-square w-full"
alt="Logo not available"
role="img"
/>
}
<span className="text-left">{asset.name}</span>
</span>
);
};
3 changes: 2 additions & 1 deletion apps/namadillo/src/App/Transfer/AvailableAmountFooter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export const AvailableAmountFooter = ({
return <></>;
}

// TODO: Replace <Currency /> usage here
return (
<div
className={clsx(
Expand All @@ -28,7 +29,7 @@ export const AvailableAmountFooter = ({
Available:
<Currency
amount={availableAmount}
currency={currency}
currency="nam"
spaceAroundSign={true}
currencyPosition="right"
/>
Expand Down
19 changes: 19 additions & 0 deletions apps/namadillo/src/App/Transfer/ChainCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { Chain } from "@chain-registry/types";
import clsx from "clsx";

type ChainCardProps = {
chain: Chain;
};

export const ChainCard = ({ chain }: ChainCardProps): JSX.Element => {
return (
<span
className={clsx(
"grid grid-cols-[40px_auto] gap-6 w-full px-4 py-2.5 items-center"
)}
>
<img src={chain.logo_URIs?.svg} alt={chain.pretty_name + " logo"} />
<span className="text-left">{chain.pretty_name}</span>
</span>
);
};
2 changes: 1 addition & 1 deletion apps/namadillo/src/App/Transfer/ConnectProviderButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export const ConnectProviderButton = ({
return (
<ActionButton
type="button"
className="inline-flex absolute top-0 right-0 w-auto text-xs px-2 py-px"
className="inline-flex top-0 right-0 w-auto text-xs px-2 py-px"
onClick={onClick}
size="xs"
backgroundColor="white"
Expand Down
125 changes: 125 additions & 0 deletions apps/namadillo/src/App/Transfer/Example.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import BigNumber from "bignumber.js";
import { useEffect, useState } from "react";

// This can be loaded async using @chain-registry/client
import {
chain as celestia,
assets as celestiaAssets,
} from "chain-registry/mainnet/celestia";
import {
chain as cosmos,
assets as cosmosAssets,
} from "chain-registry/mainnet/cosmoshub";
import {
chain as dydx,
assets as dydxAssets,
} from "chain-registry/mainnet/dydx";
import {
chain as osmosis,
assets as osmosisAssets,
} from "chain-registry/mainnet/osmosis";
import {
chain as stargaze,
assets as stargazeAssets,
} from "chain-registry/mainnet/stargaze";
import {
chain as stride,
assets as strideAssets,
} from "chain-registry/mainnet/stride";

// This will be replaced by namada registry in the future
import namadaChain from "registry/namada.json";

import { Asset, Chain } from "@chain-registry/types";
import { Panel } from "@namada/components";
import { integrations } from "@namada/integrations";
import { selectedIBCChainAtom, selectedIBCWallet } from "atoms/integrations";
import { wallets } from "integrations";
import { useAtom } from "jotai";
import { useMemo } from "react";
import { WalletProvider } from "types";
import { TransferModule } from "./TransferModule";

export const Example = (): JSX.Element => {
const [selectedWallet, setWallet] = useAtom(selectedIBCWallet);
const [chainId, setChainId] = useAtom(selectedIBCChainAtom);
const [selectedAsset, setSelectedAsset] = useState<Asset>();
const [isShielded, setShielded] = useState(true);

const sourceChainConfig: [Chain, Asset[]][] = [
[cosmos, cosmosAssets.assets],
[osmosis, osmosisAssets.assets],
[celestia, celestiaAssets.assets],
[dydx, dydxAssets.assets],
[stride, strideAssets.assets],
[stargaze, stargazeAssets.assets],
];

const sourceChains: Record<string, Chain> = useMemo(() => {
return sourceChainConfig.reduce((prev, current) => {
return {
...prev,
[current[0].chain_id]: current[0],
};
}, {});
}, []);

const sourceAssetList: Asset[] | undefined = useMemo(() => {
if (!chainId) return;
const config = sourceChainConfig.find(
(config) => config[0].chain_id === chainId
);
if (config) {
return config[1];
}
}, [chainId]);

const selectedSourceChain =
chainId && chainId in sourceChains ? sourceChains[chainId] : undefined;

useEffect(() => {
const config = sourceChainConfig.find(
(config) => config[0].chain_id === chainId
);

if (config) {
setSelectedAsset(config[1][0]);
}
}, [chainId]);

return (
<Panel className="py-20">
<TransferModule
isConnected={false}
onSubmitTransfer={() => {}}
availableWallets={Object.values(wallets)}
sourceWallet={selectedWallet ? wallets[selectedWallet] : undefined}
onChangeWallet={async (wallet: WalletProvider) => {
try {
await integrations[wallet.id].connect();
setWallet(wallet.id);
if (!chainId) {
setChainId(cosmos.chain_id);
}
} catch (err) {
console.error(err);
}
}}
onChangeSourceChain={(chain) => {
setChainId(chain.chain_id);
}}
onChangeSelectedAsset={setSelectedAsset}
availableSourceChains={Object.values(sourceChains)}
availableAssets={sourceAssetList}
selectedAsset={selectedAsset}
sourceChain={selectedSourceChain}
destinationChain={namadaChain as Chain}
destinationWallet={wallets.namada}
isShielded={isShielded}
onChangeShielded={setShielded}
availableAmount={new BigNumber(100) /* Change this */}
transactionFee={new BigNumber(0.01)}
/>
</Panel>
);
};
9 changes: 0 additions & 9 deletions apps/namadillo/src/App/Transfer/IBCFromNamadaModule.tsx

This file was deleted.

12 changes: 0 additions & 12 deletions apps/namadillo/src/App/Transfer/IBCTransfers.tsx

This file was deleted.

61 changes: 61 additions & 0 deletions apps/namadillo/src/App/Transfer/SelectAssetModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { Asset } from "@chain-registry/types";
import { Stack } from "@namada/components";
import { Search } from "App/Common/Search";
import { SelectModal } from "App/Common/SelectModal";
import clsx from "clsx";
import { useMemo, useState } from "react";
import { twMerge } from "tailwind-merge";
import { AssetCard } from "./AssetCard";

type SelectWalletModalProps = {
onClose: () => void;
onSelect: (asset: Asset) => void;
assets: Asset[];
};

export const SelectAssetModal = ({
onClose,
onSelect,
assets,
}: SelectWalletModalProps): JSX.Element => {
const [filter, setFilter] = useState("");

const filteredAssets = useMemo(() => {
return assets.filter(
(asset) =>
asset.name.indexOf(filter) >= 0 || asset.symbol.indexOf(filter) >= 0
);
}, [assets, filter]);

return (
<SelectModal title="Select Asset" onClose={onClose}>
<div className="mb-4">
<Search placeholder="Search chain" onChange={setFilter} />
</div>
<Stack
as="ul"
gap={0}
className="max-h-[400px] overflow-auto dark-scrollbar pb-4 mr-[-0.5rem]"
>
{filteredAssets.map((asset: Asset, index: number) => (
<li key={index} className="text-sm">
<button
onClick={() => {
onSelect(asset);
onClose();
}}
className={twMerge(
clsx(
"w-full rounded-sm border border-transparent",
"hover:border-neutral-400 transition-colors duration-150"
)
)}
>
<AssetCard asset={asset} />
</button>
</li>
))}
</Stack>
</SelectModal>
);
};
Loading
Loading