308 lines
11 KiB
TypeScript
308 lines
11 KiB
TypeScript
'use client';
|
|
|
|
import React, { useState } from 'react';
|
|
import Link from 'next/link';
|
|
import Image from 'next/image';
|
|
import { Check, X, ArrowRight, Shield } from 'lucide-react';
|
|
|
|
type BillingInterval = 'monthly' | 'yearly';
|
|
|
|
const PLANS = [
|
|
{
|
|
name: 'Bronze',
|
|
key: 'BRONZE' as const,
|
|
monthlyPrice: 0,
|
|
yearlyPrice: 0,
|
|
description: 'Pour démarrer et tester la plateforme',
|
|
maxUsers: 1,
|
|
maxShipments: '12/an',
|
|
commission: '5%',
|
|
support: 'Aucun',
|
|
badge: null,
|
|
features: [
|
|
{ name: 'Recherche de tarifs', included: true },
|
|
{ name: 'Réservations', included: true },
|
|
{ name: 'Tableau de bord', included: false },
|
|
{ name: 'Wiki Maritime', included: false },
|
|
{ name: 'Gestion des utilisateurs', included: false },
|
|
{ name: 'Import CSV', included: false },
|
|
{ name: 'Accès API', included: false },
|
|
{ name: 'Interface personnalisée', included: false },
|
|
{ name: 'KAM dédié', included: false },
|
|
],
|
|
cta: 'Commencer gratuitement',
|
|
ctaStyle: 'bg-gray-900 text-white hover:bg-gray-800',
|
|
popular: false,
|
|
},
|
|
{
|
|
name: 'Silver',
|
|
key: 'SILVER' as const,
|
|
monthlyPrice: 249,
|
|
yearlyPrice: 2739,
|
|
description: 'Pour les équipes en croissance',
|
|
maxUsers: 5,
|
|
maxShipments: 'Illimitées',
|
|
commission: '3%',
|
|
support: 'Email',
|
|
badge: 'silver' as const,
|
|
features: [
|
|
{ name: 'Recherche de tarifs', included: true },
|
|
{ name: 'Réservations', included: true },
|
|
{ name: 'Tableau de bord', included: true },
|
|
{ name: 'Wiki Maritime', included: true },
|
|
{ name: 'Gestion des utilisateurs', included: true },
|
|
{ name: 'Import CSV', included: true },
|
|
{ name: 'Accès API', included: false },
|
|
{ name: 'Interface personnalisée', included: false },
|
|
{ name: 'KAM dédié', included: false },
|
|
],
|
|
cta: 'Choisir Silver',
|
|
ctaStyle: 'bg-brand-turquoise text-white hover:opacity-90',
|
|
popular: true,
|
|
},
|
|
{
|
|
name: 'Gold',
|
|
key: 'GOLD' as const,
|
|
monthlyPrice: 899,
|
|
yearlyPrice: 9889,
|
|
description: 'Pour les entreprises établies',
|
|
maxUsers: 20,
|
|
maxShipments: 'Illimitées',
|
|
commission: '2%',
|
|
support: 'Direct',
|
|
badge: 'gold' as const,
|
|
features: [
|
|
{ name: 'Recherche de tarifs', included: true },
|
|
{ name: 'Réservations', included: true },
|
|
{ name: 'Tableau de bord', included: true },
|
|
{ name: 'Wiki Maritime', included: true },
|
|
{ name: 'Gestion des utilisateurs', included: true },
|
|
{ name: 'Import CSV', included: true },
|
|
{ name: 'Accès API', included: true },
|
|
{ name: 'Interface personnalisée', included: false },
|
|
{ name: 'KAM dédié', included: false },
|
|
],
|
|
cta: 'Choisir Gold',
|
|
ctaStyle: 'bg-yellow-500 text-white hover:bg-yellow-600',
|
|
popular: false,
|
|
},
|
|
{
|
|
name: 'Platinium',
|
|
key: 'PLATINIUM' as const,
|
|
monthlyPrice: -1,
|
|
yearlyPrice: -1,
|
|
description: 'Solutions sur mesure',
|
|
maxUsers: 'Illimité',
|
|
maxShipments: 'Illimitées',
|
|
commission: '1%',
|
|
support: 'KAM dédié',
|
|
badge: 'platinium' as const,
|
|
features: [
|
|
{ name: 'Recherche de tarifs', included: true },
|
|
{ name: 'Réservations', included: true },
|
|
{ name: 'Tableau de bord', included: true },
|
|
{ name: 'Wiki Maritime', included: true },
|
|
{ name: 'Gestion des utilisateurs', included: true },
|
|
{ name: 'Import CSV', included: true },
|
|
{ name: 'Accès API', included: true },
|
|
{ name: 'Interface personnalisée', included: true },
|
|
{ name: 'KAM dédié', included: true },
|
|
],
|
|
cta: 'Nous contacter',
|
|
ctaStyle: 'bg-purple-600 text-white hover:bg-purple-700',
|
|
popular: false,
|
|
},
|
|
];
|
|
|
|
function formatPrice(amount: number): string {
|
|
return new Intl.NumberFormat('fr-FR', {
|
|
style: 'currency',
|
|
currency: 'EUR',
|
|
minimumFractionDigits: 0,
|
|
maximumFractionDigits: 0,
|
|
}).format(amount);
|
|
}
|
|
|
|
export default function PricingPage() {
|
|
const [billing, setBilling] = useState<BillingInterval>('monthly');
|
|
|
|
return (
|
|
<div className="min-h-screen bg-white">
|
|
{/* Header */}
|
|
<header className="border-b">
|
|
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4 flex items-center justify-between">
|
|
<Link href="/">
|
|
<Image
|
|
src="/assets/logos/logo-black.svg"
|
|
alt="Xpeditis"
|
|
width={40}
|
|
height={48}
|
|
priority
|
|
/>
|
|
</Link>
|
|
<div className="flex items-center gap-4">
|
|
<Link href="/login" className="text-sm text-gray-600 hover:text-gray-900">
|
|
Connexion
|
|
</Link>
|
|
<Link
|
|
href="/register"
|
|
className="text-sm bg-brand-turquoise text-white px-4 py-2 rounded-lg hover:opacity-90"
|
|
>
|
|
Inscription
|
|
</Link>
|
|
</div>
|
|
</div>
|
|
</header>
|
|
|
|
{/* Hero */}
|
|
<section className="py-16 text-center">
|
|
<h1 className="text-4xl font-bold text-gray-900 mb-4">
|
|
Des tarifs simples et transparents
|
|
</h1>
|
|
<p className="text-lg text-gray-600 max-w-2xl mx-auto mb-8">
|
|
Choisissez la formule adaptée à votre activité de transport maritime.
|
|
Commencez gratuitement, évoluez selon vos besoins.
|
|
</p>
|
|
|
|
{/* Billing toggle */}
|
|
<div className="flex items-center justify-center gap-4 mb-12">
|
|
<span className={`text-sm font-medium ${billing === 'monthly' ? 'text-gray-900' : 'text-gray-500'}`}>
|
|
Mensuel
|
|
</span>
|
|
<button
|
|
onClick={() => setBilling(billing === 'monthly' ? 'yearly' : 'monthly')}
|
|
className={`relative inline-flex h-6 w-11 items-center rounded-full transition-colors ${
|
|
billing === 'yearly' ? 'bg-brand-turquoise' : 'bg-gray-300'
|
|
}`}
|
|
>
|
|
<span
|
|
className={`inline-block h-4 w-4 rounded-full bg-white transition-transform ${
|
|
billing === 'yearly' ? 'translate-x-6' : 'translate-x-1'
|
|
}`}
|
|
/>
|
|
</button>
|
|
<span className={`text-sm font-medium ${billing === 'yearly' ? 'text-gray-900' : 'text-gray-500'}`}>
|
|
Annuel
|
|
</span>
|
|
{billing === 'yearly' && (
|
|
<span className="text-xs bg-green-100 text-green-800 px-2 py-1 rounded-full font-medium">
|
|
-1 mois offert
|
|
</span>
|
|
)}
|
|
</div>
|
|
</section>
|
|
|
|
{/* Plans grid */}
|
|
<section className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 pb-20">
|
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
|
|
{PLANS.map((plan) => (
|
|
<div
|
|
key={plan.key}
|
|
className={`relative rounded-2xl border-2 p-6 flex flex-col ${
|
|
plan.popular
|
|
? 'border-brand-turquoise shadow-lg shadow-brand-turquoise/10'
|
|
: 'border-gray-200'
|
|
}`}
|
|
>
|
|
{plan.popular && (
|
|
<div className="absolute -top-3 left-1/2 -translate-x-1/2">
|
|
<span className="bg-brand-turquoise text-white text-xs font-semibold px-3 py-1 rounded-full">
|
|
Populaire
|
|
</span>
|
|
</div>
|
|
)}
|
|
|
|
{/* Plan name & badge */}
|
|
<div className="flex items-center gap-2 mb-2">
|
|
<h3 className="text-xl font-bold text-gray-900">{plan.name}</h3>
|
|
{plan.badge && (
|
|
<Shield className={`w-5 h-5 ${
|
|
plan.badge === 'silver' ? 'text-slate-500' :
|
|
plan.badge === 'gold' ? 'text-yellow-500' :
|
|
'text-purple-500'
|
|
}`} />
|
|
)}
|
|
</div>
|
|
|
|
<p className="text-sm text-gray-500 mb-4">{plan.description}</p>
|
|
|
|
{/* Price */}
|
|
<div className="mb-6">
|
|
{plan.monthlyPrice === -1 ? (
|
|
<p className="text-3xl font-bold text-gray-900">Sur devis</p>
|
|
) : plan.monthlyPrice === 0 ? (
|
|
<p className="text-3xl font-bold text-gray-900">Gratuit</p>
|
|
) : (
|
|
<>
|
|
<p className="text-3xl font-bold text-gray-900">
|
|
{billing === 'monthly'
|
|
? formatPrice(plan.monthlyPrice)
|
|
: formatPrice(Math.round(plan.yearlyPrice / 12))}
|
|
<span className="text-base font-normal text-gray-500">/mois</span>
|
|
</p>
|
|
{billing === 'yearly' && (
|
|
<p className="text-sm text-gray-500 mt-1">
|
|
{formatPrice(plan.yearlyPrice)}/an (11 mois)
|
|
</p>
|
|
)}
|
|
</>
|
|
)}
|
|
</div>
|
|
|
|
{/* Quick stats */}
|
|
<div className="space-y-2 mb-6 text-sm">
|
|
<div className="flex justify-between">
|
|
<span className="text-gray-500">Utilisateurs</span>
|
|
<span className="font-medium">{plan.maxUsers}</span>
|
|
</div>
|
|
<div className="flex justify-between">
|
|
<span className="text-gray-500">Expéditions</span>
|
|
<span className="font-medium">{plan.maxShipments}</span>
|
|
</div>
|
|
<div className="flex justify-between">
|
|
<span className="text-gray-500">Commission</span>
|
|
<span className="font-medium">{plan.commission}</span>
|
|
</div>
|
|
<div className="flex justify-between">
|
|
<span className="text-gray-500">Support</span>
|
|
<span className="font-medium">{plan.support}</span>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Features */}
|
|
<div className="flex-1 space-y-2 mb-6">
|
|
{plan.features.map((feature) => (
|
|
<div key={feature.name} className="flex items-center gap-2 text-sm">
|
|
{feature.included ? (
|
|
<Check className="w-4 h-4 text-green-500 flex-shrink-0" />
|
|
) : (
|
|
<X className="w-4 h-4 text-gray-300 flex-shrink-0" />
|
|
)}
|
|
<span className={feature.included ? 'text-gray-700' : 'text-gray-400'}>
|
|
{feature.name}
|
|
</span>
|
|
</div>
|
|
))}
|
|
</div>
|
|
|
|
{/* CTA */}
|
|
<Link
|
|
href={plan.key === 'PLATINIUM' ? '/contact' : '/register'}
|
|
className={`block text-center py-3 px-4 rounded-lg text-sm font-semibold transition-all ${plan.ctaStyle}`}
|
|
>
|
|
{plan.cta}
|
|
<ArrowRight className="inline-block w-4 h-4 ml-1" />
|
|
</Link>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</section>
|
|
|
|
{/* Footer */}
|
|
<footer className="border-t py-8 text-center text-sm text-gray-500">
|
|
<p>Tous les prix sont en euros HT. Facturation annuelle = 11 mois.</p>
|
|
</footer>
|
|
</div>
|
|
);
|
|
}
|