Files
musadaq-saas/public/shell.php
2026-05-07 13:52:09 +03:00

2462 lines
116 KiB
PHP
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="ar" dir="rtl" data-theme="light">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>مُصادَق | لوحة التحكم الذكية</title>
<link rel="icon" type="image/jpeg" href="assets/img/logo.jpg">
<link
href="https://fonts.googleapis.com/css2?family=IBM+Plex+Sans+Arabic:wght@300;400;500;600;700&family=IBM+Plex+Mono:wght@400;500&family=El+Messiri:wght@500;600;700&display=swap"
rel="stylesheet">
<script src="https://cdn.tailwindcss.com"></script>
<script defer src="https://unpkg.com/alpinejs@3.x.x/dist/cdn.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/qrious/4.0.2/qrious.min.js"></script>
<style>
/* ═══════════════════════════════════════════════
MUSADDAQ DESIGN SYSTEM - LIGHT PROFESSIONAL
═══════════════════════════════════════════════ */
:root {
--navy: #16325c;
--navy-mid: #1e4080;
--navy-light: #2d5fa6;
--navy-hover: rgba(22, 50, 92, 0.07);
--gold: #b07d1a;
--gold-bright: #f5a623;
--gold-subtle: #fef5e0;
--teal: #047857;
--teal-mid: #059669;
--teal-subtle: #d1fae5;
--amber: #b45309;
--amber-subtle: #fef3c7;
--red: #b91c1c;
--red-subtle: #fee2e2;
--blue: #1d4ed8;
--blue-subtle: #dbeafe;
--purple: #6d28d9;
--purple-subtle: #ede9fe;
--bg: #edf0f5;
--bg-card: #ffffff;
--border: #dde3ed;
--border-mid: #c8d2e0;
--text-1: #0c1a35;
--text-2: #3d5166;
--text-3: #8496ac;
--shadow-sm: 0 1px 4px rgba(15, 40, 80, 0.06);
--shadow: 0 2px 12px rgba(15, 40, 80, 0.08);
--shadow-md: 0 6px 24px rgba(15, 40, 80, 0.12);
--shadow-lg: 0 16px 48px rgba(15, 40, 80, 0.18);
/* Sidebar tokens */
--sb-bg: #16325c;
--sb-text: rgba(255, 255, 255, 0.62);
--sb-text-a: #ffffff;
--sb-hover: rgba(255, 255, 255, 0.07);
--sb-active: rgba(245, 166, 35, 0.14);
--sb-accent: #f5a623;
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: 'IBM Plex Sans Arabic', sans-serif;
background: var(--bg);
color: var(--text-1);
-webkit-font-smoothing: antialiased;
font-size: 14px;
line-height: 1.6;
}
h1,
h2,
h3,
h4 {
font-family: 'El Messiri', 'IBM Plex Sans Arabic', sans-serif;
line-height: 1.35;
}
[x-cloak] {
display: none !important;
}
/* ── SCROLLBAR ─────────────────────────────── */
::-webkit-scrollbar {
width: 5px;
height: 5px;
}
::-webkit-scrollbar-track {
background: transparent;
}
::-webkit-scrollbar-thumb {
background: #c8d2e0;
border-radius: 10px;
}
/* ── SIDEBAR ───────────────────────────────── */
.sidebar {
width: 256px;
min-width: 256px;
background: linear-gradient(175deg, #1a3d6e 0%, #0f2247 100%);
display: flex;
flex-direction: column;
height: 100vh;
position: sticky;
top: 0;
box-shadow: -6px 0 30px rgba(0, 0, 0, 0.18);
z-index: 50;
}
.sb-logo-area {
padding: 28px 20px 20px;
border-bottom: 1px solid rgba(255, 255, 255, 0.07);
}
.sb-logo-mark {
width: 40px;
height: 40px;
background: var(--gold-bright);
border-radius: 12px;
display: flex;
align-items: center;
justify-content: center;
font-size: 18px;
color: var(--navy);
flex-shrink: 0;
box-shadow: 0 4px 12px rgba(245, 166, 35, 0.4);
}
.sb-brand-name {
font-family: 'El Messiri', sans-serif;
font-size: 22px;
font-weight: 700;
color: white;
}
.sb-brand-sub {
font-size: 10px;
color: rgba(255, 255, 255, 0.35);
letter-spacing: 0.08em;
margin-top: 2px;
}
.sb-nav {
flex: 1;
padding: 16px 12px;
display: flex;
flex-direction: column;
gap: 3px;
overflow-y: auto;
}
.sb-section-label {
font-size: 10px;
font-weight: 700;
color: rgba(255, 255, 255, 0.25);
letter-spacing: 0.12em;
text-transform: uppercase;
padding: 12px 8px 6px;
margin-top: 6px;
}
.nav-btn {
display: flex;
align-items: center;
gap: 12px;
padding: 10px 12px;
border-radius: 11px;
cursor: pointer;
border: none;
background: transparent;
color: var(--sb-text);
font-family: 'IBM Plex Sans Arabic', sans-serif;
font-size: 14px;
font-weight: 500;
width: 100%;
text-align: right;
transition: all 0.18s ease;
position: relative;
}
.nav-btn:hover {
background: var(--sb-hover);
color: white;
}
.nav-btn.active {
background: var(--sb-active);
color: white;
font-weight: 600;
}
.nav-btn.active::before {
content: '';
position: absolute;
right: 0;
top: 20%;
bottom: 20%;
width: 3px;
background: var(--sb-accent);
border-radius: 3px 0 0 3px;
}
.nav-icon {
width: 34px;
height: 34px;
border-radius: 9px;
background: rgba(255, 255, 255, 0.08);
display: flex;
align-items: center;
justify-content: center;
font-size: 15px;
flex-shrink: 0;
transition: all 0.18s;
}
.nav-btn.active .nav-icon {
background: var(--sb-accent);
box-shadow: 0 3px 10px rgba(245, 166, 35, 0.35);
}
.nav-btn:hover .nav-icon {
background: rgba(255, 255, 255, 0.14);
}
.sb-user-area {
padding: 16px;
border-top: 1px solid rgba(255, 255, 255, 0.07);
}
.sb-user-card {
display: flex;
align-items: center;
gap: 10px;
padding: 10px;
border-radius: 12px;
background: rgba(255, 255, 255, 0.05);
margin-bottom: 10px;
}
.user-avatar-sb {
width: 36px;
height: 36px;
border-radius: 9px;
background: var(--gold-bright);
color: var(--navy);
display: flex;
align-items: center;
justify-content: center;
font-weight: 700;
font-size: 15px;
flex-shrink: 0;
}
.role-pill {
display: inline-block;
padding: 1px 8px;
border-radius: 20px;
font-size: 10px;
font-weight: 600;
background: rgba(255, 255, 255, 0.1);
color: rgba(255, 255, 255, 0.5);
text-transform: uppercase;
letter-spacing: 0.04em;
}
.logout-btn {
width: 100%;
display: flex;
align-items: center;
gap: 8px;
padding: 8px 10px;
border-radius: 9px;
background: transparent;
border: none;
color: rgba(255, 255, 255, 0.4);
cursor: pointer;
font-family: 'IBM Plex Sans Arabic', sans-serif;
font-size: 13px;
font-weight: 500;
transition: all 0.18s;
text-align: right;
}
.logout-btn:hover {
background: rgba(220, 38, 38, 0.12);
color: #fca5a5;
}
/* ── MAIN LAYOUT ───────────────────────────── */
.main-area {
flex: 1;
overflow-y: auto;
display: flex;
flex-direction: column;
min-width: 0;
}
.page-header {
padding: 28px 36px 24px;
background: white;
border-bottom: 1px solid var(--border);
display: flex;
align-items: center;
justify-content: space-between;
gap: 16px;
position: sticky;
top: 0;
z-index: 40;
box-shadow: var(--shadow-sm);
}
.page-title {
font-size: 22px;
font-weight: 700;
color: var(--text-1);
}
.page-subtitle {
font-size: 13px;
color: var(--text-3);
margin-top: 2px;
}
.page-content {
padding: 28px 36px;
flex: 1;
}
/* ── STAT CARDS ────────────────────────────── */
.stat-card {
background: white;
border-radius: 16px;
padding: 24px;
border: 1px solid var(--border);
box-shadow: var(--shadow-sm);
position: relative;
overflow: hidden;
transition: transform 0.2s, box-shadow 0.2s;
}
.stat-card:hover {
transform: translateY(-2px);
box-shadow: var(--shadow);
}
.stat-icon-box {
width: 50px;
height: 50px;
border-radius: 14px;
display: flex;
align-items: center;
justify-content: center;
font-size: 22px;
margin-bottom: 16px;
}
.stat-label {
font-size: 12px;
font-weight: 700;
color: var(--text-3);
text-transform: uppercase;
letter-spacing: 0.06em;
}
.stat-value {
font-size: 40px;
font-weight: 700;
margin-top: 6px;
line-height: 1;
font-family: 'El Messiri', sans-serif;
}
.stat-card::after {
content: '';
position: absolute;
left: 0;
top: 0;
bottom: 0;
width: 4px;
border-radius: 0 3px 3px 0;
}
.stat-navy::after {
background: var(--navy);
}
.stat-navy .stat-icon-box {
background: var(--navy-hover);
}
.stat-navy .stat-value {
color: var(--navy);
}
.stat-amber::after {
background: var(--gold-bright);
}
.stat-amber .stat-icon-box {
background: var(--amber-subtle);
}
.stat-amber .stat-value {
color: var(--amber);
}
.stat-teal::after {
background: var(--teal);
}
.stat-teal .stat-icon-box {
background: var(--teal-subtle);
}
.stat-teal .stat-value {
color: var(--teal);
}
.stat-red::after {
background: #e11d48;
}
.stat-red .stat-icon-box {
background: #fff1f2;
}
.stat-red .stat-value {
color: #e11d48;
}
/* ── QUICK ACTIONS ─────────────────────────── */
.quick-action-card {
background: white;
border: 1px solid var(--border);
border-radius: 14px;
padding: 18px 20px;
display: flex;
align-items: center;
gap: 14px;
cursor: pointer;
transition: all 0.2s;
text-align: right;
box-shadow: var(--shadow-sm);
}
.quick-action-card:hover {
border-color: var(--navy-light);
box-shadow: 0 4px 16px rgba(22, 50, 92, 0.12);
transform: translateY(-1px);
}
.qa-icon {
width: 44px;
height: 44px;
border-radius: 12px;
display: flex;
align-items: center;
justify-content: center;
font-size: 20px;
flex-shrink: 0;
}
/* ── DATA TABLE ────────────────────────────── */
.table-container {
background: white;
border-radius: 16px;
border: 1px solid var(--border);
box-shadow: var(--shadow-sm);
overflow: hidden;
}
.table-top-bar {
padding: 18px 24px;
border-bottom: 1px solid var(--border);
display: flex;
align-items: center;
gap: 12px;
}
.table-top-bar h3 {
font-size: 16px;
font-weight: 700;
color: var(--text-1);
}
.table-count {
padding: 2px 10px;
background: var(--bg);
border: 1px solid var(--border);
border-radius: 20px;
font-size: 12px;
font-weight: 600;
color: var(--text-3);
}
.data-table {
width: 100%;
border-collapse: collapse;
}
.data-table th {
padding: 13px 20px;
text-align: right;
font-size: 11px;
font-weight: 700;
color: var(--text-3);
text-transform: uppercase;
letter-spacing: 0.07em;
border-bottom: 1px solid var(--border);
background: #f8fafc;
white-space: nowrap;
}
.data-table td {
padding: 15px 20px;
border-bottom: 1px solid #f0f4f8;
vertical-align: middle;
}
.data-table tbody tr:last-child td {
border-bottom: none;
}
.data-table tbody tr {
transition: background 0.14s;
}
.data-table tbody tr:hover {
background: #f8fafd;
}
.empty-row {
text-align: center;
padding: 56px 24px;
}
.empty-icon {
font-size: 42px;
opacity: 0.25;
display: block;
margin-bottom: 12px;
}
.empty-msg {
font-size: 15px;
color: var(--text-3);
}
/* ── BADGES ────────────────────────────────── */
.badge {
display: inline-flex;
align-items: center;
gap: 5px;
padding: 4px 11px;
border-radius: 20px;
font-size: 12px;
font-weight: 600;
white-space: nowrap;
}
.badge-teal {
background: var(--teal-subtle);
color: var(--teal);
}
.badge-amber {
background: var(--amber-subtle);
color: var(--amber);
}
.badge-blue {
background: var(--blue-subtle);
color: var(--blue);
}
.badge-gray {
background: #f1f5f9;
color: #64748b;
}
.badge-navy {
background: var(--navy-hover);
color: var(--navy);
}
.badge-red {
background: var(--red-subtle);
color: var(--red);
}
.badge-purple {
background: var(--purple-subtle);
color: var(--purple);
}
.badge-dot {
width: 7px;
height: 7px;
border-radius: 50%;
display: inline-block;
flex-shrink: 0;
}
/* ── BUTTONS ───────────────────────────────── */
.btn {
display: inline-flex;
align-items: center;
gap: 7px;
padding: 10px 20px;
border-radius: 10px;
font-family: 'IBM Plex Sans Arabic', sans-serif;
font-size: 14px;
font-weight: 600;
cursor: pointer;
border: none;
transition: all 0.18s;
white-space: nowrap;
}
.btn:disabled {
opacity: 0.6;
cursor: not-allowed;
}
.btn-navy {
background: var(--navy);
color: white;
box-shadow: 0 2px 8px rgba(22, 50, 92, 0.22);
}
.btn-navy:hover:not(:disabled) {
background: var(--navy-mid);
transform: translateY(-1px);
box-shadow: 0 4px 14px rgba(22, 50, 92, 0.3);
}
.btn-teal {
background: var(--teal);
color: white;
box-shadow: 0 2px 8px rgba(4, 120, 87, 0.22);
}
.btn-teal:hover:not(:disabled) {
background: #065f46;
transform: translateY(-1px);
}
.btn-ghost {
background: white;
color: var(--text-2);
border: 1px solid var(--border);
}
.btn-ghost:hover {
background: var(--bg);
border-color: var(--border-mid);
}
.btn-danger-ghost {
background: transparent;
color: var(--red);
border: none;
padding: 7px 12px;
border-radius: 8px;
}
.btn-danger-ghost:hover {
background: var(--red-subtle);
}
.btn-sm {
padding: 7px 14px;
font-size: 13px;
}
.btn-icon {
padding: 8px 12px;
}
.btn-table-action {
display: inline-flex;
align-items: center;
gap: 5px;
padding: 6px 13px;
border-radius: 8px;
font-family: inherit;
font-size: 12px;
font-weight: 600;
cursor: pointer;
border: none;
transition: all 0.16s;
}
.btn-ta-navy {
background: var(--navy-hover);
color: var(--navy);
}
.btn-ta-navy:hover {
background: var(--navy);
color: white;
}
.btn-ta-teal {
background: var(--teal-subtle);
color: var(--teal);
}
.btn-ta-teal:hover {
background: var(--teal);
color: white;
}
.btn-ta-red {
background: transparent;
color: #94a3b8;
border-radius: 8px;
padding: 6px 10px;
}
.btn-ta-red:hover {
background: var(--red-subtle);
color: var(--red);
}
/* ── FORM ELEMENTS ─────────────────────────── */
.form-group {
display: flex;
flex-direction: column;
gap: 6px;
}
.form-label {
font-size: 13px;
font-weight: 600;
color: var(--text-2);
display: flex;
align-items: center;
gap: 5px;
}
.form-label-sub {
font-size: 11px;
color: var(--text-3);
font-weight: 400;
}
.form-input {
width: 100%;
padding: 11px 14px;
border: 1.5px solid var(--border);
border-radius: 10px;
font-family: 'IBM Plex Sans Arabic', sans-serif;
font-size: 14px;
color: var(--text-1);
background: white;
outline: none;
transition: border-color 0.18s, box-shadow 0.18s;
direction: rtl;
}
.form-input:focus {
border-color: var(--navy);
box-shadow: 0 0 0 3px rgba(22, 50, 92, 0.08);
}
.form-input::placeholder {
color: var(--text-3);
}
.form-input.mono {
font-family: 'IBM Plex Mono', monospace;
}
.form-section-title {
font-size: 11px;
font-weight: 700;
color: var(--text-3);
text-transform: uppercase;
letter-spacing: 0.08em;
padding-bottom: 12px;
border-bottom: 1px solid var(--border);
margin-bottom: 4px;
display: flex;
align-items: center;
gap: 8px;
}
/* ── MODALS ────────────────────────────────── */
.modal-backdrop {
position: fixed;
inset: 0;
background: rgba(12, 26, 53, 0.55);
backdrop-filter: blur(5px);
display: flex;
align-items: center;
justify-content: center;
padding: 24px;
z-index: 120;
}
.modal-box {
background: white;
border-radius: 20px;
box-shadow: var(--shadow-lg);
width: 100%;
max-width: 520px;
max-height: 92vh;
overflow-y: auto;
}
.modal-box-lg {
max-width: 680px;
}
.modal-head {
padding: 24px 28px 0;
display: flex;
align-items: flex-start;
gap: 14px;
}
.modal-head-icon {
width: 46px;
height: 46px;
border-radius: 13px;
display: flex;
align-items: center;
justify-content: center;
font-size: 20px;
flex-shrink: 0;
}
.modal-head-icon.navy {
background: var(--navy-hover);
}
.modal-head-icon.gold {
background: var(--gold-subtle);
}
.modal-head-icon.teal {
background: var(--teal-subtle);
}
.modal-title {
font-size: 19px;
font-weight: 700;
color: var(--text-1);
margin-bottom: 3px;
}
.modal-subtitle {
font-size: 13px;
color: var(--text-3);
}
.modal-body {
padding: 22px 28px;
}
.modal-footer {
padding: 18px 28px 24px;
display: flex;
gap: 10px;
}
.modal-divider {
height: 1px;
background: var(--border);
margin: 0 28px;
}
.modal-close-btn {
margin-right: auto;
background: transparent;
border: none;
color: var(--text-3);
font-size: 20px;
cursor: pointer;
padding: 2px;
line-height: 1;
transition: color 0.15s;
}
.modal-close-btn:hover {
color: var(--text-1);
}
/* ── TOAST ─────────────────────────────────── */
.toast-error {
position: fixed;
top: 20px;
left: 50%;
transform: translateX(-50%);
z-index: 300;
background: white;
border-right: 4px solid var(--red);
border-radius: 12px;
padding: 14px 22px;
box-shadow: var(--shadow-md);
color: var(--red);
font-weight: 600;
font-size: 14px;
max-width: 480px;
width: 90%;
text-align: center;
cursor: pointer;
}
/* ── COMPANY / JOFOTARA STATUS ─────────────── */
.jofotara-connected {
display: inline-flex;
align-items: center;
gap: 6px;
cursor: pointer;
font-size: 13px;
font-weight: 600;
color: var(--teal);
}
.jofotara-connect {
display: inline-flex;
align-items: center;
gap: 6px;
cursor: pointer;
font-size: 13px;
font-weight: 600;
color: var(--text-3);
text-decoration: underline;
}
.jofotara-connect:hover {
color: var(--navy);
}
.conn-dot {
width: 8px;
height: 8px;
border-radius: 50%;
flex-shrink: 0;
}
.conn-dot.on {
background: var(--teal);
box-shadow: 0 0 0 3px rgba(4, 120, 87, 0.18);
}
.conn-dot.off {
background: #cbd5e1;
}
/* ── INVOICE VIEW PANEL ────────────────────── */
.invoice-field-card {
background: #f8fafc;
border: 1px solid var(--border);
border-radius: 12px;
padding: 14px 16px;
}
.invoice-field-label {
font-size: 11px;
font-weight: 700;
color: var(--text-3);
text-transform: uppercase;
letter-spacing: 0.06em;
margin-bottom: 5px;
}
.invoice-field-value {
font-size: 15px;
font-weight: 600;
color: var(--text-1);
}
/* ── STATS MODAL TABLE ─────────────────────── */
.stats-table {
width: 100%;
border-collapse: collapse;
font-size: 13px;
}
.stats-table th {
padding: 10px 16px;
text-align: right;
font-weight: 700;
color: var(--text-3);
font-size: 11px;
text-transform: uppercase;
background: #f8fafc;
border-bottom: 1px solid var(--border);
}
.stats-table td {
padding: 12px 16px;
border-bottom: 1px solid #f0f4f8;
}
.stats-table tbody tr:last-child td {
border-bottom: none;
}
.stats-table tbody tr:hover {
background: #f8fafc;
}
.mini-stat {
background: white;
border: 1px solid var(--border);
border-radius: 14px;
padding: 20px;
}
.mini-stat-label {
font-size: 11px;
font-weight: 700;
color: var(--text-3);
text-transform: uppercase;
letter-spacing: 0.05em;
margin-bottom: 8px;
}
.mini-stat-val {
font-size: 26px;
font-weight: 700;
font-family: 'El Messiri', sans-serif;
}
</style>
</head>
<body x-data="app" x-init="init()">
<!-- ═══ TOAST ERROR ═══════════════════════════════════ -->
<div x-show="globalError" x-cloak class="toast-error" x-text="globalError" x-transition @click="globalError = ''">
</div>
<!-- ═══ MAIN LAYOUT ══════════════════════════════════ -->
<div style="display:flex; height:100vh; overflow:hidden;">
<!-- ── SIDEBAR ──────────────────────────────────── -->
<aside class="sidebar">
<!-- Logo -->
<div class="sb-logo-area">
<div style="display:flex; align-items:center; gap:12px;">
<div class="sb-logo-mark" style="overflow:hidden; background:transparent;">
<img src="assets/img/logo.jpg" alt="Musadaq Logo" style="width:100%; height:100%; object-fit:cover;">
</div>
<div>
<div class="sb-brand-name">مُصادَق</div>
<div class="sb-brand-sub">نظام إدارة المحاسبة الضريبية</div>
</div>
</div>
</div>
<!-- Navigation -->
<nav class="sb-nav">
<div class="sb-section-label">القائمة الرئيسية</div>
<button @click="setPage('dashboard')" class="nav-btn" :class="page==='dashboard' ? 'active' : ''">
<span class="nav-icon">🏠</span>
<span>الرئيسية</span>
</button>
<button x-show="user?.role !== 'viewer'" @click="setPage('companies')" class="nav-btn"
:class="page==='companies' ? 'active' : ''">
<span class="nav-icon">🏭</span>
<span>الشركات</span>
</button>
<button x-show="user?.role !== 'viewer'" @click="setPage('invoices')" class="nav-btn"
:class="page==='invoices' ? 'active' : ''">
<span class="nav-icon">📄</span>
<span>الفواتير</span>
</button>
<button x-show="user?.role === 'super_admin' || user?.role === 'admin'" @click="setPage('users')"
class="nav-btn" :class="page==='users' ? 'active' : ''">
<span class="nav-icon">👥</span>
<span>فريق العمل</span>
</button>
<div x-show="user?.role === 'super_admin' || user?.role === 'admin'">
<div class="sb-section-label">الإدارة العليا</div>
<button x-show="user?.role === 'super_admin'" @click="setPage('tenants')" class="nav-btn" :class="page==='tenants' ? 'active' : ''">
<span class="nav-icon">🏢</span>
<span>المكاتب المحاسبية</span>
</button>
<button @click="setPage('subscription')" class="nav-btn" :class="page==='subscription' ? 'active' : ''">
<span class="nav-icon">💎</span>
<span>اشتراكي</span>
</button>
</div>
</nav>
<!-- User -->
<div class="sb-user-area">
<div class="sb-user-card">
<div class="user-avatar-sb" x-text="user?.name?.[0]"></div>
<div style="overflow:hidden; flex:1;">
<div style="font-size:13px; font-weight:700; color:white; white-space:nowrap; overflow:hidden; text-overflow:ellipsis;"
x-text="user?.name"></div>
<span class="role-pill" x-text="user?.role"></span>
</div>
</div>
<button @click="logout()" class="logout-btn">
<span>🚪</span>
<span>تسجيل الخروج</span>
</button>
</div>
</aside>
<!-- ── MAIN CONTENT ──────────────────────────── -->
<div class="main-area">
<!-- Page Header -->
<div class="page-header">
<div>
<h1 class="page-title" x-text="title()"></h1>
<p class="page-subtitle" x-text="subtitle()"></p>
</div>
<div style="display:flex; align-items:center; gap:10px;">
<button x-show="page==='tenants' && user?.role === 'super_admin'" @click="showAddTenantModal = true"
class="btn btn-navy">
<span></span> إضافة مكتب
</button>
<button x-show="page==='users'" @click="showAddUserModal = true" class="btn btn-navy">
<span></span> إضافة مستخدم
</button>
<button x-show="page==='companies'" @click="showAddCompanyModal = true" class="btn btn-navy">
<span></span> إضافة شركة
</button>
<button x-show="page==='invoices'" @click="showUploadModal = true" class="btn btn-teal">
<span>📤</span> رفع فاتورة
</button>
</div>
</div>
<!-- Page Body -->
<div class="page-content" x-transition>
<!-- ════ DASHBOARD ═══════════════════════════ -->
<div x-show="page === 'dashboard'" style="display:flex; flex-direction:column; gap:24px;">
<!-- Stat Cards -->
<div style="display:grid; grid-template-columns:repeat(4,1fr); gap:18px;">
<div class="stat-card stat-navy">
<div class="stat-icon-box">📄</div>
<div class="stat-label">إجمالي الفواتير</div>
<div class="stat-value" x-text="stats.total || 0"></div>
</div>
<div class="stat-card stat-amber">
<div class="stat-icon-box"></div>
<div class="stat-label">بانتظار التدقيق</div>
<div class="stat-value" x-text="stats.pending || 0"></div>
</div>
<div class="stat-card stat-teal">
<div class="stat-icon-box"></div>
<div class="stat-label">مدققة ومعتمدة</div>
<div class="stat-value" x-text="stats.approved || 0"></div>
</div>
<template x-if="user?.role === 'super_admin'">
<div class="stat-card stat-navy">
<div class="stat-icon-box">🏢</div>
<div class="stat-label">المكاتب والمستخدمين</div>
<div class="stat-value" x-text="(stats.tenants || 0) + ' / ' + (stats.users || 0)"></div>
</div>
</template>
<template x-if="user?.role !== 'super_admin'">
<div class="stat-card" :class="subscription?.invoices?.warning ? 'stat-red' : 'stat-navy'">
<div class="stat-icon-box">📊</div>
<div class="stat-label">استهلاك الحصة</div>
<div class="stat-value" x-text="(subscription?.invoices?.percent || 0) + '%'"></div>
</div>
</template>
</div>
<!-- Quick Actions -->
<div>
<h3 style="font-size:15px; font-weight:700; color:var(--text-2); margin-bottom:14px;">إجراءات
سريعة</h3>
<div
style="display:grid; grid-template-columns:repeat(auto-fill, minmax(200px,1fr)); gap:14px;">
<div x-show="user?.role !== 'viewer'" class="quick-action-card"
@click="setPage('invoices'); showUploadModal = true">
<div class="qa-icon" style="background:var(--teal-subtle);">📤</div>
<div>
<div style="font-weight:700; font-size:14px; color:var(--text-1);">رفع فاتورة</div>
<div style="font-size:12px; color:var(--text-3); margin-top:2px;">رفع وتحليل بالذكاء
الاصطناعي</div>
</div>
</div>
<div x-show="user?.role !== 'viewer'" class="quick-action-card"
@click="setPage('companies'); showAddCompanyModal = true">
<div class="qa-icon" style="background:var(--navy-hover);">🏭</div>
<div>
<div style="font-weight:700; font-size:14px; color:var(--text-1);">إضافة شركة</div>
<div style="font-size:12px; color:var(--text-3); margin-top:2px;">تسجيل شركة جديدة
</div>
</div>
</div>
<div x-show="user?.role !== 'viewer'" class="quick-action-card"
@click="setPage('invoices')">
<div class="qa-icon" style="background:var(--amber-subtle);">📋</div>
<div>
<div style="font-weight:700; font-size:14px; color:var(--text-1);">الفواتير المعلقة
</div>
<div style="font-size:12px; color:var(--text-3); margin-top:2px;">عرض ومراجعة
الفواتير</div>
</div>
</div>
<div x-show="user?.role === 'super_admin' || user?.role === 'admin'"
class="quick-action-card" @click="setPage('users'); showAddUserModal = true">
<div class="qa-icon" style="background:var(--purple-subtle);">👤</div>
<div>
<div style="font-weight:700; font-size:14px; color:var(--text-1);">إضافة مستخدم
</div>
<div style="font-size:12px; color:var(--text-3); margin-top:2px;">إنشاء حساب جديد
</div>
</div>
</div>
</div>
</div>
</div>
<!-- ════ COMPANIES ═══════════════════════════ -->
<div x-show="page === 'companies'">
<div class="table-container">
<div class="table-top-bar">
<span style="font-size:18px;">🏭</span>
<h3>الشركات المسجلة</h3>
<span class="table-count" x-text="companies.length + ' شركة'"></span>
</div>
<table class="data-table">
<thead>
<tr>
<th>الشركة</th>
<th>الأرقام الرسمية</th>
<th style="text-align:center;">الفواتير</th>
<th style="text-align:center;">الإجمالي</th>
<th>الفوترة الحكومية</th>
<th>التقارير</th>
<th style="text-align:center;">إجراءات</th>
</tr>
</thead>
<tbody>
<tr x-show="companies.length === 0">
<td colspan="7">
<div class="empty-row">
<span class="empty-icon">🏭</span>
<p class="empty-msg">لا توجد شركات مسجلة بعد</p>
</div>
</td>
</tr>
<template x-for="c in companies" :key="c.id">
<tr>
<td>
<div style="font-weight:700; color:var(--navy); font-size:15px;"
x-text="c.name"></div>
<div style="font-size:12px; color:var(--text-3); margin-top:2px;"
x-text="c.address"></div>
</td>
<td style="font-family:'IBM Plex Mono',monospace; font-size:12px;">
<div style="color:var(--text-2);">TIN: <span
x-text="c.tax_identification_number"></span></div>
<div style="color:var(--text-3); margin-top:2px;">CRN: <span
x-text="c.commercial_registration_number || '—'"></span></div>
</td>
<td style="text-align:center; font-weight:700; color:var(--text-2);"
x-text="c.invoices_count || 0"></td>
<td style="text-align:center; font-weight:700; color:var(--teal); font-family:'IBM Plex Mono',monospace; font-size:13px;"
x-text="parseFloat(c.total_amount || 0).toLocaleString() + ' JOD'"></td>
<td>
<template x-if="c.jofotara_client_id_encrypted">
<button @click="openConnectModal(c)" class="jofotara-connected">
<span class="conn-dot on"></span>
متصل بالفوترة
</button>
</template>
<template x-if="!c.jofotara_client_id_encrypted">
<button @click="openConnectModal(c)" class="jofotara-connect">
<span class="conn-dot off"></span>
ربط الآن
</button>
</template>
</td>
<td>
<button @click="showCompanyStats(c.id)"
class="btn-table-action btn-ta-navy">
📊 تقرير
</button>
</td>
<td style="text-align:center;">
<button @click="confirmDeleteCompany(c)"
class="btn-table-action btn-ta-red">🗑️</button>
</td>
</tr>
</template>
</tbody>
</table>
</div>
</div>
<!-- ════ USERS ════════════════════════════════ -->
<div x-show="page === 'users'">
<div class="table-container">
<div class="table-top-bar">
<span style="font-size:18px;">👥</span>
<h3>فريق العمل</h3>
<span class="table-count" x-text="users.length + ' مستخدم'"></span>
</div>
<table class="data-table">
<thead>
<tr>
<th>المستخدم</th>
<th>المكتب</th>
<th>الصلاحية</th>
<th style="text-align:center;">الحالة</th>
<th style="text-align:center;">إجراءات</th>
</tr>
</thead>
<tbody>
<tr x-show="users.length === 0">
<td colspan="5">
<div class="empty-row">
<span class="empty-icon">👥</span>
<p class="empty-msg">لا يوجد مستخدمون مسجلون بعد</p>
</div>
</td>
</tr>
<template x-for="u in users" :key="u.id">
<tr>
<td>
<div style="display:flex; align-items:center; gap:10px;">
<div style="width:34px;height:34px;border-radius:9px;background:var(--navy-hover);color:var(--navy);display:flex;align-items:center;justify-content:center;font-weight:700;font-size:14px;flex-shrink:0;"
x-text="u.name?.[0]"></div>
<div>
<div style="font-weight:700; color:var(--text-1);" x-text="u.name">
</div>
<div style="font-size:12px; color:var(--text-3); font-family:'IBM Plex Mono',monospace;"
x-text="u.email"></div>
</div>
</div>
</td>
<td style="color:var(--text-2); font-size:13px;" x-text="u.tenant_name || '—'">
</td>
<td>
<span class="badge"
:class="u.role==='super_admin'?'badge-navy':(u.role==='admin'?'badge-blue':(u.role==='accountant'?'badge-teal':'badge-gray'))"
x-text="u.role==='super_admin'?'مدير عام':(u.role==='admin'?'مدير مكتب':(u.role==='accountant'?'محاسب':'مشاهد'))">
</span>
</td>
<td style="text-align:center;">
<span class="badge" :class="u.is_active ? 'badge-teal' : 'badge-red'">
<span class="badge-dot" :class="u.is_active ? 'bg-teal' : 'bg-red'"
style="background:currentColor;"></span>
<span x-text="u.is_active ? 'نشط' : 'موقف'"></span>
</span>
</td>
<td style="text-align:center;">
<button x-show="u.id !== user.id" @click="confirmDeleteUser(u)"
class="btn-table-action btn-ta-red">🗑️ حذف</button>
</td>
</tr>
</template>
</tbody>
</table>
</div>
</div>
<!-- ════ INVOICES ═════════════════════════════ -->
<div x-show="page === 'invoices'">
<div class="table-container">
<div class="table-top-bar">
<span style="font-size:18px;">📄</span>
<h3>إدارة الفواتير</h3>
<span class="table-count" x-text="invoices.length + ' فاتورة'"></span>
</div>
<table class="data-table">
<thead>
<tr>
<th>الشركة / المورد</th>
<th>التاريخ</th>
<th>المجموع الكلي</th>
<th style="text-align:center;">الحالة</th>
<th style="text-align:center;">إجراءات</th>
</tr>
</thead>
<tbody>
<tr x-show="invoices.length === 0">
<td colspan="5">
<div class="empty-row">
<span class="empty-icon">📄</span>
<p class="empty-msg">لا توجد فواتير مرفوعة بعد</p>
</div>
</td>
</tr>
<template x-for="inv in invoices" :key="inv.id">
<tr>
<td>
<div style="font-weight:700; color:var(--navy); font-size:14px;"
x-text="inv.company_name"></div>
<div style="font-size:13px; color:var(--text-2); margin-top:2px;"
x-text="inv.supplier_name"></div>
<div style="font-size:11px; color:var(--text-3); font-family:'IBM Plex Mono',monospace;"
x-text="inv.supplier_tin"></div>
</td>
<td style="color:var(--text-2); font-size:13px; font-family:'IBM Plex Mono',monospace;"
x-text="inv.invoice_date || '—'"></td>
<td style="font-weight:700; color:var(--teal); font-family:'IBM Plex Mono',monospace;"
x-text="parseFloat(inv.grand_total).toLocaleString() + ' JOD'"></td>
<td style="text-align:center;">
<span class="badge"
:class="inv.status==='extracted' ? 'badge-blue' : (inv.status==='approved' ? 'badge-teal' : 'badge-gray')"
x-text="inv.status === 'approved' ? '✓ مدققة' : (inv.status === 'extracted' ? 'جاهزة للتدقيق' : inv.status)">
</span>
</td>
<td style="text-align:center;">
<button @click="viewInvoice(inv.id)" class="btn-table-action btn-ta-navy">
👁️ عرض
</button>
</td>
</tr>
</template>
</tbody>
</table>
</div>
</div>
<!-- ════ TENANTS (SUPER ADMIN) ════════════════ -->
<div x-show="page === 'tenants' && user?.role === 'super_admin'">
<div class="table-container">
<div class="table-top-bar">
<span style="font-size:18px;">🏢</span>
<h3>المكاتب المحاسبية</h3>
<span class="table-count" x-text="tenants.length + ' مكتب'"></span>
</div>
<table class="data-table">
<thead>
<tr>
<th>المكتب المحاسبي</th>
<th style="text-align:center;">الشركات</th>
<th style="text-align:center;">الفواتير</th>
<th>التواصل</th>
<th style="text-align:center;">الحالة</th>
<th style="text-align:center;">إجراءات</th>
</tr>
</thead>
<tbody>
<tr x-show="tenants.length === 0">
<td colspan="6">
<div class="empty-row">
<span class="empty-icon">🏢</span>
<p class="empty-msg">لا توجد مكاتب مسجلة بعد</p>
</div>
</td>
</tr>
<template x-for="t in tenants" :key="t.id">
<tr>
<td>
<div style="font-weight:700; color:var(--navy); font-size:15px;"
x-text="t.name"></div>
<div style="font-size:11px; color:var(--text-3); margin-top:3px; font-family:'IBM Plex Mono',monospace;"
x-text="'انضم: ' + t.created_at.split(' ')[0]"></div>
</td>
<td style="text-align:center; font-weight:700; color:var(--text-2);"
x-text="t.companies_count || 0"></td>
<td style="text-align:center; font-weight:700; color:var(--text-2);"
x-text="t.invoices_count || 0"></td>
<td>
<div style="font-size:13px; color:var(--text-2);" x-text="t.email"></div>
<div style="font-size:12px; color:var(--text-3); font-family:'IBM Plex Mono',monospace;"
x-text="t.phone || '—'"></div>
</td>
<td style="text-align:center;">
<span class="badge"
:class="t.status==='active'?'badge-teal':(t.status==='trial'?'badge-amber':'badge-red')"
x-text="t.status==='active'?'نشط':(t.status==='trial'?'تجريبي':'معلق')">
</span>
</td>
<td style="text-align:center;">
<div style="display:inline-flex; gap:6px; align-items:center;">
<button @click="openEditTenantModal(t)"
class="btn-table-action btn-ta-navy" title="تعديل">⚙️ تعديل</button>
<button class="btn-table-action btn-ta-teal" title="تقرير"
@click="showTenantStats(t)">📊</button>
</div>
</td>
</tr>
</template>
</tbody>
</table>
</div>
</div>
<!-- ── SUBSCRIPTION PAGE ──────────────────────── -->
<div x-show="page === 'subscription'">
<div class="table-container" style="margin-bottom:24px;">
<div class="table-top-bar">
<span style="font-size:18px;">💎</span>
<h3>اشتراكي الحالي</h3>
<span class="badge badge-teal" x-text="subscription?.plan_name"></span>
</div>
<div style="padding:24px; display:grid; grid-template-columns:repeat(3, 1fr); gap:20px;">
<!-- Progress: Invoices -->
<div class="stat-card stat-navy">
<div style="display:flex; justify-content:space-between; align-items:center; margin-bottom:10px;">
<span style="font-size:13px; font-weight:700;">الفواتير الشهرية</span>
<span style="font-size:12px; font-family:'IBM Plex Mono';" x-text="subscription?.invoices?.used + ' / ' + subscription?.invoices?.limit"></span>
</div>
<div style="height:8px; background:rgba(255,255,255,0.2); border-radius:4px; overflow:hidden;">
<div :style="'width:' + (subscription?.invoices?.percent || 0) + '%; height:100%; background:var(--teal);'"></div>
</div>
<div style="font-size:11px; margin-top:8px; opacity:0.8;" x-text="'يتم التصفير في: ' + (subscription?.period_end?.split(' ')[0] || '—')"></div>
</div>
<!-- Progress: Companies -->
<div class="stat-card stat-navy">
<div style="display:flex; justify-content:space-between; align-items:center; margin-bottom:10px;">
<span style="font-size:13px; font-weight:700;">الشركات المدارة</span>
<span style="font-size:12px; font-family:'IBM Plex Mono';" x-text="subscription?.companies?.used + ' / ' + subscription?.companies?.limit"></span>
</div>
<div style="height:8px; background:rgba(255,255,255,0.2); border-radius:4px; overflow:hidden;">
<div :style="'width:' + (subscription?.companies?.percent || 0) + '%; height:100%; background:var(--teal);'"></div>
</div>
<div style="font-size:11px; margin-top:8px; opacity:0.8;">إجمالي الشركات المسموح بها</div>
</div>
<!-- Progress: Users -->
<div class="stat-card stat-navy">
<div style="display:flex; justify-content:space-between; align-items:center; margin-bottom:10px;">
<span style="font-size:13px; font-weight:700;">فريق العمل</span>
<span style="font-size:12px; font-family:'IBM Plex Mono';" x-text="subscription?.users?.used + ' / ' + subscription?.users?.limit"></span>
</div>
<div style="height:8px; background:rgba(255,255,255,0.2); border-radius:4px; overflow:hidden;">
<div :style="'width:' + (subscription?.users?.percent || 0) + '%; height:100%; background:var(--teal);'"></div>
</div>
<div style="font-size:11px; margin-top:8px; opacity:0.8;">مستخدمين نشطين في النظام</div>
</div>
</div>
</div>
<!-- Pricing Cards -->
<h3 style="font-size:18px; font-weight:700; color:var(--navy); margin:32px 0 20px;">تغيير أو ترقية الباقة</h3>
<div style="display:grid; grid-template-columns:repeat(auto-fit, minmax(250px, 1fr)); gap:20px;">
<template x-for="p in plans" :key="p.id">
<div class="table-container" style="padding:24px; display:flex; flex-direction:column; gap:16px; border:2px solid transparent;"
:style="subscription?.plan_id === p.id ? 'border-color:var(--gold);' : ''">
<div style="display:flex; justify-content:space-between; align-items:start;">
<div>
<h4 style="font-size:18px; font-weight:700; color:var(--navy);" x-text="p.name_ar"></h4>
<div style="font-size:12px; color:var(--text-3);" x-text="p.description_ar"></div>
</div>
<span x-show="subscription?.plan_id === p.id" class="badge badge-gold">باقتك الحالية</span>
</div>
<div style="font-size:32px; font-weight:800; color:var(--teal);">
<span x-text="p.price_jod"></span>
<span style="font-size:14px; font-weight:400; color:var(--text-3);">دينار / شهر</span>
</div>
<ul style="list-style:none; padding:0; margin:0; display:flex; flex-direction:column; gap:10px;">
<template x-for="f in p.features">
<li style="font-size:13px; color:var(--text-2); display:flex; gap:8px; align-items:center;">
<span style="color:var(--teal);"></span>
<span x-text="f"></span>
</li>
</template>
</ul>
<button x-show="subscription?.plan_id !== p.id" class="btn-primary" style="margin-top:auto;"
@click="alert('يرجى التواصل مع الدعم الفني لترقية باقتك إلى ' + p.name_ar)">
ترقية الباقة الآن
</button>
</div>
</template>
</div>
</div>
</div><!-- /page-content -->
</div><!-- /main-area -->
</div><!-- /flex layout -->
<!-- ════════════════════════════════════════════════════════
MODALS
════════════════════════════════════════════════════════ -->
<!-- ── COMPANY STATS MODAL ──────────────────────────── -->
<div x-show="showCompanyStatsModal" x-cloak class="modal-backdrop" @click.self="showCompanyStatsModal = false">
<div class="modal-box" style="max-width:680px;">
<div class="modal-head" style="padding-bottom:0;">
<div class="modal-head-icon teal">📊</div>
<div style="flex:1;">
<div class="modal-title" x-text="companyStats?.company?.name"></div>
<div class="modal-subtitle" style="font-family:'IBM Plex Mono',monospace;"
x-text="'TIN: ' + companyStats?.company?.tax_identification_number"></div>
</div>
<button @click="showCompanyStatsModal = false" class="modal-close-btn"></button>
</div>
<div class="modal-body">
<div style="display:grid; grid-template-columns:repeat(2,1fr); gap:12px; margin-bottom:24px;">
<div class="mini-stat">
<div class="mini-stat-label">إجمالي الفواتير</div>
<div class="mini-stat-val" x-text="companyStats?.totals?.total_invoices || 0"></div>
</div>
<div class="mini-stat">
<div class="mini-stat-label">المجموع (JOD)</div>
<div class="mini-stat-val" style="color:var(--teal);"
x-text="parseFloat(companyStats?.totals?.total_amount || 0).toLocaleString()"></div>
</div>
<div class="mini-stat">
<div class="mini-stat-label">إجمالي الضريبة</div>
<div class="mini-stat-val" style="color:var(--amber);"
x-text="parseFloat(companyStats?.totals?.total_tax || 0).toLocaleString()"></div>
</div>
<div class="mini-stat">
<div class="mini-stat-label">المعتمدة</div>
<div class="mini-stat-val" style="color:var(--blue);"
x-text="companyStats?.totals?.approved_count || 0"></div>
</div>
</div>
<div
style="font-size:12px; font-weight:700; color:var(--text-3); text-transform:uppercase; letter-spacing:0.07em; margin-bottom:12px;">
التحليل الشهري للفواتير والضرائب</div>
<div
style="border:1px solid var(--border); border-radius:12px; overflow:hidden; max-height:240px; overflow-y:auto;">
<table class="stats-table">
<thead>
<tr>
<th>الشهر</th>
<th>عدد الفواتير</th>
<th>الضريبة المستحقة</th>
<th style="color:var(--teal);">الإجمالي النهائي</th>
</tr>
</thead>
<tbody>
<template x-for="m in companyStats?.monthly" :key="m.month">
<tr>
<td style="font-family:'IBM Plex Mono',monospace; color:var(--text-2);"
x-text="m.month"></td>
<td x-text="m.total_invoices"></td>
<td style="color:var(--amber); font-family:'IBM Plex Mono',monospace;"
x-text="parseFloat(m.total_tax || 0).toLocaleString() + ' JOD'"></td>
<td style="font-weight:700; color:var(--teal); font-family:'IBM Plex Mono',monospace;"
x-text="parseFloat(m.total_amount || 0).toLocaleString() + ' JOD'"></td>
</tr>
</template>
</tbody>
</table>
</div>
</div>
</div>
</div>
<!-- ── TENANT STATS MODAL ───────────────────────────── -->
<div x-show="showTenantStatsModal" x-cloak class="modal-backdrop" @click.self="showTenantStatsModal = false">
<div class="modal-box" style="max-width:680px;">
<div class="modal-head">
<div class="modal-head-icon navy">🏢</div>
<div style="flex:1;">
<div class="modal-title" x-text="tenantStats?.tenant?.name"></div>
<div class="modal-subtitle">تقرير أداء المكتب المحاسبي</div>
</div>
<button @click="showTenantStatsModal = false" class="modal-close-btn"></button>
</div>
<div class="modal-body">
<div style="display:grid; grid-template-columns:repeat(2,1fr); gap:12px; margin-bottom:24px;">
<div class="mini-stat">
<div class="mini-stat-label">الشركات المدارة</div>
<div class="mini-stat-val" x-text="tenantStats?.summary?.total_companies || 0"></div>
</div>
<div class="mini-stat">
<div class="mini-stat-label">إجمالي الفواتير</div>
<div class="mini-stat-val" x-text="tenantStats?.summary?.total_invoices || 0"></div>
</div>
<div class="mini-stat">
<div class="mini-stat-label">المجموع (JOD)</div>
<div class="mini-stat-val" style="color:var(--teal);"
x-text="parseFloat(tenantStats?.summary?.total_amount || 0).toLocaleString()"></div>
</div>
<div class="mini-stat">
<div class="mini-stat-label">إجمالي الضرائب</div>
<div class="mini-stat-val" style="color:var(--amber);"
x-text="parseFloat(tenantStats?.summary?.total_tax || 0).toLocaleString()"></div>
</div>
</div>
<div
style="font-size:12px; font-weight:700; color:var(--text-3); text-transform:uppercase; letter-spacing:0.07em; margin-bottom:12px;">
تحليل النشاط الشهري للمكتب</div>
<div
style="border:1px solid var(--border); border-radius:12px; overflow:hidden; max-height:240px; overflow-y:auto;">
<table class="stats-table">
<thead>
<tr>
<th>الشهر</th>
<th>عدد الفواتير</th>
<th>الضريبة المستحقة</th>
<th style="color:var(--teal);">الإجمالي النهائي</th>
</tr>
</thead>
<tbody>
<template x-for="m in tenantStats?.monthly" :key="m.month">
<tr>
<td style="font-family:'IBM Plex Mono',monospace; color:var(--text-2);"
x-text="m.month"></td>
<td x-text="m.total_invoices"></td>
<td style="color:var(--amber); font-family:'IBM Plex Mono',monospace;"
x-text="parseFloat(m.total_tax || 0).toLocaleString() + ' JOD'"></td>
<td style="font-weight:700; color:var(--teal); font-family:'IBM Plex Mono',monospace;"
x-text="parseFloat(m.total_amount || 0).toLocaleString() + ' JOD'"></td>
</tr>
</template>
</tbody>
</table>
</div>
</div>
</div>
</div>
<!-- ── ADD USER MODAL ───────────────────────────────── -->
<div x-show="showAddUserModal" x-cloak class="modal-backdrop">
<div class="modal-box">
<div class="modal-head">
<div class="modal-head-icon gold">👤</div>
<div style="flex:1;">
<div class="modal-title">إضافة مستخدم جديد</div>
<div class="modal-subtitle">أدخل بيانات الحساب الجديد</div>
</div>
<button @click="showAddUserModal = false" class="modal-close-btn"></button>
</div>
<div class="modal-divider"></div>
<form @submit.prevent="createUser">
<div class="modal-body" style="display:flex; flex-direction:column; gap:14px;">
<div class="form-group">
<label class="form-label">الاسم الكامل</label>
<input type="text" x-model="newUser.name" placeholder="مثال: أحمد محمد" class="form-input"
required>
</div>
<div class="form-group">
<label class="form-label">البريد الإلكتروني</label>
<input type="email" x-model="newUser.email" placeholder="example@office.com" class="form-input"
required>
</div>
<div class="form-group">
<label class="form-label">كلمة المرور</label>
<input type="password" x-model="newUser.password" placeholder="••••••••" class="form-input"
required>
</div>
<div class="form-group">
<label class="form-label">الصلاحية</label>
<select x-model="newUser.role" class="form-input" required>
<option value="accountant">محاسب</option>
<option value="viewer">مشاهد فقط</option>
<option x-show="user?.role === 'super_admin'" value="admin">مدير مكتب</option>
</select>
</div>
<template x-if="user?.role === 'super_admin'">
<div class="form-group">
<label class="form-label">المكتب المحاسبي</label>
<select x-model="newUser.tenant_id" class="form-input" required>
<option value=""> اختر المكتب </option>
<template x-for="t in tenants" :key="t.id">
<option :value="t.id" x-text="t.name"></option>
</template>
</select>
</div>
</template>
</div>
<div class="modal-divider"></div>
<div class="modal-footer">
<button type="submit" class="btn btn-navy" :disabled="isBusy" style="flex:1;">
<span x-show="!isBusy">💾 حفظ المستخدم</span>
<span x-show="isBusy"> جاري الحفظ...</span>
</button>
<button type="button" @click="showAddUserModal = false" class="btn btn-ghost">إلغاء</button>
</div>
</form>
</div>
</div>
<!-- ── ADD COMPANY MODAL ────────────────────────────── -->
<div x-show="showAddCompanyModal" x-cloak class="modal-backdrop">
<div class="modal-box">
<div class="modal-head">
<div class="modal-head-icon navy">🏭</div>
<div style="flex:1;">
<div class="modal-title">إضافة شركة جديدة</div>
<div class="modal-subtitle">أدخل بيانات الشركة الرسمية</div>
</div>
<button @click="showAddCompanyModal = false" class="modal-close-btn"></button>
</div>
<div class="modal-divider"></div>
<form @submit.prevent="createCompany">
<div class="modal-body" style="display:flex; flex-direction:column; gap:14px;">
<div class="form-group">
<label class="form-label">اسم الشركة</label>
<input type="text" x-model="newCompany.name" placeholder="الاسم الكامل بالعربي"
class="form-input" required>
</div>
<div class="form-group">
<label class="form-label">الرقم الضريبي (TIN)</label>
<input type="text" x-model="newCompany.tax_identification_number"
placeholder="أدخل رقم التسجيل الضريبي" class="form-input mono" required>
</div>
<div class="form-group">
<label class="form-label">رقم السجل التجاري <span
class="form-label-sub">(اختياري)</span></label>
<input type="text" x-model="newCompany.commercial_registration_number"
placeholder="رقم السجل التجاري" class="form-input mono">
</div>
<div class="form-group">
<label class="form-label">العنوان <span class="form-label-sub">(اختياري)</span></label>
<input type="text" x-model="newCompany.address" placeholder="عنوان الشركة" class="form-input">
</div>
<template x-if="user?.role === 'super_admin'">
<div class="form-group">
<label class="form-label">المكتب المحاسبي المسؤول</label>
<select x-model="newCompany.tenant_id" class="form-input" required>
<option value=""> اختر المكتب </option>
<template x-for="t in tenants" :key="t.id">
<option :value="t.id" x-text="t.name"></option>
</template>
</select>
</div>
</template>
</div>
<div class="modal-divider"></div>
<div class="modal-footer">
<button type="submit" class="btn btn-navy" :disabled="isBusy" style="flex:1;">
<span x-show="!isBusy">🏭 إضافة الشركة</span>
<span x-show="isBusy"> جاري الإضافة...</span>
</button>
<button type="button" @click="showAddCompanyModal = false" class="btn btn-ghost">إلغاء</button>
</div>
</form>
</div>
</div>
<!-- ── JOFOTARA CONNECT MODAL ───────────────────────── -->
<div x-show="showConnectModal" x-cloak class="modal-backdrop">
<div class="modal-box">
<div class="modal-head">
<div class="modal-head-icon teal">🔗</div>
<div style="flex:1;">
<div class="modal-title">ربط نظام الفوترة الحكومي</div>
<div class="modal-subtitle" x-text="'الشركة: ' + currentCompany?.name"></div>
</div>
<button @click="showConnectModal = false" class="modal-close-btn"></button>
</div>
<div class="modal-divider"></div>
<form @submit.prevent="connectJoFotara">
<div class="modal-body" style="display:flex; flex-direction:column; gap:14px;">
<div
style="background:var(--teal-subtle); border:1px solid rgba(4,120,87,0.2); border-radius:10px; padding:12px 14px; font-size:13px; color:var(--teal);">
هذه البيانات تُستخرج من بوابة JoFotara الحكومية لربط الفوترة الإلكترونية
</div>
<div class="form-group">
<label class="form-label">Client ID</label>
<input type="text" x-model="connectData.client_id" placeholder="أدخل Client ID"
class="form-input mono" required>
</div>
<div class="form-group">
<label class="form-label">Secret Key</label>
<input type="password" x-model="connectData.secret_key" placeholder="أدخل Secret Key"
class="form-input mono" required>
</div>
<div class="form-group">
<label class="form-label">تسلسل مصدر الدخل <span class="form-label-sub">(مثال: 1)</span></label>
<input type="text" x-model="connectData.income_source_sequence" placeholder="1"
class="form-input mono">
</div>
</div>
<div class="modal-divider"></div>
<div class="modal-footer">
<button type="submit" class="btn btn-teal" :disabled="isBusy" style="flex:1;">
<span x-show="!isBusy">🔗 حفظ وتفعيل الربط</span>
<span x-show="isBusy"> جاري التفعيل...</span>
</button>
<button type="button" @click="showConnectModal = false" class="btn btn-ghost">إلغاء</button>
</div>
</form>
</div>
</div>
<!-- ── UPLOAD INVOICE MODAL ─────────────────────────── -->
<div x-show="showUploadModal" x-cloak class="modal-backdrop">
<div class="modal-box">
<div class="modal-head">
<div class="modal-head-icon teal">📤</div>
<div style="flex:1;">
<div class="modal-title">رفع فاتورة جديدة</div>
<div class="modal-subtitle">سيتم تحليلها آلياً بالذكاء الاصطناعي</div>
</div>
<button @click="showUploadModal = false" class="modal-close-btn"></button>
</div>
<div class="modal-divider"></div>
<form @submit.prevent="uploadInvoice">
<div class="modal-body" style="display:flex; flex-direction:column; gap:14px;">
<div class="form-group">
<label class="form-label">اختر الشركة</label>
<select x-model="uploadData.company_id" class="form-input" required>
<option value=""> يرجى اختيار الشركة </option>
<template x-for="c in companies" :key="c.id">
<option :value="c.id" x-text="c.name"></option>
</template>
</select>
</div>
<div class="form-group">
<label class="form-label">ملف الفاتورة</label>
<div style="font-size:12px; color:var(--text-3); margin-bottom:6px;">مدعوم: صور (JPG, PNG) أو
ملفات PDF</div>
<input type="file" @change="selectedFile = $event.target.files[0]" class="form-input"
style="padding:8px;" required>
</div>
</div>
<div class="modal-divider"></div>
<div class="modal-footer">
<button type="submit" class="btn btn-teal" :disabled="isUploading" style="flex:1;">
<span x-show="!isUploading">📤 رفع وتحليل</span>
<span x-show="isUploading"> جاري التحليل والاستخراج...</span>
</button>
<button type="button" @click="showUploadModal = false" class="btn btn-ghost">إلغاء</button>
</div>
</form>
</div>
</div>
<!-- ── VIEW INVOICE MODAL ───────────────────────────── -->
<div x-show="showViewModal" x-cloak class="modal-backdrop" @click.self="showViewModal = false">
<div
style="background:white; border-radius:20px; box-shadow:var(--shadow-lg); width:100%; max-width:900px; height:88vh; display:flex; overflow:hidden;">
<!-- Document Preview -->
<div
style="flex:1; background:#f0f4f8; border-left:1px solid var(--border); position:relative; overflow:hidden;">
<div style="position:absolute; top:12px; right:12px; z-index:10;">
<span class="badge badge-navy">معاينة الملف</span>
</div>
<template x-if="currentInvoice?.file_url">
<iframe :src="currentInvoice.file_url + '&token=' + token()"
style="width:100%; height:100%; border:0;"></iframe>
</template>
<div x-show="!currentInvoice?.file_url"
style="position:absolute; inset:0; display:flex; flex-direction:column; align-items:center; justify-content:center; gap:12px; color:var(--text-3);">
<span style="font-size:48px; opacity:0.3;">📄</span>
<p style="font-size:14px;">لا يوجد ملف مرفق</p>
</div>
</div>
<!-- Invoice Data Panel -->
<div style="width:340px; flex-shrink:0; display:flex; flex-direction:column; overflow:hidden;">
<!-- Header -->
<div
style="padding:20px 20px 16px; border-bottom:1px solid var(--border); display:flex; align-items:center; justify-content:space-between;">
<div>
<div style="font-size:16px; font-weight:700; color:var(--text-1);">تفاصيل الفاتورة</div>
<span class="badge" style="margin-top:4px;"
:class="currentInvoice?.status==='extracted' ? 'badge-blue' : (currentInvoice?.status==='approved' ? 'badge-teal' : 'badge-gray')"
x-text="currentInvoice?.status === 'approved' ? '✓ مدققة' : (currentInvoice?.status === 'extracted' ? 'جاهزة للتدقيق' : currentInvoice?.status)">
</span>
</div>
<button @click="showViewModal = false" class="modal-close-btn"></button>
</div>
<!-- Validation Warnings Banner -->
<div x-show="currentInvoice?.validation_warnings?.length > 0"
style="background:#fffbeb; border-bottom:1px solid #fde68a; padding:12px 16px;">
<div style="display:flex; gap:10px; align-items:flex-start;">
<span style="font-size:18px;">⚠️</span>
<div>
<div style="font-weight:700; color:#92400e; font-size:13px; margin-bottom:4px;">تنبيهات المدقق الذكي:</div>
<ul style="margin:0; padding:0; list-style:none; display:flex; flex-direction:column; gap:4px;">
<template x-for="w in currentInvoice.validation_warnings">
<li style="font-size:12px; color:#b45309; display:flex; gap:6px;">
<span></span>
<span x-text="w"></span>
</li>
</template>
</ul>
</div>
</div>
</div>
<!-- Fields -->
<div style="flex:1; overflow-y:auto; padding:16px; display:flex; flex-direction:column; gap:10px;">
<div class="invoice-field-card">
<div class="invoice-field-label">المورد (البائع)</div>
<div class="invoice-field-value" x-text="currentInvoice?.supplier_name || 'غير متوفر'"></div>
<div style="font-size:12px; color:var(--text-3); font-family:'IBM Plex Mono',monospace; margin-top:4px;"
x-text="'TIN: ' + (currentInvoice?.supplier_tin || '—')"></div>
</div>
<div class="invoice-field-card">
<div class="invoice-field-label">رقم الفاتورة والتاريخ</div>
<div class="invoice-field-value" x-text="currentInvoice?.invoice_number || '—'"></div>
<div style="font-size:13px; color:var(--text-2); font-family:'IBM Plex Mono',monospace; margin-top:3px;"
x-text="currentInvoice?.invoice_date || '—'"></div>
</div>
<div class="invoice-field-card"
style="background:var(--teal-subtle); border-color:rgba(4,120,87,0.2);">
<div class="invoice-field-label" style="color:var(--teal);">المجموع الكلي</div>
<div style="font-size:26px; font-weight:700; color:var(--teal); font-family:'El Messiri',sans-serif;"
x-text="parseFloat(currentInvoice?.grand_total || 0).toLocaleString() + ' JOD'"></div>
<div style="font-size:12px; color:var(--amber); margin-top:4px; font-family:'IBM Plex Mono',monospace;"
x-text="'الضريبة: ' + parseFloat(currentInvoice?.tax_amount || 0).toLocaleString() + ' JOD'">
</div>
</div>
<!-- Items Table -->
<div x-show="currentInvoice?.items?.length > 0"
style="border:1px solid var(--border); border-radius:10px; overflow:hidden;">
<div
style="padding:8px 12px; background:#f8fafc; font-size:11px; font-weight:700; color:var(--text-3); text-transform:uppercase; letter-spacing:0.06em;">
بنود الفاتورة</div>
<table style="width:100%; border-collapse:collapse; font-size:12px;">
<thead>
<tr>
<th
style="padding:8px 12px; text-align:right; color:var(--text-3); font-size:11px; border-bottom:1px solid var(--border);">
البند</th>
<th
style="padding:8px 12px; text-align:center; color:var(--text-3); font-size:11px; border-bottom:1px solid var(--border);">
الكمية</th>
<th
style="padding:8px 12px; text-align:left; color:var(--text-3); font-size:11px; border-bottom:1px solid var(--border);">
السعر</th>
</tr>
</thead>
<tbody>
<template x-for="item in currentInvoice?.items" :key="item.id">
<tr style="border-bottom:1px solid #f0f4f8;">
<td style="padding:8px 12px; color:var(--text-2);" x-text="item.description">
</td>
<td style="padding:8px 12px; text-align:center; color:var(--text-3); font-family:'IBM Plex Mono',monospace;"
x-text="item.quantity"></td>
<td style="padding:8px 12px; text-align:left; color:var(--teal); font-family:'IBM Plex Mono',monospace;"
x-text="item.unit_price"></td>
</tr>
</template>
</tbody>
</table>
</div>
<!-- QR Code -->
<div x-show="currentInvoice?.jofotara?.qr_image_uri || currentInvoice?.qr_code"
style="background:white; border:1px solid var(--border); border-radius:12px; padding:16px; display:flex; flex-direction:column; align-items:center; gap:8px;">
<div
style="font-size:11px; font-weight:700; color:var(--text-3); text-transform:uppercase; letter-spacing:0.07em;">
رمز QR الضريبي</div>
<img :src="getQrSrc(currentInvoice)" style="width:140px; height:140px; object-fit:contain;"
alt="QR Code">
</div>
</div>
<!-- Actions -->
<div
style="padding:14px 16px; border-top:1px solid var(--border); display:flex; flex-direction:column; gap:8px;">
<!-- Warnings Acknowledgement -->
<div x-show="currentInvoice?.status === 'extracted' && currentInvoice?.validation_warnings?.length > 0"
style="background:#f8fafc; border:1px solid var(--border); border-radius:10px; padding:10px; margin-bottom:4px;">
<label style="display:flex; gap:10px; align-items:center; cursor:pointer; user-select:none;">
<input type="checkbox" x-model="acknowledgedWarnings" style="width:16px; height:16px; accent-color:var(--teal);">
<span style="font-size:12px; font-weight:600; color:var(--text-2);">لقد راجعت التنبيهات وأتحمل مسؤولية الاعتماد</span>
</label>
</div>
<button x-show="currentInvoice?.status === 'extracted'" @click="approveInvoice" class="btn btn-teal"
:disabled="isBusy || (currentInvoice?.validation_warnings?.length > 0 && !acknowledgedWarnings)"
style="width:100%; justify-content:center;">
<span x-show="!isBusy">✔️ تدقيق واعتماد</span>
<span x-show="isBusy"> جاري التدقيق...</span>
</button>
<button x-show="currentInvoice?.status === 'extracted'"
style="width:100%; background:var(--red-subtle); color:var(--red); border:none; padding:10px; border-radius:10px; font-family:inherit; font-size:14px; font-weight:600; cursor:pointer; transition:all 0.18s;"
onmouseover="this.style.background='#fecaca'"
onmouseout="this.style.background='var(--red-subtle)'"> رفض الفاتورة</button>
<div x-show="currentInvoice?.status === 'approved'"
style="width:100%; background:var(--teal-subtle); color:var(--teal); border:1px solid rgba(4,120,87,0.2); padding:10px; border-radius:10px; font-size:14px; font-weight:700; text-align:center;">
مدققة ومعتمدة
</div>
</div>
</div>
</div>
</div>
<!-- ── EDIT TENANT MODAL ────────────────────────────── -->
<div x-show="showEditTenantModal" x-cloak class="modal-backdrop">
<div class="modal-box" style="max-width:540px;">
<div class="modal-head">
<div class="modal-head-icon navy">⚙️</div>
<div style="flex:1;">
<div class="modal-title">تعديل بيانات المكتب</div>
<div class="modal-subtitle" x-text="currentTenant.name"></div>
</div>
<button @click="showEditTenantModal = false" class="modal-close-btn"></button>
</div>
<div class="modal-divider"></div>
<form @submit.prevent="updateTenant">
<div class="modal-body" style="display:flex; flex-direction:column; gap:14px;">
<div class="form-group">
<label class="form-label">اسم المكتب</label>
<input type="text" x-model="currentTenant.name" class="form-input" required>
</div>
<div style="display:grid; grid-template-columns:1fr 1fr; gap:12px;">
<div class="form-group">
<label class="form-label">البريد الرسمي</label>
<input type="email" x-model="currentTenant.email" class="form-input" required>
</div>
<div class="form-group">
<label class="form-label">رقم الهاتف</label>
<input type="text" x-model="currentTenant.phone" class="form-input">
</div>
</div>
<div class="form-group">
<label class="form-label">حالة المكتب</label>
<select x-model="currentTenant.status" class="form-input">
<option value="active"> نشط (Active)</option>
<option value="suspended">🔴 معلق (Suspended)</option>
<option value="trial">🟡 تجريبي (Trial)</option>
</select>
</div>
</div>
<div class="modal-divider"></div>
<div class="modal-footer">
<button type="submit" class="btn btn-navy" :disabled="isBusy" style="flex:1;">
<span x-show="!isBusy">💾 حفظ التعديلات</span>
<span x-show="isBusy"> جاري الحفظ...</span>
</button>
<button type="button" @click="showEditTenantModal = false" class="btn btn-ghost">إلغاء</button>
</div>
</form>
</div>
</div>
<!-- ── ADD TENANT MODAL ─────────────────────────────── -->
<div x-show="showAddTenantModal" x-cloak class="modal-backdrop">
<div class="modal-box modal-box-lg">
<div class="modal-head">
<div class="modal-head-icon gold">🏗️</div>
<div style="flex:1;">
<div class="modal-title">إضافة مكتب محاسبي جديد</div>
<div class="modal-subtitle">سيتم إنشاء حساب المدير المسؤول تلقائياً</div>
</div>
<button @click="showAddTenantModal = false" class="modal-close-btn"></button>
</div>
<div class="modal-divider"></div>
<form @submit.prevent="createTenant">
<div class="modal-body" style="display:flex; flex-direction:column; gap:18px;">
<!-- Office Info -->
<div>
<div class="form-section-title">
<span>🏢</span> بيانات المكتب المحاسبي
</div>
<div style="display:grid; grid-template-columns:1fr 1fr; gap:12px; margin-top:14px;">
<div class="form-group" style="grid-column:1/-1;">
<label class="form-label">اسم المكتب</label>
<input type="text" x-model="newTenant.name" placeholder="اسم المكتب المحاسبي"
class="form-input" required>
</div>
<div class="form-group">
<label class="form-label">البريد الرسمي للمكتب</label>
<input type="email" x-model="newTenant.email" placeholder="info@office.com"
class="form-input" required>
</div>
<div class="form-group">
<label class="form-label">رقم الهاتف <span
class="form-label-sub">(اختياري)</span></label>
<input type="text" x-model="newTenant.phone" placeholder="+962 7x xxx xxxx"
class="form-input">
</div>
</div>
</div>
<!-- Manager Info -->
<div>
<div class="form-section-title">
<span>👤</span> بيانات المدير المسؤول
</div>
<div style="display:grid; grid-template-columns:1fr 1fr; gap:12px; margin-top:14px;">
<div class="form-group" style="grid-column:1/-1;">
<label class="form-label">الاسم الكامل للمدير</label>
<input type="text" x-model="newTenant.manager_name" placeholder="الاسم الكامل"
class="form-input" required>
</div>
<div class="form-group">
<label class="form-label">بريد المدير الإلكتروني</label>
<input type="email" x-model="newTenant.manager_email" placeholder="manager@office.com"
class="form-input" required>
</div>
<div class="form-group">
<label class="form-label">كلمة مرور الدخول</label>
<input type="password" x-model="newTenant.manager_password" placeholder="••••••••"
class="form-input" required>
</div>
</div>
</div>
</div>
<div class="modal-divider"></div>
<div class="modal-footer">
<button type="submit" class="btn btn-navy" :disabled="isBusy" style="flex:1;">
<span x-show="!isBusy">🏗️ إنشاء المكتب والمدير</span>
<span x-show="isBusy"> جاري الإنشاء...</span>
</button>
<button type="button" @click="showAddTenantModal = false" class="btn btn-ghost">إلغاء</button>
</div>
</form>
</div>
</div>
<!-- ════════════════════════════════════════════════════════
ALPINE.JS LOGIC UNCHANGED
════════════════════════════════════════════════════════ -->
<script>
document.addEventListener('alpine:init', () => {
Alpine.data('app', () => ({
user: JSON.parse(localStorage.getItem('user')),
page: 'dashboard',
users: [], companies: [], invoices: [], tenants: [], subscription: null, plans: [],
stats: { total: 0, pending: 0, approved: 0 },
showAddUserModal: false, showAddCompanyModal: false, showConnectModal: false,
showUploadModal: false, showViewModal: false, showCompanyStatsModal: false,
showAddTenantModal: false, showEditTenantModal: false, showTenantStatsModal: false,
acknowledgedWarnings: false,
isBusy: false, globalError: '',
newUser: { name: '', email: '', password: '', role: 'accountant', tenant_id: '' },
newCompany: { name: '', tax_identification_number: '', commercial_registration_number: '', address: '', tenant_id: '' },
newTenant: { name: '', email: '', phone: '', manager_name: '', manager_email: '', manager_password: '' },
connectData: { client_id: '', secret_key: '', income_source_sequence: '1' },
uploadData: { company_id: '' },
currentCompany: null, currentInvoice: null, companyStats: null,
currentTenant: { name: '', email: '', phone: '', status: '' }, tenantStats: null,
init() {
if (!this.user) { window.location.href = '/login.php'; return; }
this.loadAll();
},
setPage(p) { this.page = p; this.loadAll(); },
title() { return { dashboard: 'الرئيسية', users: 'فريق العمل', companies: 'الشركات', invoices: 'إدارة الفواتير', tenants: 'المكاتب المحاسبية', subscription: 'إدارة الاشتراك' }[this.page] || ''; },
subtitle() { return { dashboard: 'نظرة شاملة على نشاط النظام', users: 'إدارة المستخدمين والصلاحيات', companies: 'إدارة الشركات والربط بالفوترة الحكومية', invoices: 'رفع ومعالجة الفواتير الضريبية', tenants: 'إدارة المكاتب المحاسبية المشتركة', subscription: 'تفاصيل باقتك الحالية واستهلاك الموارد' }[this.page] || ''; },
token() { return localStorage.getItem('access_token'); },
showError(msg) { this.globalError = msg; setTimeout(() => this.globalError = '', 8000); },
async apiRequest(route, method = 'GET', body = null) {
try {
const options = {
method,
headers: { 'Authorization': 'Bearer ' + this.token(), 'Content-Type': 'application/json' }
};
if (body) options.body = JSON.stringify(body);
const res = await fetch('/index.php?route=' + route, options);
const json = await res.json();
if (res.status === 401) { localStorage.clear(); window.location.href = '/login.php'; return null; }
return json.success ? json.data : (this.showError(json.message), null);
} catch (e) { this.showError('فشل الاتصال بالخادم'); return null; }
},
async loadAll() {
const statsData = await this.apiRequest('v1/dashboard/stats');
this.stats = statsData ? {
total: statsData.invoices?.total || 0,
pending: statsData.invoices?.pending || 0,
approved: statsData.invoices?.approved || 0,
users: statsData.users || statsData.total_users || 0,
companies: statsData.companies || 0,
tenants: statsData.tenants || 0
} : { total: 0, pending: 0, approved: 0 };
this.companies = await this.apiRequest('v1/companies') || [];
this.subscription = await this.apiRequest('v1/subscriptions/current');
if (this.page === 'users') this.users = await this.apiRequest('v1/users') || [];
if (this.page === 'invoices') this.invoices = await this.apiRequest('v1/invoices') || [];
if (this.page === 'subscription') this.plans = await this.apiRequest('v1/subscriptions/plans') || [];
if (this.user.role === 'super_admin') this.tenants = await this.apiRequest('v1/tenants') || [];
},
//
getQrSrc(inv) {
if (!inv) return '';
if (inv.jofotara?.qr_image_uri) return inv.jofotara.qr_image_uri;
if (inv.qr_code) {
if (inv.qr_code.startsWith('data:')) return inv.qr_code;
try {
const qr = new QRious({
value: inv.qr_code,
size: 250
});
return qr.toDataURL();
} catch (e) { return ''; }
}
return '';
},
async showCompanyStats(companyId) {
this.isBusy = true;
const res = await this.apiRequest('v1/companies/stats&company_id=' + companyId);
if (res) {
this.companyStats = res;
this.showCompanyStatsModal = true;
}
this.isBusy = false;
},
async showTenantStats(tenant) {
this.isBusy = true;
const res = await this.apiRequest('v1/tenants/stats&tenant_id=' + tenant.id);
if (res) {
this.tenantStats = res;
this.tenantStats.tenant = tenant;
this.showTenantStatsModal = true;
}
this.isBusy = false;
},
async viewInvoice(id) {
this.isBusy = true;
const res = await this.apiRequest('v1/invoices/view&id=' + id);
if (res) {
this.currentInvoice = res;
this.showViewModal = true;
if (!this.currentInvoice.jofotara?.qr_image_uri && !this.currentInvoice.qr_code && this.currentInvoice.status === 'approved') {
try {
const qr = new QRious({
value: 'Invoice: ' + this.currentInvoice.invoice_number + '\nSeller: ' + this.currentInvoice.supplier_name + '\nTotal: ' + this.currentInvoice.grand_total,
size: 250
});
this.currentInvoice.qr_code = qr.toDataURL();
} catch (e) { }
}
}
this.isBusy = false;
},
async createUser() {
this.isBusy = true;
const res = await this.apiRequest('v1/users/create', 'POST', this.newUser);
if (res) { this.showAddUserModal = false; this.loadAll(); alert('تم إضافة المستخدم بنجاح'); }
this.isBusy = false;
},
async createCompany() {
this.isBusy = true;
const res = await this.apiRequest('v1/companies/create', 'POST', this.newCompany);
if (res) { this.showAddCompanyModal = false; this.loadAll(); alert('تم إضافة الشركة بنجاح'); }
this.isBusy = false;
},
async createTenant() {
this.isBusy = true;
const res = await this.apiRequest('v1/tenants/create', 'POST', this.newTenant);
if (res) {
this.showAddTenantModal = false;
this.newTenant = { name: '', email: '', phone: '', manager_name: '', manager_email: '', manager_password: '' };
this.loadAll();
alert('تم إضافة المكتب المحاسبي والمدير المسؤول بنجاح');
}
this.isBusy = false;
},
openEditTenantModal(t) {
this.currentTenant = JSON.parse(JSON.stringify(t));
this.showEditTenantModal = true;
},
async updateTenant() {
this.isBusy = true;
const res = await this.apiRequest('v1/tenants/update', 'POST', this.currentTenant);
if (res) {
this.showEditTenantModal = false;
this.loadAll();
alert('تم تحديث بيانات المكتب بنجاح');
}
this.isBusy = false;
},
openConnectModal(company) {
this.currentCompany = company;
this.connectData.client_id = '';
this.connectData.secret_key = '';
this.showConnectModal = true;
},
async connectJoFotara() {
this.isBusy = true;
const res = await this.apiRequest('v1/companies/connect', 'POST', {
id: this.currentCompany.id,
...this.connectData
});
if (res) { this.showConnectModal = false; this.loadAll(); alert('تم تفعيل الربط الضريبي بنجاح'); }
this.isBusy = false;
},
selectedFile: null,
isUploading: false,
async uploadInvoice() {
if (!this.selectedFile) return alert('الرجاء اختيار ملف');
if (!this.uploadData.company_id) return alert('الرجاء اختيار الشركة');
this.isUploading = true;
const formData = new FormData();
formData.append('company_id', this.uploadData.company_id);
formData.append('invoice', this.selectedFile);
try {
const res = await fetch('/index.php?route=v1/invoices/upload', {
method: 'POST',
headers: { 'Authorization': 'Bearer ' + this.token() },
body: formData
});
const json = await res.json();
this.isUploading = false;
if (json.success) {
this.showUploadModal = false;
this.selectedFile = null;
await this.loadAll();
this.viewInvoice(json.data.id);
} else {
this.showError(json.message);
}
} catch (e) {
this.isUploading = false;
this.showError('فشل الاتصال بالخادم أثناء الرفع');
}
},
async approveInvoice() {
if (!this.currentInvoice || this.isBusy) return;
this.isBusy = true;
try {
const res = await fetch('/index.php?route=v1/invoices/approve', {
method: 'POST',
headers: { 'Authorization': 'Bearer ' + this.token(), 'Content-Type': 'application/json' },
body: JSON.stringify({ id: this.currentInvoice.id })
});
const json = await res.json();
this.isBusy = false;
if (json.success) {
alert('تم اعتماد الفاتورة بنجاح!');
this.showViewModal = false;
this.loadAll();
} else {
this.showError(json.message);
}
} catch (e) {
this.isBusy = false;
this.showError('حدث خطأ أثناء الاعتماد');
}
},
logout() { localStorage.clear(); window.location.href = '/login.php'; }
}));
});
</script>
</body>
</html>