add review and booking policies

This commit is contained in:
root
2026-05-25 18:29:05 -04:00
parent 8ed572b3bd
commit 0d969ab095
37 changed files with 3775 additions and 113 deletions
@@ -1,7 +1,7 @@
'use client'
import { useRouter } from 'next/navigation'
import { useEffect, useState } from 'react'
import { useCallback, useEffect, useState } from 'react'
import { formatCurrency, PLAN_PRICES } from '@rentaldrivego/types'
import { EMPLOYEE_PROFILE_KEY, apiFetch } from '@/lib/api'
import { useDashboardI18n } from '@/components/I18nProvider'
@@ -35,6 +35,13 @@ interface ProviderAvailability {
paypal: boolean
}
interface PlanFeature {
id: string
plan: Plan
label: string
sortOrder: number
}
interface EmployeeProfile {
role?: string
}
@@ -69,6 +76,8 @@ export default function SubscriptionPage() {
const currency = 'MAD'
const [provider, setProvider] = useState<'AMANPAY' | 'PAYPAL'>('AMANPAY')
const [providerAvailability, setProviderAvailability] = useState<ProviderAvailability>({ amanpay: false, paypal: false })
const [planPrices, setPlanPrices] = useState<Record<string, Record<string, Record<string, number>>>>(PLAN_PRICES)
const [planFeaturesList, setPlanFeaturesList] = useState<PlanFeature[]>([])
const [paying, setPaying] = useState(false)
const [cancelling, setCancelling] = useState(false)
const copy = {
@@ -228,6 +237,15 @@ export default function SubscriptionPage() {
})
}, [router])
const fetchPlanData = useCallback(async () => {
const [prices, features] = await Promise.all([
apiFetch<Record<string, Record<string, Record<string, number>>>>('/subscriptions/plans'),
apiFetch<PlanFeature[]>('/subscriptions/features'),
])
if (prices && Object.keys(prices).length > 0) setPlanPrices(prices)
if (features) setPlanFeaturesList(features)
}, [])
useEffect(() => {
if (canViewPage !== true) return
@@ -235,6 +253,7 @@ export default function SubscriptionPage() {
apiFetch<Subscription | null>('/subscriptions/me'),
apiFetch<Invoice[]>('/subscriptions/invoices'),
apiFetch<ProviderAvailability>('/subscriptions/providers'),
fetchPlanData(),
])
.then(([sub, inv, availability]) => {
setProviderAvailability(availability)
@@ -250,7 +269,21 @@ export default function SubscriptionPage() {
})
.catch((err) => setError(err.message))
.finally(() => setLoading(false))
}, [canViewPage])
}, [canViewPage, fetchPlanData])
useEffect(() => {
if (canViewPage !== true) return
const handleFocus = () => { fetchPlanData().catch(() => {}) }
const handleVisibility = () => {
if (document.visibilityState === 'visible') fetchPlanData().catch(() => {})
}
window.addEventListener('focus', handleFocus)
document.addEventListener('visibilitychange', handleVisibility)
return () => {
window.removeEventListener('focus', handleFocus)
document.removeEventListener('visibilitychange', handleVisibility)
}
}, [canViewPage, fetchPlanData])
if (canViewPage !== true) {
return null
@@ -309,7 +342,7 @@ export default function SubscriptionPage() {
}
}
const planPrice = PLAN_PRICES[selectedPlan]?.[billingPeriod]?.[currency]
const planPrice = planPrices[selectedPlan]?.[billingPeriod]?.[currency]
const daysLeft = subscription?.trialEndAt
? Math.ceil((new Date(subscription.trialEndAt).getTime() - Date.now()) / 86400000)
: null
@@ -402,8 +435,9 @@ export default function SubscriptionPage() {
{/* Plan cards */}
<div className="grid gap-4 md:grid-cols-3">
{PLANS.map((plan) => {
const price = PLAN_PRICES[plan]?.[billingPeriod]?.[currency]
const price = planPrices[plan]?.[billingPeriod]?.[currency]
const isActive = subscription?.plan === plan && subscription?.status === 'ACTIVE'
const features = planFeaturesList.filter((f) => f.plan === plan)
return (
<button
key={plan}
@@ -423,11 +457,17 @@ export default function SubscriptionPage() {
<span className="text-sm font-normal text-slate-500">/{billingPeriod === 'MONTHLY' ? copy.perMonthShort : copy.perYearShort}</span>
</p>
<ul className="mt-3 space-y-1">
{copy.planFeatures[plan].map((f) => (
<li key={f} className="text-xs text-slate-600 flex items-center gap-1.5">
<span className="text-green-500"></span> {f}
</li>
))}
{features.length > 0
? features.map((f) => (
<li key={f.id} className="text-xs text-slate-600 flex items-center gap-1.5">
<span className="text-green-500"></span> {f.label}
</li>
))
: copy.planFeatures[plan].map((f) => (
<li key={f} className="text-xs text-slate-600 flex items-center gap-1.5">
<span className="text-green-500"></span> {f}
</li>
))}
</ul>
</button>
)