update ar currency

This commit is contained in:
root
2026-06-02 01:45:05 -04:00
parent 8f57ca9d76
commit 29886c3397
9 changed files with 49 additions and 21 deletions
@@ -2,7 +2,7 @@
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import { formatCurrency } from '@rentaldrivego/types' import { formatCurrency, getCurrencyLabel } from '@rentaldrivego/types'
import { apiFetch } from '@/lib/api' import { apiFetch } from '@/lib/api'
import { useDashboardI18n } from '@/components/I18nProvider' 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 === '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 === '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) return String(offer.discountValue)
} }
@@ -507,7 +507,7 @@ export default function OffersPage() {
</span> </span>
</div> </div>
<p className="text-2xl font-bold text-slate-900">{discountLabel(offer, t)}</p> <p className="text-2xl font-bold text-slate-900">{discountLabel(offer, t, language)}</p>
{offer.description && ( {offer.description && (
<p className="text-sm text-slate-500 line-clamp-2">{offer.description}</p> <p className="text-sm text-slate-500 line-clamp-2">{offer.description}</p>
@@ -4,6 +4,7 @@ import Image from 'next/image'
import Link from 'next/link' import Link from 'next/link'
import { useState } from 'react' import { useState } from 'react'
import { useSearchParams } from 'next/navigation' import { useSearchParams } from 'next/navigation'
import { getCurrencyLabel } from '@rentaldrivego/types'
import { useDashboardI18n } from '@/components/I18nProvider' import { useDashboardI18n } from '@/components/I18nProvider'
import { apiFetch } from '@/lib/api' import { apiFetch } from '@/lib/api'
import PublicShell from '@/components/layout/PublicShell' import PublicShell from '@/components/layout/PublicShell'
@@ -739,7 +740,7 @@ export default function SignUpPage() {
<div className="rounded-3xl border border-slate-200 bg-slate-50 p-5 text-sm text-slate-600"> <div className="rounded-3xl border border-slate-200 bg-slate-50 p-5 text-sm text-slate-600">
<p><span className="font-semibold text-slate-900">{dict.reviewWorkspace}:</span> {form.companyName.fr || form.companyName.ar || dict.companyFallback}{form.companyName.fr && form.companyName.ar ? <span className="ml-2 text-slate-400">/ {form.companyName.ar}</span> : null}</p> <p><span className="font-semibold text-slate-900">{dict.reviewWorkspace}:</span> {form.companyName.fr || form.companyName.ar || dict.companyFallback}{form.companyName.fr && form.companyName.ar ? <span className="ml-2 text-slate-400">/ {form.companyName.ar}</span> : null}</p>
<p className="mt-2"><span className="font-semibold text-slate-900">{dict.reviewLegalName}:</span> {form.legalName || '—'}</p> <p className="mt-2"><span className="font-semibold text-slate-900">{dict.reviewLegalName}:</span> {form.legalName || '—'}</p>
<p className="mt-2"><span className="font-semibold text-slate-900">{dict.reviewPlan}:</span> {form.plan} · {dict.billingPeriodOptions[form.billingPeriod]} · MAD</p> <p className="mt-2"><span className="font-semibold text-slate-900">{dict.reviewPlan}:</span> {form.plan} · {dict.billingPeriodOptions[form.billingPeriod]} · {getCurrencyLabel(language)}</p>
<p className="mt-2"><span className="font-semibold text-slate-900">{dict.reviewOwnerEmail}:</span> {form.email || '—'}</p> <p className="mt-2"><span className="font-semibold text-slate-900">{dict.reviewOwnerEmail}:</span> {form.email || '—'}</p>
<p className="mt-2"><span className="font-semibold text-slate-900">{dict.reviewCompanyEmail}:</span> {form.companyEmail || '—'}</p> <p className="mt-2"><span className="font-semibold text-slate-900">{dict.reviewCompanyEmail}:</span> {form.companyEmail || '—'}</p>
<p className="mt-2"><span className="font-semibold text-slate-900">{dict.reviewPhone}:</span> {form.companyPhone || '—'}</p> <p className="mt-2"><span className="font-semibold text-slate-900">{dict.reviewPhone}:</span> {form.companyPhone || '—'}</p>
@@ -1,4 +1,5 @@
import Link from 'next/link' import Link from 'next/link'
import { formatCurrency, type Locale } from '@rentaldrivego/types'
interface Vehicle { interface Vehicle {
id: string id: string
@@ -38,8 +39,8 @@ interface Dict {
availableVehicles: string availableVehicles: string
} }
function formatCents(cents: number) { function formatCents(cents: number, language: Locale) {
return `${(cents / 100).toLocaleString('fr-MA', { minimumFractionDigits: 2 })} MAD` return formatCurrency(cents, 'MAD', language)
} }
function formatAvailabilityDate(value?: string | null) { function formatAvailabilityDate(value?: string | null) {
@@ -55,7 +56,7 @@ function getStatusCopy(vehicle: Vehicle, dict: Dict) {
return dict.available 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 ( return (
<section> <section>
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
@@ -90,7 +91,7 @@ export default function ExploreVehicleGrid({ vehicles, dict }: { vehicles: Vehic
<div className="mt-4 flex items-end justify-between gap-3"> <div className="mt-4 flex items-end justify-between gap-3">
<div className="min-w-0"> <div className="min-w-0">
<p className="text-sm text-stone-500 dark:text-stone-400">{dict.from}</p> <p className="text-sm text-stone-500 dark:text-stone-400">{dict.from}</p>
<p className="truncate text-xl font-black text-stone-900 dark:text-stone-100">{formatCents(vehicle.dailyRate)}</p> <p className="truncate text-xl font-black text-stone-900 dark:text-stone-100">{formatCents(vehicle.dailyRate, language)}</p>
</div> </div>
<Link <Link
href={`/explore/${vehicle.company.slug}/vehicles/${vehicle.id}`} href={`/explore/${vehicle.company.slug}/vehicles/${vehicle.id}`}
@@ -145,7 +145,7 @@ export default async function CompanyProfilePage({ params }: { params: { slug: s
</p> </p>
)} )}
<div className="mt-4 flex items-end justify-between gap-3"> <div className="mt-4 flex items-end justify-between gap-3">
<p className="min-w-0 truncate text-xl font-black text-stone-900 dark:text-stone-100">{formatCurrency(vehicle.dailyRate, 'MAD')}</p> <p className="min-w-0 truncate text-xl font-black text-stone-900 dark:text-stone-100">{formatCurrency(vehicle.dailyRate, 'MAD', language)}</p>
<Link href={`/explore/${params.slug}/vehicles/${vehicle.id}`} className="shrink-0 rounded-full bg-blue-900 px-4 py-2 text-sm font-semibold text-white transition hover:bg-orange-700 dark:bg-orange-500 dark:text-white dark:hover:bg-orange-400">{dict.viewVehicle}</Link> <Link href={`/explore/${params.slug}/vehicles/${vehicle.id}`} className="shrink-0 rounded-full bg-blue-900 px-4 py-2 text-sm font-semibold text-white transition hover:bg-orange-700 dark:bg-orange-500 dark:text-white dark:hover:bg-orange-400">{dict.viewVehicle}</Link>
</div> </div>
</div> </div>
@@ -247,7 +247,7 @@ export default async function VehicleDetailPage({ params }: { params: { slug: st
<h1 className="text-3xl font-black text-stone-900 dark:text-stone-100">{vehicle.make} {vehicle.model}</h1> <h1 className="text-3xl font-black text-stone-900 dark:text-stone-100">{vehicle.make} {vehicle.model}</h1>
<p className="text-stone-500 dark:text-stone-400">{vehicle.year} · {vehicle.category}</p> <p className="text-stone-500 dark:text-stone-400">{vehicle.year} · {vehicle.category}</p>
<p className="text-3xl font-black text-stone-900 dark:text-stone-100"> <p className="text-3xl font-black text-stone-900 dark:text-stone-100">
{formatCurrency(vehicle.dailyRate, 'MAD')} {formatCurrency(vehicle.dailyRate, 'MAD', language)}
<span className="text-base font-medium text-stone-500 dark:text-stone-400"> {dict.perDay}</span> <span className="text-base font-medium text-stone-500 dark:text-stone-400"> {dict.perDay}</span>
</p> </p>
@@ -292,7 +292,7 @@ export default async function ExplorePage({ searchParams }: { searchParams?: Rec
</div> </div>
</section> </section>
<ExploreVehicleGrid vehicles={vehicles} dict={dict} /> <ExploreVehicleGrid vehicles={vehicles} dict={dict} language={language} />
<section> <section>
<h2 className="text-2xl font-bold text-stone-900 dark:text-stone-100">{dict.browseByCategory}</h2> <h2 className="text-2xl font-bold text-stone-900 dark:text-stone-100">{dict.browseByCategory}</h2>
@@ -2,7 +2,7 @@
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
import Link from 'next/link' 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 { useMarketplacePreferences } from '@/components/MarketplaceShell'
import { marketplaceFetchOrDefault } from '@/lib/api' import { marketplaceFetchOrDefault } from '@/lib/api'
import { resolveBrowserAppUrl } from '@/lib/appUrls' 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 }) { export default function PricingClient({ initialPricing = DEFAULT_PRICING }: { initialPricing?: PlatformPricing }) {
const { language } = useMarketplacePreferences() const { language } = useMarketplacePreferences()
const currencyLabel = getCurrencyLabel(language)
const dict = copy[language] const dict = copy[language]
const [billing, setBilling] = useState<Billing>('monthly') const [billing, setBilling] = useState<Billing>('monthly')
const [pricing, setPricing] = useState<PlatformPricing>(initialPricing) const [pricing, setPricing] = useState<PlatformPricing>(initialPricing)
@@ -175,12 +176,12 @@ export default function PricingClient({ initialPricing = DEFAULT_PRICING }: { in
<span className="text-4xl font-black text-stone-900 dark:text-stone-100"> <span className="text-4xl font-black text-stone-900 dark:text-stone-100">
{displayPrice} {displayPrice}
</span> </span>
<span className="mb-1 text-lg font-semibold text-stone-500 dark:text-stone-400">MAD</span> <span className="mb-1 text-lg font-semibold text-stone-500 dark:text-stone-400">{currencyLabel}</span>
<span className="mb-1 text-sm text-stone-400 dark:text-stone-500">{dict.perMonth}</span> <span className="mb-1 text-sm text-stone-400 dark:text-stone-500">{dict.perMonth}</span>
</div> </div>
{billing === 'annual' && ( {billing === 'annual' && (
<p className="mt-1 text-xs text-stone-400 dark:text-stone-500"> <p className="mt-1 text-xs text-stone-400 dark:text-stone-500">
{dict.billedAs} {annualPrice} MAD {dict.yearly} {dict.billedAs} {annualPrice} {currencyLabel} {dict.yearly}
</p> </p>
)} )}
</div> </div>
@@ -1,6 +1,7 @@
'use client' 'use client'
import { useState } from 'react' import { useState } from 'react'
import { formatCurrency } from '@rentaldrivego/types'
import { marketplacePost } from '@/lib/api' import { marketplacePost } from '@/lib/api'
import { useMarketplacePreferences } from '@/components/MarketplaceShell' import { useMarketplacePreferences } from '@/components/MarketplaceShell'
@@ -507,7 +508,7 @@ export default function BookingForm({
<p className="text-sm text-stone-600 dark:text-stone-400"> <p className="text-sm text-stone-600 dark:text-stone-400">
{t.estimatedTotal}:{' '} {t.estimatedTotal}:{' '}
<strong className="text-stone-900 dark:text-stone-100"> <strong className="text-stone-900 dark:text-stone-100">
{(dailyRate * totalDays).toLocaleString()} MAD {formatCurrency(dailyRate * totalDays, 'MAD', language)}
</strong>{' '} </strong>{' '}
({totalDays} {t.days}) ({totalDays} {t.days})
</p> </p>
+28 -4
View File
@@ -61,13 +61,37 @@ export const PLAN_FEATURES: Record<string, string[]> = {
export type Locale = 'en' | 'fr' | 'ar' export type Locale = 'en' | 'fr' | 'ar'
export type SupportedCurrency = 'MAD' 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 divisor = 100
const value = amount / divisor const value = amount / divisor
const localeMap: Record<Locale, string> = { en: 'en-US', fr: 'fr-FR', ar: 'ar-MA' } const localeMap: Record<Locale, string> = { en: 'en-US', fr: 'fr-FR', ar: 'ar-MA' }
return new Intl.NumberFormat(localeMap[locale], { const formattedValue = new Intl.NumberFormat(localeMap[resolvedLocale], {
style: 'currency',
currency: 'MAD',
minimumFractionDigits: 2, minimumFractionDigits: 2,
maximumFractionDigits: 2,
}).format(value) }).format(value)
const currencyLabel = getCurrencyLabel(resolvedLocale, _currency)
return resolvedLocale === 'en'
? `${currencyLabel} ${formattedValue}`
: `${formattedValue} ${currencyLabel}`
} }