💎 Luxury dark redesign + API integration for Trojan Horse and Elite Dashboard

This commit is contained in:
Hamza-Ayed
2026-04-22 02:01:08 +03:00
parent 2e900e395f
commit 660c551098
8 changed files with 548 additions and 324 deletions

View File

@@ -1,6 +1,6 @@
/** /**
* ════════════════════════════════════════════════════════════ * ════════════════════════════════════════════════════════════
* مُصادَق (Musadaq) — Main Layout Shell * مُصادَق (Musadaq) — Premium Dark Layout Shell
* ════════════════════════════════════════════════════════════ * ════════════════════════════════════════════════════════════
*/ */
@@ -13,36 +13,36 @@ export const MainLayout = () => {
const user = useAuthStore((state) => state.user); const user = useAuthStore((state) => state.user);
return ( return (
<div className="flex bg-slate-50 min-h-screen rtl overflow-hidden"> <div className="flex bg-slate-950 min-h-screen rtl overflow-hidden">
{/* ── Desktop Sidebar ───────────────────────────────────── */} {/* ── Desktop Sidebar ───────────────────────────────────── */}
<Sidebar /> <Sidebar />
<div className="flex-1 flex flex-col h-screen overflow-y-auto"> <div className="flex-1 flex flex-col h-screen overflow-y-auto">
{/* ── Top Navigation ──────────────────────────────────── */} {/* ── Top Navigation ──────────────────────────────────── */}
<header className="h-16 bg-white/80 backdrop-blur-md sticky top-0 z-30 border-b border-slate-100 px-8 flex items-center justify-between shadow-sm"> <header className="h-16 bg-slate-900/80 backdrop-blur-xl sticky top-0 z-30 border-b border-slate-800/60 px-8 flex items-center justify-between">
<div className="flex items-center gap-4 bg-slate-50 px-4 py-2 rounded-xl group focus-within:ring-2 focus-within:ring-primary-100 transition-all border border-transparent focus-within:border-primary-200"> <div className="flex items-center gap-4 bg-slate-800/50 px-4 py-2 rounded-xl group focus-within:ring-2 focus-within:ring-emerald-500/20 transition-all border border-slate-700/50 focus-within:border-emerald-500/30">
<Search className="w-4 h-4 text-slate-400" /> <Search className="w-4 h-4 text-slate-500" />
<input <input
type="text" type="text"
placeholder="بحث سريع..." placeholder="بحث سريع..."
className="bg-transparent border-none outline-none text-sm w-64 text-slate-900" className="bg-transparent border-none outline-none text-sm w-64 text-slate-300 placeholder-slate-500"
/> />
</div> </div>
<div className="flex items-center gap-6"> <div className="flex items-center gap-6">
<button className="p-2 text-slate-400 hover:bg-slate-50 hover:text-primary-600 rounded-xl transition-all relative"> <button className="p-2 text-slate-400 hover:bg-slate-800 hover:text-emerald-400 rounded-xl transition-all relative">
<Bell className="w-5 h-5" /> <Bell className="w-5 h-5" />
<span className="absolute top-1.5 right-1.5 w-2 h-2 bg-red-500 rounded-full border-2 border-white"></span> <span className="absolute top-1.5 right-1.5 w-2 h-2 bg-emerald-500 rounded-full border-2 border-slate-900"></span>
</button> </button>
<div className="flex items-center gap-3 pl-2 border-r border-slate-100"> <div className="flex items-center gap-3 pl-2 border-r border-slate-800">
<div className="text-left"> <div className="text-left">
<p className="text-sm font-semibold text-slate-900">{user?.name}</p> <p className="text-sm font-semibold text-white">{user?.name}</p>
<p className="text-[12px] text-slate-500 uppercase tracking-wider font-medium"> <p className="text-[10px] text-slate-500 uppercase tracking-wider font-medium">
{user?.role} {user?.role}
</p> </p>
</div> </div>
<div className="w-10 h-10 bg-slate-100 rounded-full flex items-center justify-center border-2 border-white shadow-sm ring-1 ring-slate-100"> <div className="w-10 h-10 bg-slate-800 rounded-full flex items-center justify-center border-2 border-slate-700 ring-1 ring-slate-700/50">
<User className="text-slate-400 w-5 h-5" /> <User className="text-slate-400 w-5 h-5" />
</div> </div>
</div> </div>

View File

@@ -1,16 +1,16 @@
/** /**
* ════════════════════════════════════════════════════════════ * ════════════════════════════════════════════════════════════
* مُصادَق (Musadaq) — Premium Sidebar * مُصادَق (Musadaq) — Premium Dark Sidebar
* ════════════════════════════════════════════════════════════ * ════════════════════════════════════════════════════════════
*/ */
import { NavLink, useNavigate } from 'react-router-dom'; import { NavLink, useNavigate } from 'react-router-dom';
import { import {
LayoutDashboard, LayoutDashboard,
FileText, FileText,
Building2, Building2,
Users, Users,
Settings, Settings,
LogOut, LogOut,
Crown Crown
} from 'lucide-react'; } from 'lucide-react';
@@ -35,16 +35,21 @@ export const Sidebar = () => {
}; };
return ( return (
<aside className="w-64 h-screen glass border-l border-slate-200 sticky top-0 flex flex-col p-4"> <aside className="w-64 h-screen bg-slate-950 border-l border-slate-800/60 sticky top-0 flex flex-col p-4">
{/* Brand */}
<div className="flex items-center gap-3 px-2 py-6"> <div className="flex items-center gap-3 px-2 py-6">
<div className="w-10 h-10 bg-primary-600 rounded-xl flex items-center justify-center shadow-lg shadow-primary-500/30"> <div className="w-10 h-10 bg-gradient-to-br from-emerald-500 to-emerald-600 rounded-xl flex items-center justify-center shadow-lg shadow-emerald-500/20">
<FileText className="text-white w-6 h-6" /> <FileText className="text-white w-6 h-6" />
</div> </div>
<h1 className="text-xl font-bold bg-gradient-to-br from-slate-900 to-slate-500 bg-clip-text text-transparent"> <div>
مُصادَق <h1 className="text-xl font-bold text-white">
</h1> مُصادَق
</h1>
<p className="text-[10px] text-slate-500 font-medium tracking-wider">ELITE ACCOUNTANT HUB</p>
</div>
</div> </div>
{/* Navigation */}
<nav className="flex-1 mt-4 space-y-1"> <nav className="flex-1 mt-4 space-y-1">
{menuItems.map((item) => ( {menuItems.map((item) => (
<NavLink <NavLink
@@ -52,9 +57,9 @@ export const Sidebar = () => {
to={item.path} to={item.path}
className={({ isActive }) => className={({ isActive }) =>
`flex items-center gap-3 px-4 py-3 rounded-xl transition-all duration-200 group ${ `flex items-center gap-3 px-4 py-3 rounded-xl transition-all duration-200 group ${
isActive isActive
? 'bg-primary-50 text-primary-600 shadow-sm border border-primary-100' ? 'bg-emerald-500/10 text-emerald-400 border border-emerald-500/20'
: 'text-slate-500 hover:bg-slate-50 hover:text-slate-900' : 'text-slate-400 hover:bg-slate-800/60 hover:text-slate-200 border border-transparent'
}` }`
} }
> >
@@ -64,10 +69,11 @@ export const Sidebar = () => {
))} ))}
</nav> </nav>
<div className="pt-4 border-t border-slate-100"> {/* Logout */}
<div className="pt-4 border-t border-slate-800/60">
<button <button
onClick={handleLogout} onClick={handleLogout}
className="flex items-center gap-3 px-4 py-3 w-full rounded-xl text-red-500 hover:bg-red-50 transition-all group" className="flex items-center gap-3 px-4 py-3 w-full rounded-xl text-red-400 hover:bg-red-500/10 transition-all group border border-transparent hover:border-red-500/20"
> >
<LogOut className="w-5 h-5 group-hover:-translate-x-1 transition-transform" /> <LogOut className="w-5 h-5 group-hover:-translate-x-1 transition-transform" />
<span className="font-medium">تسجيل الخروج</span> <span className="font-medium">تسجيل الخروج</span>

View File

@@ -19,25 +19,25 @@
@layer base { @layer base {
body { body {
@apply bg-slate-50 text-slate-900 antialiased; @apply bg-slate-950 text-slate-300 antialiased;
font-feature-settings: "cv02", "cv03", "cv04", "cv11"; font-feature-settings: "cv02", "cv03", "cv04", "cv11";
} }
h1, h2, h3, h4, h5, h6 { h1, h2, h3, h4, h5, h6 {
@apply font-semibold tracking-tight text-slate-900; @apply font-semibold tracking-tight text-white;
} }
} }
@layer components { @layer components {
.glass { .glass {
@apply bg-white/70 backdrop-blur-md border border-white/20 shadow-xl; @apply bg-slate-900/50 backdrop-blur-xl border border-slate-800/60 shadow-xl;
} }
.card-premium { .card-premium {
@apply bg-white border border-slate-200 shadow-sm hover:shadow-md transition-all duration-200 rounded-xl overflow-hidden; @apply bg-slate-900/50 backdrop-blur-xl border border-slate-800/60 shadow-sm hover:shadow-md hover:border-slate-700 transition-all duration-200 rounded-xl overflow-hidden;
} }
.btn-primary { .btn-primary {
@apply bg-primary-600 hover:bg-primary-700 text-white font-medium py-2 px-4 rounded-lg shadow-sm transition-all active:scale-95; @apply bg-emerald-500 hover:bg-emerald-600 text-white font-medium py-2 px-4 rounded-lg shadow-sm shadow-emerald-500/20 transition-all active:scale-95;
} }
} }

View File

@@ -1,11 +1,19 @@
import { useState, type DragEvent } from 'react'; import { useState, useRef, type DragEvent } from 'react';
import { UploadCloud, FileType, CheckCircle2, ArrowRight } from 'lucide-react'; import { UploadCloud, FileType, CheckCircle2, ArrowRight, AlertCircle, Loader2, Download } from 'lucide-react';
import { motion } from 'framer-motion'; import { motion } from 'framer-motion';
import { Link } from 'react-router-dom';
import axios from 'axios';
const API_URL = import.meta.env.VITE_API_URL || '/api';
export const TrojanHorseConverter = () => { export const TrojanHorseConverter = () => {
const [dragActive, setDragActive] = useState(false); const [dragActive, setDragActive] = useState(false);
const [file, setFile] = useState<File | null>(null); const [file, setFile] = useState<File | null>(null);
const [status, setStatus] = useState<'idle' | 'uploading' | 'success'>('idle'); const [status, setStatus] = useState<'idle' | 'uploading' | 'success' | 'error'>('idle');
const [xmlContent, setXmlContent] = useState<string>('');
const [extractedData, setExtractedData] = useState<any>(null);
const [errorMessage, setErrorMessage] = useState('');
const fileInputRef = useRef<HTMLInputElement>(null);
const handleDrag = (e: DragEvent) => { const handleDrag = (e: DragEvent) => {
e.preventDefault(); e.preventDefault();
@@ -26,76 +34,126 @@ export const TrojanHorseConverter = () => {
} }
}; };
const handleConvert = () => { const handleConvert = async () => {
if (!file) return; if (!file) return;
setStatus('uploading'); setStatus('uploading');
setErrorMessage('');
// Simulate API call to the backend Trojan endpoint
setTimeout(() => { try {
setStatus('success'); const formData = new FormData();
}, 2000); formData.append('file', file);
const response = await axios.post(`${API_URL}/public/tools/pdf-to-xml`, formData, {
headers: { 'Content-Type': 'multipart/form-data' },
});
if (response.data.success) {
setXmlContent(response.data.xmlContent);
setExtractedData(response.data.data);
setStatus('success');
} else {
setErrorMessage(response.data.message || 'حدث خطأ أثناء التحويل');
setStatus('error');
}
} catch (err: any) {
setErrorMessage(
err.response?.data?.message || 'فشل الاتصال بالخادم. تأكد من رفع ملف صالح.'
);
setStatus('error');
}
};
const handleDownloadXml = () => {
if (!xmlContent) return;
const blob = new Blob([xmlContent], { type: 'application/xml;charset=utf-8' });
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = `invoice_${Date.now()}.xml`;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
URL.revokeObjectURL(url);
};
const handleReset = () => {
setStatus('idle');
setFile(null);
setXmlContent('');
setExtractedData(null);
setErrorMessage('');
}; };
return ( return (
<div className="min-h-screen bg-slate-50 text-slate-900 font-sans selection:bg-emerald-200"> <div className="min-h-screen bg-slate-950 text-slate-300 font-sans selection:bg-emerald-500/30">
{/* Top Banner */} {/* Top Banner */}
<div className="bg-slate-900 text-center py-3 text-sm text-slate-300"> <div className="bg-gradient-to-r from-emerald-900/40 to-slate-900 text-center py-3 text-sm text-slate-400 border-b border-slate-800">
هل تدير عشرات الشركات؟ <span className="text-white font-medium ml-2 cursor-pointer hover:text-emerald-400 transition-colors">اكتشف لوحة تحكم محاسبي إيليت <ArrowRight className="inline w-4 h-4" /></span> هل تدير عشرات الشركات؟{' '}
<Link to="/login" className="text-emerald-400 font-medium hover:text-emerald-300 transition-colors">
اكتشف لوحة تحكم محاسبي إيليت <ArrowRight className="inline w-4 h-4" />
</Link>
</div> </div>
<div className="max-w-4xl mx-auto px-6 py-20"> <div className="max-w-4xl mx-auto px-6 py-20">
{/* Header */} {/* Header */}
<div className="text-center mb-16"> <div className="text-center mb-16">
<div className="inline-block px-4 py-1.5 rounded-full bg-emerald-100 text-emerald-800 text-xs font-bold mb-6"> <div className="inline-block px-4 py-1.5 rounded-full bg-emerald-500/10 text-emerald-400 text-xs font-bold mb-6 border border-emerald-500/20">
أداة مجانية 100% أداة مجانية 100% بدون تسجيل
</div> </div>
<h1 className="text-4xl md:text-5xl font-extrabold tracking-tight mb-6 text-slate-900"> <h1 className="text-4xl md:text-5xl font-extrabold tracking-tight mb-6 text-white">
حوّل فواتيرك إلى صيغة <span className="text-emerald-600">جو فوترة</span> في ثوانٍ حوّل فواتيرك إلى صيغة <span className="text-emerald-400">جو فوترة</span> في ثوانٍ
</h1> </h1>
<p className="text-lg text-slate-600 max-w-2xl mx-auto"> <p className="text-lg text-slate-400 max-w-2xl mx-auto leading-relaxed">
قم برفع فاتورة الـ PDF الخاصة بك وسيقوم الذكاء الاصطناعي باستخراج البيانات وتحويلها إلى صيغة XML المتوافقة تماماً مع نظام دائرة ضريبة الدخل والمبيعات الأردنية. قم برفع فاتورة الـ PDF الخاصة بك وسيقوم الذكاء الاصطناعي باستخراج البيانات وتحويلها إلى صيغة XML المتوافقة تماماً مع نظام دائرة ضريبة الدخل والمبيعات الأردنية.
</p> </p>
</div> </div>
{/* Upload Area */} {/* Upload Area */}
<motion.div <motion.div
initial={{ opacity: 0, y: 20 }} initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }} animate={{ opacity: 1, y: 0 }}
className="bg-white rounded-3xl shadow-xl p-8 border border-slate-100" className="bg-slate-900/50 backdrop-blur-xl rounded-3xl shadow-2xl p-8 border border-slate-800"
> >
{status === 'idle' && ( {status === 'idle' && (
<div <div
onDragEnter={handleDrag} onDragEnter={handleDrag}
onDragLeave={handleDrag} onDragLeave={handleDrag}
onDragOver={handleDrag} onDragOver={handleDrag}
onDrop={handleDrop} onDrop={handleDrop}
className={`border-2 border-dashed rounded-2xl p-12 text-center transition-all ${ className={`border-2 border-dashed rounded-2xl p-12 text-center transition-all cursor-pointer ${
dragActive ? 'border-emerald-500 bg-emerald-50/50' : 'border-slate-200 hover:border-slate-300' dragActive ? 'border-emerald-500 bg-emerald-500/5' : 'border-slate-700 hover:border-slate-600'
}`} }`}
onClick={() => !file && fileInputRef.current?.click()}
> >
<UploadCloud className={`w-16 h-16 mx-auto mb-6 ${dragActive ? 'text-emerald-500' : 'text-slate-400'}`} /> <UploadCloud className={`w-16 h-16 mx-auto mb-6 transition-colors ${dragActive ? 'text-emerald-400' : 'text-slate-600'}`} />
{file ? ( {file ? (
<div> <div>
<p className="text-lg font-medium text-slate-900 mb-2">{file.name}</p> <p className="text-lg font-medium text-white mb-2">{file.name}</p>
<p className="text-sm text-slate-500 mb-8">{(file.size / 1024 / 1024).toFixed(2)} MB</p> <p className="text-sm text-slate-500 mb-8">{(file.size / 1024 / 1024).toFixed(2)} MB</p>
<button <button
onClick={handleConvert} onClick={(e) => { e.stopPropagation(); handleConvert(); }}
className="px-8 py-3 bg-slate-900 hover:bg-slate-800 text-white rounded-xl font-medium shadow-lg transition-all w-full md:w-auto" className="px-8 py-3.5 bg-emerald-500 hover:bg-emerald-600 text-slate-950 rounded-xl font-bold shadow-lg shadow-emerald-500/20 transition-all"
> >
بدء التحويل إلى XML بدء التحويل إلى XML
</button> </button>
</div> </div>
) : ( ) : (
<div> <div>
<p className="text-xl font-medium text-slate-900 mb-2">اسحب وأفلت الفاتورة هنا</p> <p className="text-xl font-medium text-white mb-2">اسحب وأفلت الفاتورة هنا</p>
<p className="text-sm text-slate-500 mb-8">يدعم PDF, PNG, JPG</p> <p className="text-sm text-slate-500 mb-8">يدعم PDF, PNG, JPG</p>
<label className="px-8 py-3 bg-emerald-500 hover:bg-emerald-600 text-white rounded-xl font-medium shadow-lg shadow-emerald-500/30 transition-all cursor-pointer inline-block"> <span className="px-8 py-3.5 bg-emerald-500 hover:bg-emerald-600 text-slate-950 rounded-xl font-bold shadow-lg shadow-emerald-500/30 transition-all inline-block">
اختر ملف اختر ملف
<input type="file" className="hidden" onChange={(e) => e.target.files && setFile(e.target.files[0])} accept=".pdf,.png,.jpg" /> </span>
</label> <input
ref={fileInputRef}
type="file"
className="hidden"
onChange={(e) => e.target.files && setFile(e.target.files[0])}
accept=".pdf,.png,.jpg,.jpeg"
/>
</div> </div>
)} )}
</div> </div>
@@ -103,52 +161,104 @@ export const TrojanHorseConverter = () => {
{status === 'uploading' && ( {status === 'uploading' && (
<div className="py-20 text-center"> <div className="py-20 text-center">
<div className="w-16 h-16 border-4 border-slate-200 border-t-emerald-500 rounded-full animate-spin mx-auto mb-6"></div> <Loader2 className="w-16 h-16 text-emerald-400 animate-spin mx-auto mb-6" />
<h3 className="text-xl font-medium text-slate-900 mb-2">جاري استخراج البيانات...</h3> <h3 className="text-xl font-medium text-white mb-2">جاري استخراج البيانات...</h3>
<p className="text-slate-500">يقوم الذكاء الاصطناعي بقراءة الفاتورة وتنسيقها</p> <p className="text-slate-400">يقوم الذكاء الاصطناعي بقراءة الفاتورة وتنسيقها. قد يستغرق الأمر عدة ثوانٍ.</p>
</div> </div>
)} )}
{status === 'success' && ( {status === 'error' && (
<motion.div <motion.div
initial={{ scale: 0.9, opacity: 0 }} initial={{ scale: 0.9, opacity: 0 }}
animate={{ scale: 1, opacity: 1 }} animate={{ scale: 1, opacity: 1 }}
className="py-12 text-center" className="py-12 text-center"
> >
<div className="w-20 h-20 bg-emerald-100 rounded-full flex items-center justify-center mx-auto mb-6"> <div className="w-20 h-20 bg-red-500/10 rounded-full flex items-center justify-center mx-auto mb-6 border border-red-500/20">
<CheckCircle2 className="w-10 h-10 text-emerald-600" /> <AlertCircle className="w-10 h-10 text-red-400" />
</div> </div>
<h3 className="text-2xl font-bold text-slate-900 mb-4">تم التحويل بنجاح!</h3> <h3 className="text-2xl font-bold text-white mb-4">حدث خطأ</h3>
<p className="text-slate-400 mb-8 max-w-md mx-auto">{errorMessage}</p>
<div className="flex flex-col sm:flex-row gap-4 justify-center mt-8"> <button
<button className="px-6 py-3 bg-emerald-500 hover:bg-emerald-600 text-white rounded-xl font-medium flex items-center justify-center gap-2"> onClick={handleReset}
<FileType className="w-5 h-5" /> تحميل ملف XML className="px-6 py-3 bg-slate-800 hover:bg-slate-700 text-white rounded-xl font-medium border border-slate-700 transition-all"
>
حاول مرة أخرى
</button>
</motion.div>
)}
{status === 'success' && (
<motion.div
initial={{ scale: 0.9, opacity: 0 }}
animate={{ scale: 1, opacity: 1 }}
className="py-12 text-center"
>
<div className="w-20 h-20 bg-emerald-500/10 rounded-full flex items-center justify-center mx-auto mb-6 border border-emerald-500/20">
<CheckCircle2 className="w-10 h-10 text-emerald-400" />
</div>
<h3 className="text-2xl font-bold text-white mb-2">تم التحويل بنجاح!</h3>
{/* Extracted Data Preview */}
{extractedData && (
<div className="mt-6 mb-8 bg-slate-800/50 rounded-xl p-4 text-right max-w-md mx-auto border border-slate-700/50">
<div className="grid grid-cols-2 gap-3 text-sm">
{extractedData.supplier_name && (
<>
<span className="text-slate-500">المورد:</span>
<span className="text-white font-medium">{extractedData.supplier_name}</span>
</>
)}
{extractedData.invoice_number && (
<>
<span className="text-slate-500">رقم الفاتورة:</span>
<span className="text-white font-medium">{extractedData.invoice_number}</span>
</>
)}
{extractedData.grand_total && (
<>
<span className="text-slate-500">المبلغ الإجمالي:</span>
<span className="text-emerald-400 font-bold">{Number(extractedData.grand_total).toFixed(3)} JOD</span>
</>
)}
</div>
</div>
)}
<div className="flex flex-col sm:flex-row gap-4 justify-center">
<button
onClick={handleDownloadXml}
className="px-6 py-3.5 bg-emerald-500 hover:bg-emerald-600 text-slate-950 rounded-xl font-bold flex items-center justify-center gap-2 shadow-lg shadow-emerald-500/20 transition-all"
>
<Download className="w-5 h-5" /> تحميل ملف XML
</button> </button>
<button <button
onClick={() => { setStatus('idle'); setFile(null); }} onClick={handleReset}
className="px-6 py-3 bg-white border border-slate-200 hover:bg-slate-50 text-slate-700 rounded-xl font-medium" className="px-6 py-3 bg-slate-800 hover:bg-slate-700 text-white rounded-xl font-medium border border-slate-700 transition-all"
> >
تحويل فاتورة أخرى تحويل فاتورة أخرى
</button> </button>
</div> </div>
{/* Upsell Banner for Accountants */} {/* Upsell Banner for Accountants */}
<div className="mt-12 bg-slate-900 rounded-2xl p-6 text-left flex flex-col md:flex-row items-center justify-between gap-6"> <div className="mt-12 bg-gradient-to-r from-slate-800 to-slate-900 rounded-2xl p-6 text-right flex flex-col md:flex-row items-center justify-between gap-6 border border-slate-700/50">
<div> <div>
<h4 className="text-white font-bold mb-1 flex items-center gap-2"> <h4 className="text-white font-bold mb-1 flex items-center gap-2">
<span className="text-emerald-400">مُصادَق</span> | هل أنت محاسب؟ <span className="text-emerald-400">مُصادَق</span> | هل أنت محاسب؟
</h4> </h4>
<p className="text-slate-400 text-sm">توقف عن تحويل الفواتير واحدة تلو الأخرى. جرب لوحة تحكم إيليت وأتمت عملك لـ 50 شركة بنقرة واحدة.</p> <p className="text-slate-400 text-sm">توقف عن تحويل الفواتير واحدة تلو الأخرى. جرب لوحة تحكم إيليت وأتمت عملك لـ 50 شركة بنقرة واحدة.</p>
</div> </div>
<button className="whitespace-nowrap px-6 py-2.5 bg-white text-slate-900 rounded-lg font-medium hover:bg-slate-100"> <Link
to="/register"
className="whitespace-nowrap px-6 py-2.5 bg-emerald-500 text-slate-950 rounded-lg font-bold hover:bg-emerald-400 transition-all shadow-lg shadow-emerald-500/20"
>
اكتشف إيليت اكتشف إيليت
</button> </Link>
</div> </div>
</motion.div> </motion.div>
)} )}
</motion.div> </motion.div>
</div> </div>
</div> </div>
); );

View File

@@ -1,6 +1,6 @@
/** /**
* ════════════════════════════════════════════════════════════ * ════════════════════════════════════════════════════════════
* مُصادَق (Musadaq) — Premium Login Page * مُصادَق (Musadaq) — Premium Dark Login Page
* ════════════════════════════════════════════════════════════ * ════════════════════════════════════════════════════════════
*/ */
@@ -10,7 +10,7 @@ import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod'; import { zodResolver } from '@hookform/resolvers/zod';
import * as z from 'zod'; import * as z from 'zod';
import { motion, AnimatePresence } from 'framer-motion'; import { motion, AnimatePresence } from 'framer-motion';
import { LogIn, Mail, Lock, AlertCircle, Loader2 } from 'lucide-react'; import { LogIn, Mail, Lock, AlertCircle, Loader2, Zap } from 'lucide-react';
import apiClient from '../../api/client'; import apiClient from '../../api/client';
import { useAuthStore } from '../../store/authStore'; import { useAuthStore } from '../../store/authStore';
@@ -47,34 +47,34 @@ export default function LoginPage() {
}; };
return ( return (
<div className="min-h-screen bg-slate-50 flex items-center justify-center p-6 relative overflow-hidden rtl"> <div className="min-h-screen bg-slate-950 flex items-center justify-center p-6 relative overflow-hidden rtl">
{/* ── Background Aesthetics ────────────────────────────────── */} {/* ── Background Aesthetics ────────────────────────────────── */}
<div className="absolute top-0 left-0 w-full h-full opacity-10 pointer-events-none"> <div className="absolute top-0 left-0 w-full h-full pointer-events-none">
<div className="absolute top-[-20%] left-[-10%] w-[600px] h-[600px] bg-primary-300 rounded-full blur-[120px]" /> <div className="absolute top-[-20%] left-[-10%] w-[600px] h-[600px] bg-emerald-500/5 rounded-full blur-[150px]" />
<div className="absolute bottom-[-20%] right-[-10%] w-[600px] h-[600px] bg-blue-300 rounded-full blur-[120px]" /> <div className="absolute bottom-[-20%] right-[-10%] w-[600px] h-[600px] bg-blue-500/5 rounded-full blur-[150px]" />
</div> </div>
<motion.div <motion.div
initial={{ opacity: 0, y: 20 }} initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }} animate={{ opacity: 1, y: 0 }}
className="w-full max-w-md glass p-10 rounded-3xl shadow-2xl relative z-10" className="w-full max-w-md bg-slate-900/50 backdrop-blur-xl border border-slate-800/60 p-10 rounded-3xl shadow-2xl relative z-10"
> >
<div className="text-center mb-10"> <div className="text-center mb-10">
<div className="w-16 h-16 bg-primary-600 rounded-2xl flex items-center justify-center mx-auto mb-6 shadow-xl shadow-primary-500/20"> <div className="w-16 h-16 bg-gradient-to-br from-emerald-500 to-emerald-600 rounded-2xl flex items-center justify-center mx-auto mb-6 shadow-xl shadow-emerald-500/20">
<LogIn className="text-white w-8 h-8" /> <LogIn className="text-white w-8 h-8" />
</div> </div>
<h1 className="text-3xl font-bold text-slate-900 mb-2">أهلاً بك في مُصادَق</h1> <h1 className="text-3xl font-bold text-white mb-2">أهلاً بك في مُصادَق</h1>
<p className="text-slate-500">منصة أتمتة الفواتير الضريبية الأردنية</p> <p className="text-slate-400">منصة أتمتة الفواتير الضريبية الأردنية</p>
</div> </div>
<form onSubmit={handleSubmit(onSubmit)} className="space-y-6"> <form onSubmit={handleSubmit(onSubmit)} className="space-y-6">
<AnimatePresence mode="wait"> <AnimatePresence mode="wait">
{error && ( {error && (
<motion.div <motion.div
initial={{ opacity: 0, x: -10 }} initial={{ opacity: 0, x: -10 }}
animate={{ opacity: 1, x: 0 }} animate={{ opacity: 1, x: 0 }}
exit={{ opacity: 0, x: 10 }} exit={{ opacity: 0, x: 10 }}
className="bg-red-50 border border-red-100 p-4 rounded-xl flex items-center gap-3 text-red-600 text-sm font-medium" className="bg-red-500/10 border border-red-500/20 p-4 rounded-xl flex items-center gap-3 text-red-400 text-sm font-medium"
> >
<AlertCircle className="w-5 h-5 flex-shrink-0" /> <AlertCircle className="w-5 h-5 flex-shrink-0" />
<span>{error}</span> <span>{error}</span>
@@ -83,55 +83,56 @@ export default function LoginPage() {
</AnimatePresence> </AnimatePresence>
<div> <div>
<label className="block text-sm font-semibold text-slate-700 mb-2 mr-1">البريد الإلكتروني</label> <label className="block text-sm font-semibold text-slate-300 mb-2 mr-1">البريد الإلكتروني</label>
<div className="relative group"> <div className="relative group">
<Mail className="absolute left-4 top-1/2 -translate-y-1/2 w-5 h-5 text-slate-400 group-focus-within:text-primary-500 transition-colors" /> <Mail className="absolute left-4 top-1/2 -translate-y-1/2 w-5 h-5 text-slate-500 group-focus-within:text-emerald-400 transition-colors" />
<input <input
{...register('email')} {...register('email')}
className="w-full bg-slate-50/50 border border-slate-200 rounded-xl py-3 pl-4 pr-11 focus:ring-4 focus:ring-primary-500/10 focus:border-primary-500 outline-none transition-all" className="w-full bg-slate-800/50 border border-slate-700/50 rounded-xl py-3 pl-4 pr-11 focus:ring-2 focus:ring-emerald-500/20 focus:border-emerald-500/50 outline-none transition-all text-white placeholder-slate-500"
placeholder="name@company.com" placeholder="name@company.com"
/> />
</div> </div>
{errors.email && <p className="text-red-500 text-[12px] mt-1 mr-1">{errors.email.message}</p>} {errors.email && <p className="text-red-400 text-[12px] mt-1 mr-1">{errors.email.message}</p>}
</div> </div>
<div> <div>
<label className="block text-sm font-semibold text-slate-700 mb-2 mr-1">كلمة المرور</label> <label className="block text-sm font-semibold text-slate-300 mb-2 mr-1">كلمة المرور</label>
<div className="relative group"> <div className="relative group">
<Lock className="absolute left-4 top-1/2 -translate-y-1/2 w-5 h-5 text-slate-400 group-focus-within:text-primary-500 transition-colors" /> <Lock className="absolute left-4 top-1/2 -translate-y-1/2 w-5 h-5 text-slate-500 group-focus-within:text-emerald-400 transition-colors" />
<input <input
{...register('password')} {...register('password')}
type="password" type="password"
className="w-full bg-slate-50/50 border border-slate-200 rounded-xl py-3 pl-4 pr-11 focus:ring-4 focus:ring-primary-500/10 focus:border-primary-500 outline-none transition-all" className="w-full bg-slate-800/50 border border-slate-700/50 rounded-xl py-3 pl-4 pr-11 focus:ring-2 focus:ring-emerald-500/20 focus:border-emerald-500/50 outline-none transition-all text-white placeholder-slate-500"
placeholder="••••••••" placeholder="••••••••"
/> />
</div> </div>
{errors.password && <p className="text-red-500 text-[12px] mt-1 mr-1">{errors.password.message}</p>} {errors.password && <p className="text-red-400 text-[12px] mt-1 mr-1">{errors.password.message}</p>}
</div> </div>
<button <button
type="submit" type="submit"
disabled={isLoading} disabled={isLoading}
className="w-full btn-primary h-14 text-lg mt-4 flex items-center justify-center gap-3 shadow-lg shadow-primary-500/25" className="w-full bg-gradient-to-r from-emerald-500 to-emerald-600 hover:from-emerald-600 hover:to-emerald-700 text-white h-14 text-lg rounded-xl font-bold mt-4 flex items-center justify-center gap-3 shadow-lg shadow-emerald-500/20 transition-all disabled:opacity-50"
> >
{isLoading ? <Loader2 className="w-6 h-6 animate-spin" /> : 'تسجيل الدخول'} {isLoading ? <Loader2 className="w-6 h-6 animate-spin" /> : 'تسجيل الدخول'}
</button> </button>
</form> </form>
<div className="mt-8 text-center text-slate-500 text-sm"> <div className="mt-8 text-center text-slate-400 text-sm">
ليس لديك حساب؟{' '} ليس لديك حساب؟{' '}
<Link to="/register" className="text-primary-600 font-bold hover:underline"> <Link to="/register" className="text-emerald-400 font-bold hover:underline">
أنشئ حساباً جديداً أنشئ حساباً جديداً
</Link> </Link>
</div> </div>
{/* Trojan Horse Marketing Link */} {/* Trojan Horse Marketing Link */}
<div className="mt-6 pt-6 border-t border-slate-100 text-center"> <div className="mt-6 pt-6 border-t border-slate-800/60 text-center">
<Link <Link
to="/free-converter" to="/free-converter"
className="inline-flex items-center justify-center gap-2 px-6 py-3 bg-emerald-50 text-emerald-600 rounded-xl font-bold hover:bg-emerald-100 transition-colors w-full border border-emerald-200 shadow-sm" className="inline-flex items-center justify-center gap-2 px-6 py-3 bg-emerald-500/10 text-emerald-400 rounded-xl font-bold hover:bg-emerald-500/20 transition-colors w-full border border-emerald-500/20"
> >
🚀 جرب أداة تحويل فواتير PDF إلى XML مجاناً <Zap className="w-4 h-4" />
جرب أداة تحويل فواتير PDF إلى XML مجاناً
</Link> </Link>
</div> </div>
</motion.div> </motion.div>

View File

@@ -1,6 +1,6 @@
/** /**
* ════════════════════════════════════════════════════════════ * ════════════════════════════════════════════════════════════
* مُصادَق (Musadaq) — Premium Register Page * مُصادَق (Musadaq) — Premium Dark Register Page
* ════════════════════════════════════════════════════════════ * ════════════════════════════════════════════════════════════
*/ */
@@ -51,32 +51,32 @@ export default function RegisterPage() {
}; };
return ( return (
<div className="min-h-screen bg-slate-50 flex items-center justify-center p-6 relative overflow-hidden rtl font-sans"> <div className="min-h-screen bg-slate-950 flex items-center justify-center p-6 relative overflow-hidden rtl font-sans">
{/* ── Background Aesthetics ────────────────────────────────── */} {/* ── Background Aesthetics ────────────────────────────────── */}
<div className="absolute top-0 left-0 w-full h-full opacity-10 pointer-events-none"> <div className="absolute top-0 left-0 w-full h-full pointer-events-none">
<div className="absolute top-[-20%] right-[-10%] w-[600px] h-[600px] bg-primary-300 rounded-full blur-[120px]" /> <div className="absolute top-[-20%] right-[-10%] w-[600px] h-[600px] bg-emerald-500/5 rounded-full blur-[150px]" />
<div className="absolute bottom-[-20%] left-[-10%] w-[600px] h-[600px] bg-blue-300 rounded-full blur-[120px]" /> <div className="absolute bottom-[-20%] left-[-10%] w-[600px] h-[600px] bg-blue-500/5 rounded-full blur-[150px]" />
</div> </div>
<motion.div <motion.div
initial={{ opacity: 0, scale: 0.95 }} initial={{ opacity: 0, scale: 0.95 }}
animate={{ opacity: 1, scale: 1 }} animate={{ opacity: 1, scale: 1 }}
className="w-full max-w-lg glass p-10 rounded-3xl shadow-2xl relative z-10" className="w-full max-w-lg bg-slate-900/50 backdrop-blur-xl border border-slate-800/60 p-10 rounded-3xl shadow-2xl relative z-10"
> >
<div className="text-center mb-8"> <div className="text-center mb-8">
<div className="w-16 h-16 bg-primary-600 rounded-2xl flex items-center justify-center mx-auto mb-6 shadow-xl shadow-primary-500/20"> <div className="w-16 h-16 bg-gradient-to-br from-emerald-500 to-emerald-600 rounded-2xl flex items-center justify-center mx-auto mb-6 shadow-xl shadow-emerald-500/20">
<UserPlus className="text-white w-8 h-8" /> <UserPlus className="text-white w-8 h-8" />
</div> </div>
<h1 className="text-3xl font-bold text-slate-900 mb-2">إنشاء حساب جديد</h1> <h1 className="text-3xl font-bold text-white mb-2">إنشاء حساب جديد</h1>
<p className="text-slate-500">ابدأ رحلتك في أتمتة الفواتير الضريبية</p> <p className="text-slate-400">ابدأ رحلتك في أتمتة الفواتير الضريبية</p>
</div> </div>
{/* ── Progress Indicator ─────────────────────────────────── */} {/* ── Progress Indicator ─────────────────────────────────── */}
<div className="flex gap-2 mb-8 items-center justify-center"> <div className="flex gap-2 mb-8 items-center justify-center">
{[1, 2].map((i) => ( {[1, 2].map((i) => (
<div <div
key={i} key={i}
className={`h-1.5 rounded-full transition-all duration-300 ${step >= i ? 'w-12 bg-primary-600' : 'w-4 bg-slate-200'}`} className={`h-1.5 rounded-full transition-all duration-300 ${step >= i ? 'w-12 bg-emerald-500' : 'w-4 bg-slate-700'}`}
/> />
))} ))}
</div> </div>
@@ -84,7 +84,7 @@ export default function RegisterPage() {
<form onSubmit={handleSubmit(onSubmit)} className="space-y-6"> <form onSubmit={handleSubmit(onSubmit)} className="space-y-6">
<AnimatePresence mode="wait"> <AnimatePresence mode="wait">
{step === 1 ? ( {step === 1 ? (
<motion.div <motion.div
key="step1" key="step1"
initial={{ opacity: 0, x: 20 }} initial={{ opacity: 0, x: 20 }}
animate={{ opacity: 1, x: 0 }} animate={{ opacity: 1, x: 0 }}
@@ -92,25 +92,25 @@ export default function RegisterPage() {
className="space-y-6" className="space-y-6"
> >
<div> <div>
<label className="block text-sm font-semibold text-slate-700 mb-2 mr-1">اسم مكتب المحاسبة</label> <label className="block text-sm font-semibold text-slate-300 mb-2 mr-1">اسم مكتب المحاسبة</label>
<div className="relative group"> <div className="relative group">
<Building className="absolute left-4 top-1/2 -translate-y-1/2 w-5 h-5 text-slate-400 group-focus-within:text-primary-500 transition-colors" /> <Building className="absolute left-4 top-1/2 -translate-y-1/2 w-5 h-5 text-slate-500 group-focus-within:text-emerald-400 transition-colors" />
<input <input
{...register('tenantName')} {...register('tenantName')}
className="w-full bg-slate-50/50 border border-slate-200 rounded-xl py-3 pl-4 pr-11 focus:ring-4 focus:ring-primary-500/10 focus:border-primary-500 outline-none transition-all" className="w-full bg-slate-800/50 border border-slate-700/50 rounded-xl py-3 pl-4 pr-11 focus:ring-2 focus:ring-emerald-500/20 focus:border-emerald-500/50 outline-none transition-all text-white placeholder-slate-500"
placeholder="شركة الفوترة للمحاسبة" placeholder="شركة الفوترة للمحاسبة"
/> />
</div> </div>
{errors.tenantName && <p className="text-red-500 text-[12px] mt-1 mr-1">{errors.tenantName.message}</p>} {errors.tenantName && <p className="text-red-400 text-[12px] mt-1 mr-1">{errors.tenantName.message}</p>}
</div> </div>
<div> <div>
<label className="block text-sm font-semibold text-slate-700 mb-2 mr-1">رقم الهاتف (اختياري)</label> <label className="block text-sm font-semibold text-slate-300 mb-2 mr-1">رقم الهاتف (اختياري)</label>
<div className="relative group"> <div className="relative group">
<Phone className="absolute left-4 top-1/2 -translate-y-1/2 w-5 h-5 text-slate-400 group-focus-within:text-primary-500 transition-colors" /> <Phone className="absolute left-4 top-1/2 -translate-y-1/2 w-5 h-5 text-slate-500 group-focus-within:text-emerald-400 transition-colors" />
<input <input
{...register('phone')} {...register('phone')}
className="w-full bg-slate-50/50 border border-slate-200 rounded-xl py-3 pl-4 pr-11 focus:ring-4 focus:ring-primary-500/10 focus:border-primary-500 outline-none transition-all" className="w-full bg-slate-800/50 border border-slate-700/50 rounded-xl py-3 pl-4 pr-11 focus:ring-2 focus:ring-emerald-500/20 focus:border-emerald-500/50 outline-none transition-all text-white placeholder-slate-500"
placeholder="079 XXXXXXX" placeholder="079 XXXXXXX"
/> />
</div> </div>
@@ -119,14 +119,14 @@ export default function RegisterPage() {
<button <button
type="button" type="button"
onClick={nextStep} onClick={nextStep}
className="w-full btn-primary h-14 text-lg flex items-center justify-center gap-3" className="w-full bg-gradient-to-r from-emerald-500 to-emerald-600 hover:from-emerald-600 hover:to-emerald-700 text-white h-14 text-lg rounded-xl font-bold flex items-center justify-center gap-3 shadow-lg shadow-emerald-500/20 transition-all"
> >
التالي التالي
<ArrowLeft className="w-5 h-5" /> <ArrowLeft className="w-5 h-5" />
</button> </button>
</motion.div> </motion.div>
) : ( ) : (
<motion.div <motion.div
key="step2" key="step2"
initial={{ opacity: 0, x: 20 }} initial={{ opacity: 0, x: 20 }}
animate={{ opacity: 1, x: 0 }} animate={{ opacity: 1, x: 0 }}
@@ -134,49 +134,49 @@ export default function RegisterPage() {
className="space-y-6" className="space-y-6"
> >
<div> <div>
<label className="block text-sm font-semibold text-slate-700 mb-2 mr-1">الاسم الكامل (للمدير)</label> <label className="block text-sm font-semibold text-slate-300 mb-2 mr-1">الاسم الكامل (للمدير)</label>
<div className="relative group"> <div className="relative group">
<input <input
{...register('name')} {...register('name')}
className="w-full bg-slate-50/50 border border-slate-200 rounded-xl py-3 px-4 focus:ring-4 focus:ring-primary-500/10 focus:border-primary-500 outline-none transition-all" className="w-full bg-slate-800/50 border border-slate-700/50 rounded-xl py-3 px-4 focus:ring-2 focus:ring-emerald-500/20 focus:border-emerald-500/50 outline-none transition-all text-white placeholder-slate-500"
placeholder="أحمد محمد" placeholder="أحمد محمد"
/> />
</div> </div>
{errors.name && <p className="text-red-500 text-[12px] mt-1 mr-1">{errors.name.message}</p>} {errors.name && <p className="text-red-400 text-[12px] mt-1 mr-1">{errors.name.message}</p>}
</div> </div>
<div> <div>
<label className="block text-sm font-semibold text-slate-700 mb-2 mr-1">البريد الإلكتروني</label> <label className="block text-sm font-semibold text-slate-300 mb-2 mr-1">البريد الإلكتروني</label>
<div className="relative group"> <div className="relative group">
<Mail className="absolute left-4 top-1/2 -translate-y-1/2 w-5 h-5 text-slate-400 group-focus-within:text-primary-500 transition-colors" /> <Mail className="absolute left-4 top-1/2 -translate-y-1/2 w-5 h-5 text-slate-500 group-focus-within:text-emerald-400 transition-colors" />
<input <input
{...register('email')} {...register('email')}
className="w-full bg-slate-50/50 border border-slate-200 rounded-xl py-3 pl-4 pr-11 focus:ring-4 focus:ring-primary-500/10 focus:border-primary-500 outline-none transition-all" className="w-full bg-slate-800/50 border border-slate-700/50 rounded-xl py-3 pl-4 pr-11 focus:ring-2 focus:ring-emerald-500/20 focus:border-emerald-500/50 outline-none transition-all text-white placeholder-slate-500"
placeholder="admin@office.com" placeholder="admin@office.com"
/> />
</div> </div>
{errors.email && <p className="text-red-500 text-[12px] mt-1 mr-1">{errors.email.message}</p>} {errors.email && <p className="text-red-400 text-[12px] mt-1 mr-1">{errors.email.message}</p>}
</div> </div>
<div> <div>
<label className="block text-sm font-semibold text-slate-700 mb-2 mr-1">كلمة المرور</label> <label className="block text-sm font-semibold text-slate-300 mb-2 mr-1">كلمة المرور</label>
<div className="relative group"> <div className="relative group">
<Lock className="absolute left-4 top-1/2 -translate-y-1/2 w-5 h-5 text-slate-400 group-focus-within:text-primary-500 transition-colors" /> <Lock className="absolute left-4 top-1/2 -translate-y-1/2 w-5 h-5 text-slate-500 group-focus-within:text-emerald-400 transition-colors" />
<input <input
{...register('password')} {...register('password')}
type="password" type="password"
className="w-full bg-slate-50/50 border border-slate-200 rounded-xl py-3 pl-4 pr-11 focus:ring-4 focus:ring-primary-500/10 focus:border-primary-500 outline-none transition-all" className="w-full bg-slate-800/50 border border-slate-700/50 rounded-xl py-3 pl-4 pr-11 focus:ring-2 focus:ring-emerald-500/20 focus:border-emerald-500/50 outline-none transition-all text-white placeholder-slate-500"
placeholder="••••••••" placeholder="••••••••"
/> />
</div> </div>
{errors.password && <p className="text-red-500 text-[12px] mt-1 mr-1">{errors.password.message}</p>} {errors.password && <p className="text-red-400 text-[12px] mt-1 mr-1">{errors.password.message}</p>}
</div> </div>
<div className="flex gap-4"> <div className="flex gap-4">
<button <button
type="button" type="button"
onClick={() => setStep(1)} onClick={() => setStep(1)}
className="flex-1 bg-slate-100 hover:bg-slate-200 text-slate-600 font-bold py-4 rounded-xl transition-all flex items-center justify-center gap-2" className="flex-1 bg-slate-800 hover:bg-slate-700 text-slate-300 font-bold py-4 rounded-xl transition-all flex items-center justify-center gap-2 border border-slate-700/50"
> >
<ArrowRight className="w-5 h-5" /> <ArrowRight className="w-5 h-5" />
السابق السابق
@@ -184,7 +184,7 @@ export default function RegisterPage() {
<button <button
type="submit" type="submit"
disabled={isLoading} disabled={isLoading}
className="flex-[2] btn-primary py-4 flex items-center justify-center gap-2" className="flex-[2] bg-gradient-to-r from-emerald-500 to-emerald-600 hover:from-emerald-600 hover:to-emerald-700 text-white py-4 rounded-xl font-bold flex items-center justify-center gap-2 shadow-lg shadow-emerald-500/20 transition-all disabled:opacity-50"
> >
{isLoading ? <Loader2 className="w-6 h-6 animate-spin" /> : 'إنشاء الحساب'} {isLoading ? <Loader2 className="w-6 h-6 animate-spin" /> : 'إنشاء الحساب'}
</button> </button>
@@ -194,9 +194,9 @@ export default function RegisterPage() {
</AnimatePresence> </AnimatePresence>
</form> </form>
<div className="mt-8 text-center text-slate-500 text-sm"> <div className="mt-8 text-center text-slate-400 text-sm">
لديك حساب بالفعل؟{' '} لديك حساب بالفعل؟{' '}
<Link to="/login" className="text-primary-600 font-bold hover:underline"> <Link to="/login" className="text-emerald-400 font-bold hover:underline">
سجل دخولك من هنا سجل دخولك من هنا
</Link> </Link>
</div> </div>

View File

@@ -1,22 +1,23 @@
/** /**
* ════════════════════════════════════════════════════════════ * ════════════════════════════════════════════════════════════
* مُصادَق (Musadaq) — Dashboard Page * مُصادَق (Musadaq) — Premium Dark Dashboard Page
* ════════════════════════════════════════════════════════════ * ════════════════════════════════════════════════════════════
*/ */
import { useState, useEffect } from 'react'; import { useState, useEffect } from 'react';
import { import {
FileText, FileText,
TrendingUp, TrendingUp,
ArrowUpRight, ArrowUpRight,
ArrowDownRight,
Clock, Clock,
CheckCircle2, CheckCircle2,
Building2 Building2,
Loader2,
Upload,
AlertTriangle,
} from 'lucide-react'; } from 'lucide-react';
import { motion } from 'framer-motion'; import { motion } from 'framer-motion';
import apiClient from '../../api/client'; import apiClient from '../../api/client';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
export const DashboardPage = () => { export const DashboardPage = () => {
@@ -41,44 +42,41 @@ export const DashboardPage = () => {
if (isLoading) { if (isLoading) {
return ( return (
<div className="flex-1 flex justify-center items-center"> <div className="flex-1 flex flex-col justify-center items-center py-32">
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-primary-600"></div> <Loader2 className="w-12 h-12 text-emerald-400 animate-spin mb-4" />
<p className="text-slate-400">جاري تحميل البيانات...</p>
</div> </div>
); );
} }
const statCards = [ const statCards = [
{ {
title: 'إجمالي الفواتير', title: 'إجمالي الفواتير',
value: stats?.totalInvoices || 0, value: stats?.stats?.totalInvoices || 0,
icon: FileText, icon: FileText,
color: 'bg-blue-500', gradient: 'from-blue-500 to-blue-600',
trend: '+12%', glow: 'shadow-blue-500/20',
isUp: true
}, },
{ {
title: 'الفواتير المصدقة', title: 'الفواتير المصدقة',
value: stats?.approvedInvoices || 0, value: stats?.stats?.approvedInvoices || 0,
icon: CheckCircle2, icon: CheckCircle2,
color: 'bg-emerald-500', gradient: 'from-emerald-500 to-emerald-600',
trend: '+8%', glow: 'shadow-emerald-500/20',
isUp: true
}, },
{ {
title: 'إجمالي الشركات', title: 'إجمالي الشركات',
value: stats?.companiesCount || 0, value: stats?.stats?.companiesCount || 0,
icon: Building2, icon: Building2,
color: 'bg-purple-500', gradient: 'from-purple-500 to-purple-600',
trend: '+2', glow: 'shadow-purple-500/20',
isUp: true
}, },
{ {
title: 'إجمالي الضرائب (JOD)', title: 'إجمالي الضرائب (JOD)',
value: Number(stats?.totalTax || 0).toLocaleString('ar-JO', { minimumFractionDigits: 3 }), value: Number(stats?.stats?.totalTax || 0).toLocaleString('ar-JO', { minimumFractionDigits: 3 }),
icon: TrendingUp, icon: TrendingUp,
color: 'bg-amber-500', gradient: 'from-amber-500 to-amber-600',
trend: '+5%', glow: 'shadow-amber-500/20',
isUp: true
}, },
]; ];
@@ -86,11 +84,11 @@ export const DashboardPage = () => {
<div className="space-y-8 animate-in fade-in duration-700"> <div className="space-y-8 animate-in fade-in duration-700">
<header className="flex justify-between items-end"> <header className="flex justify-between items-end">
<div> <div>
<h2 className="text-3xl font-black text-slate-900 tracking-tight">لوحة التحكم</h2> <h2 className="text-3xl font-black text-white tracking-tight">لوحة التحكم</h2>
<p className="text-slate-500 mt-1 font-medium">مرحباً بك مجدداً! إليك ملخص نشاط مكتبك اليوم.</p> <p className="text-slate-400 mt-1 font-medium">مرحباً بك مجدداً! إليك ملخص نشاط مكتبك اليوم.</p>
</div> </div>
<div className="flex gap-3"> <div className="flex gap-3">
<button className="glass border-slate-200 px-5 py-2.5 rounded-2xl text-slate-600 font-bold text-sm hover:bg-white transition-all"> <button className="bg-slate-800/60 border border-slate-700/50 px-5 py-2.5 rounded-xl text-slate-300 font-bold text-sm hover:bg-slate-800 transition-all">
آخر 30 يوم آخر 30 يوم
</button> </button>
</div> </div>
@@ -99,24 +97,28 @@ export const DashboardPage = () => {
{/* ── Stats Grid ────────────────────────────────────────── */} {/* ── Stats Grid ────────────────────────────────────────── */}
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6"> <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
{statCards.map((card, idx) => ( {statCards.map((card, idx) => (
<motion.div <motion.div
key={card.title} key={card.title}
initial={{ opacity: 0, y: 20 }} initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }} animate={{ opacity: 1, y: 0 }}
transition={{ delay: idx * 0.1 }} transition={{ delay: idx * 0.1 }}
className="card-premium p-6 group hover:scale-[1.02] transition-all cursor-default" className="bg-slate-900/50 backdrop-blur-xl border border-slate-800/60 p-6 rounded-2xl group hover:border-slate-700 transition-all relative overflow-hidden"
> >
<div className="flex justify-between items-start mb-4"> {/* Subtle ambient glow on hover */}
<div className={`w-12 h-12 ${card.color} rounded-2xl flex items-center justify-center text-white shadow-lg shadow-inherit/20`}> <div className={`absolute -inset-10 opacity-0 group-hover:opacity-10 blur-3xl transition-opacity duration-500 bg-gradient-to-r ${card.gradient}`} />
<card.icon className="w-6 h-6" />
<div className="relative z-10">
<div className="flex justify-between items-start mb-4">
<div className={`w-12 h-12 bg-gradient-to-br ${card.gradient} rounded-2xl flex items-center justify-center text-white shadow-lg ${card.glow}`}>
<card.icon className="w-6 h-6" />
</div>
<span className="flex items-center gap-1 text-xs font-bold text-emerald-400 bg-emerald-500/10 px-2 py-1 rounded-lg border border-emerald-500/20">
<ArrowUpRight className="w-3 h-3" />
</span>
</div> </div>
<span className={`flex items-center gap-1 text-xs font-bold ${card.isUp ? 'text-emerald-600 bg-emerald-50' : 'text-red-600 bg-red-50'} px-2 py-1 rounded-lg`}> <h3 className="text-slate-400 font-bold text-sm mb-1">{card.title}</h3>
{card.trend} <div className="text-2xl font-black text-white tracking-tight">{card.value}</div>
{card.isUp ? <ArrowUpRight className="w-3 h-3" /> : <ArrowDownRight className="w-3 h-3" />}
</span>
</div> </div>
<h3 className="text-slate-500 font-bold text-sm mb-1">{card.title}</h3>
<div className="text-2xl font-black text-slate-900 tracking-tight">{card.value}</div>
</motion.div> </motion.div>
))} ))}
</div> </div>
@@ -125,39 +127,49 @@ export const DashboardPage = () => {
{/* ── Recent Activities ────────────────────────────────── */} {/* ── Recent Activities ────────────────────────────────── */}
<div className="lg:col-span-2 space-y-4"> <div className="lg:col-span-2 space-y-4">
<div className="flex items-center justify-between px-2"> <div className="flex items-center justify-between px-2">
<h3 className="text-xl font-bold text-slate-900 flex items-center gap-2"> <h3 className="text-xl font-bold text-white flex items-center gap-2">
<Clock className="w-5 h-5 text-primary-600" /> <Clock className="w-5 h-5 text-emerald-400" />
آخر الفواتير المرفوعة آخر الفواتير المرفوعة
</h3> </h3>
<button className="text-primary-600 text-sm font-bold hover:underline">عرض الكل</button> <button
onClick={() => navigate('/invoices')}
className="text-emerald-400 text-sm font-bold hover:underline"
>
عرض الكل
</button>
</div> </div>
<div className="card-premium overflow-hidden bg-white border border-slate-100"> <div className="bg-slate-900/50 backdrop-blur-xl border border-slate-800/60 rounded-2xl overflow-hidden">
{(!stats?.recentActivities || stats.recentActivities.length === 0) ? ( {(!stats?.recentActivities || stats.recentActivities.length === 0) ? (
<div className="p-12 text-center text-slate-400 font-medium"> <div className="p-12 text-center text-slate-500 font-medium">
لا توجد نشاطات حديثة بعد. لا توجد نشاطات حديثة بعد.
</div> </div>
) : ( ) : (
<table className="w-full text-right"> <table className="w-full text-right">
<thead className="bg-slate-50 border-b border-slate-100"> <thead className="bg-slate-800/50 border-b border-slate-700/50">
<tr> <tr>
<th className="px-6 py-4 text-xs font-bold text-slate-500">الفاتورة</th> <th className="px-6 py-4 text-xs font-bold text-slate-400">الفاتورة</th>
<th className="px-6 py-4 text-xs font-bold text-slate-500">الشركة</th> <th className="px-6 py-4 text-xs font-bold text-slate-400">الشركة</th>
<th className="px-6 py-4 text-xs font-bold text-slate-500">المبلغ</th> <th className="px-6 py-4 text-xs font-bold text-slate-400">الحالة</th>
<th className="px-6 py-4 text-xs font-bold text-slate-500">الحالة</th>
</tr> </tr>
</thead> </thead>
<tbody className="divide-y divide-slate-100"> <tbody className="divide-y divide-slate-800/50">
{stats.recentActivities.map((inv: any) => ( {stats.recentActivities.map((inv: any) => (
<tr key={inv.id} className="hover:bg-slate-50/50 transition-colors"> <tr key={inv.id} className="hover:bg-slate-800/30 transition-colors">
<td className="px-6 py-4 font-bold text-slate-800">{inv.invoice_number || 'OCR_PENDING'}</td> <td className="px-6 py-4 font-bold text-white">{inv.number || 'قيد الاستخراج...'}</td>
<td className="px-6 py-4 text-slate-600">{inv.company?.name}</td> <td className="px-6 py-4 text-slate-400">{inv.company || '—'}</td>
<td className="px-6 py-4 font-mono font-bold text-slate-700">{Number(inv.total_amount || 0).toFixed(3)}</td>
<td className="px-6 py-4"> <td className="px-6 py-4">
<span className={`px-2 py-1 rounded-md text-[10px] font-bold ${ <span className={`px-2.5 py-1 rounded-md text-[10px] font-bold ${
inv.status === 'approved' ? 'bg-emerald-50 text-emerald-600' : 'bg-amber-50 text-amber-600' inv.status === 'approved'
? 'bg-emerald-500/10 text-emerald-400 border border-emerald-500/20'
: inv.status === 'validation_failed' || inv.status === 'rejected'
? 'bg-red-500/10 text-red-400 border border-red-500/20'
: 'bg-amber-500/10 text-amber-400 border border-amber-500/20'
}`}> }`}>
{inv.status === 'approved' ? 'مصدقة' : 'قيد المعالجة'} {inv.status === 'approved' ? 'مصدقة' :
inv.status === 'validation_failed' ? 'مرفوضة' :
inv.status === 'rejected' ? 'مرفوضة' :
'قيد المعالجة'}
</span> </span>
</td> </td>
</tr> </tr>
@@ -170,33 +182,46 @@ export const DashboardPage = () => {
{/* ── Quick Actions ────────────────────────────────────── */} {/* ── Quick Actions ────────────────────────────────────── */}
<div className="space-y-4"> <div className="space-y-4">
<h3 className="text-xl font-bold text-slate-900 px-2">إجراءات سريعة</h3> <h3 className="text-xl font-bold text-white px-2">إجراءات سريعة</h3>
<div className="grid grid-cols-1 gap-4"> <div className="grid grid-cols-1 gap-4">
<button <button
onClick={() => navigate('/invoices')} onClick={() => navigate('/invoices')}
className="flex items-center gap-4 p-4 rounded-2xl bg-primary-600 text-white shadow-xl shadow-primary-500/25 hover:bg-primary-700 transition-all group" className="flex items-center gap-4 p-4 rounded-2xl bg-gradient-to-r from-emerald-500 to-emerald-600 text-white shadow-xl shadow-emerald-500/20 hover:shadow-emerald-500/30 transition-all group"
> >
<div className="w-10 h-10 rounded-xl bg-white/20 flex items-center justify-center group-hover:scale-110 transition-transform"> <div className="w-10 h-10 rounded-xl bg-white/20 flex items-center justify-center group-hover:scale-110 transition-transform">
<FileText className="w-5 h-5" /> <Upload className="w-5 h-5" />
</div> </div>
<div className="text-right"> <div className="text-right">
<div className="font-bold">رفع فاتورة جديدة</div> <div className="font-bold">رفع فاتورة جديدة</div>
<div className="text-xs text-white/70">معالجة فورية بالذكاء الاصطناعي</div> <div className="text-xs text-white/70">معالجة فورية بالذكاء الاصطناعي</div>
</div> </div>
</button> </button>
<button <button
onClick={() => navigate('/companies')} onClick={() => navigate('/companies')}
className="flex items-center gap-4 p-4 rounded-2xl bg-white border border-slate-200 text-slate-800 hover:border-primary-500 transition-all group" className="flex items-center gap-4 p-4 rounded-2xl bg-slate-900/50 border border-slate-800/60 text-slate-300 hover:border-emerald-500/30 transition-all group"
> >
<div className="w-10 h-10 rounded-xl bg-slate-50 flex items-center justify-center group-hover:bg-primary-50 group-hover:text-primary-600 transition-all"> <div className="w-10 h-10 rounded-xl bg-slate-800 flex items-center justify-center group-hover:bg-emerald-500/10 group-hover:text-emerald-400 transition-all">
<Building2 className="w-5 h-5" /> <Building2 className="w-5 h-5" />
</div> </div>
<div className="text-right"> <div className="text-right">
<div className="font-bold">إضافة شركة</div> <div className="font-bold text-white">إضافة شركة</div>
<div className="text-xs text-slate-500">تسجيل عميل جديد في المكتب</div> <div className="text-xs text-slate-500">تسجيل عميل جديد في المكتب</div>
</div> </div>
</button> </button>
<button
onClick={() => navigate('/elite-dashboard')}
className="flex items-center gap-4 p-4 rounded-2xl bg-slate-900/50 border border-slate-800/60 text-slate-300 hover:border-emerald-500/30 transition-all group"
>
<div className="w-10 h-10 rounded-xl bg-slate-800 flex items-center justify-center group-hover:bg-amber-500/10 group-hover:text-amber-400 transition-all">
<AlertTriangle className="w-5 h-5" />
</div>
<div className="text-right">
<div className="font-bold text-white">مراقبة المخاطر</div>
<div className="text-xs text-slate-500">لوحة النخبة ودرجات الخطر الضريبي</div>
</div>
</button>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -1,22 +1,38 @@
import { Building2, TrendingUp, AlertTriangle, ChevronDown } from 'lucide-react'; import { useState, useEffect } from 'react';
import { Building2, TrendingUp, AlertTriangle, ChevronDown, Loader2, RefreshCw, Crown } from 'lucide-react';
import { motion } from 'framer-motion'; import { motion } from 'framer-motion';
import apiClient from '../../api/client';
// Mock data matching the API structure we built in the backend interface CompanyStats {
const mockCompanies = [ id: string;
{ id: '1', name: 'Apex Innovations', totalInvoices: 24, pendingAmount: 78450, totalTax: 12500, failedCount: 2, riskScore: 85, status: 'High' }, name: string;
{ id: '2', name: 'Quantum Solutions', totalInvoices: 26, pendingAmount: 112000, totalTax: 18000, failedCount: 0, riskScore: 32, status: 'Low' }, taxId: string;
{ id: '3', name: 'Nomad Ventures', totalInvoices: 45, pendingAmount: 319000, totalTax: 45000, failedCount: 5, riskScore: 68, status: 'Medium' }, totalInvoices: number;
{ id: '4', name: 'Elevate Tech', totalInvoices: 12, pendingAmount: 188000, totalTax: 30000, failedCount: 1, riskScore: 85, status: 'High' }, totalTax: number;
{ id: '5', name: 'Horizon Group', totalInvoices: 33, pendingAmount: 95000, totalTax: 14000, failedCount: 3, riskScore: 68, status: 'Medium' }, failedCount: number;
]; riskScore: number;
}
const RiskGauge = ({ score, status }: { score: number, status: string }) => { const getRiskStatus = (score: number) => {
if (score >= 70) return 'High';
if (score >= 30) return 'Medium';
return 'Low';
};
const RiskGauge = ({ score }: { score: number }) => {
const status = getRiskStatus(score);
const getColor = () => { const getColor = () => {
if (status === 'High') return 'text-red-500'; if (status === 'High') return 'text-red-500';
if (status === 'Medium') return 'text-orange-500'; if (status === 'Medium') return 'text-orange-500';
return 'text-emerald-500'; return 'text-emerald-500';
}; };
const getLabel = () => {
if (status === 'High') return 'مرتفع';
if (status === 'Medium') return 'متوسط';
return 'منخفض';
};
return ( return (
<div className="flex flex-col items-center"> <div className="flex flex-col items-center">
<div className="relative w-16 h-16"> <div className="relative w-16 h-16">
@@ -41,104 +57,170 @@ const RiskGauge = ({ score, status }: { score: number, status: string }) => {
{score} {score}
</div> </div>
</div> </div>
<span className={`text-xs mt-1 ${getColor()}`}>{status}</span> <span className={`text-xs mt-1 ${getColor()}`}>{getLabel()}</span>
</div> </div>
); );
}; };
export const MultiEntityDashboard = () => { export const MultiEntityDashboard = () => {
const [companies, setCompanies] = useState<CompanyStats[]>([]);
const [isLoading, setIsLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
const fetchData = async () => {
setIsLoading(true);
setError(null);
try {
const { data } = await apiClient.get('/dashboard/multi-entity');
setCompanies(data);
} catch (err: any) {
console.error('Failed to fetch multi-entity stats', err);
setError('فشل في جلب بيانات الشركات. تأكد من تسجيل الدخول.');
} finally {
setIsLoading(false);
}
};
useEffect(() => {
fetchData();
}, []);
if (isLoading) {
return (
<div className="flex-1 flex flex-col justify-center items-center py-32">
<Loader2 className="w-12 h-12 text-emerald-400 animate-spin mb-4" />
<p className="text-slate-400">جاري تحميل بيانات الشركات...</p>
</div>
);
}
return ( return (
<div className="min-h-screen bg-slate-950 text-slate-300 font-sans p-8 selection:bg-emerald-500/30"> <div className="space-y-8 animate-in fade-in duration-700">
{/* Header */} {/* Header */}
<header className="flex justify-between items-center mb-10"> <header className="flex justify-between items-center">
<div> <div>
<h1 className="text-3xl font-light tracking-tight text-white flex items-center gap-3"> <h2 className="text-3xl font-light tracking-tight text-slate-900 dark:text-white flex items-center gap-3">
<span className="font-semibold text-emerald-400">مُصادَق</span> | لوحة تحكم الشركات <Crown className="w-7 h-7 text-emerald-500" />
</h1> <span className="font-semibold text-emerald-500">مُصادَق</span> | لوحة تحكم الشركات
<p className="text-slate-400 mt-2 text-sm">نظرة عامة على الموقف الضريبي لجميع عملائك (Elite View)</p> </h2>
<p className="text-slate-500 mt-2 text-sm">نظرة عامة على الموقف الضريبي لجميع عملائك (Elite View)</p>
</div> </div>
<div className="flex gap-4"> <div className="flex gap-4">
<button className="px-4 py-2 bg-slate-800 hover:bg-slate-700 text-white rounded-lg text-sm border border-slate-700 transition-colors flex items-center gap-2"> <button
آخر 30 يوم <ChevronDown className="w-4 h-4" /> onClick={fetchData}
className="px-4 py-2 bg-slate-100 dark:bg-slate-800 hover:bg-slate-200 dark:hover:bg-slate-700 text-slate-700 dark:text-white rounded-lg text-sm border border-slate-200 dark:border-slate-700 transition-colors flex items-center gap-2"
>
<RefreshCw className="w-4 h-4" /> تحديث
</button> </button>
<button className="px-5 py-2 bg-emerald-500 hover:bg-emerald-600 text-slate-950 font-medium rounded-lg text-sm shadow-[0_0_15px_rgba(16,185,129,0.3)] transition-all"> <button className="px-4 py-2 bg-slate-100 dark:bg-slate-800 hover:bg-slate-200 dark:hover:bg-slate-700 text-slate-700 dark:text-white rounded-lg text-sm border border-slate-200 dark:border-slate-700 transition-colors flex items-center gap-2">
+ إضافة شركة جديدة آخر 30 يوم <ChevronDown className="w-4 h-4" />
</button> </button>
</div> </div>
</header> </header>
{/* Error State */}
{error && (
<div className="bg-red-50 dark:bg-red-500/10 border border-red-200 dark:border-red-500/20 rounded-xl p-4 flex items-center gap-3 text-red-600 dark:text-red-400">
<AlertTriangle className="w-5 h-5 flex-shrink-0" />
<span className="text-sm font-medium">{error}</span>
<button onClick={fetchData} className="mr-auto text-sm underline hover:no-underline">إعادة المحاولة</button>
</div>
)}
{/* Empty State */}
{!error && companies.length === 0 && (
<div className="text-center py-20">
<Building2 className="w-16 h-16 text-slate-300 dark:text-slate-600 mx-auto mb-6" />
<h3 className="text-xl font-bold text-slate-900 dark:text-white mb-2">لا توجد شركات بعد</h3>
<p className="text-slate-500 mb-6">أضف شركات عملائك لتبدأ بمتابعة الموقف الضريبي لكل شركة.</p>
<button className="px-5 py-2.5 bg-emerald-500 hover:bg-emerald-600 text-white font-medium rounded-lg text-sm shadow-lg shadow-emerald-500/20 transition-all">
+ إضافة شركة جديدة
</button>
</div>
)}
{/* Grid */} {/* Grid */}
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6"> {companies.length > 0 && (
{mockCompanies.map((company, index) => ( <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6">
<motion.div {companies.map((company, index) => {
initial={{ opacity: 0, y: 20 }} const status = getRiskStatus(company.riskScore);
animate={{ opacity: 1, y: 0 }} const approvedEstimate = Math.max(0, company.totalInvoices - company.failedCount);
transition={{ delay: index * 0.1 }} const approvedPct = company.totalInvoices > 0 ? Math.round((approvedEstimate / company.totalInvoices) * 100) : 0;
key={company.id} const failedPct = company.totalInvoices > 0 ? Math.round((company.failedCount / company.totalInvoices) * 100) : 0;
className="bg-slate-900/50 backdrop-blur-xl border border-slate-800 rounded-2xl p-6 relative overflow-hidden hover:border-slate-700 transition-colors group"
>
{/* Ambient glow */}
<div className={`absolute -inset-20 opacity-0 group-hover:opacity-20 blur-3xl transition-opacity duration-500 rounded-full
${company.status === 'High' ? 'bg-red-500' : company.status === 'Medium' ? 'bg-orange-500' : 'bg-emerald-500'}
`} />
<div className="relative z-10"> return (
<div className="flex justify-between items-start mb-6"> <motion.div
<div className="flex items-center gap-3"> initial={{ opacity: 0, y: 20 }}
<div className="w-10 h-10 rounded-lg bg-slate-800 flex items-center justify-center border border-slate-700"> animate={{ opacity: 1, y: 0 }}
<Building2 className="w-5 h-5 text-emerald-400" /> transition={{ delay: index * 0.08 }}
</div> key={company.id}
<div> className="card-premium p-6 relative overflow-hidden group"
<h3 className="text-white font-medium text-lg">{company.name}</h3> >
<p className="text-xs text-slate-500">الرقم الضريبي: 00{company.id}829471</p> {/* Ambient glow */}
</div> <div className={`absolute -inset-20 opacity-0 group-hover:opacity-10 blur-3xl transition-opacity duration-500 rounded-full
</div> ${status === 'High' ? 'bg-red-500' : status === 'Medium' ? 'bg-orange-500' : 'bg-emerald-500'}
</div> `} />
<div className="grid grid-cols-2 gap-4 mb-6"> <div className="relative z-10">
<div> <div className="flex justify-between items-start mb-6">
<p className="text-xs text-slate-400 mb-1">التدفق النقدي (المبيعات)</p> <div className="flex items-center gap-3">
<p className="text-2xl font-light text-white">${(company.pendingAmount / 1000).toFixed(1)}k</p> <div className="w-10 h-10 rounded-lg bg-slate-100 dark:bg-slate-800 flex items-center justify-center border border-slate-200 dark:border-slate-700">
<div className="flex items-center gap-1 mt-1 text-xs text-emerald-400"> <Building2 className="w-5 h-5 text-emerald-500" />
<TrendingUp className="w-3 h-3" /> مستقر </div>
<div>
<h3 className="text-slate-900 dark:text-white font-medium text-lg">{company.name}</h3>
<p className="text-xs text-slate-400">{company.taxId || '—'}</p>
</div>
</div>
</div> </div>
</div>
<div className="flex justify-end">
<div>
<p className="text-xs text-slate-400 mb-1 text-center">درجة الخطر الضريبي</p>
<RiskGauge score={company.riskScore} status={company.status} />
</div>
</div>
</div>
<div className="pt-4 border-t border-slate-800/50"> <div className="grid grid-cols-2 gap-4 mb-6">
<div className="flex justify-between items-center mb-2"> <div>
<p className="text-sm text-slate-300">الفواتير المعلقة</p> <p className="text-xs text-slate-500 mb-1">إجمالي الضريبة</p>
<span className="text-xs text-slate-500">{company.totalInvoices} فاتورة | ${company.totalTax} ضرائب</span> <p className="text-2xl font-light text-slate-900 dark:text-white">
{company.totalTax > 0 ? `${(company.totalTax / 1000).toFixed(1)}k` : '0'}
</p>
<div className="flex items-center gap-1 mt-1 text-xs text-emerald-500">
<TrendingUp className="w-3 h-3" /> JOD
</div>
</div>
<div className="flex justify-end">
<div>
<p className="text-xs text-slate-500 mb-1 text-center">درجة الخطر الضريبي</p>
<RiskGauge score={company.riskScore} />
</div>
</div>
</div>
<div className="pt-4 border-t border-slate-100 dark:border-slate-800/50">
<div className="flex justify-between items-center mb-2">
<p className="text-sm text-slate-600 dark:text-slate-300">{company.totalInvoices} فاتورة</p>
{company.failedCount > 0 && (
<span className="text-xs text-red-400 flex items-center gap-1">
<AlertTriangle className="w-3 h-3" /> {company.failedCount} مرفوضة
</span>
)}
</div>
{/* Progress Bar */}
<div className="h-1.5 w-full bg-slate-100 dark:bg-slate-800 rounded-full overflow-hidden flex">
<div className="h-full bg-emerald-500 transition-all" style={{ width: `${approvedPct}%` }}></div>
<div className="h-full bg-red-500 transition-all" style={{ width: `${failedPct}%` }}></div>
</div>
<div className="flex justify-between mt-2 text-[10px] text-slate-400">
<span>ناجحة ({approvedPct}%)</span>
{company.failedCount > 0 && <span className="text-red-400">مرفوضة ({failedPct}%)</span>}
</div>
</div>
</div> </div>
</motion.div>
{/* Minimal Progress Bar */} );
<div className="h-1.5 w-full bg-slate-800 rounded-full overflow-hidden flex"> })}
<div className="h-full bg-emerald-500" style={{ width: '60%' }}></div> </div>
<div className="h-full bg-orange-500" style={{ width: '25%' }}></div> )}
<div className="h-full bg-red-500" style={{ width: '15%' }}></div>
</div>
<div className="flex justify-between mt-2 text-[10px] text-slate-500">
<span>تم الرفع (60%)</span>
{company.failedCount > 0 && (
<span className="text-red-400 flex items-center gap-1">
<AlertTriangle className="w-3 h-3" /> {company.failedCount} مرفوضة
</span>
)}
</div>
</div>
</div>
</motion.div>
))}
</div>
</div> </div>
); );
}; };