diff --git a/apps/dashboard/src/app/(dashboard)/offers/page.tsx b/apps/dashboard/src/app/(dashboard)/offers/page.tsx index 21ce8b1..de93951 100644 --- a/apps/dashboard/src/app/(dashboard)/offers/page.tsx +++ b/apps/dashboard/src/app/(dashboard)/offers/page.tsx @@ -2,7 +2,7 @@ import { useEffect, useState } from 'react' import dayjs from 'dayjs' -import { formatCurrency } from '@rentaldrivego/types' +import { formatCurrency, getCurrencyLabel } from '@rentaldrivego/types' import { apiFetch } from '@/lib/api' import { useDashboardI18n } from '@/components/I18nProvider' @@ -296,11 +296,11 @@ const copy = { }, } -function discountLabel(offer: Offer, t: typeof copy['en']): string { +function discountLabel(offer: Offer, t: typeof copy['en'], language: 'en' | 'fr' | 'ar'): string { if (offer.type === 'PERCENTAGE') return `${offer.discountValue}%` - if (offer.type === 'FIXED_AMOUNT') return formatCurrency(offer.discountValue, 'MAD') + if (offer.type === 'FIXED_AMOUNT') return formatCurrency(offer.discountValue, 'MAD', language) if (offer.type === 'FREE_DAY') return t.freeDay - if (offer.type === 'SPECIAL_RATE') return `${offer.specialRate ?? offer.discountValue} MAD/day` + if (offer.type === 'SPECIAL_RATE') return `${offer.specialRate ?? offer.discountValue} ${getCurrencyLabel(language)}${language === 'fr' ? '/jour' : language === 'ar' ? '/يوم' : '/day'}` return String(offer.discountValue) } @@ -507,7 +507,7 @@ export default function OffersPage() { -

{discountLabel(offer, t)}

+

{discountLabel(offer, t, language)}

{offer.description && (

{offer.description}

diff --git a/apps/dashboard/src/app/sign-up/[[...sign-up]]/page.tsx b/apps/dashboard/src/app/sign-up/[[...sign-up]]/page.tsx index 36c203e..1969111 100644 --- a/apps/dashboard/src/app/sign-up/[[...sign-up]]/page.tsx +++ b/apps/dashboard/src/app/sign-up/[[...sign-up]]/page.tsx @@ -4,6 +4,7 @@ import Image from 'next/image' import Link from 'next/link' import { useState } from 'react' import { useSearchParams } from 'next/navigation' +import { getCurrencyLabel } from '@rentaldrivego/types' import { useDashboardI18n } from '@/components/I18nProvider' import { apiFetch } from '@/lib/api' import PublicShell from '@/components/layout/PublicShell' @@ -739,7 +740,7 @@ export default function SignUpPage() {

{dict.reviewWorkspace}: {form.companyName.fr || form.companyName.ar || dict.companyFallback}{form.companyName.fr && form.companyName.ar ? / {form.companyName.ar} : null}

{dict.reviewLegalName}: {form.legalName || '—'}

-

{dict.reviewPlan}: {form.plan} · {dict.billingPeriodOptions[form.billingPeriod]} · MAD

+

{dict.reviewPlan}: {form.plan} · {dict.billingPeriodOptions[form.billingPeriod]} · {getCurrencyLabel(language)}

{dict.reviewOwnerEmail}: {form.email || '—'}

{dict.reviewCompanyEmail}: {form.companyEmail || '—'}

{dict.reviewPhone}: {form.companyPhone || '—'}

diff --git a/apps/marketplace/src/app/(public)/explore/ExploreVehicleGrid.tsx b/apps/marketplace/src/app/(public)/explore/ExploreVehicleGrid.tsx index 16b0379..52b8586 100644 --- a/apps/marketplace/src/app/(public)/explore/ExploreVehicleGrid.tsx +++ b/apps/marketplace/src/app/(public)/explore/ExploreVehicleGrid.tsx @@ -1,4 +1,5 @@ import Link from 'next/link' +import { formatCurrency, type Locale } from '@rentaldrivego/types' interface Vehicle { id: string @@ -38,8 +39,8 @@ interface Dict { availableVehicles: string } -function formatCents(cents: number) { - return `${(cents / 100).toLocaleString('fr-MA', { minimumFractionDigits: 2 })} MAD` +function formatCents(cents: number, language: Locale) { + return formatCurrency(cents, 'MAD', language) } function formatAvailabilityDate(value?: string | null) { @@ -55,7 +56,7 @@ function getStatusCopy(vehicle: Vehicle, dict: Dict) { return dict.available } -export default function ExploreVehicleGrid({ vehicles, dict }: { vehicles: Vehicle[]; dict: Dict }) { +export default function ExploreVehicleGrid({ vehicles, dict, language }: { vehicles: Vehicle[]; dict: Dict; language: Locale }) { return (
@@ -90,7 +91,7 @@ export default function ExploreVehicleGrid({ vehicles, dict }: { vehicles: Vehic

{dict.from}

-

{formatCents(vehicle.dailyRate)}

+

{formatCents(vehicle.dailyRate, language)}

)}
-

{formatCurrency(vehicle.dailyRate, 'MAD')}

+

{formatCurrency(vehicle.dailyRate, 'MAD', language)}

{dict.viewVehicle}
diff --git a/apps/marketplace/src/app/(public)/explore/[slug]/vehicles/[id]/page.tsx b/apps/marketplace/src/app/(public)/explore/[slug]/vehicles/[id]/page.tsx index a13ac2c..8dde0a0 100644 --- a/apps/marketplace/src/app/(public)/explore/[slug]/vehicles/[id]/page.tsx +++ b/apps/marketplace/src/app/(public)/explore/[slug]/vehicles/[id]/page.tsx @@ -247,7 +247,7 @@ export default async function VehicleDetailPage({ params }: { params: { slug: st

{vehicle.make} {vehicle.model}

{vehicle.year} · {vehicle.category}

- {formatCurrency(vehicle.dailyRate, 'MAD')} + {formatCurrency(vehicle.dailyRate, 'MAD', language)} {dict.perDay}

diff --git a/apps/marketplace/src/app/(public)/explore/page.tsx b/apps/marketplace/src/app/(public)/explore/page.tsx index f7da186..9e81de0 100644 --- a/apps/marketplace/src/app/(public)/explore/page.tsx +++ b/apps/marketplace/src/app/(public)/explore/page.tsx @@ -292,7 +292,7 @@ export default async function ExplorePage({ searchParams }: { searchParams?: Rec
- +

{dict.browseByCategory}

diff --git a/apps/marketplace/src/app/(public)/pricing/PricingClient.tsx b/apps/marketplace/src/app/(public)/pricing/PricingClient.tsx index f267281..af70cfb 100644 --- a/apps/marketplace/src/app/(public)/pricing/PricingClient.tsx +++ b/apps/marketplace/src/app/(public)/pricing/PricingClient.tsx @@ -2,7 +2,7 @@ import { useEffect, useState } from 'react' import Link from 'next/link' -import { PLAN_FEATURES, PLAN_PRICES } from '@rentaldrivego/types' +import { getCurrencyLabel, PLAN_FEATURES, PLAN_PRICES } from '@rentaldrivego/types' import { useMarketplacePreferences } from '@/components/MarketplaceShell' import { marketplaceFetchOrDefault } from '@/lib/api' import { resolveBrowserAppUrl } from '@/lib/appUrls' @@ -96,6 +96,7 @@ function annualSavingsPct(prices: PricingMatrix, plan: string): number { export default function PricingClient({ initialPricing = DEFAULT_PRICING }: { initialPricing?: PlatformPricing }) { const { language } = useMarketplacePreferences() + const currencyLabel = getCurrencyLabel(language) const dict = copy[language] const [billing, setBilling] = useState('monthly') const [pricing, setPricing] = useState(initialPricing) @@ -175,12 +176,12 @@ export default function PricingClient({ initialPricing = DEFAULT_PRICING }: { in {displayPrice} - MAD + {currencyLabel} {dict.perMonth}
{billing === 'annual' && (

- {dict.billedAs} {annualPrice} MAD {dict.yearly} + {dict.billedAs} {annualPrice} {currencyLabel} {dict.yearly}

)} diff --git a/apps/marketplace/src/components/BookingForm.tsx b/apps/marketplace/src/components/BookingForm.tsx index a4bc299..59e4f7b 100644 --- a/apps/marketplace/src/components/BookingForm.tsx +++ b/apps/marketplace/src/components/BookingForm.tsx @@ -1,6 +1,7 @@ 'use client' import { useState } from 'react' +import { formatCurrency } from '@rentaldrivego/types' import { marketplacePost } from '@/lib/api' import { useMarketplacePreferences } from '@/components/MarketplaceShell' @@ -507,7 +508,7 @@ export default function BookingForm({

{t.estimatedTotal}:{' '} - {(dailyRate * totalDays).toLocaleString()} MAD + {formatCurrency(dailyRate * totalDays, 'MAD', language)} {' '} ({totalDays} {t.days})

diff --git a/packages/types/src/api.ts b/packages/types/src/api.ts index 1d6dfcc..1d69796 100644 --- a/packages/types/src/api.ts +++ b/packages/types/src/api.ts @@ -61,13 +61,37 @@ export const PLAN_FEATURES: Record = { export type Locale = 'en' | 'fr' | 'ar' export type SupportedCurrency = 'MAD' -export function formatCurrency(amount: number, _currency: SupportedCurrency = 'MAD', locale: Locale = 'en'): string { +function resolveLocale(locale?: Locale): Locale { + if (locale) return locale + + const lang = + typeof globalThis === 'object' && 'document' in globalThis + ? (globalThis as { document?: { documentElement?: { lang?: string } } }).document?.documentElement?.lang + : undefined + + if (lang === 'en' || lang === 'fr' || lang === 'ar') { + return lang + } + + return 'en' +} + +export function getCurrencyLabel(locale?: Locale, _currency: SupportedCurrency = 'MAD'): string { + return resolveLocale(locale) === 'ar' ? 'درهم' : 'MAD' +} + +export function formatCurrency(amount: number, _currency: SupportedCurrency = 'MAD', locale?: Locale): string { + const resolvedLocale = resolveLocale(locale) const divisor = 100 const value = amount / divisor const localeMap: Record = { en: 'en-US', fr: 'fr-FR', ar: 'ar-MA' } - return new Intl.NumberFormat(localeMap[locale], { - style: 'currency', - currency: 'MAD', + const formattedValue = new Intl.NumberFormat(localeMap[resolvedLocale], { minimumFractionDigits: 2, + maximumFractionDigits: 2, }).format(value) + const currencyLabel = getCurrencyLabel(resolvedLocale, _currency) + + return resolvedLocale === 'en' + ? `${currencyLabel} ${formattedValue}` + : `${formattedValue} ${currencyLabel}` }