// Modals.jsx — Global modal components for Sanad Platform
// Exports: TrialExpiredModal, CheckoutModal, AuthModal, AboutModal, TermsModal
/* ── Shared Modal Backdrop ───────────────────────────── */
function ModalBackdrop({ onClose, children, wide }) {
React.useEffect(() => {
const h = (e) => { if (e.key === 'Escape') onClose(); };
document.addEventListener('keydown', h);
return () => document.removeEventListener('keydown', h);
}, []);
return (
e.stopPropagation()} style={{
background: sanadColors.bgElevated,
borderRadius: 20,
boxShadow: '0 0 0 1px rgba(239,231,214,0.10), 0 24px 64px rgba(0,0,0,0.22)',
width: '100%', maxWidth: wide ? 780 : 480,
maxHeight: '92vh', overflowY: 'auto',
direction: 'rtl', fontFamily: sanadFonts.arabic,
animation: 'modalIn 280ms cubic-bezier(0.16,1,0.3,1) both',
position: 'relative',
}}>
{children}
);
}
/* ── Trial Expired Modal ─────────────────────────────── */
function TrialExpiredModal({ onClose, onViewPlans }) {
return (
{/* Close */}
{/* Hero section */}
{/* Decorative rings */}
{/* Icon */}
انتهت التجربة المجانية
باقتك الحالية انتهت
اشترك الآن واستمتع بمزايا منصة ليكسا القانونية في النظام السعودي
ليكسا: أكبر وأذكى منصة قانونية سعودية
{/* Mini pricing preview */}
اختر الباقة المناسبة لك
{[
{ name:'الاحترافية', price:'٣٩', period:'ر.س/شهر', badge:'الأكثر شيوعاً', highlight:true,
features:['أسئلة غير محدودة', 'تحليل المستندات', 'بحث متكامل'] },
{ name:'الأعمال', price:'١٥٩', period:'ر.س/شهر', badge:null, highlight:false,
features:['كل مزايا الاحترافية', 'مستخدمون متعددون', 'دعم أولوية'] },
].map((p, i) => (
e.currentTarget.style.transform='translateY(-2px)'}
onMouseLeave={e => e.currentTarget.style.transform='none'}
>
{p.badge && (
{p.badge}
)}
{p.name}
{p.price}
{p.period}
{p.features.map((f, j) => (
))}
))}
عرض الباقات
متابعة بالنسخة المجانية
);
}
/* ── Checkout Modal ──────────────────────────────────── */
function CheckoutModal({ plan, billing, onClose, onSuccess }) {
const [coupon, setCoupon] = React.useState('');
const [couponApplied, setCouponApplied] = React.useState(false);
const [couponError, setCouponError] = React.useState('');
const [payMethod, setPayMethod] = React.useState('mada');
const [card, setCard] = React.useState({ num:'', exp:'', cvv:'', name:'' });
const [agreeTerms, setAgreeTerms] = React.useState(false);
const [loading, setLoading] = React.useState(false);
const [done, setDone] = React.useState(false);
const rawPrice = plan?.id === 'pro' ? 49 : plan?.id === 'business' ? 199 : 0;
const annualDiscount = billing === 'annual' ? 0.6 : 1;
const couponDiscount = couponApplied ? 0.9 : 1;
const finalMonthly = Math.round(rawPrice * annualDiscount * couponDiscount);
const finalTotal = billing === 'annual' ? finalMonthly * 12 : finalMonthly;
const applyCoupon = () => {
if (coupon.trim().toUpperCase() === 'SANAD10') {
setCouponApplied(true); setCouponError('');
} else {
setCouponError('الكوبون غير صحيح');
}
};
const handlePay = () => {
if (!agreeTerms) return;
setLoading(true);
setTimeout(() => { setLoading(false); setDone(true); }, 1800);
};
if (done) return (
تم الاشتراك بنجاح!
مرحباً بك في باقة {plan?.name}. ستصلك رسالة تأكيد على بريدك الإلكتروني.
العودة للمنصة
);
return (
{/* Left: Summary */}
ملخص الطلب
باقة {plan?.name}
{billing === 'annual' ? 'اشتراك سنوي' : 'اشتراك شهري'}
{billing === 'annual' &&
}
{couponApplied &&
}
الإجمالي
{finalTotal} ر.س
{billing === 'annual' &&
{finalMonthly} ر.س/شهر
}
{/* Coupon */}
كوبون خصم
setCoupon(e.target.value)} placeholder="أدخل الكوبون" disabled={couponApplied}
style={{ flex:1, padding:'9px 12px', borderRadius:8, border:'1px solid rgba(255,255,255,0.1)', background:'rgba(255,255,255,0.06)', color:sanadColors.textInverted, fontFamily:sanadFonts.arabic, fontSize:13, outline:'none', direction:'rtl' }} />
{couponApplied ? '✓' : 'تطبيق'}
{couponError &&
{couponError}
}
{couponApplied &&
تم تطبيق الخصم بنجاح
}
{/* Right: Payment */}
وسيلة الدفع
{/* Payment method toggle */}
{[['mada', 'مدى'], ['visa', 'Visa']].map(([id, label]) => (
setPayMethod(id)} style={{
flex:1, padding:'10px', borderRadius:10, border:'none', cursor:'pointer',
background: payMethod === id ? sanadColors.brandSubtle : sanadColors.bg,
boxShadow: payMethod === id ? `0 0 0 2px ${sanadColors.brand}` : '0 0 0 1px rgba(239,231,214,0.12)',
fontFamily:sanadFonts.arabic, fontSize:14, fontWeight:500,
color: payMethod === id ? sanadColors.brand : sanadColors.textSecondary,
transition:'all 150ms ease',
}}>{label}
))}
{/* Card fields */}
setCard(c => ({ ...c, name:v }))} />
setCard(c => ({ ...c, num:v }))} />
setCard(c => ({ ...c, exp:v }))} />
setCard(c => ({ ...c, cvv:v }))} />
{/* Terms */}
setAgreeTerms(!agreeTerms)} style={{
width:18, height:18, borderRadius:5, border:`2px solid ${agreeTerms ? sanadColors.brand : sanadColors.border}`,
background: agreeTerms ? sanadColors.brand : 'transparent',
flexShrink:0, display:'flex', alignItems:'center', justifyContent:'center', marginTop:1,
transition:'all 150ms ease', cursor:'pointer',
}}>
{agreeTerms &&
}
أوافق على الشروط والأحكام وسياسة الخصوصية
{loading ? 'جارٍ المعالجة…' : `ادفع ${finalTotal} ر.س`}
مدفوعات مشفّرة وآمنة بالكامل
);
}
function Row({ label, value, light, highlight }) {
return (
{label}
{value}
);
}
function CardInput({ label, placeholder, value, onChange }) {
return (
{label}
onChange(e.target.value)} placeholder={placeholder}
style={{ width:'100%', padding:'10px 12px', borderRadius:9, border:`1px solid ${sanadColors.border}`, background:sanadColors.bg, fontFamily:sanadFonts.arabic, fontSize:13, color:sanadColors.textPrimary, outline:'none', direction:'rtl', transition:'border 150ms' }}
onFocus={e => e.target.style.border=`1px solid ${sanadColors.brand}`}
onBlur={e => e.target.style.border=`1px solid ${sanadColors.border}`}
/>
);
}
/* ── Auth Modal (Signup / Login) ─────────────────────── */
function AuthModal({ mode: initMode, onClose }) {
const [mode, setMode] = React.useState(initMode || 'signup'); // signup | login | otp
const [phone, setPhone] = React.useState('');
const [otp, setOtp] = React.useState(['','','','','','']);
const [loading, setLoading] = React.useState(false);
const sendOtp = () => {
if (!phone.trim()) return;
setLoading(true);
setTimeout(() => { setLoading(false); setMode('otp'); }, 1000);
};
const verifyOtp = () => {
setLoading(true);
setTimeout(() => { setLoading(false); onClose(); }, 1200);
};
return (
{/* Logo */}
{mode === 'otp' ? (
<>
أدخل رمز التحقق
أرسلنا رمزاً مؤلفاً من ٦ أرقام إلى{phone}
{otp.map((v, i) => (
{
const val = e.target.value.replace(/\D/,'');
const next = [...otp]; next[i] = val; setOtp(next);
if (val && i < 5) document.getElementById(`otp-${i+1}`)?.focus();
}}
id={`otp-${i}`}
style={{ width:44, height:52, borderRadius:10, border:`2px solid ${v ? sanadColors.brand : sanadColors.border}`, background:sanadColors.bg, textAlign:'center', fontSize:22, fontWeight:700, color:sanadColors.textPrimary, outline:'none', fontFamily:sanadFonts.arabic }} />
))}
{loading ? 'جارٍ التحقق…' : 'تأكيد الرمز'}
setMode(initMode)} style={{ width:'100%', padding:'10px', border:'none', background:'transparent', color:sanadColors.textMuted, fontFamily:sanadFonts.arabic, fontSize:13, cursor:'pointer' }}>
إعادة إرسال الرمز
>
) : (
<>
{mode === 'signup' ? 'ابدأ التجربة المجانية' : 'مرحباً بعودتك'}
{mode === 'signup' ? 'جرّب ليكسا مجاناً' : 'سجّل دخولك لمتابعة جلساتك القانونية'}
{/* Google */}
e.currentTarget.style.boxShadow='0 2px 8px rgba(0,0,0,0.10)'}
onMouseLeave={e => e.currentTarget.style.boxShadow='none'}
>
{mode === 'signup' ? 'التسجيل عبر Google' : 'الدخول عبر Google'}
{loading ? 'جارٍ الإرسال…' : 'إرسال رمز التحقق'}
{mode === 'signup' ? 'لديك حساب؟ ' : 'ليس لديك حساب؟ '}
setMode(mode === 'signup' ? 'login' : 'signup')}>
{mode === 'signup' ? 'تسجيل الدخول' : 'إنشاء حساب'}
>
)}
);
}
/* ── About Modal ─────────────────────────────────────── */
function AboutModal({ onClose }) {
const [tab, setTab] = React.useState('about'); // about | contact
const [form, setForm] = React.useState({ name:'', email:'', msg:'' });
const [sent, setSent] = React.useState(false);
const send = () => {
if (!form.name || !form.msg) return;
setSent(true);
};
return (
{/* Tabs */}
{[['about','من نحن'],['contact','تواصل معنا']].map(([id, label]) => (
setTab(id)} style={{
padding:'10px 20px 12px', border:'none', background:'transparent', cursor:'pointer',
fontFamily:sanadFonts.arabic, fontSize:14, fontWeight:tab===id ? 600 : 400,
color: tab===id ? sanadColors.brand : sanadColors.textMuted,
borderBottom: tab===id ? `2px solid ${sanadColors.brand}` : '2px solid transparent',
marginBottom:-1, transition:'all 150ms',
}}>{label}
))}
{tab === 'about' ? (
ليكسا — منصة قانونية ذكية
تأسست عام ٢٠٢٤ · الرياض، المملكة العربية السعودية
ليكسا هي أكبر وأذكى منصة قانونية سعودية، تجمع بين قوة الذكاء الاصطناعي وعمق القانون السعودي لتمكين الأفراد والمنشآت من الوصول إلى المعلومات القانونية بسهولة وثقة.
نؤمن بأن العدالة تبدأ بالمعرفة، وأن كل شخص يستحق فهم حقوقه دون الحاجة إلى وسيط معقد. رسالتنا: جعل القانون في متناول الجميع.
{[['٢٠٢٤','سنة التأسيس'],['١٢٠٠٠+','مستخدم موثوق'],['٣٢٠+','محامٍ معتمد']].map(([val,label],i) => (
))}
) : (
تواصل معنا
يسعدنا سماع رأيك واستفساراتك في أي وقت
{sent ? (
تم إرسال رسالتك بنجاح!
سنتواصل معك خلال ٢٤ ساعة
) : (
setForm(f=>({...f,name:v}))} />
setForm(f=>({...f,email:v}))} />
إرسال الرسالة
📧 support@saqq.sa
📞 920000000
)}
)}
);
}
/* ── Terms Modal ─────────────────────────────────────── */
function TermsModal({ onClose }) {
return (
الشروط والأحكام
آخر تحديث: ١ محرم ١٤٤٧هـ
{[
{ title:'١. طبيعة الخدمة', body:'تقدم منصة ليكسا معلومات قانونية عامة استناداً إلى الأنظمة واللوائح السعودية، ولا تُعدّ الاستجابات المقدمة استشارات قانونية رسمية. يُنصح دائماً بالتواصل مع محامٍ مرخص للقضايا المعقدة.' },
{ title:'٢. الخصوصية وحماية البيانات', body:'نلتزم بأحكام نظام حماية البيانات الشخصية السعودي. لن يتم مشاركة بياناتك مع أطراف ثالثة إلا بموافقتك الصريحة أو وفق ما يقتضيه القانون.' },
{ title:'٣. الاشتراكات والإلغاء', body:'يحق لك إلغاء اشتراكك في أي وقت، وسيستمر وصولك حتى نهاية الفترة المدفوعة. لا تُسترد الرسوم المدفوعة إلا في حالات محددة وفق سياسة الاسترداد.' },
{ title:'٤. الملكية الفكرية', body:'جميع المحتويات والتصاميم والخوارزميات المستخدمة في المنصة محمية بموجب نظام الملكية الفكرية السعودي. يُحظر نسخ أو توزيع أي محتوى دون إذن صريح.' },
{ title:'٥. تحديد المسؤولية', body:'لا تتحمل منصة ليكسا مسؤولية أي قرارات قانونية يتخذها المستخدم اعتماداً على المعلومات المقدمة دون الرجوع إلى مختص قانوني.' },
].map((s, i) => (
))}
مفهوم، أوافق
);
}
/* ── Consultation Request Modal ──────────────────────── */
function ConsultationModal({ lawyer, onClose, onSubmit }) {
const [form, setForm] = React.useState({ name:'', topic:'' });
const [submitted, setSubmitted] = React.useState(false);
const submit = () => {
if (!form.name || !form.topic) return;
setSubmitted(true);
setTimeout(() => { onSubmit(lawyer); onClose(); }, 2000);
};
return (
{submitted ? (
تم إرسال الطلب!
طلبك وصل إلى {lawyer?.name}. سيتم إعلامك بمجرد قبول الطلب.
) : (
<>
{lawyer?.name?.split(' ').map(w=>w[0]).join('').slice(0,2)}
طلب استشارة
{lawyer?.name} · {lawyer?.spec}
setForm(f=>({...f,name:v}))} />
إرسال الطلب
سعر الاستشارة: {lawyer?.price}
>
)}
);
}
/* ══════════════════════════════════════════════════════
SAVE TO FILES MODAL — shared across all platform pages
══════════════════════════════════════════════════════ */
const SAMPLE_FOLDERS_SAVE = [
{ id: 1, name: 'قضية شركة النخبة', count: 12 },
{ id: 2, name: 'استشارات نظام العمل', count: 5 },
{ id: 3, name: 'عقود إيجار ٢٠٢٦', count: 3 },
];
function SaveToFilesModal({ onClose, onSave }) {
const [search, setSearch] = React.useState('');
const [folders, setFolders] = React.useState([]);
const [selected, setSelected] = React.useState(null);
const [note, setNote] = React.useState('');
const [creating, setCreating] = React.useState(false);
const [newName, setNewName] = React.useState('');
const [saved, setSaved] = React.useState(false);
// نجيب المجلدات الحقيقية من الـ API
React.useEffect(() => {
if (!window.api) return;
window.api.folders.list().then(list => {
setFolders((list || []).map(f => ({ id: f.id, name: f.name, count: f.files_count || 0 })));
}).catch(() => {});
}, []);
const filtered = folders.filter(f => !search || f.name.includes(search));
const handleCreate = async () => {
if (!newName.trim()) return;
try {
const f = await window.api.folders.create(newName.trim());
setFolders(prev => [{ id: f.id, name: f.name, count: 0 }, ...prev]);
setSelected(f.id);
setCreating(false);
setNewName('');
} catch (e) { /* ignore */ }
};
const handleSave = () => {
setSaved(true);
setTimeout(() => {
// نمرر object فيه id عشان onSave في AssistantView يقدر ياخد folder.id
const folderObj = selected ? { id: selected } : null;
if (onSave) onSave(folderObj, note);
onClose();
}, 900);
};
return (
e.stopPropagation()} style={{ background:sanadColors.bgElevated,borderRadius:18,width:'100%',maxWidth:440,boxShadow:'0 0 0 1px rgba(239,231,214,0.10),0 20px 56px rgba(0,0,0,0.22)',direction:'rtl',fontFamily:sanadFonts.arabic,overflow:'hidden' }}>
{/* Header */}
{/* Search */}
setSearch(e.target.value)} placeholder="ابحث في ملفاتك…"
style={{ width:'100%',padding:'8px 34px 8px 12px',borderRadius:8,border:`1px solid ${sanadColors.border}`,background:sanadColors.bg,fontFamily:sanadFonts.arabic,fontSize:13,color:sanadColors.textPrimary,outline:'none',direction:'rtl',boxSizing:'border-box',transition:'border-color 150ms' }}
onFocus={e=>e.target.style.borderColor=sanadColors.focus}
onBlur={e=>e.target.style.borderColor=sanadColors.border}
/>
{/* Folder list */}
{filtered.map(f => (
setSelected(selected===f.id?null:f.id)} style={{
width:'100%',display:'flex',alignItems:'center',justifyContent:'space-between',
padding:'9px 12px',borderRadius:9,border:'none',cursor:'pointer',
background:selected===f.id?sanadColors.brandSubtle:'transparent',
boxShadow:selected===f.id?`0 0 0 1.5px ${sanadColors.brand}`:'none',
transition:'all 140ms',textAlign:'right',fontFamily:sanadFonts.arabic,
}}>
{f.count}
))}
{filtered.length === 0 && (
لا توجد ملفات مطابقة
)}
{/* Divider */}
{/* Create new */}
{creating ? (
setNewName(e.target.value)} autoFocus
placeholder="اسم الملف الجديد…"
onKeyDown={e=>{ if(e.key==='Enter') handleCreate(); if(e.key==='Escape') setCreating(false); }}
style={{ flex:1,padding:'8px 12px',borderRadius:8,border:`1.5px solid ${sanadColors.focus}`,background:sanadColors.bg,fontFamily:sanadFonts.arabic,fontSize:13,color:sanadColors.textPrimary,outline:'none',direction:'rtl' }}
/>
إنشاء
setCreating(false)} style={{ padding:'8px 12px',borderRadius:8,border:'none',background:sanadColors.bgSubtle,color:sanadColors.textMuted,cursor:'pointer' }}>
) : (
setCreating(true)} style={{ width:'100%',padding:'8px 12px',borderRadius:9,border:`1.5px dashed ${sanadColors.border}`,background:'transparent',cursor:'pointer',fontFamily:sanadFonts.arabic,fontSize:13,color:sanadColors.textSecondary,display:'flex',alignItems:'center',gap:7,marginBottom:12,transition:'all 140ms' }}
onMouseEnter={e=>{e.currentTarget.style.borderColor=sanadColors.brand;e.currentTarget.style.color=sanadColors.brand;}}
onMouseLeave={e=>{e.currentTarget.style.borderColor=sanadColors.border;e.currentTarget.style.color=sanadColors.textSecondary;}}
>
إنشاء ملف جديد
)}
{/* Note */}
{/* Actions */}
إلغاء
{saved ? (
تم الحفظ
) : 'حفظ'}
);
}
/* ══════════════════════════════════════════════════════
UPGRADE POPUP — shown when a locked feature is tapped
══════════════════════════════════════════════════════ */
const UPGRADE_FEATURES = {
'save-files': { icon: '📁', title: 'حفظ في ملفاتي', related: ['ملفاتي (مساحات غير محدودة)', 'تنظيم البحوث والردود', 'تصدير كـ PDF أو Word'] },
'create-docs': { icon: '✍️', title: 'تحليل/إنشاء المستندات', related: ['تحليل العقود والمستندات', 'إنشاء عقود جاهزة', '١٠ مستندات / شهر'] },
'publish-course': { icon: '📚', title: 'نشر كورس أو فعالية', related: ['نشر كورسات قانونية', 'إنشاء فعاليات', 'بروفايل مزود محتوى'] },
'lawyer-profile': { icon: '⚖️', title: 'تفعيل بروفايل محامٍ', related: ['بروفايل عام في صفحة المحامين', 'استقبال استشارات مدفوعة', 'شارة "محترف"'] },
'ai-limit': { icon: '💬', title: 'المزيد من أسئلة المساعد', related: ['١,٥٠٠ كريدت شهرياً', 'أسئلة غير محدودة', 'تحليل مستندات'] },
'search-limit': { icon: '🔍', title: 'المزيد من بحثات الأنظمة', related: ['١٠٠ مصدر بحث / شهر', 'نتائج غير محدودة', 'حفظ نتائج البحث'] },
'team': { icon: '👥', title: 'إضافة عضو لفريقك', related: ['حتى ٥ مستخدمين', 'لوحة إدارة الفريق', 'مشاركة ملفاتي بين الفريق'] },
'company-profile':{ icon: '🏛️', title: 'بروفايل شركة أو مكتب', related: ['بروفايل شركة/مكتب', 'شارة Premium', 'أولوية الظهور'] },
};
function UpgradePopup({ featureKey = 'save-files', onClose, onNavigatePricing }) {
const feat = UPGRADE_FEATURES[featureKey] || UPGRADE_FEATURES['save-files'];
return (
e.stopPropagation()} style={{ background:sanadColors.bgElevated,borderRadius:20,width:'100%',maxWidth:460,boxShadow:'0 0 0 1px rgba(239,231,214,0.10),0 24px 64px rgba(0,0,0,0.24)',direction:'rtl',fontFamily:sanadFonts.arabic,overflow:'hidden' }}>
{/* Header */}
e.currentTarget.style.background='rgba(255,255,255,0.16)'}
onMouseLeave={e=>e.currentTarget.style.background='rgba(255,255,255,0.08)'}
>
{feat.icon}
ميزة {feat.title}
متاحة لمشتركي باقة الاحترافي والشركات
{/* Benefits */}
بترقيتك، ستحصل على:
{feat.related.map((r,i) => (
))}
{/* Plan choices */}
اختر باقتك:
{[
{ id:'pro', name:'الاحترافي', icon:'💼', price:'٢٤٩ ر.س/شهر', sub:'للأفراد', cta:'اشترك', variant:'primary' },
{ id:'business', name:'الشركات', icon:'👑', price:'٨٩٩ ر.س/شهر', sub:'للمكاتب', cta:'تواصل معنا', variant:'secondary', dark:true },
].map(p => (
{ onClose(); if(onNavigatePricing) onNavigatePricing(); }} style={{
padding:'14px',borderRadius:12,border:`1.5px solid ${p.variant==='primary'?sanadColors.brand:sanadColors.border}`,
background:p.dark?sanadColors.bgDark:p.variant==='primary'?sanadColors.brandSubtle:sanadColors.bgSubtle,
cursor:'pointer',transition:'all 150ms',
}}
onMouseEnter={e=>e.currentTarget.style.boxShadow=`0 4px 14px rgba(0,0,0,0.12)`}
onMouseLeave={e=>e.currentTarget.style.boxShadow='none'}
>
{p.icon}
{p.name}
{p.sub}
{p.price}
{p.cta}
))}
{ onClose(); if(onNavigatePricing) onNavigatePricing(); }} style={{ background:'transparent',border:'none',cursor:'pointer',fontFamily:sanadFonts.arabic,fontSize:13,color:sanadColors.brand,textDecoration:'underline',padding:'4px' }}>
عرض المقارنة الكاملة
ربما لاحقاً
);
}
Object.assign(window, {
TrialExpiredModal, CheckoutModal, AuthModal, AboutModal, TermsModal, ConsultationModal,
SaveToFilesModal, UpgradePopup,
});