/* eslint-disable no-nested-ternary */
import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
import Toast from '@arcblock/ux/lib/Toast';
import type { PriceCurrency, PriceRecurring, TPricingTableExpanded, TPricingTableItem } from '@blocklet/payment-types';
import { CheckOutlined } from '@mui/icons-material';
import {
Avatar,
Box,
Chip,
List,
ListItem,
ListItemIcon,
ListItemText,
MenuItem,
Select,
Stack,
ToggleButton,
ToggleButtonGroup,
Typography,
} from '@mui/material';
import { styled } from '@mui/system';
import { useSetState } from 'ahooks';
import { useEffect, useMemo, useState } from 'react';
import { BN } from '@ocap/util';
import isEmpty from 'lodash/isEmpty';
import { usePaymentContext } from '../contexts/payment';
import {
formatError,
formatPriceAmount,
formatRecurring,
getPriceCurrencyOptions,
getPriceUintAmountByCurrency,
isMobileSafari,
} from '../libs/util';
import { useMobile } from '../hooks/mobile';
import TruncatedText from './truncated-text';
import LoadingButton from './loading-button';
type SortOrder = { [key: string]: number };
const sortOrder: SortOrder = {
year: 1,
month: 2,
day: 3,
hour: 4,
};
const groupItemsByRecurring = (items: TPricingTableItem[], currency: { id: string; symbol: string }) => {
const grouped: { [key: string]: TPricingTableItem[] } = {};
const recurring: { [key: string]: PriceRecurring } = {};
(items || []).forEach((x) => {
const key = [x.price.recurring?.interval, x.price.recurring?.interval_count].join('-');
if (x.price.currency_options?.find((c: PriceCurrency) => c.currency_id === currency.id)) {
recurring[key] = x.price.recurring as PriceRecurring;
}
if (!grouped[key]) {
grouped[key] = [];
}
// @ts-ignore
grouped[key].push(x);
});
return { recurring, grouped };
};
type Props = {
table: TPricingTableExpanded;
onSelect: (priceId: string, currencyId: string) => void;
alignItems?: 'center' | 'left';
mode?: 'checkout' | 'select';
interval?: string;
hideCurrency?: boolean;
};
export default function PricingTable({
table,
alignItems = 'center',
interval = '',
mode = 'checkout',
onSelect,
hideCurrency = false,
}: Props) {
const { t, locale } = useLocaleContext();
const { isMobile } = useMobile();
const {
settings: { paymentMethods = [] },
livemode,
setLivemode,
refresh,
} = usePaymentContext();
const isMobileSafariEnv = isMobileSafari();
useEffect(() => {
if (table) {
if (livemode !== table.livemode) {
setLivemode(table.livemode);
}
}
}, [table, livemode, setLivemode, refresh]);
const [currency, setCurrency] = useState(table.currency || {});
const { recurring, grouped } = useMemo(() => groupItemsByRecurring(table.items, currency), [table.items, currency]);
const recurringKeysList = useMemo(() => {
if (isEmpty(recurring)) {
return [];
}
return Object.keys(recurring).sort((a, b) => {
const [aType, aValue] = a.split('-');
const [bType, bValue] = b.split('-');
if (sortOrder[aType] !== sortOrder[bType]) {
return sortOrder[aType] - sortOrder[bType];
}
if (aValue && bValue) {
// @ts-ignore
return bValue - aValue;
}
// @ts-ignore
return b - a;
});
}, [recurring]);
const [state, setState] = useSetState({ interval });
const currencyMap = useMemo(() => {
if (!paymentMethods || paymentMethods.length === 0) {
return {};
}
const ans: { [key: string]: any } = {};
paymentMethods.forEach((paymentMethod) => {
const { payment_currencies: paymentCurrencies = [] } = paymentMethod;
if (paymentCurrencies && paymentCurrencies.length > 0) {
paymentCurrencies.forEach((x: { id: string; symbol: string }) => {
ans[x.id] = {
...x,
method: paymentMethod.name,
};
});
}
});
return ans;
}, [paymentMethods]);
const currencyList = useMemo(() => {
const visited: { [key: string]: boolean } = {};
if (!state.interval) {
return [];
}
(grouped[state.interval] || []).forEach((x: TPricingTableItem) => {
getPriceCurrencyOptions(x.price).forEach((c: PriceCurrency) => {
visited[c?.currency_id] = true;
});
});
return Object.keys(visited)
.map((x) => currencyMap[x])
.filter((v) => v);
}, [currencyMap, grouped, state.interval]);
const productList = useMemo(() => {
return (grouped[state.interval as string] || []).filter((x: TPricingTableItem) => {
const price = getPriceUintAmountByCurrency(x.price, currency);
if (new BN(price).isZero() || !price) {
return false;
}
return true;
});
}, [grouped, state.interval, currency]);
useEffect(() => {
if (table) {
if (!state.interval || !grouped[state.interval]) {
const keys = Object.keys(recurring);
if (keys[0]) {
setState({ interval: keys[0] });
}
}
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [table]);
const Root = styled(Box)`
.btn-row {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
align-items: center;
width: 100%;
gap: 20px;
}
.price-table-wrap {
scrollbar-width: none;
-ms-overflow-style: none;
&::-webkit-scrollbar {
display: none;
}
}
@media (max-width: ${({ theme }) => theme.breakpoints.values.sm}px) {
// .price-table-item {
// width: 90% !important;
// }
// .btn-row {
// padding: 0 20px;
// }
}
@media (min-width: ${({ theme }) => theme.breakpoints.values.md}px) {
.price-table-wrap:has(> div:nth-of-type(1)) {
max-width: 360px !important;
}
.price-table-wrap:has(> div:nth-of-type(2)) {
max-width: 780px !important;
}
.price-table-wrap:has(> div:nth-of-type(3)) {
max-width: 1200px !important;
}
}
`;
return (
{recurringKeysList.length > 0 && (
{isMobile && recurringKeysList.length > 1 ? (
) : (
{
if (value !== null) {
setState({ interval: value });
}
}}
exclusive>
{recurringKeysList.map((x) => (
x === state.interval
? `${palette.background.default} !important`
: `${palette.grey[100]} !important`,
border: '0px',
'&.Mui-selected': {
borderRadius: '9999px !important',
border: '1px solid',
borderColor: 'divider',
},
}}>
{formatRecurring(recurring[x] as PriceRecurring, true, '', locale)}
))}
)}
)}
{currencyList.length > 0 && !hideCurrency && (
)}
{productList?.map((x: TPricingTableItem & { is_selected?: boolean; is_disabled?: boolean }) => {
let action: string = x.subscription_data?.trial_period_days
? t('payment.checkout.try')
: t('payment.checkout.subscription');
if (mode === 'select') {
action = x.is_selected ? t('payment.checkout.selected') : t('payment.checkout.select');
}
const [amount, unit] = formatPriceAmount(x.price, currency, x.product.unit_label).split('/');
return (
{x.is_highlight && (
)}
{amount}
{unit ? (
/ {unit}
) : (
''
)}
{x.product.description}
{x.product.features.length > 0 && (
{x.product.features.map((f: any) => (
))}
)}
);
})}
);
}
function Subscribe({ x, action, onSelect, currencyId }: any) {
const [state, setState] = useState({ loading: '', loaded: false });
const handleSelect = async (priceId: string) => {
try {
setState({ loading: priceId, loaded: true });
await onSelect(priceId, currencyId);
} catch (err) {
console.error(err);
Toast.error(formatError(err));
}
};
return (
handleSelect(x.price_id)}>
{action}
);
}