185 lines
10 KiB
PHP
185 lines
10 KiB
PHP
<!DOCTYPE html>
|
|
<html lang="ar" dir="rtl" data-theme="dark">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>مُصادَق — أتمتة الفوترة الضريبية</title>
|
|
|
|
<!-- Styles -->
|
|
<link rel="stylesheet" href="assets/css/app.css">
|
|
<script src="https://cdn.tailwindcss.com"></script>
|
|
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
|
|
|
<script>
|
|
tailwind.config = {
|
|
darkMode: 'class',
|
|
theme: {
|
|
extend: {
|
|
colors: {
|
|
primary: '#10b981',
|
|
'primary-dark': '#059669',
|
|
dark: '#0a0f1a',
|
|
card: '#0f172a'
|
|
}
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
</head>
|
|
<body class="bg-dark text-slate-100 antialiased overflow-x-hidden">
|
|
|
|
<div id="app">
|
|
<!-- Navigation -->
|
|
<nav class="fixed top-0 w-full z-50 glass border-b border-white/10 px-6 py-4 flex items-center justify-between">
|
|
<div class="flex items-center gap-3">
|
|
<div class="w-10 h-10 bg-primary rounded-xl flex items-center justify-center shadow-lg shadow-primary/20">
|
|
<span class="text-white font-bold text-xl">م</span>
|
|
</div>
|
|
<h1 class="text-xl font-bold bg-clip-text text-transparent bg-gradient-to-r from-white to-slate-400">مُصادَق</h1>
|
|
</div>
|
|
|
|
<div class="flex items-center gap-4" id="nav-user" style="display:none;">
|
|
<button class="p-2 hover:bg-white/5 rounded-lg transition-colors">
|
|
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 17h5l-1.405-1.405A2.032 2.032 0 0118 14.158V11a6.002 6.002 0 00-4-5.659V5a2 2 0 10-4 0v.341C7.67 6.165 6 8.388 6 11v3.159c0 .538-.214 1.055-.595 1.436L4 17h5m6 0v1a3 3 0 11-6 0v-1m6 0H9"></path></svg>
|
|
</button>
|
|
<div class="w-10 h-10 rounded-full bg-slate-800 border border-white/10"></div>
|
|
</div>
|
|
</nav>
|
|
|
|
<!-- AI Floating Assistant -->
|
|
<div class="fixed bottom-8 right-8 z-[60]">
|
|
<button onclick="document.getElementById('ai-chat').classList.toggle('hidden')" class="w-16 h-16 bg-gradient-to-tr from-primary to-emerald-400 rounded-full flex items-center justify-center shadow-2xl shadow-primary/40 hover:scale-110 transition-transform">
|
|
<svg class="w-8 h-8 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 11a7 7 0 01-7 7m0 0a7 7 0 01-7-7m7 7v4m0 0H8m4 0h4m-4-8a3 3 0 01-3-3V5a3 3 0 116 0v6a3 3 0 01-3 3z"></path></svg>
|
|
</button>
|
|
|
|
<!-- Chat Popover -->
|
|
<div id="ai-chat" class="hidden absolute bottom-20 right-0 w-80 glass rounded-3xl border border-white/10 p-6 shadow-2xl">
|
|
<h4 class="font-bold mb-4 flex items-center gap-2">
|
|
<span class="w-2 h-2 bg-primary rounded-full animate-pulse"></span>
|
|
مُساعد مُصادَق الذكي
|
|
</h4>
|
|
<div id="ai-answer" class="bg-white/5 rounded-xl p-3 mb-4 min-h-[60px] text-sm text-slate-300">كيف يمكنني مساعدتك اليوم؟</div>
|
|
<div class="relative">
|
|
<input type="text" id="ai-query" class="w-full bg-white/10 border border-white/10 rounded-xl px-4 py-2 text-sm focus:outline-none focus:border-primary" placeholder="اسأل عن فواتيرك...">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Main Content -->
|
|
<main class="pt-24 pb-12 px-6 max-w-7xl mx-auto">
|
|
<div id="page-content"></div>
|
|
</main>
|
|
</div>
|
|
|
|
<script>
|
|
// ══════════════════════════════════════════════════════════
|
|
// مُصادَق — API Client (Inlined for reliability)
|
|
// ══════════════════════════════════════════════════════════
|
|
const API = {
|
|
baseUrl: 'index.php?route=/api/v1',
|
|
accessToken: localStorage.getItem('access_token'),
|
|
async post(path, body) {
|
|
const headers = { 'Accept': 'application/json', 'Content-Type': 'application/json' };
|
|
if (this.accessToken) headers['Authorization'] = `Bearer ${this.accessToken}`;
|
|
const res = await fetch(`${this.baseUrl}${path}`, { method: 'POST', headers, body: JSON.stringify(body) });
|
|
const data = await res.json();
|
|
if (!res.ok) throw data;
|
|
return data;
|
|
}
|
|
};
|
|
|
|
// ── Router ──
|
|
const isLoggedIn = () => !!localStorage.getItem('access_token');
|
|
const pageContent = document.getElementById('page-content');
|
|
|
|
function loginPage() {
|
|
return `
|
|
<div class="flex flex-col items-center justify-center min-h-[60vh]">
|
|
<div class="w-full max-w-md p-8 glass rounded-3xl glow border border-white/10">
|
|
<h2 class="text-3xl font-bold mb-2 text-center">مرحباً بك مجدداً</h2>
|
|
<form id="login-form" class="space-y-6">
|
|
<input type="email" id="login-email" class="w-full bg-white/5 border border-white/10 rounded-xl px-4 py-3 focus:outline-none focus:border-primary" placeholder="البريد الإلكتروني" required>
|
|
<input type="password" id="login-password" class="w-full bg-white/5 border border-white/10 rounded-xl px-4 py-3 focus:outline-none focus:border-primary" placeholder="كلمة المرور" required>
|
|
<div id="login-error" class="text-red-400 text-sm text-center hidden"></div>
|
|
<button type="submit" class="w-full bg-primary hover:bg-primary-dark text-white font-bold py-3 rounded-xl shadow-lg">دخول</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
`;
|
|
}
|
|
|
|
function dashboardPage() {
|
|
return `<div class="space-y-8">
|
|
<h2 class="text-3xl font-bold">لوحة التحكم</h2>
|
|
<div class="grid grid-cols-1 md:grid-cols-4 gap-6">
|
|
<div class="glass p-6 rounded-3xl border border-white/10 glow"><p class="text-slate-400 text-sm">فواتير الشهر</p><h3 class="text-3xl font-bold">1,284</h3></div>
|
|
<div class="glass p-6 rounded-3xl border border-white/10"><p class="text-slate-400 text-sm">تمت المصادقة</p><h3 class="text-3xl font-bold text-primary">1,150</h3></div>
|
|
<div class="glass p-6 rounded-3xl border border-white/10"><p class="text-slate-400 text-sm">قيد المعالجة</p><h3 class="text-3xl font-bold text-yellow-400">94</h3></div>
|
|
<div class="glass p-6 rounded-3xl border border-red-500/20"><p class="text-slate-400 text-sm">تنبيهات المخاطر</p><h3 class="text-3xl font-bold text-red-400">4</h3></div>
|
|
</div>
|
|
<div class="glass p-8 rounded-3xl border border-white/10">
|
|
<h4 class="font-bold mb-6">تحليل الفواتير الأسبوعي</h4>
|
|
<canvas id="invoiceChart" height="250"></canvas>
|
|
</div>
|
|
</div>`;
|
|
}
|
|
|
|
function initCharts() {
|
|
const ctx = document.getElementById('invoiceChart');
|
|
if (ctx) {
|
|
new Chart(ctx, {
|
|
type: 'line',
|
|
data: {
|
|
labels: ['الأحد', 'الاثنين', 'الثلاثاء', 'الأربعاء', 'الخميس', 'الجمعة', 'السبت'],
|
|
datasets: [{ label: 'الفواتير', data: [65, 59, 80, 81, 56, 55, 40], borderColor: '#10b981', tension: 0.4 }]
|
|
},
|
|
options: { scales: { y: { grid: { color: 'rgba(255,255,255,0.05)' } }, x: { grid: { display: false } } } }
|
|
});
|
|
}
|
|
}
|
|
|
|
function navigate() {
|
|
if (isLoggedIn()) {
|
|
pageContent.innerHTML = dashboardPage();
|
|
document.getElementById('nav-user').style.display = 'flex';
|
|
setTimeout(initCharts, 100);
|
|
} else {
|
|
pageContent.innerHTML = loginPage();
|
|
document.getElementById('nav-user').style.display = 'none';
|
|
setTimeout(() => {
|
|
const form = document.getElementById('login-form');
|
|
if (form) form.onsubmit = async (e) => {
|
|
e.preventDefault();
|
|
const email = document.getElementById('login-email').value;
|
|
const password = document.getElementById('login-password').value;
|
|
try {
|
|
const res = await API.post('/auth/login', { email, password });
|
|
localStorage.setItem('access_token', res.data.access_token);
|
|
API.accessToken = res.data.access_token;
|
|
navigate();
|
|
} catch (err) {
|
|
const errEl = document.getElementById('login-error');
|
|
errEl.textContent = err.message || 'خطأ في الدخول';
|
|
errEl.classList.remove('hidden');
|
|
}
|
|
};
|
|
}, 50);
|
|
}
|
|
}
|
|
|
|
document.getElementById('ai-query').onkeydown = async (e) => {
|
|
if (e.key === 'Enter') {
|
|
const query = e.target.value;
|
|
document.getElementById('ai-answer').textContent = 'جاري التحليل...';
|
|
try {
|
|
const res = await API.post('/ai/query', { query });
|
|
document.getElementById('ai-answer').textContent = res.data.answer;
|
|
} catch (err) { document.getElementById('ai-answer').textContent = 'خطأ في الاتصال.'; }
|
|
}
|
|
};
|
|
|
|
navigate();
|
|
</script>
|
|
</body>
|
|
</html>
|