update subscription algorithm

This commit is contained in:
root
2026-05-25 03:12:19 -04:00
parent 95376d3223
commit c9cbe479aa
42 changed files with 3098 additions and 307 deletions
@@ -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()}&currency=${currency}`}
href={`${dashboardUrl}/sign-up?plan=${plan.key}&billing=${billing.toUpperCase()}&currency=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">