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

feat: [CM-607][Sale Widget] Get order config from product skus + qty #1749

Merged
merged 13 commits into from
May 14, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ import { SalePaymentTypes } from '../events/sale';
* @property {WalletProviderName | undefined} walletProviderName
*/
export type SaleWidgetParams = {
/** The total price to pay for the items in the sale */
amount?: string;
/** Environment id from Immutable Hub */
environmentId?: string;
/** The list of products to be purchased */
Expand Down
7 changes: 6 additions & 1 deletion packages/checkout/widgets-lib/src/lib/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ import {
NATIVE,
} from './constants';

export const tokenSymbolNameOverrides = {
timx: 'imx',
};

export const sortTokensByAmount = (
config: CheckoutConfiguration,
tokens: GetBalanceResult[],
Expand Down Expand Up @@ -71,7 +75,8 @@ export const calculateCryptoToFiat = (
): string => {
if (!amount) return zeroString;

const conversion = conversions.get(symbol.toLowerCase());
const name = tokenSymbolNameOverrides[symbol.toLowerCase()] || symbol.toLowerCase();
const conversion = conversions.get(name);
if (!conversion) return zeroString;

const parsedAmount = parseFloat(amount);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@ export default function SaleWidget(props: SaleWidgetProps) {
const { t } = useTranslation();
const {
config,
amount,
items,
environmentId,
collectionName,
Expand Down Expand Up @@ -119,7 +118,6 @@ export default function SaleWidget(props: SaleWidgetProps) {
value={{
config,
items,
amount,
environment: config.environment,
environmentId,
provider,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import {
} from 'components/ConnectLoader/ConnectLoader';
import { getL2ChainId } from 'lib';
import {
isValidAmount,
isValidWalletProvider,
} from 'lib/validations/widgetValidators';
import { ThemeProvider } from 'components/ThemeProvider/ThemeProvider';
Expand Down Expand Up @@ -63,12 +62,6 @@ export class Sale extends Base<WidgetType.SALE> {
validatedParams.walletProviderName = undefined;
}

if (!isValidAmount(params.amount)) {
// eslint-disable-next-line no-console
console.warn('[IMTBL]: invalid "amount" widget input');
validatedParams.amount = '';
}

// TODO: fix the logic here when proper , currently saying if valid then reset to empty array.
if (!this.isValidProucts(params.items ?? [])) {
// eslint-disable-next-line no-console
Expand Down Expand Up @@ -125,7 +118,6 @@ export class Sale extends Base<WidgetType.SALE> {
<Suspense fallback={<LoadingView loadingText={t('views.LOADING_VIEW.text')} />}>
<SaleWidget
config={config}
amount={this.parameters.amount!}
items={this.parameters.items!}
environmentId={this.parameters.environmentId!}
collectionName={this.parameters.collectionName!}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,37 +1,45 @@
import { Heading, MenuItem } from '@biom3/react';
import { Heading, MenuItem, MenuItemSize } from '@biom3/react';
import { SaleItem } from '@imtbl/checkout-sdk';
import { useTranslation } from 'react-i18next';
import { calculateCryptoToFiat, tokenValueFormat } from 'lib/utils';
import { ReactElement } from 'react';
import { FundingBalance } from '../types';
import { OrderQuotePricing, FundingBalance } from '../types';

export interface OrderItemProps<
RC extends ReactElement | undefined = undefined,
> {
item: SaleItem;
balance: FundingBalance;
pricing: OrderQuotePricing | undefined;
conversions: Map<string, number>;
size?: MenuItemSize;
rc?: RC;
}

export function OrderItem<RC extends ReactElement | undefined = undefined>({
item,
balance,
pricing,
conversions,
size,
rc = <span />,
}: OrderItemProps<RC>) {
const { t } = useTranslation();

const { token, fundsRequired } = balance.fundingItem;
const { token } = balance.fundingItem;
const amount = pricing?.amount || 0;

const amount = fundsRequired.formattedAmount;
const fiatAmount = calculateCryptoToFiat(amount, token.symbol, conversions);
const fiatAmount = calculateCryptoToFiat(
amount.toString(),
token.symbol,
conversions,
);

return (
<MenuItem
rc={rc}
emphasized
size="medium"
size={size || 'medium'}
key={item.name}
sx={{
pointerEvents: 'none',
Expand All @@ -41,20 +49,20 @@ export function OrderItem<RC extends ReactElement | undefined = undefined>({
<MenuItem.FramedImage imageUrl={item.image} />
<MenuItem.Label>{item.name}</MenuItem.Label>
<MenuItem.Caption>
{item.qty > 1
? t('views.ORDER_SUMMARY.orderItem.quantity', { qty: item.qty })
: null}
{t('views.ORDER_SUMMARY.orderItem.quantity', { qty: item.qty })}
</MenuItem.Caption>
<MenuItem.PriceDisplay
use={<Heading size="xSmall" />}
price={t('views.ORDER_SUMMARY.currency.price', {
symbol: token.symbol,
amount: tokenValueFormat(amount),
})}
fiatAmount={t('views.ORDER_SUMMARY.currency.fiat', {
amount: fiatAmount,
})}
/>
{amount > 0 && (
<MenuItem.PriceDisplay
use={<Heading size="xSmall" />}
price={t('views.ORDER_SUMMARY.currency.price', {
symbol: token.symbol,
amount: tokenValueFormat(amount),
})}
fiatAmount={t('views.ORDER_SUMMARY.currency.fiat', {
amount: fiatAmount,
})}
/>
)}
</MenuItem>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,22 @@ import { listVariants, listItemVariants } from 'lib/animation/listAnimation';

import { motion } from 'framer-motion';
import { OrderItem } from './OrderItem';
import { FundingBalance } from '../types';
import { OrderQuoteProduct, FundingBalance } from '../types';
import { getPricingBySymbol } from '../utils/pricing';

type OrderItemsProps = {
items: SaleItem[];
balance: FundingBalance;
pricing: Record<string, OrderQuoteProduct>;
conversions: Map<string, number>;
};

export function OrderItems({ items, balance, conversions }: OrderItemsProps) {
export function OrderItems({
items,
balance,
pricing,
conversions,
}: OrderItemsProps) {
return (
<Box
rc={
Expand All @@ -25,6 +32,12 @@ export function OrderItems({ items, balance, conversions }: OrderItemsProps) {
item={item}
balance={balance}
conversions={conversions}
size={items.length > 1 ? 'small' : 'medium'}
pricing={getPricingBySymbol(
balance.fundingItem.token.symbol,
pricing?.[item.productId]?.pricing,
conversions,
)}
rc={<motion.div variants={listItemVariants} custom={idx} />}
/>
))}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { EventTargetContext } from '../../../context/event-target-context/EventT
import { sendSaleWidgetCloseEvent } from '../SaleWidgetEvents';
import { SelectCoinDropdown } from './SelectCoinDropdown';
import { CoinsDrawer } from './CoinsDrawer';
import { FundingBalance } from '../types';
import { OrderQuoteProduct, FundingBalance } from '../types';
import { OrderItems } from './OrderItems';
import { useSaleEvent } from '../hooks/useSaleEvents';

Expand All @@ -23,6 +23,7 @@ type OrderReviewProps = {
conversions: Map<string, number>;
loadingBalances: boolean;
items: SaleItem[];
pricing: Record<string, OrderQuoteProduct>;
transactionRequirement?: TransactionRequirement;
onBackButtonClick: () => void;
onProceedToBuy: (fundingBalance: FundingBalance) => void;
Expand All @@ -32,6 +33,7 @@ type OrderReviewProps = {

export function OrderReview({
items,
pricing,
fundingBalances,
conversions,
collectionName,
Expand Down Expand Up @@ -82,29 +84,36 @@ export function OrderReview({
display: 'flex',
flexDirection: 'column',
justifyContent: 'space-between',
height: '0',
}}
>
<Heading
size="small"
sx={{
px: 'base.spacing.x4',
pb: 'base.spacing.x4',
}}
>
{t('views.ORDER_SUMMARY.orderReview.heading')}
</Heading>
<Box
sx={{
display: 'flex',
flexDirection: 'column',
paddingX: 'base.spacing.x2',
paddingY: 'base.spacing.x8',
px: 'base.spacing.x2',
pb: 'base.spacing.x8',
maxh: '60%',
height: '100%',
overflowY: 'scroll',
scrollbarWidth: 'none',
rowGap: 'base.spacing.x4',
}}
>
<Heading
size="small"
sx={{
paddingX: 'base.spacing.x4',
}}
>
{t('views.ORDER_SUMMARY.orderReview.heading')}
</Heading>
<Box sx={{ paddingX: 'base.spacing.x2' }}>
<Box sx={{ px: 'base.spacing.x2' }}>
<OrderItems
items={items}
balance={fundingBalances[selectedCurrencyIndex]}
pricing={pricing}
conversions={conversions}
/>
</Box>
Expand All @@ -116,6 +125,7 @@ export function OrderReview({
conversions={conversions}
canOpen={fundingBalances.length > 1}
loading={loadingBalances}
priceDisplay={items.length > 1}
/>
<CoinsDrawer
conversions={conversions}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,10 +105,7 @@ export function SelectCoinDropdown({
? t('views.ORDER_SUMMARY.currency.fiat', { amount: fiatAmount })
: undefined
}
price={t('views.ORDER_SUMMARY.currency.price', {
symbol: token.symbol,
amount: tokenValueFormat(fundsRequired.formattedAmount),
})}
price={tokenValueFormat(fundsRequired.formattedAmount)}
/>
)}
{canOpen && (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export function WithCard(props: WithCardProps) {
signResponse,
goToErrorView,
environment,
clientConfig,
orderQuote,
} = useSaleContext();
const executeTxn = signResponse?.transactions.find((txn) => txn.methodCall.startsWith('execute'));

Expand Down Expand Up @@ -77,7 +77,7 @@ export function WithCard(props: WithCardProps) {
onOrderFailed={onOrderFailed}
onFailedToLoad={onFailedToLoad}
environment={environment}
contractId={clientConfig.contractId}
contractId={orderQuote.config.contractId}
/>
);
}
Loading
Loading