257 lines
9.8 KiB
JavaScript
257 lines
9.8 KiB
JavaScript
|
|
'use client';
|
||
|
|
|
||
|
|
import { useState, useEffect } from 'react';
|
||
|
|
import { motion, AnimatePresence } from 'framer-motion';
|
||
|
|
import { useRouter } from 'next/navigation';
|
||
|
|
import Link from 'next/link';
|
||
|
|
import { Home, Search, Rocket, ArrowLeft, ArrowRight } from 'lucide-react';
|
||
|
|
|
||
|
|
const STORAGE_KEY = 'sweethome_onboarding_completed';
|
||
|
|
|
||
|
|
const steps = [
|
||
|
|
{
|
||
|
|
icon: Home,
|
||
|
|
title: 'مرحباً بك في SweetHome',
|
||
|
|
description: 'نحن هنا لمساعدتك في إيجاد العقار المثالي الذي تحلم به. اكتشف آلاف العقارات المتاحة للإيجار والبيع في جميع أنحاء سوريا.',
|
||
|
|
gradient: 'from-amber-500 to-orange-600',
|
||
|
|
},
|
||
|
|
{
|
||
|
|
icon: Search,
|
||
|
|
title: 'ابحث عن منزل أحلامك',
|
||
|
|
description: 'استخدم محرك البحث الذكي لدينا للعثور على العقار المناسب. تصفح حسب الموقع، السعر، النوع، والمزيد من الفلاتر المتقدمة.',
|
||
|
|
gradient: 'from-blue-500 to-indigo-600',
|
||
|
|
},
|
||
|
|
{
|
||
|
|
icon: Rocket,
|
||
|
|
title: 'انطلق الآن',
|
||
|
|
description: 'انشئ حسابك مجاناً وابدأ رحلة البحث عن منزلك الجديد. يمكنك حفظ العقارات المفضلة والتواصل مع المالكين مباشرة.',
|
||
|
|
gradient: 'from-emerald-500 to-teal-600',
|
||
|
|
},
|
||
|
|
];
|
||
|
|
|
||
|
|
export default function OnboardingPage() {
|
||
|
|
const router = useRouter();
|
||
|
|
const [currentStep, setCurrentStep] = useState(0);
|
||
|
|
const [direction, setDirection] = useState(0);
|
||
|
|
|
||
|
|
useEffect(() => {
|
||
|
|
const completed = localStorage.getItem(STORAGE_KEY);
|
||
|
|
if (completed === 'true') {
|
||
|
|
router.replace('/');
|
||
|
|
}
|
||
|
|
}, [router]);
|
||
|
|
|
||
|
|
const goToStep = (index) => {
|
||
|
|
setDirection(index > currentStep ? 1 : -1);
|
||
|
|
setCurrentStep(index);
|
||
|
|
};
|
||
|
|
|
||
|
|
const nextStep = () => {
|
||
|
|
if (currentStep < steps.length - 1) {
|
||
|
|
goToStep(currentStep + 1);
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
const prevStep = () => {
|
||
|
|
if (currentStep > 0) {
|
||
|
|
goToStep(currentStep - 1);
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
const handleFinish = () => {
|
||
|
|
localStorage.setItem(STORAGE_KEY, 'true');
|
||
|
|
};
|
||
|
|
|
||
|
|
const step = steps[currentStep];
|
||
|
|
const isLastStep = currentStep === steps.length - 1;
|
||
|
|
const isFirstStep = currentStep === 0;
|
||
|
|
const IconComponent = step.icon;
|
||
|
|
|
||
|
|
const slideVariants = {
|
||
|
|
enter: (dir) => ({ x: dir > 0 ? 300 : -300, opacity: 0 }),
|
||
|
|
center: { x: 0, opacity: 1 },
|
||
|
|
exit: (dir) => ({ x: dir > 0 ? -300 : 300, opacity: 0 }),
|
||
|
|
};
|
||
|
|
|
||
|
|
return (
|
||
|
|
<div className="min-h-screen bg-gradient-to-br from-gray-950 via-gray-900 to-gray-950 flex items-center justify-center p-4 relative overflow-hidden">
|
||
|
|
<div className="absolute inset-0 overflow-hidden">
|
||
|
|
{[...Array(30)].map((_, i) => (
|
||
|
|
<motion.div
|
||
|
|
key={i}
|
||
|
|
className="absolute rounded-full bg-white/5"
|
||
|
|
style={{
|
||
|
|
left: `${Math.random() * 100}%`,
|
||
|
|
top: `${Math.random() * 100}%`,
|
||
|
|
width: Math.random() * 6 + 2,
|
||
|
|
height: Math.random() * 6 + 2,
|
||
|
|
}}
|
||
|
|
animate={{
|
||
|
|
y: [0, -30, 0],
|
||
|
|
opacity: [0.1, 0.4, 0.1],
|
||
|
|
}}
|
||
|
|
transition={{
|
||
|
|
duration: Math.random() * 8 + 6,
|
||
|
|
repeat: Infinity,
|
||
|
|
delay: Math.random() * 4,
|
||
|
|
ease: 'easeInOut',
|
||
|
|
}}
|
||
|
|
/>
|
||
|
|
))}
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<motion.div
|
||
|
|
className={`absolute top-1/4 -left-20 w-72 h-72 bg-${step.gradient.split(' ')[0].replace('from-', '')}/10 rounded-full blur-3xl`}
|
||
|
|
animate={{ scale: [1, 1.3, 1], x: [0, 40, 0] }}
|
||
|
|
transition={{ duration: 10, repeat: Infinity }}
|
||
|
|
/>
|
||
|
|
<motion.div
|
||
|
|
className={`absolute bottom-1/4 -right-20 w-80 h-80 bg-${step.gradient.split(' ')[1]}/10 rounded-full blur-3xl`}
|
||
|
|
animate={{ scale: [1, 1.2, 1], x: [0, -30, 0] }}
|
||
|
|
transition={{ duration: 12, repeat: Infinity }}
|
||
|
|
/>
|
||
|
|
|
||
|
|
<div className="relative w-full max-w-lg z-10">
|
||
|
|
<div className="bg-white/10 backdrop-blur-2xl rounded-3xl shadow-2xl border border-white/10 overflow-hidden">
|
||
|
|
<AnimatePresence mode="wait" custom={direction}>
|
||
|
|
<motion.div
|
||
|
|
key={currentStep}
|
||
|
|
custom={direction}
|
||
|
|
variants={slideVariants}
|
||
|
|
initial="enter"
|
||
|
|
animate="center"
|
||
|
|
exit="exit"
|
||
|
|
transition={{ type: 'spring', stiffness: 300, damping: 30 }}
|
||
|
|
className="p-10"
|
||
|
|
>
|
||
|
|
<div className={`bg-gradient-to-br ${step.gradient} rounded-2xl p-8 text-center mb-8 relative overflow-hidden`}>
|
||
|
|
<motion.div
|
||
|
|
className="absolute -top-12 -right-12 w-32 h-32 bg-white/10 rounded-full"
|
||
|
|
animate={{ scale: [1, 1.2, 1] }}
|
||
|
|
transition={{ duration: 4, repeat: Infinity }}
|
||
|
|
/>
|
||
|
|
<motion.div
|
||
|
|
className="absolute -bottom-8 -left-8 w-24 h-24 bg-white/10 rounded-full"
|
||
|
|
animate={{ scale: [1, 1.3, 1] }}
|
||
|
|
transition={{ duration: 5, repeat: Infinity }}
|
||
|
|
/>
|
||
|
|
<div className="relative z-10">
|
||
|
|
<motion.div
|
||
|
|
initial={{ scale: 0, rotate: -180 }}
|
||
|
|
animate={{ scale: 1, rotate: 0 }}
|
||
|
|
transition={{ type: 'spring', stiffness: 200, delay: 0.1 }}
|
||
|
|
className="w-24 h-24 mx-auto bg-white/20 rounded-3xl flex items-center justify-center backdrop-blur-sm"
|
||
|
|
>
|
||
|
|
<IconComponent className="w-12 h-12 text-white" />
|
||
|
|
</motion.div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div className="text-center mb-8">
|
||
|
|
<motion.h1
|
||
|
|
initial={{ opacity: 0, y: 20 }}
|
||
|
|
animate={{ opacity: 1, y: 0 }}
|
||
|
|
transition={{ delay: 0.15 }}
|
||
|
|
className="text-3xl font-bold text-white mb-4"
|
||
|
|
>
|
||
|
|
{step.title}
|
||
|
|
</motion.h1>
|
||
|
|
<motion.p
|
||
|
|
initial={{ opacity: 0, y: 20 }}
|
||
|
|
animate={{ opacity: 1, y: 0 }}
|
||
|
|
transition={{ delay: 0.25 }}
|
||
|
|
className="text-gray-300 leading-relaxed text-base"
|
||
|
|
>
|
||
|
|
{step.description}
|
||
|
|
</motion.p>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<motion.div
|
||
|
|
initial={{ opacity: 0 }}
|
||
|
|
animate={{ opacity: 1 }}
|
||
|
|
transition={{ delay: 0.35 }}
|
||
|
|
className="flex items-center justify-center gap-2 mb-8"
|
||
|
|
>
|
||
|
|
{steps.map((_, index) => (
|
||
|
|
<button
|
||
|
|
key={index}
|
||
|
|
onClick={() => goToStep(index)}
|
||
|
|
className={`rounded-full transition-all duration-300 ${
|
||
|
|
index === currentStep
|
||
|
|
? 'w-8 h-3 bg-gradient-to-r ' + step.gradient
|
||
|
|
: 'w-3 h-3 bg-white/20 hover:bg-white/40'
|
||
|
|
}`}
|
||
|
|
/>
|
||
|
|
))}
|
||
|
|
</motion.div>
|
||
|
|
|
||
|
|
<motion.div
|
||
|
|
initial={{ opacity: 0, y: 10 }}
|
||
|
|
animate={{ opacity: 1, y: 0 }}
|
||
|
|
transition={{ delay: 0.4 }}
|
||
|
|
className="flex items-center justify-between gap-4"
|
||
|
|
>
|
||
|
|
{!isFirstStep ? (
|
||
|
|
<motion.button
|
||
|
|
whileHover={{ scale: 1.05 }}
|
||
|
|
whileTap={{ scale: 0.95 }}
|
||
|
|
onClick={prevStep}
|
||
|
|
className="flex items-center gap-2 px-5 py-3 rounded-xl text-gray-300 hover:text-white hover:bg-white/10 transition-all border border-white/10"
|
||
|
|
>
|
||
|
|
<ArrowRight className="w-5 h-5" />
|
||
|
|
<span>السابق</span>
|
||
|
|
</motion.button>
|
||
|
|
) : (
|
||
|
|
<div />
|
||
|
|
)}
|
||
|
|
|
||
|
|
{!isLastStep ? (
|
||
|
|
<motion.button
|
||
|
|
whileHover={{ scale: 1.05 }}
|
||
|
|
whileTap={{ scale: 0.95 }}
|
||
|
|
onClick={nextStep}
|
||
|
|
className={`flex items-center gap-2 px-6 py-3 rounded-xl text-white font-medium bg-gradient-to-r ${step.gradient} hover:shadow-lg transition-all`}
|
||
|
|
>
|
||
|
|
<span>التالي</span>
|
||
|
|
<ArrowLeft className="w-5 h-5" />
|
||
|
|
</motion.button>
|
||
|
|
) : (
|
||
|
|
<div className="flex gap-3">
|
||
|
|
<Link href="/auth/choose-role" onClick={handleFinish}>
|
||
|
|
<motion.button
|
||
|
|
whileHover={{ scale: 1.05 }}
|
||
|
|
whileTap={{ scale: 0.95 }}
|
||
|
|
className="px-6 py-3 rounded-xl bg-white text-gray-900 font-bold hover:bg-gray-100 transition-all"
|
||
|
|
>
|
||
|
|
تسجيل جديد
|
||
|
|
</motion.button>
|
||
|
|
</Link>
|
||
|
|
<Link href="/login" onClick={handleFinish}>
|
||
|
|
<motion.button
|
||
|
|
whileHover={{ scale: 1.05 }}
|
||
|
|
whileTap={{ scale: 0.95 }}
|
||
|
|
className="px-6 py-3 rounded-xl bg-gradient-to-r from-emerald-500 to-teal-600 text-white font-bold hover:shadow-lg transition-all"
|
||
|
|
>
|
||
|
|
تسجيل دخول
|
||
|
|
</motion.button>
|
||
|
|
</Link>
|
||
|
|
</div>
|
||
|
|
)}
|
||
|
|
</motion.div>
|
||
|
|
</motion.div>
|
||
|
|
</AnimatePresence>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<motion.p
|
||
|
|
initial={{ opacity: 0 }}
|
||
|
|
animate={{ opacity: 1 }}
|
||
|
|
transition={{ delay: 0.8 }}
|
||
|
|
className="text-center text-gray-500 text-xs mt-4"
|
||
|
|
>
|
||
|
|
{currentStep + 1} / {steps.length}
|
||
|
|
</motion.p>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
);
|
||
|
|
}
|