Skip to content

Commit

Permalink
Namadillo: first sketch on Transfer module (#1119)
Browse files Browse the repository at this point in the history
* feat(namadillo): creating basic file structure

* feat(namadillo): creating ChainSelectBox component and relative structure

* feat(namadillo): button connect wallet

* feat(namadillo): adding selected asset button

* feat(namadillo): adding AvailableAmountFooter component

* feat(namadillo): creating simple TransferDestination component

* feat(namadillo): writing tests for TransferDestination

* feat(namadillo): improving and writing tests for TransferSource component

* feat(namadillo): sketching modals and organizing code

* feat(namadillo): verifying if provider is connected and improving modals

* feat(namadillo): renaming components

* feat: addressing reviewing comments
  • Loading branch information
pedrorezende authored Sep 19, 2024
1 parent 08a92cb commit 2c1b5d5
Show file tree
Hide file tree
Showing 32 changed files with 1,124 additions and 3 deletions.
40 changes: 40 additions & 0 deletions apps/namadillo/src/App/Common/SelectModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { Modal } from "@namada/components";
import clsx from "clsx";
import React from "react";
import { IoClose } from "react-icons/io5";
import { ModalTransition } from "./ModalTransition";

type SelectModalProps = {
children: React.ReactNode;
title: React.ReactNode;
onClose: () => void;
};

export const SelectModal = ({
children,
title,
onClose,
}: 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"
)}
>
<header className="flex w-full justify-center items-center relative mb-4 text-light leading-8">
{title}
<i
className="cursor-pointer text-white absolute right-0 text-xl p-1.5 hover:text-yellow z-50"
onClick={onClose}
>
<IoClose />
</i>
</header>
{children}
</div>
</ModalTransition>
</Modal>
);
};
42 changes: 42 additions & 0 deletions apps/namadillo/src/App/Common/TabSelector.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import clsx from "clsx";
import { twMerge } from "tailwind-merge";
type TabSelectorItem = {
text: React.ReactNode;
id: string;
className?: string;
};

type TabSelectorProps = {
items: TabSelectorItem[];
active: string;
onChange: (item: TabSelectorItem) => void;
};

export const TabSelector = ({
items,
active,
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>
);
};
54 changes: 54 additions & 0 deletions apps/namadillo/src/App/Transfer/AvailableAmountFooter.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { ActionButton, Currency } from "@namada/components";
import { KnownCurrencies } from "@namada/utils";
import BigNumber from "bignumber.js";
import clsx from "clsx";

type AvailableAmountFooterProps = {
availableAmount?: BigNumber;
currency?: keyof typeof KnownCurrencies;
onClickMax?: () => void;
};

export const AvailableAmountFooter = ({
availableAmount,
currency,
onClickMax,
}: AvailableAmountFooterProps): JSX.Element => {
if (!currency || availableAmount === undefined) {
return <></>;
}

return (
<div
className={clsx(
"flex justify-between items-center text-sm text-neutral-500 font-light"
)}
>
<span className="flex gap-2">
Available:
<Currency
amount={availableAmount}
currency={currency}
spaceAroundSign={true}
currencyPosition="right"
/>
</span>
<span>
{onClickMax && (
<ActionButton
type="button"
size="xs"
disabled={availableAmount.eq(0)}
onClick={onClickMax}
outlineColor="neutral"
className="text-neutral-500 text-xs py-0 px-3"
backgroundHoverColor="white"
backgroundColor="transparent"
>
Max
</ActionButton>
)}
</span>
</div>
);
};
Empty file.
21 changes: 21 additions & 0 deletions apps/namadillo/src/App/Transfer/ConnectProviderButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { ActionButton } from "@namada/components";

type ConnectProviderButtonProps = {
onClick?: () => void;
};

export const ConnectProviderButton = ({
onClick,
}: ConnectProviderButtonProps): JSX.Element => {
return (
<ActionButton
type="button"
className="inline-flex absolute top-0 right-0 w-auto text-xs px-2 py-px"
onClick={onClick}
size="xs"
backgroundColor="white"
>
Connect Wallet
</ActionButton>
);
};
35 changes: 35 additions & 0 deletions apps/namadillo/src/App/Transfer/CustomAddressForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { Input, Stack } from "@namada/components";

type CustomAddressFormProps = {
onChangeAddress?: (address: string | undefined) => void;
customAddress?: string;
memo?: string;
onChangeMemo?: (address: string) => void;
};

export const CustomAddressForm = ({
customAddress,
onChangeAddress,
memo,
onChangeMemo,
}: CustomAddressFormProps): JSX.Element => {
return (
<Stack as="fieldset" gap={2}>
{onChangeAddress && (
<Input
label="Recipient address"
value={customAddress}
onChange={(e) => onChangeAddress(e.target.value)}
/>
)}
{onChangeMemo && (
<Input
label="Memo"
value={memo}
onChange={(e) => onChangeMemo(e.target.value)}
placeholder="Required for centralized exchanges"
/>
)}
</Stack>
);
};
20 changes: 20 additions & 0 deletions apps/namadillo/src/App/Transfer/EmptyResourceIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import clsx from "clsx";
import { twMerge } from "tailwind-merge";
type EmptyResourceProps = { className?: string };

export const EmptyResourceIcon = ({
className = "",
}: EmptyResourceProps): JSX.Element => {
return (
<i
className={twMerge(
clsx(
"flex items-center justify-center aspect-square rounded-full bg-neutral-900 relative ",
"before:h-[50%] before:w-[50%] before:bg-neutral-700 before:rounded-full group-hover:before:bg-neutral-600",
"before:transition-colors before:duration-300",
className
)
)}
/>
);
};
9 changes: 9 additions & 0 deletions apps/namadillo/src/App/Transfer/IBCFromNamadaModule.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { TransferModule } from "./TransferModule";

export const IBCFromNamadaModule = (): JSX.Element => {
return (
<div>
<TransferModule isConnected={false} onSubmitTransfer={() => {}} />
</div>
);
};
12 changes: 12 additions & 0 deletions apps/namadillo/src/App/Transfer/IBCTransfers.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { Panel } from "@namada/components";
import { IBCFromNamadaModule } from "./IBCFromNamadaModule";

export const IBCTransfers = (): JSX.Element => {
return (
<div>
<Panel>
<IBCFromNamadaModule />
</Panel>
</div>
);
};
15 changes: 15 additions & 0 deletions apps/namadillo/src/App/Transfer/SelectAssetsModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { SelectModal } from "App/Common/SelectModal";

type SelectItemsModalProps = {
onClose: () => void;
};

export const SelectAssetsModal = ({
onClose,
}: SelectItemsModalProps): JSX.Element => {
return (
<SelectModal onClose={onClose} title="Select Asset">
<></>
</SelectModal>
);
};
34 changes: 34 additions & 0 deletions apps/namadillo/src/App/Transfer/SelectChainModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { Stack } from "@namada/components";
import { SelectModal } from "App/Common/SelectModal";
import clsx from "clsx";
import { Chain } from "types";

type SelectChainModalProps = {
onClose: () => void;
chains: Chain[];
};

export const SelectChainModal = ({
onClose,
chains,
}: SelectChainModalProps): JSX.Element => {
return (
<SelectModal title="Select Source Chain" onClose={onClose}>
<Stack as="ul">
{chains.map((chain) => (
<li key={chain.chainId}>
<button
className={clsx(
"grid grid-cols-[30px_auto] w-full px-6 py-2.5 rounded-sm border",
"hover:border-neutral-400"
)}
>
<img src={chain.iconUrl} />
<span>{chain.name}</span>
</button>
</li>
))}
</Stack>
</SelectModal>
);
};
43 changes: 43 additions & 0 deletions apps/namadillo/src/App/Transfer/SelectProviderModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { SelectModal } from "App/Common/SelectModal";
import { Provider } from "types";

type SelectProviderModalProps = {
onClose: () => void;
providers: Provider[];
onConnect: (provider: Provider) => void;
};

export const SelectProviderModal = ({
onClose,
onConnect,
providers,
}: SelectProviderModalProps): JSX.Element => {
return (
<SelectModal title="Source" onClose={onClose}>
<ul>
{providers.map((provider: Provider, index) => (
<li key={index} className="px-5 text-sm">
<button
className="flex justify-between items-center w-full"
onClick={() => onConnect(provider)}
>
<span className="flex gap-2 items-center text-white">
<img
src={provider.iconUrl}
className="w-8 aspect-square rounded-sm"
/>
{provider.name}
</span>
<span
onClick={() => onConnect(provider)}
className="text-xs text-neutral-400"
>
Connect
</span>
</button>
</li>
))}
</ul>
</SelectModal>
);
};
51 changes: 51 additions & 0 deletions apps/namadillo/src/App/Transfer/SelectedAsset.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import clsx from "clsx";
import { GoChevronDown } from "react-icons/go";
import { Asset, Chain } from "types";
import { EmptyResourceIcon } from "./EmptyResourceIcon";

type SelectedAssetProps = {
chain?: Chain;
asset?: Asset;
onClick?: () => void;
};

export const SelectedAsset = ({
chain,
asset,
onClick,
}: SelectedAssetProps): JSX.Element => {
const selectorClassList = clsx(
`flex items-center gap-2.5 text-lg text-white font-light cursor-pointer uppercase`
);

return (
<button
type="button"
className="block group"
disabled={!chain}
onClick={onClick}
aria-description={
asset ? `${asset.name} is selected` : `No asset selected`
}
>
{!asset && (
<span className={selectorClassList}>
<EmptyResourceIcon className="w-15" />
Asset
<GoChevronDown className="text-sm" />
</span>
)}
{asset && (
<span className={selectorClassList}>
<img
className="w-7 h-7 object-cover object-center bg-neutral-800 rounded-full"
alt={`${asset.name} image`}
style={{ backgroundImage: `url(${asset.iconUrl})` }}
/>
{asset.denomination}
<GoChevronDown />
</span>
)}
</button>
);
};
Loading

1 comment on commit 2c1b5d5

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.