Commit 32927760 authored by Mahmoud Aglan's avatar Mahmoud Aglan

Update pricing page to match real packages + add subscription calculator slider

4 tiers in EGP: نسبة فقط (Free/12%), المبتدئ (1000/7.5%), المؤسسي (3500/5%),
الاحترافي (10000/3.5%). Interactive slider shows total cost based on monthly
collections volume, highlights the best-value plan dynamically.
Co-Authored-By: 's avatarClaude Opus 4.6 <noreply@anthropic.com>
parent 7d7030f4
"use client";
import { useState } from "react";
import { Check, X } from "lucide-react";
import { Check, X, Clock } from "lucide-react";
import { motion } from "framer-motion";
import Navbar from "@/components/layout/Navbar";
import Footer from "@/components/layout/Footer";
import Container from "@/components/shared/Container";
import AnimateOnScroll from "@/components/shared/AnimateOnScroll";
import PricingCalculator from "@/components/sections/PricingCalculator";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import {
......@@ -16,7 +17,7 @@ import {
AccordionContent,
} from "@/components/ui/accordion";
import { content } from "@/lib/content";
import { fadeUp, staggerContainer, staggerItem } from "@/lib/animations";
import { staggerContainer, staggerItem } from "@/lib/animations";
const pricing = content.ar.pricing;
......@@ -80,13 +81,13 @@ export default function PricingPage() {
initial="hidden"
whileInView="visible"
viewport={{ once: true, amount: 0.2 }}
className="grid grid-cols-1 md:grid-cols-3 gap-6 lg:gap-8 items-stretch"
className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-5 lg:gap-6 items-stretch"
>
{pricing.plans.map((plan, index) => (
{pricing.plans.map((plan) => (
<motion.div
key={plan.name}
variants={staggerItem}
className={`relative flex flex-col rounded-2xl border bg-white p-6 lg:p-8 shadow-sm transition-shadow hover:shadow-md ${
className={`relative flex flex-col rounded-2xl border bg-white p-5 lg:p-6 shadow-sm transition-shadow hover:shadow-md ${
plan.highlighted
? "border-2 border-sky-500 shadow-sky-100"
: "border-slate-200"
......@@ -102,50 +103,60 @@ export default function PricingPage() {
)}
{/* Plan Header */}
<div className="text-center mb-6">
<div className="text-center mb-4">
<h3 className="text-xl font-bold text-navy-800">
{plan.name}
</h3>
<p className="mt-1 text-sm text-slate-500">
{plan.description}
<p className="mt-1 text-xs text-slate-500">
{plan.subtitle}
</p>
</div>
{/* Price */}
<div className="text-center mb-2">
<span className="text-4xl lg:text-5xl font-bold text-navy-800" dir="ltr">
<div className="text-center mb-1">
<span className="text-3xl lg:text-4xl font-bold text-navy-800">
{plan.price}
</span>
</div>
{plan.period && (
<span className="text-sm text-slate-500 ms-1">
<p className="text-center text-sm text-slate-500 mb-3">
{plan.period}
</span>
</p>
)}
</div>
{/* Platform Fee */}
{"platformFee" in plan && plan.platformFee && (
<div className="text-center mb-6">
<span className="inline-flex items-center gap-1.5 rounded-full bg-sky-50 px-3 py-1 text-xs font-medium text-sky-700">
{pricing.platformFeeLabel}: {plan.platformFee}
<div className="text-center mb-4">
<span className="inline-flex items-center gap-1.5 rounded-full bg-sky-50 px-3 py-1.5 text-xs font-medium text-sky-700">
<span>نسبة المنصة:</span>
<span className="font-bold">{plan.platformFee}</span>
<span className="text-sky-500">{pricing.collectionsLabel}</span>
</span>
</div>
)}
{/* Trial Badge */}
<div className="flex justify-center mb-5">
<span className="inline-flex items-center gap-1 text-xs text-slate-500">
<Clock className="w-3 h-3" />
{pricing.trialBadge}
</span>
</div>
<hr className="border-slate-100 mb-5" />
{/* Features */}
<ul className="flex-1 space-y-3 mb-8">
<ul className="flex-1 space-y-2.5 mb-6">
{plan.features.map((feature) => (
<li
key={feature.text}
className="flex items-center gap-3"
className="flex items-start gap-2.5"
>
{feature.included ? (
<Check className="h-4 w-4 text-emerald-500 shrink-0" />
<Check className="h-4 w-4 text-emerald-500 shrink-0 mt-0.5" />
) : (
<X className="h-4 w-4 text-slate-300 shrink-0" />
<X className="h-4 w-4 text-slate-300 shrink-0 mt-0.5" />
)}
<span
className={`text-sm ${
className={`text-sm leading-snug ${
feature.included
? "text-slate-700"
: "text-slate-400"
......@@ -173,8 +184,11 @@ export default function PricingPage() {
</Container>
</section>
{/* Pricing Calculator */}
<PricingCalculator />
{/* FAQ */}
<section className="py-16 bg-slate-50">
<section className="py-16 bg-white">
<Container className="max-w-3xl">
<AnimateOnScroll>
<h2 className="text-2xl sm:text-3xl font-bold text-navy-800 text-center mb-10">
......
"use client";
import { useState, useMemo } from "react";
import { motion } from "framer-motion";
import Container from "@/components/shared/Container";
import AnimateOnScroll from "@/components/shared/AnimateOnScroll";
import { content } from "@/lib/content";
const pricing = content.ar.pricing;
const PLANS = pricing.plans.map((p) => ({
name: p.name,
subscription: p.priceNumeric,
feePercent: p.platformFeeNumeric,
}));
const MIN_COLLECTIONS = 10000;
const MAX_COLLECTIONS = 500000;
const STEP = 5000;
function formatMoney(amount: number): string {
return amount.toLocaleString("ar-EG") + " ج.م.";
}
export default function PricingCalculator() {
const [collections, setCollections] = useState(460000);
const calculations = useMemo(() => {
return PLANS.map((plan) => {
const commission = Math.round(collections * plan.feePercent);
const total = plan.subscription + commission;
return {
name: plan.name,
subscription: plan.subscription,
feePercent: plan.feePercent,
commission,
total,
};
});
}, [collections]);
const bestValueIndex = useMemo(() => {
let minTotal = Infinity;
let bestIdx = 0;
calculations.forEach((calc, idx) => {
if (calc.total < minTotal) {
minTotal = calc.total;
bestIdx = idx;
}
});
return bestIdx;
}, [calculations]);
return (
<section className="py-16 bg-slate-50">
<Container className="max-w-3xl">
<AnimateOnScroll>
<div className="text-center mb-10">
<h2 className="text-2xl sm:text-3xl font-bold text-navy-800">
{pricing.calculatorTitle}: {formatMoney(collections)}
</h2>
</div>
{/* Slider */}
<div className="mb-10 px-2">
<input
type="range"
min={MIN_COLLECTIONS}
max={MAX_COLLECTIONS}
step={STEP}
value={collections}
onChange={(e) => setCollections(Number(e.target.value))}
className="w-full h-2 bg-slate-200 rounded-lg appearance-none cursor-pointer accent-navy-800
[&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:w-5 [&::-webkit-slider-thumb]:h-5
[&::-webkit-slider-thumb]:bg-navy-800 [&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:cursor-pointer
[&::-moz-range-thumb]:w-5 [&::-moz-range-thumb]:h-5 [&::-moz-range-thumb]:bg-navy-800
[&::-moz-range-thumb]:rounded-full [&::-moz-range-thumb]:border-0 [&::-moz-range-thumb]:cursor-pointer"
dir="ltr"
/>
<div className="flex justify-between mt-2 text-xs text-slate-500" dir="ltr">
<span>{formatMoney(MIN_COLLECTIONS)}</span>
<span>{formatMoney(MAX_COLLECTIONS)}</span>
</div>
</div>
{/* Plan Cards */}
<div className="space-y-4">
{calculations.map((calc, index) => {
const isBest = index === bestValueIndex;
return (
<motion.div
key={calc.name}
layout
className={`relative rounded-2xl border-2 bg-white p-5 sm:p-6 transition-all ${
isBest
? "border-navy-800 shadow-lg"
: "border-slate-200"
}`}
>
{isBest && (
<span className="absolute -top-3 start-4 inline-flex items-center rounded-full bg-teal-500 px-3 py-0.5 text-xs font-semibold text-white">
{pricing.bestValueBadge}
</span>
)}
<div className="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3">
<h3 className="text-lg font-bold text-navy-800">
{calc.name}
</h3>
<div className="flex flex-wrap items-center gap-x-4 gap-y-1 text-sm text-slate-600">
<span>
اشتراك: {formatMoney(calc.subscription)}
</span>
<span>
عمولة: {formatMoney(calc.commission)} ({(calc.feePercent * 100).toFixed(calc.feePercent * 100 % 1 === 0 ? 0 : 1)}%)
</span>
</div>
</div>
<div className="mt-3 text-end">
<span className="text-2xl font-black text-navy-800">
{formatMoney(calc.total)}
</span>
</div>
</motion.div>
);
})}
</div>
</AnimateOnScroll>
</Container>
</section>
);
}
......@@ -149,79 +149,115 @@ export const content = {
},
pricing: {
title: "اختر الباقة المناسبة",
subtitle: ٤ يوم تجربة مجانية على كل الباقات",
subtitle: ٠ يوم تجربة مجانية على كل الباقات",
monthly: "شهري",
yearly: "سنوي",
yearlyDiscount: "وفر ٢٠%",
platformFeeLabel: "رسوم معاملات",
platformFeeLabel: "نسبة المنصة",
collectionsLabel: "من التحصيلات",
trialBadge: "10 يوم تجريبي",
calculatorTitle: "حجم التحصيلات الشهرية",
bestValueBadge: "الأوفر",
plans: [
{
name: "أساسي",
price: "$20",
period: "/شهر",
platformFee: "5%",
description: "مثالي للأكاديميات الصغيرة والناشئة",
name: "نسبة فقط",
subtitle: "ابدأ بدون أي تكلفة ثابتة",
price: "مجاناً",
priceNumeric: 0,
period: "",
platformFee: "12%",
platformFeeNumeric: 0.12,
description: "مناسب للأكاديميات تحت التأسيس",
features: [
{ text: "حتى ٢٠٠ لاعب", included: true },
{ text: "فرع واحد", included: true },
{ text: "٥ مستخدمين", included: true },
{ text: "إدارة مالية", included: true },
{ text: "حضور وغياب", included: true },
{ text: "اشتراك شهري: ٠ ج.م", included: true },
{ text: "كل مزايا النظام الأساسية", included: true },
{ text: "إدارة المشتركين والحضور", included: true },
{ text: "الفواتير والمدفوعات", included: true },
{ text: "تقارير أساسية", included: true },
{ text: "نقاط البيع", included: false },
{ text: "المخزون", included: false },
{ text: "دعم عبر WhatsApp", included: true },
],
cta: "ابدأ مجاناً",
highlighted: false,
},
{
name: "احترافي",
price: "$60",
period: "/شهر",
platformFee: "3%",
description: "للأكاديميات المتوسطة والكبيرة",
badge: "الأكثر شيوعاً",
name: "المبتدئ",
subtitle: "للأكاديميات الصغيرة والناشئة",
price: "1,000",
priceNumeric: 1000,
period: "ج.م / شهرياً",
platformFee: "7.5%",
platformFeeNumeric: 0.075,
description: "للأكاديميات الصغيرة والناشئة",
features: [
{ text: "حتى ١,٠٠٠ لاعب", included: true },
{ text: "حتى ٥ فروع", included: true },
{ text: "١٥ مستخدم", included: true },
{ text: "كل المميزات", included: true },
{ text: "نقاط البيع", included: true },
{ text: "المخزون", included: true },
{ text: "تقارير متقدمة", included: true },
{ text: "إدارة البرامج والمجموعات", included: true },
{ text: "الجدول الأسبوعي", included: true },
{ text: "التسجيلات وقوائم الانتظار", included: true },
{ text: "تقارير متوسطة", included: true },
{ text: "إشعارات بريد إلكتروني", included: true },
{ text: "دعم أولوية", included: true },
],
cta: "ابدأ الآن",
highlighted: false,
},
{
name: "المؤسسي",
subtitle: "للأكاديميات المتوسطة والنامية",
price: "3,500",
priceNumeric: 3500,
period: "ج.م / شهرياً",
platformFee: "5%",
platformFeeNumeric: 0.05,
description: "للأكاديميات المتوسطة والنامية",
badge: "الأكثر طلباً",
features: [
{ text: "كل مزايا باقة \"المبتدئ\"", included: true },
{ text: "محرك التسعير الذكي", included: true },
{ text: "المنشآت ونظام الحارات", included: true },
{ text: "المخازن والمنتجات", included: true },
{ text: "الموارد البشرية والرواتب", included: true },
{ text: "نقطة البيع (POS)", included: true },
{ text: "إشعارات SMS + بريد", included: true },
{ text: "تقارير متقدمة + تصدير", included: true },
{ text: "صلاحيات متقدمة متعددة الأدوار", included: true },
{ text: "فترة تجريبية 10 أيام", included: true },
{ text: "فترة سماح 14 يوم", included: true },
],
cta: "ابدأ الآن",
highlighted: true,
},
{
name: "مؤسسي",
price: "$100",
period: "/شهر",
platformFee: "1%",
description: "للمؤسسات والأندية الكبيرة",
name: "الاحترافي",
subtitle: "للأكاديميات الكبيرة والسلاسل",
price: "10,000",
priceNumeric: 10000,
period: "ج.م / شهرياً",
platformFee: "3.5%",
platformFeeNumeric: 0.035,
description: "للأكاديميات الكبيرة والسلاسل",
features: [
{ text: "لاعبين غير محدودين", included: true },
{ text: "فروع غير محدودة", included: true },
{ text: "مستخدمين غير محدودين", included: true },
{ text: "كل المميزات", included: true },
{ text: "API كامل", included: true },
{ text: "دعم مخصص", included: true },
{ text: "تخصيص حسب الطلب", included: true },
{ text: "مدير حساب", included: true },
{ text: "كل مزايا الباقة المؤسسية", included: true },
{ text: "فروع متعددة بلا حدود", included: true },
{ text: "تطبيقات مدربين + أولياء أمور", included: true },
{ text: "API للتكامل مع أنظمة خارجية", included: true },
{ text: "تخصيصات حسب الطلب", included: true },
{ text: "مدير حساب مخصص", included: true },
{ text: "تدريب فريق العمل", included: true },
{ text: "أقل نسبة منصة (3.5%)", included: true },
{ text: "SLA + ضمان وقت التشغيل", included: true },
{ text: "استضافة خاصة (اختياري)", included: true },
],
cta: حدث معنا",
cta: واصل معنا",
highlighted: false,
},
],
faq: [
{
q: "هل فيه فترة تجربة مجانية؟",
a: "نعم، ١٤ يوم تجربة كاملة على أي باقة بدون بطاقة ائتمان. لو مش مناسبة، لا تدفع شيء.",
a: "نعم، ١٠ أيام تجربة كاملة على أي باقة بدون بطاقة ائتمان. لو مش مناسبة، لا تدفع شيء.",
},
{
q: "إيه هي رسوم المعاملات؟",
a: "نسبة بسيطة تُضاف على كل تحصيل يتم عبر المنصة. كل ما ترقيت باقتك، قلت النسبة. الباقة المؤسسية ١% فقط.",
q: "إيه هي نسبة المنصة؟",
a: "نسبة بسيطة تُحسب على كل تحصيل يتم عبر المنصة. كل ما ترقيت باقتك، قلت النسبة. الباقة الاحترافية ٣.٥% فقط.",
},
{
q: "هل أقدر أغير الباقة بعدين؟",
......@@ -237,12 +273,16 @@ export const content = {
},
{
q: "هل بتدعموا أكثر من فرع؟",
a: "نعم، الباقة الاحترافية تدعم حتى ٥ فروع والمؤسسية بدون حد.",
a: "نعم، الباقة الاحترافية تدعم فروع بلا حدود.",
},
{
q: "هل فيه خصم للدفع السنوي؟",
a: "نعم، الدفع السنوي يوفر ٢٠% — يعني شهرين ببلاش.",
},
{
q: "هل يمكن البدء بباقة نسبة فقط ثم الترقية؟",
a: "بالضبط! ابدأ بدون أي تكلفة ثابتة ولما أكاديميتك تكبر ترقّى لباقة أقل نسبة.",
},
],
},
about: {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment