refactor: update billing card logic and localization
- Renamed variables for clarity, changing `isLifetimeMember` to `isLifetimePlan` and `canUpgrade` logic to improve readability. - Added localization support for the price label in both English and Chinese. - Optimized the UI to conditionally display messages for free and lifetime plans, enhancing user experience.
This commit is contained in:
parent
9b0d354683
commit
be82337924
@ -440,13 +440,13 @@
|
||||
"loading": "Loading...",
|
||||
"createCustomerPortalFailed": "Failed to open Stripe customer portal"
|
||||
},
|
||||
"price": "Price:",
|
||||
"nextBillingDate": "Next billing date:",
|
||||
"trialEnds": "Trial ends:",
|
||||
"freePlanMessage": "You are currently on the free plan with limited features",
|
||||
"lifetimeMessage": "You have lifetime access to all premium features",
|
||||
"manageSubscription": "Manage Subscription",
|
||||
"billingHistory": "Billing History",
|
||||
"manageBilling": "Manage Subscription and Billing",
|
||||
"manageSubscription": "Manage Subscription and Billing",
|
||||
"manageBilling": "Manage Billing",
|
||||
"upgradePlan": "Upgrade Plan",
|
||||
"retry": "Retry",
|
||||
"errorMessage": "Failed to get data"
|
||||
|
@ -440,13 +440,13 @@
|
||||
"loading": "加载中...",
|
||||
"createCustomerPortalFailed": "打开Stripe客户界面失败"
|
||||
},
|
||||
"price": "价格:",
|
||||
"nextBillingDate": "下次账单日期:",
|
||||
"trialEnds": "试用结束日期:",
|
||||
"freePlanMessage": "您当前使用的是功能有限的免费方案",
|
||||
"lifetimeMessage": "您拥有所有高级功能的终身使用权限",
|
||||
"manageSubscription": "管理订阅",
|
||||
"billingHistory": "账单历史",
|
||||
"manageBilling": "管理订阅和账单",
|
||||
"manageSubscription": "管理订阅和账单",
|
||||
"manageBilling": "管理账单",
|
||||
"retry": "重试",
|
||||
"errorMessage": "获取数据失败"
|
||||
},
|
||||
|
@ -1,9 +1,10 @@
|
||||
'use client';
|
||||
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Separator } from '@/components/ui/separator';
|
||||
import { useCopyToClipboard } from '@/hooks/use-clipboard';
|
||||
import { isUrlCached } from '@/lib/serviceWorker';
|
||||
import { cn, titleToNumber } from '@/lib/utils';
|
||||
import { cn } from '@/lib/utils';
|
||||
import * as RadioGroup from '@radix-ui/react-radio-group';
|
||||
import { Check, Code2, Copy, Eye, Maximize, Terminal } from 'lucide-react';
|
||||
import Link from 'next/link';
|
||||
@ -16,7 +17,6 @@ import {
|
||||
type ImperativePanelGroupHandle,
|
||||
} from 'react-resizable-panels';
|
||||
import { useMedia } from 'use-media';
|
||||
import { Button } from '@/components/ui/button';
|
||||
|
||||
export interface BlockPreviewProps {
|
||||
code?: string;
|
||||
@ -36,6 +36,11 @@ const LGSIZE = 82;
|
||||
|
||||
const getCacheKey = (src: string) => `iframe-cache-${src}`;
|
||||
|
||||
const titleToNumber = (title: string): number => {
|
||||
const titles = ["one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen", "twenty"];
|
||||
return titles.indexOf(title.toLowerCase()) + 1;
|
||||
};
|
||||
|
||||
export const BlockPreview: React.FC<BlockPreviewProps> = ({
|
||||
code,
|
||||
preview,
|
||||
|
@ -27,7 +27,7 @@ export default function BillingCard() {
|
||||
console.log('billing card, currentUser:', currentUser);
|
||||
|
||||
// Check if user is a lifetime member
|
||||
const isLifetimeMember = currentUser?.lifetimeMember === true;
|
||||
const isLifetimePlan = currentUser?.lifetimeMember === true;
|
||||
const hasCustomerId = Boolean(currentUser?.customerId);
|
||||
|
||||
// Get all available plans
|
||||
@ -35,7 +35,7 @@ export default function BillingCard() {
|
||||
console.log('billing card, plans:', plans);
|
||||
|
||||
// Determine current plan based on user status
|
||||
const currentPlan = isLifetimeMember
|
||||
const currentPlan = isLifetimePlan
|
||||
? plans.find(plan => plan.isLifetime)
|
||||
: subscription
|
||||
? plans.find(plan => plan.id === subscription?.planId)
|
||||
@ -43,7 +43,9 @@ export default function BillingCard() {
|
||||
console.log('billing card, currentPlan:', currentPlan);
|
||||
|
||||
// Show upgrade button if user is on free plan
|
||||
const canUpgrade = currentPlan?.isFree;
|
||||
// OPTIMIZE: should we show upgrade button if user has a subscription?
|
||||
const isFreePlan = currentPlan?.isFree;
|
||||
const canUpgrade = !isFreePlan;
|
||||
console.log('billing card, canUpgrade:', canUpgrade);
|
||||
|
||||
// Get subscription price details
|
||||
@ -60,9 +62,9 @@ export default function BillingCard() {
|
||||
|
||||
// Fetch customer subscription data
|
||||
const fetchSubscription = async () => {
|
||||
console.log('fetchSubscription, isLifetimeMember:', isLifetimeMember, 'hasCustomerId:', hasCustomerId);
|
||||
console.log('fetchSubscription, isLifetimeMember:', isLifetimePlan, 'hasCustomerId:', hasCustomerId);
|
||||
// Skip fetching if user is a lifetime member
|
||||
if (isLifetimeMember) return;
|
||||
if (isLifetimePlan) return;
|
||||
|
||||
// Skip fetching if user doesn't have a customer ID
|
||||
if (!hasCustomerId) return;
|
||||
@ -155,12 +157,13 @@ export default function BillingCard() {
|
||||
<CardDescription>{t('currentPlan.description')}</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4">
|
||||
{/* Plan name and status */}
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="text-3xl font-medium">
|
||||
{currentPlan?.name}
|
||||
</div>
|
||||
<Badge variant={currentPlan?.isFree || isLifetimeMember ? 'outline' : 'default'}>
|
||||
{isLifetimeMember
|
||||
<Badge variant={currentPlan?.isFree || isLifetimePlan ? 'outline' : 'default'}>
|
||||
{isLifetimePlan
|
||||
? t('status.lifetime')
|
||||
: subscription?.status === 'active'
|
||||
? t('status.active')
|
||||
@ -170,11 +173,25 @@ export default function BillingCard() {
|
||||
</Badge>
|
||||
</div>
|
||||
|
||||
{/* Subscription plan details */}
|
||||
{/* Free plan message */}
|
||||
{isFreePlan && (
|
||||
<div className="text-sm text-muted-foreground">
|
||||
{t('freePlanMessage')}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Lifetime plan message */}
|
||||
{isLifetimePlan && (
|
||||
<div className="text-sm text-muted-foreground">
|
||||
{t('lifetimeMessage')}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Subscription plan message */}
|
||||
{subscription && currentPrice && (
|
||||
<div className="text-sm text-muted-foreground space-y-1">
|
||||
<div className="text-sm text-muted-foreground space-y-2">
|
||||
<div>
|
||||
{formatPrice(currentPrice.amount, currentPrice.currency)} / {currentPrice.interval === PlanIntervals.MONTH ?
|
||||
{t('price')} {formatPrice(currentPrice.amount, currentPrice.currency)} / {currentPrice.interval === PlanIntervals.MONTH ?
|
||||
t('interval.month') :
|
||||
currentPrice.interval === PlanIntervals.YEAR ?
|
||||
t('interval.year') :
|
||||
@ -192,37 +209,13 @@ export default function BillingCard() {
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Free plan message */}
|
||||
{currentPlan?.isFree && (
|
||||
<div className="text-sm text-muted-foreground">
|
||||
{t('freePlanMessage')}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Lifetime access message */}
|
||||
{isLifetimeMember && (
|
||||
<div className="text-sm text-muted-foreground">
|
||||
{t('lifetimeMessage')}
|
||||
</div>
|
||||
)}
|
||||
</CardContent>
|
||||
<CardFooter>
|
||||
<div className="grid w-full gap-3">
|
||||
{/* Manage subscription button - only shown if user has a customer ID */}
|
||||
{hasCustomerId && currentUser?.customerId && (
|
||||
<CustomerPortalButton
|
||||
customerId={currentUser.customerId}
|
||||
className="w-full"
|
||||
>
|
||||
{t('manageBilling')}
|
||||
</CustomerPortalButton>
|
||||
)}
|
||||
|
||||
{/* View pricing plans button - only shown if user can upgrade */}
|
||||
{canUpgrade && (
|
||||
<div className="w-full gap-4 flex flex-col">
|
||||
{/* Show upgrade plan button - only shown if user can upgrade */}
|
||||
{isFreePlan && (
|
||||
<Button
|
||||
variant={subscription ? "outline" : "default"}
|
||||
variant="default"
|
||||
className="w-full cursor-pointer"
|
||||
asChild
|
||||
>
|
||||
@ -231,6 +224,26 @@ export default function BillingCard() {
|
||||
</LocaleLink>
|
||||
</Button>
|
||||
)}
|
||||
|
||||
{/* Manage billing button - only shown if user is lifetime member */}
|
||||
{isLifetimePlan && currentUser?.customerId && (
|
||||
<CustomerPortalButton
|
||||
customerId={currentUser.customerId}
|
||||
className="w-full"
|
||||
>
|
||||
{t('manageBilling')}
|
||||
</CustomerPortalButton>
|
||||
)}
|
||||
|
||||
{/* Manage subscription button - only shown if user has subscription */}
|
||||
{subscription && currentUser?.customerId && (
|
||||
<CustomerPortalButton
|
||||
customerId={currentUser.customerId}
|
||||
className="w-full"
|
||||
>
|
||||
{t('manageSubscription')}
|
||||
</CustomerPortalButton>
|
||||
)}
|
||||
</div>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
|
Loading…
Reference in New Issue
Block a user