| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| import React from 'react'; |
| import { |
| Banner, |
| Modal, |
| Typography, |
| Card, |
| Button, |
| Select, |
| Divider, |
| Tooltip, |
| } from '@douyinfe/semi-ui'; |
| import { Crown, CalendarClock, Package } from 'lucide-react'; |
| import { SiStripe } from 'react-icons/si'; |
| import { IconCreditCard } from '@douyinfe/semi-icons'; |
| import { renderQuota } from '../../../helpers'; |
| import { getCurrencyConfig } from '../../../helpers/render'; |
| import { |
| formatSubscriptionDuration, |
| formatSubscriptionResetPeriod, |
| } from '../../../helpers/subscriptionFormat'; |
|
|
| const { Text } = Typography; |
|
|
| const SubscriptionPurchaseModal = ({ |
| t, |
| visible, |
| onCancel, |
| selectedPlan, |
| paying, |
| selectedEpayMethod, |
| setSelectedEpayMethod, |
| epayMethods = [], |
| enableOnlineTopUp = false, |
| enableStripeTopUp = false, |
| enableCreemTopUp = false, |
| purchaseLimitInfo = null, |
| onPayStripe, |
| onPayCreem, |
| onPayEpay, |
| }) => { |
| const plan = selectedPlan?.plan; |
| const totalAmount = Number(plan?.total_amount || 0); |
| const { symbol, rate } = getCurrencyConfig(); |
| const price = plan ? Number(plan.price_amount || 0) : 0; |
| const convertedPrice = price * rate; |
| const displayPrice = convertedPrice.toFixed( |
| Number.isInteger(convertedPrice) ? 0 : 2, |
| ); |
| |
| const hasStripe = enableStripeTopUp && !!plan?.stripe_price_id; |
| const hasCreem = enableCreemTopUp && !!plan?.creem_product_id; |
| const hasEpay = enableOnlineTopUp && epayMethods.length > 0; |
| const hasAnyPayment = hasStripe || hasCreem || hasEpay; |
| const purchaseLimit = Number(purchaseLimitInfo?.limit || 0); |
| const purchaseCount = Number(purchaseLimitInfo?.count || 0); |
| const purchaseLimitReached = |
| purchaseLimit > 0 && purchaseCount >= purchaseLimit; |
|
|
| return ( |
| <Modal |
| title={ |
| <div className='flex items-center'> |
| <Crown className='mr-2' size={18} /> |
| {t('购买订阅套餐')} |
| </div> |
| } |
| visible={visible} |
| onCancel={onCancel} |
| footer={null} |
| size='small' |
| centered |
| > |
| {plan ? ( |
| <div className='space-y-4 pb-10'> |
| {/* 套餐信息 */} |
| <Card className='!rounded-xl !border-0 bg-slate-50 dark:bg-slate-800'> |
| <div className='space-y-3'> |
| <div className='flex justify-between items-center'> |
| <Text strong className='text-slate-700 dark:text-slate-200'> |
| {t('套餐名称')}: |
| </Text> |
| <Typography.Text |
| ellipsis={{ rows: 1, showTooltip: true }} |
| className='text-slate-900 dark:text-slate-100' |
| style={{ maxWidth: 200 }} |
| > |
| {plan.title} |
| </Typography.Text> |
| </div> |
| <div className='flex justify-between items-center'> |
| <Text strong className='text-slate-700 dark:text-slate-200'> |
| {t('有效期')}: |
| </Text> |
| <div className='flex items-center'> |
| <CalendarClock size={14} className='mr-1 text-slate-500' /> |
| <Text className='text-slate-900 dark:text-slate-100'> |
| {formatSubscriptionDuration(plan, t)} |
| </Text> |
| </div> |
| </div> |
| {formatSubscriptionResetPeriod(plan, t) !== t('不重置') && ( |
| <div className='flex justify-between items-center'> |
| <Text strong className='text-slate-700 dark:text-slate-200'> |
| {t('重置周期')}: |
| </Text> |
| <Text className='text-slate-900 dark:text-slate-100'> |
| {formatSubscriptionResetPeriod(plan, t)} |
| </Text> |
| </div> |
| )} |
| <div className='flex justify-between items-center'> |
| <Text strong className='text-slate-700 dark:text-slate-200'> |
| {t('总额度')}: |
| </Text> |
| <div className='flex items-center'> |
| <Package size={14} className='mr-1 text-slate-500' /> |
| {totalAmount > 0 ? ( |
| <Tooltip content={`${t('原生额度')}:${totalAmount}`}> |
| <Text className='text-slate-900 dark:text-slate-100'> |
| {renderQuota(totalAmount)} |
| </Text> |
| </Tooltip> |
| ) : ( |
| <Text className='text-slate-900 dark:text-slate-100'> |
| {t('不限')} |
| </Text> |
| )} |
| </div> |
| </div> |
| {plan?.upgrade_group ? ( |
| <div className='flex justify-between items-center'> |
| <Text strong className='text-slate-700 dark:text-slate-200'> |
| {t('升级分组')}: |
| </Text> |
| <Text className='text-slate-900 dark:text-slate-100'> |
| {plan.upgrade_group} |
| </Text> |
| </div> |
| ) : null} |
| <Divider margin={8} /> |
| <div className='flex justify-between items-center'> |
| <Text strong className='text-slate-700 dark:text-slate-200'> |
| {t('应付金额')}: |
| </Text> |
| <Text strong className='text-xl text-purple-600'> |
| {symbol} |
| {displayPrice} |
| </Text> |
| </div> |
| </div> |
| </Card> |
| |
| {/* 支付方式 */} |
| {purchaseLimitReached && ( |
| <Banner |
| type='warning' |
| description={`${t('已达到购买上限')} (${purchaseCount}/${purchaseLimit})`} |
| className='!rounded-xl' |
| closeIcon={null} |
| /> |
| )} |
| |
| {hasAnyPayment ? ( |
| <div className='space-y-3'> |
| <Text size='small' type='tertiary'> |
| {t('选择支付方式')}: |
| </Text> |
| |
| {/* Stripe / Creem */} |
| {(hasStripe || hasCreem) && ( |
| <div className='flex gap-2'> |
| {hasStripe && ( |
| <Button |
| theme='light' |
| className='flex-1' |
| icon={<SiStripe size={14} color='#635BFF' />} |
| onClick={onPayStripe} |
| loading={paying} |
| disabled={purchaseLimitReached} |
| > |
| Stripe |
| </Button> |
| )} |
| {hasCreem && ( |
| <Button |
| theme='light' |
| className='flex-1' |
| icon={<IconCreditCard />} |
| onClick={onPayCreem} |
| loading={paying} |
| disabled={purchaseLimitReached} |
| > |
| Creem |
| </Button> |
| )} |
| </div> |
| )} |
| |
| {/* 易支付 */} |
| {hasEpay && ( |
| <div className='flex gap-2'> |
| <Select |
| value={selectedEpayMethod} |
| onChange={setSelectedEpayMethod} |
| style={{ flex: 1 }} |
| size='default' |
| placeholder={t('选择支付方式')} |
| optionList={epayMethods.map((m) => ({ |
| value: m.type, |
| label: m.name || m.type, |
| }))} |
| disabled={purchaseLimitReached} |
| /> |
| <Button |
| theme='solid' |
| type='primary' |
| onClick={onPayEpay} |
| loading={paying} |
| disabled={!selectedEpayMethod || purchaseLimitReached} |
| > |
| {t('支付')} |
| </Button> |
| </div> |
| )} |
| </div> |
| ) : ( |
| <Banner |
| type='info' |
| description={t('管理员未开启在线支付功能,请联系管理员配置。')} |
| className='!rounded-xl' |
| closeIcon={null} |
| /> |
| )} |
| </div> |
| ) : null} |
| </Modal> |
| ); |
| }; |
|
|
| export default SubscriptionPurchaseModal; |
|
|