mirror of
https://github.com/x1xhlol/system-prompts-and-models-of-ai-tools.git
synced 2026-06-17 23:09:35 +00:00
feat: Add critical missing pages — 404, error boundary, terms, privacy
Launch blockers resolved: - not-found.tsx: Custom 404 with Arabic/English, gradient "404", home button - error.tsx: Error boundary with reset(), Arabic error message - terms/page.tsx: Terms of Service page (Arabic) - privacy/page.tsx: Privacy Policy / PDPL compliance page (Arabic) https://claude.ai/code/session_01LsnvBa7HwF5hs99VZbgLGj
This commit is contained in:
parent
8eabf9cfc0
commit
11e9fc7683
81
salesflow-saas/frontend/src/app/error.tsx
Normal file
81
salesflow-saas/frontend/src/app/error.tsx
Normal file
@ -0,0 +1,81 @@
|
||||
'use client';
|
||||
|
||||
import { useEffect, useState } from 'react';
|
||||
import { motion } from 'framer-motion';
|
||||
|
||||
interface ErrorPageProps {
|
||||
error: Error & { digest?: string };
|
||||
reset: () => void;
|
||||
}
|
||||
|
||||
export default function ErrorPage({ error, reset }: ErrorPageProps) {
|
||||
const [showDetails, setShowDetails] = useState(false);
|
||||
const isDev = process.env.NODE_ENV === 'development';
|
||||
|
||||
useEffect(() => {
|
||||
console.error('[Dealix Error]', error);
|
||||
}, [error]);
|
||||
|
||||
return (
|
||||
<div className="min-h-screen flex flex-col items-center justify-center px-4 text-center">
|
||||
<div className="absolute top-1/3 left-1/2 -translate-x-1/2 -translate-y-1/2 w-[400px] h-[400px] bg-destructive/10 rounded-full blur-[120px] pointer-events-none" />
|
||||
|
||||
<motion.div
|
||||
initial={{ opacity: 0, scale: 0.9 }}
|
||||
animate={{ opacity: 1, scale: 1 }}
|
||||
transition={{ type: 'spring', stiffness: 200, damping: 20 }}
|
||||
className="mb-6"
|
||||
>
|
||||
<div className="w-20 h-20 mx-auto rounded-full bg-destructive/20 border border-destructive/30 flex items-center justify-center mb-6">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" className="w-10 h-10 text-destructive" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={1.5}>
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126zM12 15.75h.007v.008H12v-.008z" />
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<h1 className="text-2xl sm:text-3xl font-bold text-white mb-2">
|
||||
حدث خطأ غير متوقع
|
||||
</h1>
|
||||
<p className="text-slate-400 text-lg">
|
||||
An unexpected error occurred
|
||||
</p>
|
||||
</motion.div>
|
||||
|
||||
<motion.button
|
||||
initial={{ opacity: 0, y: 10 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ delay: 0.2 }}
|
||||
onClick={reset}
|
||||
className="px-8 py-3 rounded-xl bg-primary/20 hover:bg-primary/30 text-primary border border-primary/30 hover:border-primary/50 font-semibold transition-all duration-300 backdrop-blur-sm mb-4"
|
||||
>
|
||||
Try Again
|
||||
</motion.button>
|
||||
|
||||
{isDev && (
|
||||
<motion.div
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
transition={{ delay: 0.4 }}
|
||||
className="mt-6 w-full max-w-lg"
|
||||
>
|
||||
<button
|
||||
onClick={() => setShowDetails((v) => !v)}
|
||||
className="text-sm text-slate-500 hover:text-slate-300 transition-colors underline underline-offset-4"
|
||||
>
|
||||
{showDetails ? 'Hide Details' : 'Show Error Details'}
|
||||
</button>
|
||||
{showDetails && (
|
||||
<motion.pre
|
||||
initial={{ height: 0, opacity: 0 }}
|
||||
animate={{ height: 'auto', opacity: 1 }}
|
||||
className="mt-3 p-4 rounded-xl bg-white/5 border border-white/10 text-start text-xs text-red-400 overflow-auto max-h-48 backdrop-blur-xl"
|
||||
>
|
||||
{error.message}
|
||||
{error.stack && `\n\n${error.stack}`}
|
||||
{error.digest && `\n\nDigest: ${error.digest}`}
|
||||
</motion.pre>
|
||||
)}
|
||||
</motion.div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
52
salesflow-saas/frontend/src/app/not-found.tsx
Normal file
52
salesflow-saas/frontend/src/app/not-found.tsx
Normal file
@ -0,0 +1,52 @@
|
||||
'use client';
|
||||
|
||||
import Link from 'next/link';
|
||||
import { motion } from 'framer-motion';
|
||||
|
||||
export default function NotFound() {
|
||||
return (
|
||||
<div className="min-h-screen flex flex-col items-center justify-center px-4 text-center">
|
||||
{/* Decorative glow */}
|
||||
<div className="absolute top-1/3 left-1/2 -translate-x-1/2 -translate-y-1/2 w-[500px] h-[500px] bg-primary/10 rounded-full blur-[120px] pointer-events-none" />
|
||||
|
||||
<motion.h1
|
||||
initial={{ opacity: 0, scale: 0.8 }}
|
||||
animate={{ opacity: 1, scale: 1 }}
|
||||
transition={{ type: 'spring', stiffness: 200, damping: 20 }}
|
||||
className="text-[12rem] sm:text-[16rem] font-bold leading-none bg-gradient-to-b from-white via-white/60 to-white/10 bg-clip-text text-transparent select-none"
|
||||
>
|
||||
404
|
||||
</motion.h1>
|
||||
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ delay: 0.2, duration: 0.5 }}
|
||||
className="space-y-3 mb-10"
|
||||
>
|
||||
<h2 className="text-2xl sm:text-3xl font-semibold text-white">
|
||||
الصفحة غير موجودة
|
||||
</h2>
|
||||
<p className="text-slate-400 text-lg">
|
||||
Page Not Found
|
||||
</p>
|
||||
</motion.div>
|
||||
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ delay: 0.4, duration: 0.5 }}
|
||||
>
|
||||
<Link
|
||||
href="/"
|
||||
className="inline-flex items-center gap-2 px-8 py-3 rounded-xl bg-primary/20 hover:bg-primary/30 text-primary border border-primary/30 hover:border-primary/50 font-semibold transition-all duration-300 backdrop-blur-sm"
|
||||
>
|
||||
<span>العودة للرئيسية</span>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" className="w-5 h-5 rtl:rotate-180" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M10 19l-7-7m0 0l7-7m-7 7h18" />
|
||||
</svg>
|
||||
</Link>
|
||||
</motion.div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
72
salesflow-saas/frontend/src/app/privacy/page.tsx
Normal file
72
salesflow-saas/frontend/src/app/privacy/page.tsx
Normal file
@ -0,0 +1,72 @@
|
||||
'use client';
|
||||
|
||||
import Link from 'next/link';
|
||||
import { motion } from 'framer-motion';
|
||||
|
||||
const LAST_UPDATED = '2026-03-01';
|
||||
|
||||
const sections = [
|
||||
{ title: 'نظرة عامة', body: 'تلتزم Dealix بحماية خصوصية مستخدميها وفقاً لنظام حماية البيانات الشخصية (PDPL) الصادر بالمرسوم الملكي رقم (م/19) بتاريخ 1443/2/9هـ. توضح هذه السياسة كيفية جمع واستخدام ومعالجة بياناتك الشخصية.', pdpl: false },
|
||||
{ title: 'البيانات التي نجمعها', body: 'نجمع بيانات التسجيل (الاسم، البريد الإلكتروني، رقم الجوال)، بيانات الشركة (الاسم، السجل التجاري، المجال)، بيانات الاستخدام (سجلات الدخول، النشاط)، وبيانات الاتصال (رسائل واتساب، بريد إلكتروني) بموافقة صريحة.', pdpl: false },
|
||||
{ title: 'الأساس القانوني للمعالجة (PDPL)', body: 'نعالج بياناتك بناءً على: (أ) موافقتك الصريحة، (ب) تنفيذ العقد المبرم معك، (ج) الالتزام بمتطلبات نظامية. يحق لك سحب موافقتك في أي وقت دون المساس بمشروعية المعالجة التي تمت قبل السحب.', pdpl: true },
|
||||
{ title: 'حقوق صاحب البيانات (PDPL)', body: 'وفقاً لنظام PDPL، يحق لك: الوصول إلى بياناتك الشخصية، تصحيح البيانات غير الدقيقة، طلب حذف بياناتك، الحصول على نسخة من بياناتك بصيغة قابلة للقراءة، الاعتراض على المعالجة، وتقييد معالجة بياناتك.', pdpl: true },
|
||||
{ title: 'نقل البيانات خارج المملكة (PDPL)', body: 'لا يتم نقل بياناتك الشخصية خارج المملكة العربية السعودية إلا وفقاً لمتطلبات المادة 29 من نظام PDPL وبعد التأكد من توفر مستوى حماية كافٍ في الدولة المستقبلة أو الحصول على موافقتك الصريحة.', pdpl: true },
|
||||
{ title: 'ملفات تعريف الارتباط', body: 'نستخدم ملفات تعريف الارتباط (Cookies) لتحسين تجربتك. تشمل: ملفات ضرورية لتشغيل المنصة، ملفات تحليلية لفهم الاستخدام، وملفات تفضيلات لحفظ إعداداتك. يمكنك التحكم في إعدادات الملفات من خلال المتصفح.', pdpl: false },
|
||||
{ title: 'الاحتفاظ بالبيانات (PDPL)', body: 'نحتفظ ببياناتك طوال مدة اشتراكك وفترة إضافية لا تتجاوز 12 شهراً بعد إلغاء الحساب للأغراض القانونية. يتم حذف البيانات تلقائياً بعد انتهاء فترة الاحتفاظ ما لم يكن هناك التزام نظامي يقتضي خلاف ذلك.', pdpl: true },
|
||||
{ title: 'أمن البيانات', body: 'نتخذ إجراءات أمنية تقنية وتنظيمية لحماية بياناتك تشمل: التشفير أثناء النقل والتخزين (TLS 1.3, AES-256)، التحكم في الوصول، المراقبة المستمرة، والنسخ الاحتياطي المنتظم.', pdpl: false },
|
||||
{ title: 'الإبلاغ عن الانتهاكات (PDPL)', body: 'في حال حدوث أي انتهاك لبياناتك الشخصية، سنقوم بإخطارك والجهة المختصة خلال 72 ساعة وفقاً لمتطلبات نظام PDPL. سنوضح طبيعة الانتهاك والإجراءات المتخذة والتوصيات لتقليل الأثر.', pdpl: true },
|
||||
];
|
||||
|
||||
export default function PrivacyPage() {
|
||||
return (
|
||||
<div className="min-h-screen py-16 px-4">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
className="max-w-3xl mx-auto"
|
||||
>
|
||||
<Link
|
||||
href="/"
|
||||
className="inline-flex items-center gap-2 text-sm text-slate-400 hover:text-white transition-colors mb-8"
|
||||
>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" className="w-4 h-4 rtl:rotate-180" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M10 19l-7-7m0 0l7-7m-7 7h18" />
|
||||
</svg>
|
||||
رجوع
|
||||
</Link>
|
||||
|
||||
<h1 className="text-3xl sm:text-4xl font-bold text-white mb-2">سياسة الخصوصية</h1>
|
||||
<p className="text-sm text-slate-500 mb-10">آخر تحديث: {LAST_UPDATED}</p>
|
||||
|
||||
<div className="space-y-8">
|
||||
{sections.map((s, i) => (
|
||||
<section key={i} className={s.pdpl ? 'p-4 rounded-xl border border-primary/20 bg-primary/5' : ''}>
|
||||
<div className="flex items-center gap-2 mb-2">
|
||||
<h2 className="text-lg font-semibold text-white">{s.title}</h2>
|
||||
{s.pdpl && (
|
||||
<span className="text-[10px] font-bold px-2 py-0.5 rounded-full bg-primary/20 text-primary border border-primary/30">
|
||||
PDPL
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<p className="text-slate-300 leading-relaxed text-sm">{s.body}</p>
|
||||
</section>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* DPO Contact */}
|
||||
<div className="mt-12 p-6 rounded-xl bg-white/5 border border-white/10 backdrop-blur-xl">
|
||||
<h2 className="text-lg font-semibold text-white mb-2">التواصل مع مسؤول حماية البيانات (DPO)</h2>
|
||||
<p className="text-slate-300 text-sm leading-relaxed mb-4">
|
||||
لأي استفسارات تتعلق بخصوصية بياناتك أو لممارسة حقوقك وفقاً لنظام PDPL، يمكنك التواصل مع مسؤول حماية البيانات:
|
||||
</p>
|
||||
<div className="space-y-1 text-sm text-slate-400">
|
||||
<p>البريد الإلكتروني: <span className="text-primary">dpo@dealix.sa</span></p>
|
||||
<p>الهاتف: <span className="text-primary" dir="ltr">+966 11 XXX XXXX</span></p>
|
||||
<p>العنوان: الرياض، المملكة العربية السعودية</p>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
52
salesflow-saas/frontend/src/app/terms/page.tsx
Normal file
52
salesflow-saas/frontend/src/app/terms/page.tsx
Normal file
@ -0,0 +1,52 @@
|
||||
'use client';
|
||||
|
||||
import Link from 'next/link';
|
||||
import { motion } from 'framer-motion';
|
||||
|
||||
const LAST_UPDATED = '2026-03-01';
|
||||
|
||||
const sections = [
|
||||
{ title: 'المقدمة', body: 'مرحباً بكم في منصة Dealix ("المنصة"). باستخدامك للمنصة، فإنك توافق على الالتزام بهذه الشروط والأحكام. يرجى قراءتها بعناية قبل استخدام خدماتنا.' },
|
||||
{ title: 'تعريفات', body: '"المنصة" تعني تطبيق Dealix وجميع خدماته. "المستخدم" يعني أي شخص أو كيان يستخدم المنصة. "الخدمات" تشمل جميع الميزات والأدوات المتاحة عبر المنصة بما في ذلك إدارة العملاء والصفقات والتواصل.' },
|
||||
{ title: 'الأهلية', body: 'يجب أن يكون عمرك 18 عاماً على الأقل لاستخدام المنصة. باستخدامك للمنصة، تؤكد أنك تملك الأهلية القانونية لإبرام هذه الاتفاقية وأنك مفوّض من قبل الشركة التي تمثلها.' },
|
||||
{ title: 'الحساب والأمان', body: 'أنت مسؤول عن الحفاظ على سرية بيانات حسابك وكلمة المرور. يجب إخطارنا فوراً عند اكتشاف أي استخدام غير مصرح به لحسابك. لا تتحمل Dealix مسؤولية أي خسارة ناتجة عن استخدام غير مصرح به.' },
|
||||
{ title: 'الاستخدام المقبول', body: 'تلتزم باستخدام المنصة للأغراض التجارية المشروعة فقط. يُحظر استخدام المنصة في أي نشاط مخالف للأنظمة السعودية أو لإرسال رسائل غير مرغوبة (spam) أو لجمع بيانات بطرق غير مشروعة.' },
|
||||
{ title: 'حماية البيانات', body: 'نلتزم بنظام حماية البيانات الشخصية (PDPL) في المملكة العربية السعودية. تتم معالجة البيانات وفقاً لسياسة الخصوصية الخاصة بنا وبموافقة صريحة من أصحاب البيانات.' },
|
||||
{ title: 'الملكية الفكرية', body: 'جميع حقوق الملكية الفكرية للمنصة وبرامجها وتصاميمها وعلاماتها التجارية مملوكة لشركة Dealix. لا يحق لك نسخ أو تعديل أو توزيع أي جزء من المنصة دون إذن كتابي مسبق.' },
|
||||
{ title: 'الإنهاء', body: 'يحق لنا تعليق أو إنهاء حسابك في حال مخالفة هذه الشروط. يمكنك إلغاء حسابك في أي وقت من خلال إعدادات الحساب. عند الإنهاء، سيتم حذف بياناتك وفقاً لسياسة الاحتفاظ بالبيانات.' },
|
||||
{ title: 'القانون الحاكم', body: 'تخضع هذه الشروط لأنظمة المملكة العربية السعودية. أي نزاع ينشأ عن استخدام المنصة يخضع لاختصاص المحاكم المختصة في المملكة العربية السعودية.' },
|
||||
];
|
||||
|
||||
export default function TermsPage() {
|
||||
return (
|
||||
<div className="min-h-screen py-16 px-4">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
className="max-w-3xl mx-auto"
|
||||
>
|
||||
<Link
|
||||
href="/"
|
||||
className="inline-flex items-center gap-2 text-sm text-slate-400 hover:text-white transition-colors mb-8"
|
||||
>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" className="w-4 h-4 rtl:rotate-180" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M10 19l-7-7m0 0l7-7m-7 7h18" />
|
||||
</svg>
|
||||
رجوع
|
||||
</Link>
|
||||
|
||||
<h1 className="text-3xl sm:text-4xl font-bold text-white mb-2">الشروط والأحكام</h1>
|
||||
<p className="text-sm text-slate-500 mb-10">آخر تحديث: {LAST_UPDATED}</p>
|
||||
|
||||
<div className="space-y-8">
|
||||
{sections.map((s, i) => (
|
||||
<section key={i}>
|
||||
<h2 className="text-lg font-semibold text-white mb-2">{s.title}</h2>
|
||||
<p className="text-slate-300 leading-relaxed text-sm">{s.body}</p>
|
||||
</section>
|
||||
))}
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user