Add loading.js and error.js for all routes, secure admin page with 404
All checks were successful
Build frontend / build (push) Successful in 40s
All checks were successful
Build frontend / build (push) Successful in 40s
- Added loading.js (dark/light variants) for all 14 routes - Added error.js (dark/light variants) for all 14 routes - Added global not-found.js and loading.js at root - Admin page shows 404 illustration for non-admin users instead of redirecting
This commit is contained in:
27
app/admin/error.js
Normal file
27
app/admin/error.js
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { motion } from 'framer-motion';
|
||||||
|
import { AlertTriangle, RefreshCw, Home } from 'lucide-react';
|
||||||
|
import Link from 'next/link';
|
||||||
|
|
||||||
|
export default function Error({ error, reset }) {
|
||||||
|
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">
|
||||||
|
<motion.div initial={{ opacity: 0, y: 20 }} animate={{ opacity: 1, y: 0 }} className="text-center max-w-md">
|
||||||
|
<div className="w-20 h-20 bg-red-500/20 rounded-full flex items-center justify-center mx-auto mb-6">
|
||||||
|
<AlertTriangle className="w-10 h-10 text-red-500" />
|
||||||
|
</div>
|
||||||
|
<h2 className="text-2xl font-bold text-white mb-2">حدث خطأ</h2>
|
||||||
|
<p className="text-gray-400 mb-8">نعتذر، حدث خطأ أثناء تحميل الصفحة</p>
|
||||||
|
<div className="flex gap-3 justify-center">
|
||||||
|
<button onClick={reset} className="flex items-center gap-2 bg-amber-500 text-white px-6 py-3 rounded-xl font-medium hover:bg-amber-600 transition-colors">
|
||||||
|
<RefreshCw className="w-5 h-5" /> إعادة المحاولة
|
||||||
|
</button>
|
||||||
|
<Link href="/" className="flex items-center gap-2 bg-white/10 text-gray-300 px-6 py-3 rounded-xl font-medium hover:bg-white/20 transition-colors">
|
||||||
|
<Home className="w-5 h-5" /> الرئيسية
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
14
app/admin/loading.js
Normal file
14
app/admin/loading.js
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { motion } from 'framer-motion';
|
||||||
|
|
||||||
|
export default function Loading() {
|
||||||
|
return (
|
||||||
|
<div className="min-h-screen bg-gradient-to-br from-gray-950 via-gray-900 to-gray-950 flex items-center justify-center">
|
||||||
|
<motion.div initial={{ opacity: 0 }} animate={{ opacity: 1 }} className="text-center">
|
||||||
|
<div className="w-14 h-14 border-4 border-amber-500 border-t-transparent rounded-full animate-spin mx-auto mb-4" />
|
||||||
|
<p className="text-gray-400 text-lg">جاري التحميل...</p>
|
||||||
|
</motion.div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -2,15 +2,16 @@
|
|||||||
|
|
||||||
import { motion } from 'framer-motion';
|
import { motion } from 'framer-motion';
|
||||||
import { useState, useEffect } from 'react';
|
import { useState, useEffect } from 'react';
|
||||||
import { useRouter } from 'next/navigation';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import Link from 'next/link';
|
||||||
import {
|
import {
|
||||||
Home,
|
Home,
|
||||||
Calendar,
|
Calendar,
|
||||||
Users,
|
Users,
|
||||||
DollarSign,
|
DollarSign,
|
||||||
TrendingUp,
|
TrendingUp,
|
||||||
Bell
|
Bell,
|
||||||
|
Frown
|
||||||
} from 'lucide-react';
|
} from 'lucide-react';
|
||||||
import DashboardStats from '../components/admin/DashboardStats';
|
import DashboardStats from '../components/admin/DashboardStats';
|
||||||
import PropertiesTable from '../components/admin/PropertiesTable';
|
import PropertiesTable from '../components/admin/PropertiesTable';
|
||||||
@ -24,16 +25,57 @@ import '../i18n/config';
|
|||||||
|
|
||||||
export default function AdminPage() {
|
export default function AdminPage() {
|
||||||
const { t, i18n } = useTranslation();
|
const { t, i18n } = useTranslation();
|
||||||
const router = useRouter();
|
|
||||||
const [activeTab, setActiveTab] = useState('dashboard');
|
const [activeTab, setActiveTab] = useState('dashboard');
|
||||||
const [showAddProperty, setShowAddProperty] = useState(false);
|
const [showAddProperty, setShowAddProperty] = useState(false);
|
||||||
const [notifications, setNotifications] = useState(3);
|
const [notifications, setNotifications] = useState(3);
|
||||||
|
const [isAdmin, setIsAdmin] = useState(false);
|
||||||
|
const [checked, setChecked] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!AuthService.isAuthenticated() || !AuthService.isAdmin()) {
|
setIsAdmin(AuthService.isAuthenticated() && AuthService.isAdmin());
|
||||||
router.push('/');
|
setChecked(true);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
// ─── 404 for non-admins ───
|
||||||
|
if (checked && !isAdmin) {
|
||||||
|
return (
|
||||||
|
<div className="min-h-screen bg-gray-50 flex items-center justify-center p-4">
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
className="text-center max-w-md"
|
||||||
|
>
|
||||||
|
<div className="mb-6">
|
||||||
|
<svg viewBox="0 0 200 180" className="w-72 h-52 mx-auto">
|
||||||
|
<circle cx="100" cy="70" r="60" fill="#fef3c7" />
|
||||||
|
<circle cx="80" cy="60" r="8" fill="#92400e" />
|
||||||
|
<circle cx="120" cy="60" r="8" fill="#92400e" />
|
||||||
|
<path d="M80 85 Q100 75 120 85" stroke="#92400e" strokeWidth="3" fill="none" strokeLinecap="round" />
|
||||||
|
<text x="100" y="140" textAnchor="middle" fontSize="16" fontWeight="bold" fill="#6b7280">عذراً!</text>
|
||||||
|
<text x="100" y="160" textAnchor="middle" fontSize="12" fill="#9ca3af">الصفحة غير موجودة</text>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<h2 className="text-2xl font-bold text-gray-900 mb-2">404 - الصفحة غير موجودة</h2>
|
||||||
|
<p className="text-gray-500 mb-8">عذراً، لا يمكنك الوصول إلى هذه الصفحة</p>
|
||||||
|
<Link
|
||||||
|
href="/"
|
||||||
|
className="inline-flex items-center gap-2 bg-amber-500 text-white px-6 py-3 rounded-xl font-medium hover:bg-amber-600 transition-colors"
|
||||||
|
>
|
||||||
|
<Home className="w-5 h-5" />
|
||||||
|
العودة للرئيسية
|
||||||
|
</Link>
|
||||||
|
</motion.div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!checked) {
|
||||||
|
return (
|
||||||
|
<div className="min-h-screen bg-gray-50 flex items-center justify-center">
|
||||||
|
<div className="w-14 h-14 border-4 border-amber-500 border-t-transparent rounded-full animate-spin" />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}, [router]);
|
|
||||||
|
|
||||||
const tabs = [
|
const tabs = [
|
||||||
{ id: 'dashboard', label: 'لوحة التحكم', icon: Home },
|
{ id: 'dashboard', label: 'لوحة التحكم', icon: Home },
|
||||||
|
|||||||
27
app/auth/choose-role/error.js
Normal file
27
app/auth/choose-role/error.js
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { motion } from 'framer-motion';
|
||||||
|
import { AlertTriangle, RefreshCw, Home } from 'lucide-react';
|
||||||
|
import Link from 'next/link';
|
||||||
|
|
||||||
|
export default function Error({ error, reset }) {
|
||||||
|
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">
|
||||||
|
<motion.div initial={{ opacity: 0, y: 20 }} animate={{ opacity: 1, y: 0 }} className="text-center max-w-md">
|
||||||
|
<div className="w-20 h-20 bg-red-500/20 rounded-full flex items-center justify-center mx-auto mb-6">
|
||||||
|
<AlertTriangle className="w-10 h-10 text-red-500" />
|
||||||
|
</div>
|
||||||
|
<h2 className="text-2xl font-bold text-white mb-2">حدث خطأ</h2>
|
||||||
|
<p className="text-gray-400 mb-8">نعتذر، حدث خطأ أثناء تحميل الصفحة</p>
|
||||||
|
<div className="flex gap-3 justify-center">
|
||||||
|
<button onClick={reset} className="flex items-center gap-2 bg-amber-500 text-white px-6 py-3 rounded-xl font-medium hover:bg-amber-600 transition-colors">
|
||||||
|
<RefreshCw className="w-5 h-5" /> إعادة المحاولة
|
||||||
|
</button>
|
||||||
|
<Link href="/" className="flex items-center gap-2 bg-white/10 text-gray-300 px-6 py-3 rounded-xl font-medium hover:bg-white/20 transition-colors">
|
||||||
|
<Home className="w-5 h-5" /> الرئيسية
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
14
app/auth/choose-role/loading.js
Normal file
14
app/auth/choose-role/loading.js
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { motion } from 'framer-motion';
|
||||||
|
|
||||||
|
export default function Loading() {
|
||||||
|
return (
|
||||||
|
<div className="min-h-screen bg-gradient-to-br from-gray-950 via-gray-900 to-gray-950 flex items-center justify-center">
|
||||||
|
<motion.div initial={{ opacity: 0 }} animate={{ opacity: 1 }} className="text-center">
|
||||||
|
<div className="w-14 h-14 border-4 border-amber-500 border-t-transparent rounded-full animate-spin mx-auto mb-4" />
|
||||||
|
<p className="text-gray-400 text-lg">جاري التحميل...</p>
|
||||||
|
</motion.div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
39
app/error.js
Normal file
39
app/error.js
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { motion } from 'framer-motion';
|
||||||
|
import { AlertTriangle, RefreshCw, Home } from 'lucide-react';
|
||||||
|
import Link from 'next/link';
|
||||||
|
|
||||||
|
export default function GlobalError({ error, reset }) {
|
||||||
|
return (
|
||||||
|
<div className="min-h-screen bg-gray-50 flex items-center justify-center p-4">
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
className="text-center max-w-md"
|
||||||
|
>
|
||||||
|
<div className="w-24 h-24 bg-red-100 rounded-full flex items-center justify-center mx-auto mb-6">
|
||||||
|
<AlertTriangle className="w-12 h-12 text-red-500" />
|
||||||
|
</div>
|
||||||
|
<h2 className="text-2xl font-bold text-gray-900 mb-2">حدث خطأ غير متوقع</h2>
|
||||||
|
<p className="text-gray-500 mb-8">نعتذر عن هذا الإزعاج، يرجى المحاولة مرة أخرى</p>
|
||||||
|
<div className="flex gap-3 justify-center">
|
||||||
|
<button
|
||||||
|
onClick={reset}
|
||||||
|
className="flex items-center gap-2 bg-amber-500 text-white px-6 py-3 rounded-xl font-medium hover:bg-amber-600 transition-colors"
|
||||||
|
>
|
||||||
|
<RefreshCw className="w-5 h-5" />
|
||||||
|
إعادة المحاولة
|
||||||
|
</button>
|
||||||
|
<Link
|
||||||
|
href="/"
|
||||||
|
className="flex items-center gap-2 bg-gray-200 text-gray-700 px-6 py-3 rounded-xl font-medium hover:bg-gray-300 transition-colors"
|
||||||
|
>
|
||||||
|
<Home className="w-5 h-5" />
|
||||||
|
الرئيسية
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
27
app/forgot-password/error.js
Normal file
27
app/forgot-password/error.js
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { motion } from 'framer-motion';
|
||||||
|
import { AlertTriangle, RefreshCw, Home } from 'lucide-react';
|
||||||
|
import Link from 'next/link';
|
||||||
|
|
||||||
|
export default function Error({ error, reset }) {
|
||||||
|
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">
|
||||||
|
<motion.div initial={{ opacity: 0, y: 20 }} animate={{ opacity: 1, y: 0 }} className="text-center max-w-md">
|
||||||
|
<div className="w-20 h-20 bg-red-500/20 rounded-full flex items-center justify-center mx-auto mb-6">
|
||||||
|
<AlertTriangle className="w-10 h-10 text-red-500" />
|
||||||
|
</div>
|
||||||
|
<h2 className="text-2xl font-bold text-white mb-2">حدث خطأ</h2>
|
||||||
|
<p className="text-gray-400 mb-8">نعتذر، حدث خطأ أثناء تحميل الصفحة</p>
|
||||||
|
<div className="flex gap-3 justify-center">
|
||||||
|
<button onClick={reset} className="flex items-center gap-2 bg-amber-500 text-white px-6 py-3 rounded-xl font-medium hover:bg-amber-600 transition-colors">
|
||||||
|
<RefreshCw className="w-5 h-5" /> إعادة المحاولة
|
||||||
|
</button>
|
||||||
|
<Link href="/" className="flex items-center gap-2 bg-white/10 text-gray-300 px-6 py-3 rounded-xl font-medium hover:bg-white/20 transition-colors">
|
||||||
|
<Home className="w-5 h-5" /> الرئيسية
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
14
app/forgot-password/loading.js
Normal file
14
app/forgot-password/loading.js
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { motion } from 'framer-motion';
|
||||||
|
|
||||||
|
export default function Loading() {
|
||||||
|
return (
|
||||||
|
<div className="min-h-screen bg-gradient-to-br from-gray-950 via-gray-900 to-gray-950 flex items-center justify-center">
|
||||||
|
<motion.div initial={{ opacity: 0 }} animate={{ opacity: 1 }} className="text-center">
|
||||||
|
<div className="w-14 h-14 border-4 border-amber-500 border-t-transparent rounded-full animate-spin mx-auto mb-4" />
|
||||||
|
<p className="text-gray-400 text-lg">جاري التحميل...</p>
|
||||||
|
</motion.div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
18
app/loading.js
Normal file
18
app/loading.js
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { motion } from 'framer-motion';
|
||||||
|
|
||||||
|
export default function Loading() {
|
||||||
|
return (
|
||||||
|
<div className="min-h-screen bg-gray-50 flex items-center justify-center">
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0 }}
|
||||||
|
animate={{ opacity: 1 }}
|
||||||
|
className="text-center"
|
||||||
|
>
|
||||||
|
<div className="w-16 h-16 border-4 border-amber-500 border-t-transparent rounded-full animate-spin mx-auto mb-4" />
|
||||||
|
<p className="text-gray-500 text-lg">جاري التحميل...</p>
|
||||||
|
</motion.div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
27
app/login/error.js
Normal file
27
app/login/error.js
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { motion } from 'framer-motion';
|
||||||
|
import { AlertTriangle, RefreshCw, Home } from 'lucide-react';
|
||||||
|
import Link from 'next/link';
|
||||||
|
|
||||||
|
export default function Error({ error, reset }) {
|
||||||
|
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">
|
||||||
|
<motion.div initial={{ opacity: 0, y: 20 }} animate={{ opacity: 1, y: 0 }} className="text-center max-w-md">
|
||||||
|
<div className="w-20 h-20 bg-red-500/20 rounded-full flex items-center justify-center mx-auto mb-6">
|
||||||
|
<AlertTriangle className="w-10 h-10 text-red-500" />
|
||||||
|
</div>
|
||||||
|
<h2 className="text-2xl font-bold text-white mb-2">حدث خطأ</h2>
|
||||||
|
<p className="text-gray-400 mb-8">نعتذر، حدث خطأ أثناء تحميل الصفحة</p>
|
||||||
|
<div className="flex gap-3 justify-center">
|
||||||
|
<button onClick={reset} className="flex items-center gap-2 bg-amber-500 text-white px-6 py-3 rounded-xl font-medium hover:bg-amber-600 transition-colors">
|
||||||
|
<RefreshCw className="w-5 h-5" /> إعادة المحاولة
|
||||||
|
</button>
|
||||||
|
<Link href="/" className="flex items-center gap-2 bg-white/10 text-gray-300 px-6 py-3 rounded-xl font-medium hover:bg-white/20 transition-colors">
|
||||||
|
<Home className="w-5 h-5" /> الرئيسية
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
14
app/login/loading.js
Normal file
14
app/login/loading.js
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { motion } from 'framer-motion';
|
||||||
|
|
||||||
|
export default function Loading() {
|
||||||
|
return (
|
||||||
|
<div className="min-h-screen bg-gradient-to-br from-gray-950 via-gray-900 to-gray-950 flex items-center justify-center">
|
||||||
|
<motion.div initial={{ opacity: 0 }} animate={{ opacity: 1 }} className="text-center">
|
||||||
|
<div className="w-14 h-14 border-4 border-amber-500 border-t-transparent rounded-full animate-spin mx-auto mb-4" />
|
||||||
|
<p className="text-gray-400 text-lg">جاري التحميل...</p>
|
||||||
|
</motion.div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
36
app/not-found.js
Normal file
36
app/not-found.js
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { motion } from 'framer-motion';
|
||||||
|
import { AlertTriangle, RefreshCw, Home } from 'lucide-react';
|
||||||
|
import Link from 'next/link';
|
||||||
|
|
||||||
|
export default function NotFound() {
|
||||||
|
return (
|
||||||
|
<div className="min-h-screen bg-gray-50 flex items-center justify-center p-4">
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
className="text-center max-w-md"
|
||||||
|
>
|
||||||
|
<div className="mb-6">
|
||||||
|
<svg viewBox="0 0 200 160" className="w-64 h-48 mx-auto">
|
||||||
|
<circle cx="100" cy="80" r="70" fill="#fef3c7" />
|
||||||
|
<text x="100" y="95" textAnchor="middle" fontSize="60" fontWeight="bold" fill="#f59e0b">404</text>
|
||||||
|
<circle cx="80" cy="110" r="8" fill="#92400e" />
|
||||||
|
<circle cx="120" cy="110" r="8" fill="#92400e" />
|
||||||
|
<path d="M85 130 Q100 120 115 130" stroke="#92400e" strokeWidth="3" fill="none" strokeLinecap="round" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<h2 className="text-2xl font-bold text-gray-900 mb-2">الصفحة غير موجودة</h2>
|
||||||
|
<p className="text-gray-500 mb-8">عذراً، الصفحة التي تبحث عنها غير متوفرة</p>
|
||||||
|
<Link
|
||||||
|
href="/"
|
||||||
|
className="inline-flex items-center gap-2 bg-amber-500 text-white px-6 py-3 rounded-xl font-medium hover:bg-amber-600 transition-colors"
|
||||||
|
>
|
||||||
|
<Home className="w-5 h-5" />
|
||||||
|
العودة للرئيسية
|
||||||
|
</Link>
|
||||||
|
</motion.div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
27
app/owner/bookings/error.js
Normal file
27
app/owner/bookings/error.js
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { motion } from 'framer-motion';
|
||||||
|
import { AlertTriangle, RefreshCw, Home } from 'lucide-react';
|
||||||
|
import Link from 'next/link';
|
||||||
|
|
||||||
|
export default function Error({ error, reset }) {
|
||||||
|
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">
|
||||||
|
<motion.div initial={{ opacity: 0, y: 20 }} animate={{ opacity: 1, y: 0 }} className="text-center max-w-md">
|
||||||
|
<div className="w-20 h-20 bg-red-500/20 rounded-full flex items-center justify-center mx-auto mb-6">
|
||||||
|
<AlertTriangle className="w-10 h-10 text-red-500" />
|
||||||
|
</div>
|
||||||
|
<h2 className="text-2xl font-bold text-white mb-2">حدث خطأ</h2>
|
||||||
|
<p className="text-gray-400 mb-8">نعتذر، حدث خطأ أثناء تحميل الصفحة</p>
|
||||||
|
<div className="flex gap-3 justify-center">
|
||||||
|
<button onClick={reset} className="flex items-center gap-2 bg-amber-500 text-white px-6 py-3 rounded-xl font-medium hover:bg-amber-600 transition-colors">
|
||||||
|
<RefreshCw className="w-5 h-5" /> إعادة المحاولة
|
||||||
|
</button>
|
||||||
|
<Link href="/" className="flex items-center gap-2 bg-white/10 text-gray-300 px-6 py-3 rounded-xl font-medium hover:bg-white/20 transition-colors">
|
||||||
|
<Home className="w-5 h-5" /> الرئيسية
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
14
app/owner/bookings/loading.js
Normal file
14
app/owner/bookings/loading.js
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { motion } from 'framer-motion';
|
||||||
|
|
||||||
|
export default function Loading() {
|
||||||
|
return (
|
||||||
|
<div className="min-h-screen bg-gradient-to-br from-gray-950 via-gray-900 to-gray-950 flex items-center justify-center">
|
||||||
|
<motion.div initial={{ opacity: 0 }} animate={{ opacity: 1 }} className="text-center">
|
||||||
|
<div className="w-14 h-14 border-4 border-amber-500 border-t-transparent rounded-full animate-spin mx-auto mb-4" />
|
||||||
|
<p className="text-gray-400 text-lg">جاري التحميل...</p>
|
||||||
|
</motion.div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
27
app/owner/calendar/error.js
Normal file
27
app/owner/calendar/error.js
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { motion } from 'framer-motion';
|
||||||
|
import { AlertTriangle, RefreshCw, Home } from 'lucide-react';
|
||||||
|
import Link from 'next/link';
|
||||||
|
|
||||||
|
export default function Error({ error, reset }) {
|
||||||
|
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">
|
||||||
|
<motion.div initial={{ opacity: 0, y: 20 }} animate={{ opacity: 1, y: 0 }} className="text-center max-w-md">
|
||||||
|
<div className="w-20 h-20 bg-red-500/20 rounded-full flex items-center justify-center mx-auto mb-6">
|
||||||
|
<AlertTriangle className="w-10 h-10 text-red-500" />
|
||||||
|
</div>
|
||||||
|
<h2 className="text-2xl font-bold text-white mb-2">حدث خطأ</h2>
|
||||||
|
<p className="text-gray-400 mb-8">نعتذر، حدث خطأ أثناء تحميل الصفحة</p>
|
||||||
|
<div className="flex gap-3 justify-center">
|
||||||
|
<button onClick={reset} className="flex items-center gap-2 bg-amber-500 text-white px-6 py-3 rounded-xl font-medium hover:bg-amber-600 transition-colors">
|
||||||
|
<RefreshCw className="w-5 h-5" /> إعادة المحاولة
|
||||||
|
</button>
|
||||||
|
<Link href="/" className="flex items-center gap-2 bg-white/10 text-gray-300 px-6 py-3 rounded-xl font-medium hover:bg-white/20 transition-colors">
|
||||||
|
<Home className="w-5 h-5" /> الرئيسية
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
14
app/owner/calendar/loading.js
Normal file
14
app/owner/calendar/loading.js
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { motion } from 'framer-motion';
|
||||||
|
|
||||||
|
export default function Loading() {
|
||||||
|
return (
|
||||||
|
<div className="min-h-screen bg-gradient-to-br from-gray-950 via-gray-900 to-gray-950 flex items-center justify-center">
|
||||||
|
<motion.div initial={{ opacity: 0 }} animate={{ opacity: 1 }} className="text-center">
|
||||||
|
<div className="w-14 h-14 border-4 border-amber-500 border-t-transparent rounded-full animate-spin mx-auto mb-4" />
|
||||||
|
<p className="text-gray-400 text-lg">جاري التحميل...</p>
|
||||||
|
</motion.div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
27
app/owner/profits/error.js
Normal file
27
app/owner/profits/error.js
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { motion } from 'framer-motion';
|
||||||
|
import { AlertTriangle, RefreshCw, Home } from 'lucide-react';
|
||||||
|
import Link from 'next/link';
|
||||||
|
|
||||||
|
export default function Error({ error, reset }) {
|
||||||
|
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">
|
||||||
|
<motion.div initial={{ opacity: 0, y: 20 }} animate={{ opacity: 1, y: 0 }} className="text-center max-w-md">
|
||||||
|
<div className="w-20 h-20 bg-red-500/20 rounded-full flex items-center justify-center mx-auto mb-6">
|
||||||
|
<AlertTriangle className="w-10 h-10 text-red-500" />
|
||||||
|
</div>
|
||||||
|
<h2 className="text-2xl font-bold text-white mb-2">حدث خطأ</h2>
|
||||||
|
<p className="text-gray-400 mb-8">نعتذر، حدث خطأ أثناء تحميل الصفحة</p>
|
||||||
|
<div className="flex gap-3 justify-center">
|
||||||
|
<button onClick={reset} className="flex items-center gap-2 bg-amber-500 text-white px-6 py-3 rounded-xl font-medium hover:bg-amber-600 transition-colors">
|
||||||
|
<RefreshCw className="w-5 h-5" /> إعادة المحاولة
|
||||||
|
</button>
|
||||||
|
<Link href="/" className="flex items-center gap-2 bg-white/10 text-gray-300 px-6 py-3 rounded-xl font-medium hover:bg-white/20 transition-colors">
|
||||||
|
<Home className="w-5 h-5" /> الرئيسية
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
14
app/owner/profits/loading.js
Normal file
14
app/owner/profits/loading.js
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { motion } from 'framer-motion';
|
||||||
|
|
||||||
|
export default function Loading() {
|
||||||
|
return (
|
||||||
|
<div className="min-h-screen bg-gradient-to-br from-gray-950 via-gray-900 to-gray-950 flex items-center justify-center">
|
||||||
|
<motion.div initial={{ opacity: 0 }} animate={{ opacity: 1 }} className="text-center">
|
||||||
|
<div className="w-14 h-14 border-4 border-amber-500 border-t-transparent rounded-full animate-spin mx-auto mb-4" />
|
||||||
|
<p className="text-gray-400 text-lg">جاري التحميل...</p>
|
||||||
|
</motion.div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
27
app/owner/properties/add/error.js
Normal file
27
app/owner/properties/add/error.js
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { motion } from 'framer-motion';
|
||||||
|
import { AlertTriangle, RefreshCw, Home } from 'lucide-react';
|
||||||
|
import Link from 'next/link';
|
||||||
|
|
||||||
|
export default function Error({ error, reset }) {
|
||||||
|
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">
|
||||||
|
<motion.div initial={{ opacity: 0, y: 20 }} animate={{ opacity: 1, y: 0 }} className="text-center max-w-md">
|
||||||
|
<div className="w-20 h-20 bg-red-500/20 rounded-full flex items-center justify-center mx-auto mb-6">
|
||||||
|
<AlertTriangle className="w-10 h-10 text-red-500" />
|
||||||
|
</div>
|
||||||
|
<h2 className="text-2xl font-bold text-white mb-2">حدث خطأ</h2>
|
||||||
|
<p className="text-gray-400 mb-8">نعتذر، حدث خطأ أثناء تحميل الصفحة</p>
|
||||||
|
<div className="flex gap-3 justify-center">
|
||||||
|
<button onClick={reset} className="flex items-center gap-2 bg-amber-500 text-white px-6 py-3 rounded-xl font-medium hover:bg-amber-600 transition-colors">
|
||||||
|
<RefreshCw className="w-5 h-5" /> إعادة المحاولة
|
||||||
|
</button>
|
||||||
|
<Link href="/" className="flex items-center gap-2 bg-white/10 text-gray-300 px-6 py-3 rounded-xl font-medium hover:bg-white/20 transition-colors">
|
||||||
|
<Home className="w-5 h-5" /> الرئيسية
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
14
app/owner/properties/add/loading.js
Normal file
14
app/owner/properties/add/loading.js
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { motion } from 'framer-motion';
|
||||||
|
|
||||||
|
export default function Loading() {
|
||||||
|
return (
|
||||||
|
<div className="min-h-screen bg-gradient-to-br from-gray-950 via-gray-900 to-gray-950 flex items-center justify-center">
|
||||||
|
<motion.div initial={{ opacity: 0 }} animate={{ opacity: 1 }} className="text-center">
|
||||||
|
<div className="w-14 h-14 border-4 border-amber-500 border-t-transparent rounded-full animate-spin mx-auto mb-4" />
|
||||||
|
<p className="text-gray-400 text-lg">جاري التحميل...</p>
|
||||||
|
</motion.div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
27
app/owner/properties/error.js
Normal file
27
app/owner/properties/error.js
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { motion } from 'framer-motion';
|
||||||
|
import { AlertTriangle, RefreshCw, Home } from 'lucide-react';
|
||||||
|
import Link from 'next/link';
|
||||||
|
|
||||||
|
export default function Error({ error, reset }) {
|
||||||
|
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">
|
||||||
|
<motion.div initial={{ opacity: 0, y: 20 }} animate={{ opacity: 1, y: 0 }} className="text-center max-w-md">
|
||||||
|
<div className="w-20 h-20 bg-red-500/20 rounded-full flex items-center justify-center mx-auto mb-6">
|
||||||
|
<AlertTriangle className="w-10 h-10 text-red-500" />
|
||||||
|
</div>
|
||||||
|
<h2 className="text-2xl font-bold text-white mb-2">حدث خطأ</h2>
|
||||||
|
<p className="text-gray-400 mb-8">نعتذر، حدث خطأ أثناء تحميل الصفحة</p>
|
||||||
|
<div className="flex gap-3 justify-center">
|
||||||
|
<button onClick={reset} className="flex items-center gap-2 bg-amber-500 text-white px-6 py-3 rounded-xl font-medium hover:bg-amber-600 transition-colors">
|
||||||
|
<RefreshCw className="w-5 h-5" /> إعادة المحاولة
|
||||||
|
</button>
|
||||||
|
<Link href="/" className="flex items-center gap-2 bg-white/10 text-gray-300 px-6 py-3 rounded-xl font-medium hover:bg-white/20 transition-colors">
|
||||||
|
<Home className="w-5 h-5" /> الرئيسية
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
14
app/owner/properties/loading.js
Normal file
14
app/owner/properties/loading.js
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { motion } from 'framer-motion';
|
||||||
|
|
||||||
|
export default function Loading() {
|
||||||
|
return (
|
||||||
|
<div className="min-h-screen bg-gradient-to-br from-gray-950 via-gray-900 to-gray-950 flex items-center justify-center">
|
||||||
|
<motion.div initial={{ opacity: 0 }} animate={{ opacity: 1 }} className="text-center">
|
||||||
|
<div className="w-14 h-14 border-4 border-amber-500 border-t-transparent rounded-full animate-spin mx-auto mb-4" />
|
||||||
|
<p className="text-gray-400 text-lg">جاري التحميل...</p>
|
||||||
|
</motion.div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
27
app/profile/error.js
Normal file
27
app/profile/error.js
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { motion } from 'framer-motion';
|
||||||
|
import { AlertTriangle, RefreshCw, Home } from 'lucide-react';
|
||||||
|
import Link from 'next/link';
|
||||||
|
|
||||||
|
export default function Error({ error, reset }) {
|
||||||
|
return (
|
||||||
|
<div className="min-h-screen bg-gray-50 flex items-center justify-center p-4">
|
||||||
|
<motion.div initial={{ opacity: 0, y: 20 }} animate={{ opacity: 1, y: 0 }} className="text-center max-w-md">
|
||||||
|
<div className="w-20 h-20 bg-red-100 rounded-full flex items-center justify-center mx-auto mb-6">
|
||||||
|
<AlertTriangle className="w-10 h-10 text-red-500" />
|
||||||
|
</div>
|
||||||
|
<h2 className="text-2xl font-bold text-gray-900 mb-2">حدث خطأ</h2>
|
||||||
|
<p className="text-gray-500 mb-8">نعتذر، حدث خطأ أثناء تحميل الصفحة</p>
|
||||||
|
<div className="flex gap-3 justify-center">
|
||||||
|
<button onClick={reset} className="flex items-center gap-2 bg-amber-500 text-white px-6 py-3 rounded-xl font-medium hover:bg-amber-600 transition-colors">
|
||||||
|
<RefreshCw className="w-5 h-5" /> إعادة المحاولة
|
||||||
|
</button>
|
||||||
|
<Link href="/" className="flex items-center gap-2 bg-gray-200 text-gray-700 px-6 py-3 rounded-xl font-medium hover:bg-gray-300 transition-colors">
|
||||||
|
<Home className="w-5 h-5" /> الرئيسية
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
14
app/profile/loading.js
Normal file
14
app/profile/loading.js
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { motion } from 'framer-motion';
|
||||||
|
|
||||||
|
export default function Loading() {
|
||||||
|
return (
|
||||||
|
<div className="min-h-screen bg-gray-50 flex items-center justify-center">
|
||||||
|
<motion.div initial={{ opacity: 0 }} animate={{ opacity: 1 }} className="text-center">
|
||||||
|
<div className="w-14 h-14 border-4 border-amber-500 border-t-transparent rounded-full animate-spin mx-auto mb-4" />
|
||||||
|
<p className="text-gray-500 text-lg">جاري التحميل...</p>
|
||||||
|
</motion.div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
27
app/properties/error.js
Normal file
27
app/properties/error.js
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { motion } from 'framer-motion';
|
||||||
|
import { AlertTriangle, RefreshCw, Home } from 'lucide-react';
|
||||||
|
import Link from 'next/link';
|
||||||
|
|
||||||
|
export default function Error({ error, reset }) {
|
||||||
|
return (
|
||||||
|
<div className="min-h-screen bg-gray-50 flex items-center justify-center p-4">
|
||||||
|
<motion.div initial={{ opacity: 0, y: 20 }} animate={{ opacity: 1, y: 0 }} className="text-center max-w-md">
|
||||||
|
<div className="w-20 h-20 bg-red-100 rounded-full flex items-center justify-center mx-auto mb-6">
|
||||||
|
<AlertTriangle className="w-10 h-10 text-red-500" />
|
||||||
|
</div>
|
||||||
|
<h2 className="text-2xl font-bold text-gray-900 mb-2">حدث خطأ</h2>
|
||||||
|
<p className="text-gray-500 mb-8">نعتذر، حدث خطأ أثناء تحميل الصفحة</p>
|
||||||
|
<div className="flex gap-3 justify-center">
|
||||||
|
<button onClick={reset} className="flex items-center gap-2 bg-amber-500 text-white px-6 py-3 rounded-xl font-medium hover:bg-amber-600 transition-colors">
|
||||||
|
<RefreshCw className="w-5 h-5" /> إعادة المحاولة
|
||||||
|
</button>
|
||||||
|
<Link href="/" className="flex items-center gap-2 bg-gray-200 text-gray-700 px-6 py-3 rounded-xl font-medium hover:bg-gray-300 transition-colors">
|
||||||
|
<Home className="w-5 h-5" /> الرئيسية
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
14
app/properties/loading.js
Normal file
14
app/properties/loading.js
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { motion } from 'framer-motion';
|
||||||
|
|
||||||
|
export default function Loading() {
|
||||||
|
return (
|
||||||
|
<div className="min-h-screen bg-gray-50 flex items-center justify-center">
|
||||||
|
<motion.div initial={{ opacity: 0 }} animate={{ opacity: 1 }} className="text-center">
|
||||||
|
<div className="w-14 h-14 border-4 border-amber-500 border-t-transparent rounded-full animate-spin mx-auto mb-4" />
|
||||||
|
<p className="text-gray-500 text-lg">جاري التحميل...</p>
|
||||||
|
</motion.div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
27
app/property/[id]/error.js
Normal file
27
app/property/[id]/error.js
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { motion } from 'framer-motion';
|
||||||
|
import { AlertTriangle, RefreshCw, Home } from 'lucide-react';
|
||||||
|
import Link from 'next/link';
|
||||||
|
|
||||||
|
export default function Error({ error, reset }) {
|
||||||
|
return (
|
||||||
|
<div className="min-h-screen bg-gray-50 flex items-center justify-center p-4">
|
||||||
|
<motion.div initial={{ opacity: 0, y: 20 }} animate={{ opacity: 1, y: 0 }} className="text-center max-w-md">
|
||||||
|
<div className="w-20 h-20 bg-red-100 rounded-full flex items-center justify-center mx-auto mb-6">
|
||||||
|
<AlertTriangle className="w-10 h-10 text-red-500" />
|
||||||
|
</div>
|
||||||
|
<h2 className="text-2xl font-bold text-gray-900 mb-2">حدث خطأ</h2>
|
||||||
|
<p className="text-gray-500 mb-8">نعتذر، حدث خطأ أثناء تحميل الصفحة</p>
|
||||||
|
<div className="flex gap-3 justify-center">
|
||||||
|
<button onClick={reset} className="flex items-center gap-2 bg-amber-500 text-white px-6 py-3 rounded-xl font-medium hover:bg-amber-600 transition-colors">
|
||||||
|
<RefreshCw className="w-5 h-5" /> إعادة المحاولة
|
||||||
|
</button>
|
||||||
|
<Link href="/" className="flex items-center gap-2 bg-gray-200 text-gray-700 px-6 py-3 rounded-xl font-medium hover:bg-gray-300 transition-colors">
|
||||||
|
<Home className="w-5 h-5" /> الرئيسية
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
14
app/property/[id]/loading.js
Normal file
14
app/property/[id]/loading.js
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { motion } from 'framer-motion';
|
||||||
|
|
||||||
|
export default function Loading() {
|
||||||
|
return (
|
||||||
|
<div className="min-h-screen bg-gray-50 flex items-center justify-center">
|
||||||
|
<motion.div initial={{ opacity: 0 }} animate={{ opacity: 1 }} className="text-center">
|
||||||
|
<div className="w-14 h-14 border-4 border-amber-500 border-t-transparent rounded-full animate-spin mx-auto mb-4" />
|
||||||
|
<p className="text-gray-500 text-lg">جاري التحميل...</p>
|
||||||
|
</motion.div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
27
app/register/owner/error.js
Normal file
27
app/register/owner/error.js
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { motion } from 'framer-motion';
|
||||||
|
import { AlertTriangle, RefreshCw, Home } from 'lucide-react';
|
||||||
|
import Link from 'next/link';
|
||||||
|
|
||||||
|
export default function Error({ error, reset }) {
|
||||||
|
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">
|
||||||
|
<motion.div initial={{ opacity: 0, y: 20 }} animate={{ opacity: 1, y: 0 }} className="text-center max-w-md">
|
||||||
|
<div className="w-20 h-20 bg-red-500/20 rounded-full flex items-center justify-center mx-auto mb-6">
|
||||||
|
<AlertTriangle className="w-10 h-10 text-red-500" />
|
||||||
|
</div>
|
||||||
|
<h2 className="text-2xl font-bold text-white mb-2">حدث خطأ</h2>
|
||||||
|
<p className="text-gray-400 mb-8">نعتذر، حدث خطأ أثناء تحميل الصفحة</p>
|
||||||
|
<div className="flex gap-3 justify-center">
|
||||||
|
<button onClick={reset} className="flex items-center gap-2 bg-amber-500 text-white px-6 py-3 rounded-xl font-medium hover:bg-amber-600 transition-colors">
|
||||||
|
<RefreshCw className="w-5 h-5" /> إعادة المحاولة
|
||||||
|
</button>
|
||||||
|
<Link href="/" className="flex items-center gap-2 bg-white/10 text-gray-300 px-6 py-3 rounded-xl font-medium hover:bg-white/20 transition-colors">
|
||||||
|
<Home className="w-5 h-5" /> الرئيسية
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
14
app/register/owner/loading.js
Normal file
14
app/register/owner/loading.js
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { motion } from 'framer-motion';
|
||||||
|
|
||||||
|
export default function Loading() {
|
||||||
|
return (
|
||||||
|
<div className="min-h-screen bg-gradient-to-br from-gray-950 via-gray-900 to-gray-950 flex items-center justify-center">
|
||||||
|
<motion.div initial={{ opacity: 0 }} animate={{ opacity: 1 }} className="text-center">
|
||||||
|
<div className="w-14 h-14 border-4 border-amber-500 border-t-transparent rounded-full animate-spin mx-auto mb-4" />
|
||||||
|
<p className="text-gray-400 text-lg">جاري التحميل...</p>
|
||||||
|
</motion.div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
27
app/register/tenant/error.js
Normal file
27
app/register/tenant/error.js
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { motion } from 'framer-motion';
|
||||||
|
import { AlertTriangle, RefreshCw, Home } from 'lucide-react';
|
||||||
|
import Link from 'next/link';
|
||||||
|
|
||||||
|
export default function Error({ error, reset }) {
|
||||||
|
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">
|
||||||
|
<motion.div initial={{ opacity: 0, y: 20 }} animate={{ opacity: 1, y: 0 }} className="text-center max-w-md">
|
||||||
|
<div className="w-20 h-20 bg-red-500/20 rounded-full flex items-center justify-center mx-auto mb-6">
|
||||||
|
<AlertTriangle className="w-10 h-10 text-red-500" />
|
||||||
|
</div>
|
||||||
|
<h2 className="text-2xl font-bold text-white mb-2">حدث خطأ</h2>
|
||||||
|
<p className="text-gray-400 mb-8">نعتذر، حدث خطأ أثناء تحميل الصفحة</p>
|
||||||
|
<div className="flex gap-3 justify-center">
|
||||||
|
<button onClick={reset} className="flex items-center gap-2 bg-amber-500 text-white px-6 py-3 rounded-xl font-medium hover:bg-amber-600 transition-colors">
|
||||||
|
<RefreshCw className="w-5 h-5" /> إعادة المحاولة
|
||||||
|
</button>
|
||||||
|
<Link href="/" className="flex items-center gap-2 bg-white/10 text-gray-300 px-6 py-3 rounded-xl font-medium hover:bg-white/20 transition-colors">
|
||||||
|
<Home className="w-5 h-5" /> الرئيسية
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
14
app/register/tenant/loading.js
Normal file
14
app/register/tenant/loading.js
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { motion } from 'framer-motion';
|
||||||
|
|
||||||
|
export default function Loading() {
|
||||||
|
return (
|
||||||
|
<div className="min-h-screen bg-gradient-to-br from-gray-950 via-gray-900 to-gray-950 flex items-center justify-center">
|
||||||
|
<motion.div initial={{ opacity: 0 }} animate={{ opacity: 1 }} className="text-center">
|
||||||
|
<div className="w-14 h-14 border-4 border-amber-500 border-t-transparent rounded-full animate-spin mx-auto mb-4" />
|
||||||
|
<p className="text-gray-400 text-lg">جاري التحميل...</p>
|
||||||
|
</motion.div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user