🚀 مُصادَق: تحديث برمجي جديد 2026-05-03 02:22

This commit is contained in:
Hamza-Ayed
2026-05-03 02:22:39 +03:00
parent 355fb45935
commit 623df3f9fa

View File

@@ -56,6 +56,10 @@
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path></svg>
الفواتير المرفوعة
</a>
<a href="#" onclick="navigateTo('users')" id="nav-users" class="nav-link flex items-center gap-3 px-6 py-3 text-slate-400 hover:text-white transition-colors">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4.354a4 4 0 110 5.292M15 21H3v-1a6 6 0 0112 0v1zm0 0h6v-1a6 6 0 00-9-5.197M13 7a4 4 0 11-8 0 4 4 0 018 0z"></path></svg>
المستخدمين
</a>
</nav>
<div class="p-6 border-t border-white/10">
<button onclick="logout()" class="flex items-center gap-3 text-red-400 hover:text-red-300 transition-colors w-full">
@@ -160,6 +164,30 @@
if (page === 'dashboard') await renderDashboard();
else if (page === 'companies') await renderCompanies();
else if (page === 'invoices') await renderInvoices();
else if (page === 'users') await renderUsers();
}
// ── Users View ───────────────────────────────────────────
async function renderUsers() {
document.getElementById('page-title').textContent = 'إدارة المستخدمين';
try {
// We'll build the API for this later, for now just show a placeholder
contentDiv.innerHTML = `
<div class="flex justify-between items-center mb-6">
<p class="text-slate-400">لوحة تحكم السوبر يوزر لإدارة المحاسبين والمدراء وربطهم بالشركات.</p>
<button class="bg-primary hover:bg-primary-dark text-white px-6 py-2 rounded-xl transition-all shadow-lg flex items-center gap-2 font-bold">
+ إضافة مستخدم
</button>
</div>
<div class="glass-panel p-12 rounded-3xl text-center">
<svg class="w-16 h-16 text-slate-600 mx-auto mb-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4.354a4 4 0 110 5.292M15 21H3v-1a6 6 0 0112 0v1zm0 0h6v-1a6 6 0 00-9-5.197M13 7a4 4 0 11-8 0 4 4 0 018 0z"></path></svg>
<h3 class="text-xl font-bold mb-2">قريباً...</h3>
<p class="text-slate-500">جاري برمجة واجهات ربط المحاسبين بالشركات وتحديد الصلاحيات الخاصة بهم.</p>
</div>
`;
} catch(err) {
contentDiv.innerHTML = `<div class="text-red-400">خطأ في جلب المستخدمين</div>`;
}
}
// ── Login View ───────────────────────────────────────────
@@ -284,16 +312,16 @@
html += `
<div class="glass-panel p-6 rounded-3xl flex flex-col h-full border-t-4 border-t-primary">
<h3 class="text-xl font-bold mb-1">${company.name}</h3>
<p class="text-slate-400 text-sm font-mono mb-4">الرقم الضريبي: ${company.tax_number}</p>
<p class="text-slate-400 text-sm font-mono mb-4">الرقم الضريبي: ${company.tax_identification_number || company.tax_number || 'غير متوفر'}</p>
<div class="mt-auto space-y-3">
<div class="flex items-center justify-between text-sm p-3 bg-black/20 rounded-xl border border-white/5">
<span class="text-slate-400">بوابة JoFotara</span>
${company.jofotara_client_id
${company.jofotara_client_id_encrypted
? '<span class="text-primary font-bold">مربوط ✓</span>'
: '<span class="text-yellow-400 font-bold">غير مربوط ⚠</span>'}
</div>
<button onclick="showJoFotaraModal(${company.id})" class="w-full py-2 bg-white/5 hover:bg-white/10 rounded-xl text-sm transition border border-white/10">إعدادات الربط</button>
<button onclick="showJoFotaraModal('${company.id}')" class="w-full py-2 bg-white/5 hover:bg-white/10 rounded-xl text-sm transition border border-white/10">إعدادات الربط</button>
</div>
</div>
`;
@@ -450,50 +478,65 @@
};
}
function showUploadInvoiceModal() {
const modals = document.getElementById('modals');
modals.innerHTML = `
<div class="fixed inset-0 bg-black/60 backdrop-blur-sm z-[100] flex items-center justify-center" id="invoice-modal">
<div class="glass-panel p-8 rounded-3xl w-full max-w-md border border-white/10 shadow-2xl">
<h3 class="text-2xl font-bold mb-6">رفع فاتورة للتدقيق</h3>
<form id="upload-invoice-form" class="space-y-4" enctype="multipart/form-data">
<input type="text" id="inv-comp-id" class="w-full bg-black/20 border border-white/10 rounded-xl px-4 py-3 text-white focus:border-primary outline-none" placeholder="معرف الشركة (Company ID)" required>
<div class="p-4 border-2 border-dashed border-white/20 rounded-xl bg-black/10 text-center">
<p class="text-sm text-slate-400 mb-2">اختر ملف الفاتورة (JSON/XML/PDF)</p>
<input type="file" id="inv-file" class="text-sm w-full" required>
</div>
<div class="flex gap-3 mt-6">
<button type="button" onclick="document.getElementById('invoice-modal').remove()" class="flex-1 py-3 bg-white/5 hover:bg-white/10 rounded-xl transition">إلغاء</button>
<button type="submit" class="flex-1 py-3 bg-primary hover:bg-primary-dark text-white font-bold rounded-xl shadow-lg transition">تحقق ورفع</button>
</div>
</form>
async function showUploadInvoiceModal() {
try {
// Fetch companies to populate the select dropdown
const res = await API.get('/companies');
const companies = res.data;
let optionsHtml = '<option value="" disabled selected>-- اختر الشركة --</option>';
companies.forEach(c => {
optionsHtml += \`<option value="\${c.id}">\${c.name} (\${c.tax_identification_number || ''})</option>\`;
});
const modals = document.getElementById('modals');
modals.innerHTML = \`
<div class="fixed inset-0 bg-black/60 backdrop-blur-sm z-[100] flex items-center justify-center" id="invoice-modal">
<div class="glass-panel p-8 rounded-3xl w-full max-w-md border border-white/10 shadow-2xl">
<h3 class="text-2xl font-bold mb-6">رفع فاتورة للتدقيق</h3>
<form id="upload-invoice-form" class="space-y-4" enctype="multipart/form-data">
<select id="inv-comp-id" class="w-full bg-black/20 border border-white/10 rounded-xl px-4 py-3 text-white focus:border-primary outline-none" required>
\${optionsHtml}
</select>
<div class="p-4 border-2 border-dashed border-white/20 rounded-xl bg-black/10 text-center">
<p class="text-sm text-slate-400 mb-2">اختر ملف الفاتورة (JSON/XML/PDF)</p>
<input type="file" id="inv-file" class="text-sm w-full" required>
</div>
<div class="flex gap-3 mt-6">
<button type="button" onclick="document.getElementById('invoice-modal').remove()" class="flex-1 py-3 bg-white/5 hover:bg-white/10 rounded-xl transition">إلغاء</button>
<button type="submit" class="flex-1 py-3 bg-primary hover:bg-primary-dark text-white font-bold rounded-xl shadow-lg transition">تحقق ورفع</button>
</div>
</form>
</div>
</div>
</div>
`;
\`;
document.getElementById('upload-invoice-form').onsubmit = async (e) => {
e.preventDefault();
try {
const companyId = document.getElementById('inv-comp-id').value;
const fileInput = document.getElementById('inv-file');
const formData = new FormData();
formData.append('company_id', companyId);
formData.append('invoice', fileInput.files[0]);
const btn = e.target.querySelector('button[type="submit"]');
btn.textContent = 'جاري التحقق...';
btn.disabled = true;
document.getElementById('upload-invoice-form').onsubmit = async (e) => {
e.preventDefault();
try {
const companyId = document.getElementById('inv-comp-id').value;
const fileInput = document.getElementById('inv-file');
const formData = new FormData();
formData.append('company_id', companyId);
formData.append('invoice', fileInput.files[0]);
const btn = e.target.querySelector('button[type="submit"]');
btn.textContent = 'جاري التحقق...';
btn.disabled = true;
await API.upload('/invoices/upload', formData);
document.getElementById('invoice-modal').remove();
renderInvoices();
} catch(err) {
alert(err.error?.message_ar || 'صيغة البيانات غير صحيحة أو حدث خطأ ضريبي.');
e.target.querySelector('button[type="submit"]').textContent = 'تحقق ورفع';
e.target.querySelector('button[type="submit"]').disabled = false;
}
};
await API.upload('/invoices/upload', formData);
document.getElementById('invoice-modal').remove();
renderInvoices();
} catch(err) {
alert(err.error?.message_ar || 'صيغة البيانات غير صحيحة أو حدث خطأ ضريبي.');
e.target.querySelector('button[type="submit"]').textContent = 'تحقق ورفع';
e.target.querySelector('button[type="submit"]').disabled = false;
}
};
} catch(err) {
alert('خطأ في جلب بيانات الشركات المربوطة بك.');
}
}
// ── Init Engine ──────────────────────────────────────────