Skip to content

Commit

Permalink
[NO CHANGELOG] [Add Funds Widget] Options drawer (#2124)
Browse files Browse the repository at this point in the history
Co-authored-by: Mimi Tran <[email protected]>
  • Loading branch information
jiyounglee and mimi-imtbl authored Aug 29, 2024
1 parent 3bc1af9 commit 7cacae4
Show file tree
Hide file tree
Showing 7 changed files with 403 additions and 58 deletions.
21 changes: 21 additions & 0 deletions packages/checkout/widgets-lib/src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -638,6 +638,27 @@
"actionText": "Try again"
}
}
},
"ADD_FUNDS": {
"drawer": {
"options": {
"swap": {
"heading": "Swap",
"caption": "Swap tokens on this network.",
"disabledCaption": "Currently not available."
},
"debit": {
"heading": "Debit Card",
"caption": "The recommended way to pay with card.",
"disabledCaption": "Unavailable for your selection. We recommend adding tokens."
},
"credit": {
"heading": "Credit Card",
"caption": "Not recommended since transactions may be blocked by your bank.",
"disabledCaption": "Unavailable for your selection. We recommend adding tokens."
}
}
}
}
},
"footers": {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { IconProps, MenuItem, MenuItemSize } from '@biom3/react';
import { ReactElement } from 'react';
import { useTranslation } from 'react-i18next';

export enum OptionTypes {
SWAP = 'swap',
DEBIT = 'debit',
CREDIT = 'credit',
}

export interface OptionProps<RC extends ReactElement | undefined = undefined> {
rc?: RC;
type: OptionTypes;
onClick: (type: OptionTypes) => void;
disabled?: boolean;
caption?: string;
size?: MenuItemSize;
}

export function Option<RC extends ReactElement | undefined = undefined>({
type,
onClick,
disabled = false,
caption,
size,
rc = <span />,
}: OptionProps<RC>) {
const { t } = useTranslation();

const icon: Record<OptionTypes, IconProps['icon']> = {
[OptionTypes.SWAP]: 'Coins',
[OptionTypes.DEBIT]: 'BankCard',
[OptionTypes.CREDIT]: 'BankCard',
};

const handleClick = () => onClick(type);

const menuItemProps = {
disabled,
emphasized: true,
onClick: disabled ? undefined : handleClick,
};

return (
<MenuItem
rc={rc}
size={size || 'medium'}
sx={{
marginBottom: 'base.spacing.x1',
userSelect: 'none',
...(disabled && {
filter: 'opacity(0.5)',
cursor: 'not-allowed !important',
}),
}}
{...menuItemProps}
>
<MenuItem.FramedIcon icon={icon[type]} />
<MenuItem.Label size="medium">
{t(`views.ADD_FUNDS.drawer.options.${type}.heading`)}
</MenuItem.Label>
{!disabled && <MenuItem.IntentIcon />}
<MenuItem.Caption>
{caption
|| t(
`views.ADD_FUNDS.drawer.options.${type}.${
disabled ? 'disabledCaption' : 'caption'
}`,
)}
</MenuItem.Caption>
</MenuItem>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { Box, MenuItemSize } from '@biom3/react';

import { motion } from 'framer-motion';
import { useEffect, useMemo } from 'react';
import {
listItemVariants,
listVariants,
} from '../../../lib/animation/listAnimation';
import { Option, OptionTypes } from './Option';

const defaultOptions: OptionTypes[] = [
OptionTypes.SWAP,
OptionTypes.DEBIT,
OptionTypes.CREDIT,
];

export interface OptionsProps {
onClick: (type: OptionTypes) => void;
disabledOptions?: OptionTypes[];
options?: OptionTypes[];
captions?: Partial<Record<OptionTypes, string>>;
size?: MenuItemSize;
hideDisabledOptions?: boolean;
}

export function Options(props: OptionsProps) {
const {
disabledOptions = [],
options,
onClick,
captions,
size,
hideDisabledOptions,
} = props;
const filteredOptions = useMemo(
() => (options || defaultOptions).filter(
(option) => !hideDisabledOptions || !disabledOptions.includes(option),
),
[options, disabledOptions, hideDisabledOptions],
);

useEffect(() => {
if (filteredOptions.length === 1) {
onClick(filteredOptions[0]);
}
}, [options, onClick]);

return (
<Box
testId="options-list"
sx={{
width: '100%',
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
alignItems: 'flex-start',
}}
rc={
<motion.div variants={listVariants} initial="hidden" animate="show" />
}
>
{filteredOptions.map((type, idx: number) => (
<Option
key={`option-type-${type}`}
type={type}
size={size}
onClick={onClick}
disabled={disabledOptions.includes(type)}
caption={captions?.[type]}
rc={<motion.div custom={idx} variants={listItemVariants} />}
/>
))}
</Box>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { Box, Drawer } from '@biom3/react';
import { motion } from 'framer-motion';
import { listVariants } from '../../../lib/animation/listAnimation';
import { Options } from './Options';
import { OptionTypes } from './Option';

type OptionsDrawerProps = {
visible: boolean;
onClose: () => void;
onPayWithCard?: (paymentType: OptionTypes) => void;
};

export function OptionsDrawer({
visible,
onClose,
onPayWithCard,
}: OptionsDrawerProps) {
return (
<Drawer
size="full"
visible={visible}
showHeaderBar
onCloseDrawer={onClose}
headerBarTitle="Pay with ..."
>
<Drawer.Content
rc={
<motion.div variants={listVariants} initial="hidden" animate="show" />
}
>
<Box
sx={{
height: '100%',
display: 'flex',
flexDirection: 'column',
justifyContent: 'space-between',
px: 'base.spacing.x4',
}}
>
<Options
onClick={onPayWithCard ?? (() => {})}
size="medium"
hideDisabledOptions
options={[
OptionTypes.SWAP,
OptionTypes.DEBIT,
OptionTypes.CREDIT,
]}
disabledOptions={[]}
captions={{
[OptionTypes.SWAP]: 'Swap',
[OptionTypes.DEBIT]: 'Debit',
[OptionTypes.CREDIT]: 'Credit',
}}
/>
</Box>
</Drawer.Content>
</Drawer>
);
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import { Web3Provider } from '@ethersproject/providers';
import { createContext } from 'react';
import { Checkout } from '@imtbl/checkout-sdk';
import { Checkout, TokenInfo } from '@imtbl/checkout-sdk';

export interface AddFundsState {
checkout: Checkout | null;
provider: Web3Provider | null;
allowedTokens: TokenInfo[] | null;
}

export const initialAddFundsState: AddFundsState = {
checkout: null,
provider: null,
allowedTokens: null,
};

export interface AddFundsContextState {
Expand All @@ -22,12 +24,14 @@ export interface AddFundsAction {
}

type ActionPayload =
| SetCheckoutPayload
| SetProviderPayload;
| SetCheckoutPayload
| SetProviderPayload
| SetAllowedTokensPayload;

export enum AddFundsActions {
SET_CHECKOUT = 'SET_CHECKOUT',
SET_PROVIDER = 'SET_PROVIDER',
SET_ALLOWED_TOKENS = 'SET_ALLOWED_TOKENS',
}

export interface SetCheckoutPayload {
Expand All @@ -40,11 +44,15 @@ export interface SetProviderPayload {
provider: Web3Provider;
}

export interface SetAllowedTokensPayload {
type: AddFundsActions.SET_ALLOWED_TOKENS;
allowedTokens: TokenInfo[];
}

// eslint-disable-next-line @typescript-eslint/naming-convention
export const AddFundsContext = createContext<AddFundsContextState>({
addFundsState: initialAddFundsState,
addFundsDispatch: () => {
},
addFundsDispatch: () => {},
});

AddFundsContext.displayName = 'AddFundsContext';
Expand All @@ -66,6 +74,11 @@ export const addFundsReducer: Reducer<AddFundsState, AddFundsAction> = (
...state,
provider: action.payload.provider,
};
case AddFundsActions.SET_ALLOWED_TOKENS:
return {
...state,
allowedTokens: action.payload.allowedTokens,
};
default:
return state;
}
Expand Down
Loading

0 comments on commit 7cacae4

Please sign in to comment.