update subscription algorithm
This commit is contained in:
@@ -5,29 +5,12 @@ import Link from 'next/link'
|
||||
import { useMarketplacePreferences } from '@/components/MarketplaceShell'
|
||||
import { resolveBrowserAppUrl } from '@/lib/appUrls'
|
||||
|
||||
type Currency = 'MAD' | 'USD' | 'EUR'
|
||||
type Billing = 'monthly' | 'annual'
|
||||
|
||||
const SYMBOL: Record<Currency, string> = { MAD: 'MAD', USD: '$', EUR: '€' }
|
||||
|
||||
const LANGUAGE_CURRENCY: Record<string, Currency> = { ar: 'MAD', fr: 'EUR', en: 'USD' }
|
||||
|
||||
const PRICES: Record<string, Record<Currency, { monthly: number; annual: number }>> = {
|
||||
STARTER: {
|
||||
MAD: { monthly: 299, annual: 299 },
|
||||
USD: { monthly: 29, annual: 290 },
|
||||
EUR: { monthly: 27, annual: 270 },
|
||||
},
|
||||
GROWTH: {
|
||||
MAD: { monthly: 599, annual: 399 },
|
||||
USD: { monthly: 59, annual: 590 },
|
||||
EUR: { monthly: 55, annual: 550 },
|
||||
},
|
||||
PRO: {
|
||||
MAD: { monthly: 999, annual: 9990 },
|
||||
USD: { monthly: 99, annual: 990 },
|
||||
EUR: { monthly: 92, annual: 920 },
|
||||
},
|
||||
const PRICES: Record<string, { monthly: number; annual: number }> = {
|
||||
STARTER: { monthly: 299, annual: 2990 },
|
||||
GROWTH: { monthly: 399, annual: 3990 },
|
||||
PRO: { monthly: 499, annual: 4990 },
|
||||
}
|
||||
|
||||
const PLANS = [
|
||||
@@ -110,14 +93,8 @@ const copy = {
|
||||
},
|
||||
} as const
|
||||
|
||||
function fmt(value: number, currency: Currency, billing: Billing): string {
|
||||
const sym = SYMBOL[currency]
|
||||
const amount = billing === 'annual' ? Math.round(value / 12) : value
|
||||
return currency === 'MAD' ? `${amount} ${sym}` : `${sym}${amount}`
|
||||
}
|
||||
|
||||
function annualSavingsPct(plan: string, currency: Currency): number {
|
||||
const { monthly, annual } = PRICES[plan][currency]
|
||||
function annualSavingsPct(plan: string): number {
|
||||
const { monthly, annual } = PRICES[plan]
|
||||
const wouldPay = monthly * 12
|
||||
return Math.round(((wouldPay - annual) / wouldPay) * 100)
|
||||
}
|
||||
@@ -125,58 +102,34 @@ function annualSavingsPct(plan: string, currency: Currency): number {
|
||||
export default function PricingClient() {
|
||||
const { language } = useMarketplacePreferences()
|
||||
const dict = copy[language]
|
||||
const [currency, setCurrency] = useState<Currency>(() => LANGUAGE_CURRENCY[language] ?? 'MAD')
|
||||
const [billing, setBilling] = useState<Billing>('monthly')
|
||||
|
||||
useEffect(() => {
|
||||
setCurrency(LANGUAGE_CURRENCY[language] ?? 'MAD')
|
||||
}, [language])
|
||||
const dashboardUrl = resolveBrowserAppUrl(process.env.NEXT_PUBLIC_DASHBOARD_URL ?? 'http://localhost:3000/dashboard')
|
||||
|
||||
const savings = annualSavingsPct('STARTER', currency)
|
||||
const savings = annualSavingsPct('STARTER')
|
||||
|
||||
return (
|
||||
<div className="space-y-10">
|
||||
{/* Toggles */}
|
||||
<div className="flex flex-col items-center gap-6 sm:flex-row sm:justify-center">
|
||||
{/* Billing toggle */}
|
||||
<div className="flex items-center gap-1 rounded-full border border-stone-200 bg-white p-1 shadow-sm dark:border-blue-800 dark:bg-[#0d1b38]">
|
||||
{(['monthly', 'annual'] as Billing[]).map((b) => (
|
||||
<button
|
||||
key={b}
|
||||
onClick={() => setBilling(b)}
|
||||
className={`relative rounded-full px-5 py-2 text-sm font-semibold transition-colors ${
|
||||
billing === b
|
||||
? 'bg-stone-900 text-white dark:bg-white dark:text-stone-900'
|
||||
: 'text-stone-600 hover:text-stone-900 dark:text-stone-400 dark:hover:text-stone-100'
|
||||
}`}
|
||||
>
|
||||
{b === 'monthly' ? dict.monthly : dict.annual}
|
||||
{b === 'annual' && billing !== 'annual' && (
|
||||
<span className="ml-2 rounded-full bg-orange-100 px-2 py-0.5 text-[10px] font-bold text-orange-700 dark:bg-orange-950/50 dark:text-orange-400">
|
||||
-{savings}%
|
||||
</span>
|
||||
)}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Currency toggle */}
|
||||
<div className="flex items-center gap-1 rounded-full border border-stone-200 bg-white p-1 shadow-sm dark:border-blue-800 dark:bg-[#0d1b38]">
|
||||
{(['MAD', 'USD', 'EUR'] as Currency[]).map((c) => (
|
||||
<button
|
||||
key={c}
|
||||
onClick={() => setCurrency(c)}
|
||||
className={`rounded-full px-4 py-2 text-sm font-semibold transition-colors ${
|
||||
currency === c
|
||||
? 'bg-orange-500 text-white dark:bg-orange-400 dark:text-stone-900'
|
||||
: 'text-stone-600 hover:text-stone-900 dark:text-stone-400 dark:hover:text-stone-100'
|
||||
}`}
|
||||
>
|
||||
{c}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
{/* Billing toggle */}
|
||||
<div className="flex items-center justify-center gap-1 rounded-full border border-stone-200 bg-white p-1 shadow-sm dark:border-blue-800 dark:bg-[#0d1b38]">
|
||||
{(['monthly', 'annual'] as Billing[]).map((b) => (
|
||||
<button
|
||||
key={b}
|
||||
onClick={() => setBilling(b)}
|
||||
className={`relative rounded-full px-5 py-2 text-sm font-semibold transition-colors ${
|
||||
billing === b
|
||||
? 'bg-stone-900 text-white dark:bg-white dark:text-stone-900'
|
||||
: 'text-stone-600 hover:text-stone-900 dark:text-stone-400 dark:hover:text-stone-100'
|
||||
}`}
|
||||
>
|
||||
{b === 'monthly' ? dict.monthly : dict.annual}
|
||||
{b === 'annual' && billing !== 'annual' && (
|
||||
<span className="ml-2 rounded-full bg-orange-100 px-2 py-0.5 text-[10px] font-bold text-orange-700 dark:bg-orange-950/50 dark:text-orange-400">
|
||||
-{savings}%
|
||||
</span>
|
||||
)}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{billing === 'annual' && (
|
||||
@@ -188,11 +141,10 @@ export default function PricingClient() {
|
||||
{/* Plan cards */}
|
||||
<div className="grid gap-6 md:grid-cols-3">
|
||||
{PLANS.map((plan) => {
|
||||
const price = PRICES[plan.key][currency]
|
||||
const price = PRICES[plan.key]
|
||||
const displayPrice = billing === 'annual'
|
||||
? Math.round(price.annual / 12)
|
||||
: price.monthly
|
||||
const sym = SYMBOL[currency]
|
||||
|
||||
return (
|
||||
<div
|
||||
@@ -218,20 +170,14 @@ export default function PricingClient() {
|
||||
<div className="mt-6">
|
||||
<div className="flex items-end gap-1">
|
||||
<span className="text-4xl font-black text-stone-900 dark:text-stone-100">
|
||||
{currency === 'MAD' ? displayPrice : `${sym}${displayPrice}`}
|
||||
{displayPrice}
|
||||
</span>
|
||||
{currency === 'MAD' && (
|
||||
<span className="mb-1 text-lg font-semibold text-stone-500 dark:text-stone-400">{sym}</span>
|
||||
)}
|
||||
<span className="mb-1 text-lg font-semibold text-stone-500 dark:text-stone-400">MAD</span>
|
||||
<span className="mb-1 text-sm text-stone-400 dark:text-stone-500">{dict.perMonth}</span>
|
||||
</div>
|
||||
{billing === 'annual' && (
|
||||
<p className="mt-1 text-xs text-stone-400 dark:text-stone-500">
|
||||
{dict.billedAs}{' '}
|
||||
{currency === 'MAD'
|
||||
? `${price.annual} ${sym}`
|
||||
: `${sym}${price.annual}`}{' '}
|
||||
{dict.yearly}
|
||||
{dict.billedAs} {price.annual} MAD {dict.yearly}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
@@ -254,7 +200,7 @@ export default function PricingClient() {
|
||||
</ul>
|
||||
|
||||
<Link
|
||||
href={`${dashboardUrl}/sign-up?plan=${plan.key}&billing=${billing.toUpperCase()}¤cy=${currency}`}
|
||||
href={`${dashboardUrl}/sign-up?plan=${plan.key}&billing=${billing.toUpperCase()}¤cy=MAD`}
|
||||
className={`mt-10 block rounded-full px-6 py-3 text-center text-sm font-semibold transition-colors ${
|
||||
plan.highlight
|
||||
? 'bg-orange-500 text-white hover:bg-orange-600 dark:bg-orange-400 dark:text-stone-900 dark:hover:bg-orange-300'
|
||||
|
||||
@@ -159,9 +159,9 @@ export default function RenterProfilePage() {
|
||||
/>
|
||||
<SelectField
|
||||
label={dict.currency}
|
||||
value={profile?.preferredCurrency || 'MAD'}
|
||||
options={['MAD', 'USD', 'EUR']}
|
||||
onChange={(value) => setProfile((current) => current ? { ...current, preferredCurrency: value } : current)}
|
||||
value="MAD"
|
||||
options={['MAD']}
|
||||
onChange={() => {}}
|
||||
/>
|
||||
</div>
|
||||
<div className="mt-8 flex justify-end">
|
||||
|
||||
Reference in New Issue
Block a user