/** * @fileoverview Unified Wallet UI, Ledger Statement & Points Converter * @module ui/wallet-ui * @description بناء واجهة المحفظة الرقمية الموحدة، كشف الحساب المالي، محول النقاط الفوري، وخزنة الكبسولات الزمنية. */ (global => { 'use strict'; const LEDGER_SALT = global.FritreeAppConstants?.SECURITY_SALTS?.LEDGER_SALT || "FritreeLedgerVerificationSalt_2026_Enterprise_Production_Wallet_SHA256_UltraSeal"; const LedgerState = { activeTab: 'fsj4xyo5el', filterAsset: 'all', filterDirection: 'all', searchQuery: '', dateFrom: '', dateTo: '', isInitialized: false, isClaimingCapsuleLock: false, isSwappingPointsLock: false }; /** * بناء الهيكل البصري لقسم المحفظة الرقمية الموحدة */ const buildWalletLayoutElements = () => { const contentArea = document.getElementById('s7ihkirolg'); if (!contentArea) return false; const sidebar = document.getElementById('bmh59axx92'); if (sidebar && !sidebar.querySelector('[data-target="j2nzw12azj"]')) { const navItem = document.createElement('div'); navItem.className = 'f2rj8bz2yt'; navItem.setAttribute('data-target', 'j2nzw12azj'); navItem.innerHTML = ' المحفظة الموحدة والخزنة'; sidebar.appendChild(navItem); navItem.addEventListener('click', () => { window.location.hash = 'j2nzw12azj'; }); } const host = document.getElementById('fritree-dynamic-panes-host') || contentArea; let pane = document.getElementById('j2nzw12azj'); if (pane) { if (pane.parentElement !== host) { host.appendChild(pane); } return true; } pane = document.createElement('section'); pane.className = 'rjiai07g77'; pane.id = 'j2nzw12azj'; pane.innerHTML = `
المحفظة وإدارة الأرصدة والكبسولات
رصيد الدولار (USD) 0.00 $
نقاط فيسبوك 0 FB
نقاط واتساب 0 WA
الكبسولات المجمدة 0 كبسولة 0.00 $
كشف الحساب والعمليات
تبديل النقاط
تحويل الرصيد
شحن الرصيد
خزنة الكبسولات
إجمالي المعاملات: 0 عملية
تاريخ العملية تفاصيل الحركة نوع الأصل قيمة التغيير التوثيق
لا توجد أي عمليات مالية مسجلة في المحفظة حالياً.
`; host.appendChild(pane); return true; }; /** * ربط التبديل بين علامات تبويب المحفظة */ const bindWalletTabToggles = () => { const walletPanel = document.getElementById('wefkbdgu3v'); if (!walletPanel) return; const tabs = walletPanel.querySelectorAll('.pfe6btieb6 .n9cqm6ze7d[data-wallet-sub]'); const validWalletPaneIds = ['fsj4xyo5el', 'j3cvbn5t2y', 'sq5nufndhg', 'smzzdticgj', 'kflnifnkxu']; tabs.forEach(tab => { tab.addEventListener('click', () => { tabs.forEach(t => t.classList.remove('vn5qn7dmpk')); tab.classList.add('vn5qn7dmpk'); const targetPaneId = tab.getAttribute('data-wallet-sub'); LedgerState.activeTab = targetPaneId; const panes = walletPanel.querySelectorAll('.gitkevh3xv'); panes.forEach(pane => { if (validWalletPaneIds.includes(pane.id)) { pane.style.display = (pane.id === targetPaneId) ? 'block' : 'none'; } }); if (targetPaneId === 'j3cvbn5t2y') { if (global.FritreeWalletExporter && typeof global.FritreeWalletExporter.init === 'function') { global.FritreeWalletExporter.init(); } } else if (targetPaneId === 'sq5nufndhg') { if (global.FritreeWalletRedeemer && typeof global.FritreeWalletRedeemer.init === 'function') { global.FritreeWalletRedeemer.init(); } } else if (targetPaneId === 'kflnifnkxu') { renderConverterUI(); } else if (targetPaneId === 'fsj4xyo5el') { renderLedgerTable(); } else if (targetPaneId === 'smzzdticgj') { renderTimeCapsulesList(); } }); }); }; const signTransactionReceipt = async (txId, amount, type, desc, timestamp) => { const payloadString = `${txId}:${amount}:${type}:${desc}:${timestamp}:${LEDGER_SALT}`; if (global.FritreeCrypto && typeof global.FritreeCrypto.sha256 === 'function') { return await global.FritreeCrypto.sha256(payloadString); } return "tx_sig_fallback_" + txId; }; const verifyTransactionReceipt = async (tx) => { if (!tx || !tx.id || !tx.signature) return false; const computedSignature = await signTransactionReceipt(tx.id, tx.amount, tx.type, tx.desc, tx.date); return computedSignature === tx.signature; }; const auditTransactionHistory = async () => { try { const pointsTransactions = await global.FritreeStorage.get('pointsTransactions', []); if (!Array.isArray(pointsTransactions) || pointsTransactions.length === 0) return true; let changed = false; for (let i = 0; i < pointsTransactions.length; i++) { const tx = pointsTransactions[i]; if (tx.signature) { const isValid = await verifyTransactionReceipt(tx); if (!isValid) { tx.signature = await signTransactionReceipt(tx.id, tx.amount, tx.type, tx.desc, tx.date); changed = true; } } else { tx.signature = await signTransactionReceipt(tx.id, tx.amount, tx.type, tx.desc, tx.date); changed = true; } } if (changed) { await global.FritreeStorage.set('pointsTransactions', pointsTransactions); } return true; } catch (e) { console.error("[مدقق المحفظة] فشل تدقيق توقيع سجل المعاملات المالية:", e); return false; } }; /** * رسم جدول كشف الحساب والعمليات المالية */ const renderLedgerTable = async () => { const tbody = document.getElementById('fcgxo3g6pn'); if (!tbody) return; await auditTransactionHistory(); const pointsTransactions = await global.FritreeStorage.get('pointsTransactions', []); const searchVal = (document.getElementById('hwhpohdf9p')?.value || '').toLowerCase().trim(); const assetFilter = document.getElementById('rwvvh5aw1o')?.value || 'all'; const dirFilter = document.getElementById('ydho523nfo')?.value || 'all'; const dateFrom = document.getElementById('nzekdiqxul')?.value || ''; const dateTo = document.getElementById('blve5jub6v')?.value || ''; let filtered = pointsTransactions.filter(tx => { const matchesSearch = !searchVal || (tx.desc && tx.desc.toLowerCase().includes(searchVal)) || (tx.id && tx.id.toLowerCase().includes(searchVal)) || (tx.amount && String(tx.amount).includes(searchVal)); let matchesAsset = true; if (assetFilter === 'usd') matchesAsset = !tx.type.includes('fb') && !tx.type.includes('wa'); else if (assetFilter === 'fb') matchesAsset = tx.type.includes('fb'); else if (assetFilter === 'wa') matchesAsset = tx.type.includes('wa'); let matchesDir = true; const isAdd = tx.type === 'add' || tx.type === 'add_fb' || tx.type === 'add_wa' || tx.type === 'swap_in'; if (dirFilter === 'inflow') matchesDir = isAdd; else if (dirFilter === 'outflow') matchesDir = !isAdd; let matchesDate = true; if (dateFrom && tx.date) matchesDate = matchesDate && new Date(tx.date) >= new Date(dateFrom); if (dateTo && tx.date) matchesDate = matchesDate && new Date(tx.date) <= new Date(dateTo + 'T23:59:59'); return matchesSearch && matchesAsset && matchesDir && matchesDate; }); const summaryLbl = document.getElementById('kfbbnqp3gb'); if (summaryLbl) { summaryLbl.innerHTML = ` إجمالي المعاملات المطابقة: ${filtered.length.toLocaleString('en-US')} عملية (من أصل ${pointsTransactions.length.toLocaleString('en-US')})`; } tbody.innerHTML = ''; if (filtered.length === 0) { tbody.innerHTML = ` لا توجد أي عمليات مالية مسجلة في المحفظة حالياً. `; return; } const list = [...filtered].reverse(); list.forEach(tx => { const tr = document.createElement('tr'); tr.style.cssText = 'border-bottom: 1px solid var(--border);'; const isAdd = tx.type === 'add' || tx.type === 'add_fb' || tx.type === 'add_wa' || tx.type === 'swap_in'; const typeColor = isAdd ? 'var(--success-hover)' : 'var(--danger)'; const prefix = isAdd ? '+' : '-'; let assetName = 'دولار ($)'; let displayAmt = ''; if (tx.type.includes('fb')) { assetName = 'نقاط FB'; displayAmt = `${parseInt(tx.amount, 10).toLocaleString('en-US')} FB`; } else if (tx.type.includes('wa')) { assetName = 'نقاط WA'; displayAmt = `${parseInt(tx.amount, 10).toLocaleString('en-US')} WA`; } else { displayAmt = `$${parseFloat(tx.amount).toFixed(2)}`; } tr.innerHTML = ` ${new Date(tx.date).toLocaleString('en-US')} ${tx.desc} ${assetName} ${prefix}${displayAmt} `; tbody.appendChild(tr); }); }; /** * رسم قائمة الكبسولات الزمنية */ const renderTimeCapsulesList = async () => { const container = document.getElementById('e8w1onnjl1'); const badgeCount = document.getElementById('f8q8ytlir2'); const sumValLabel = document.getElementById('nhcriyrkc8'); if (!container) return; const capsules = await global.FritreeStorage.get('local_time_capsules', []) || []; if (badgeCount) badgeCount.textContent = `${capsules.length.toLocaleString('en-US')} كبسولة`; let totalUsdValue = 0; capsules.forEach(c => { totalUsdValue += (parseFloat(c.usd) || 0); }); if (sumValLabel) sumValLabel.textContent = totalUsdValue.toFixed(2); container.innerHTML = ''; if (capsules.length === 0) { container.innerHTML = `
لا توجد كبسولات زمنية مجدولة حالياً.
`; return; } const now = Date.now(); capsules.forEach(cap => { const unlockTime = new Date(cap.unlockDate).getTime(); const isUnlocked = now >= unlockTime; const card = document.createElement('div'); card.style.cssText = ` background: var(--bg-card); border: 1px solid var(--border); border-radius: var(--radius-lg); padding: 12px 16px; display: flex; justify-content: space-between; align-items: center; direction: rtl; text-align: right; box-shadow: var(--shadow-xs); box-sizing: border-box; flex-wrap: wrap; gap: 8px; `; card.innerHTML = `
${cap.title || 'كبسولة شحن زمنية'} المبلغ المكتوم: $${parseFloat(cap.usd || 0).toFixed(2)} | FB: ${(cap.fb || 0).toLocaleString('en-US')} | WA: ${(cap.wa || 0).toLocaleString('en-US')} تاريخ الفتح المجدول: ${new Date(cap.unlockDate).toLocaleString('en-US')}
`; const claimBtn = card.querySelector('.dlch9mdf6r'); if (claimBtn && isUnlocked) { claimBtn.onclick = async () => { await claimTimeCapsule(cap.id); }; } container.appendChild(card); }); }; /** * فك واسترداد رصيد كبسولة زمنية */ const claimTimeCapsule = async (capsuleId) => { if (LedgerState.isClaimingCapsuleLock) return; LedgerState.isClaimingCapsuleLock = true; try { let capsules = await global.FritreeStorage.get('local_time_capsules', []) || []; const capIndex = capsules.findIndex(c => c.id === capsuleId); if (capIndex === -1) { alert("خطأ: تعذر العثور على الكبسولة أو تم استردادها سابقاً."); return; } const cap = capsules[capIndex]; const unlockTime = new Date(cap.unlockDate).getTime(); if (Date.now() < unlockTime) { alert("موعد فتح الكبسولة لم يحن بعد!"); return; } const usd = parseFloat(cap.usd) || 0; const fb = parseInt(cap.fb, 10) || 0; const wa = parseInt(cap.wa, 10) || 0; capsules.splice(capIndex, 1); await global.FritreeStorage.set('local_time_capsules', capsules); if (usd > 0) await global.FritreeAppState.addPoints(usd, `فك كبسولة زمنية مجدولة: +$${usd.toFixed(2)}`); if (fb > 0) await global.FritreeAppState.addFbCards(fb, `فك كبسولة زمنية مجدولة: +${fb} FB`); if (wa > 0) await global.FritreeAppState.addWaCards(wa, `فك كبسولة زمنية مجدولة: +${wa} WA`); await global.FritreeAppState.saveAccountData(); if (global.FritreeShellLayout) global.FritreeShellLayout.updatePointsUI(); alert(`تم فك الكبسولة واسترداد الأرصدة بنجاح!\n+$${usd.toFixed(2)} USD | +${fb} FB | +${wa} WA`); await renderTimeCapsulesList(); await renderLedgerTable(); } catch (e) { console.error("[Fritree Capsule Claim] Failed to unlock capsule:", e); alert("حدث خطأ أثناء محاولة استرداد الكبسولة."); } finally { LedgerState.isClaimingCapsuleLock = false; } }; /** * تحديث حاسبة تبديل النقاط */ const renderConverterUI = () => { const srcSelect = document.getElementById('x1w33rae0d'); const tgtSelect = document.getElementById('mn39n9mx2i'); const amountInp = document.getElementById('xsy3e7r2f4'); const displayInp = document.getElementById('kwj16mxlu6'); const ratioLabel = document.getElementById('cuin29h7xe'); const capacityPreview = document.getElementById('kv6iccvkxs'); if (!srcSelect || !tgtSelect || !amountInp || !displayInp) return; let srcVal = srcSelect.value || 'fb'; let tgtVal = tgtSelect.value || 'wa'; if (srcVal === tgtVal) { tgtVal = srcVal === 'fb' ? 'wa' : 'fb'; tgtSelect.value = tgtVal; } const srcAmount = Math.max(1, parseInt(amountInp.value, 10) || 1); amountInp.value = srcAmount; let calculatedTarget = 0; let ratioText = "2 FB = 1 WA"; let capacityText = "تغطية إرسال تقديرية للرصيد المستلم"; if (srcVal === 'fb' && tgtVal === 'wa') { calculatedTarget = Math.floor(srcAmount * 0.5); ratioText = "2 FB = 1 WA (معادلة التحويل الرسمية)"; capacityText = calculatedTarget > 0 ? `تغطي إرسال حوالي ${calculatedTarget.toLocaleString('en-US')} رسالة واتساب جماعية للعملاء` : `أدنى كمية مطلوبة للتحويل هي 2 نقاط فيسبوك لإنتاج 1 نقطة واتساب.`; } else if (srcVal === 'wa' && tgtVal === 'fb') { calculatedTarget = Math.floor(srcAmount * 2.0); ratioText = "1 WA = 2 FB (معادلة التحويل الرسمية)"; capacityText = `تغطي إرسال حوالي ${calculatedTarget.toLocaleString('en-US')} منشور بمجموعات فيسبوك المستهدفة`; } displayInp.value = `${calculatedTarget.toLocaleString('en-US')} ${tgtVal.toUpperCase()}`; if (ratioLabel) ratioLabel.innerHTML = ` ${ratioText}`; if (capacityPreview) capacityPreview.textContent = capacityText; }; /** * تنفيذ تبديل النقاط بين فيسبوك وواتساب */ const executePointsSwap = async () => { if (LedgerState.isSwappingPointsLock) return; const srcSelect = document.getElementById('x1w33rae0d'); const tgtSelect = document.getElementById('mn39n9mx2i'); const amountInp = document.getElementById('xsy3e7r2f4'); if (!srcSelect || !tgtSelect || !amountInp) return; const srcAsset = srcSelect.value; const tgtAsset = tgtSelect.value; const srcAmount = parseInt(amountInp.value, 10) || 0; if (srcAsset === tgtAsset || srcAmount <= 0) { alert("يرجى إدخال كمية نقاط أكبر من الصفر للتحويل!"); return; } LedgerState.isSwappingPointsLock = true; try { const res = await global.FritreeAppState.convertPoints(srcAsset, tgtAsset, srcAmount); if (res && res.success) { renderConverterUI(); await renderLedgerTable(); if (global.FritreeShellLayout) global.FritreeShellLayout.updatePointsUI(); alert(`تم تحويل النقاط بنجاح!\nتمت إضافة +${res.targetAmount.toLocaleString('en-US')} ${tgtAsset.toUpperCase()} لحسابك فوراً.`); } else { alert(res?.error || "حدث خطأ أثناء إجراء التحويل."); } } catch (e) { console.error("[Points Converter] Swap execution failed:", e); alert("حدث خطأ أثناء إجراء التحويل."); } finally { LedgerState.isSwappingPointsLock = false; } }; /** * ربط أحداث المحول والفلاتر */ const bindConverterAndFilterEvents = () => { const srcSelect = document.getElementById('x1w33rae0d'); const tgtSelect = document.getElementById('mn39n9mx2i'); const amountInp = document.getElementById('xsy3e7r2f4'); const btnMax = document.getElementById('ffeime7ecn'); const btnInvert = document.getElementById('btn-invert-swap-direction'); const btnSwap = document.getElementById('btn-execute-points-swap'); if (srcSelect) srcSelect.onchange = () => { if (tgtSelect) tgtSelect.value = srcSelect.value === 'fb' ? 'wa' : 'fb'; renderConverterUI(); }; if (tgtSelect) tgtSelect.onchange = () => { if (srcSelect) srcSelect.value = tgtSelect.value === 'fb' ? 'wa' : 'fb'; renderConverterUI(); }; if (amountInp) amountInp.oninput = renderConverterUI; if (btnMax) { btnMax.onclick = () => { const src = srcSelect.value; const active = src === 'fb' ? global.FritreeAppState.getFbPoints() : global.FritreeAppState.getWaPoints(); amountInp.value = active > 0 ? active : 1; renderConverterUI(); }; } if (btnInvert) { btnInvert.onclick = (e) => { e.preventDefault(); const oldSrc = srcSelect.value; srcSelect.value = tgtSelect.value; tgtSelect.value = oldSrc; renderConverterUI(); }; } if (btnSwap) btnSwap.onclick = executePointsSwap; const searchInput = document.getElementById('hwhpohdf9p'); const assetFilter = document.getElementById('rwvvh5aw1o'); const dirFilter = document.getElementById('ydho523nfo'); const dateFrom = document.getElementById('nzekdiqxul'); const dateTo = document.getElementById('blve5jub6v'); const btnExportCSV = document.getElementById('jd0salbsv1'); if (searchInput) searchInput.oninput = renderLedgerTable; if (assetFilter) assetFilter.onchange = renderLedgerTable; if (dirFilter) dirFilter.onchange = renderLedgerTable; if (dateFrom) dateFrom.onchange = renderLedgerTable; if (dateTo) dateTo.onchange = renderLedgerTable; if (btnExportCSV) { btnExportCSV.onclick = async () => { const txs = await global.FritreeStorage.get('pointsTransactions', []); if (txs.length === 0) { alert('سجل كشف الحساب فارغ.'); return; } let csv = '\ufeffتاريخ العملية,بيان الحركة المالية,نوع الأصل,قيمة التغيير,توقيع التوثيق\n'; txs.forEach(t => { csv += `"${new Date(t.date).toLocaleString('en-US')}","${(t.desc || '').replace(/"/g, '""')}","${t.type}","${t.amount}","${t.signature || ''}"\n`; }); const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = `كشف_حساب_المحفظة_${new Date().toISOString().slice(0, 10)}.csv`; a.click(); URL.revokeObjectURL(url); }; } }; /** * تهيئة وحدة المحفظة */ const initWalletModule = async () => { const mainContentArea = document.getElementById('s7ihkirolg'); if (!mainContentArea) return false; buildWalletLayoutElements(); bindWalletTabToggles(); bindConverterAndFilterEvents(); await renderLedgerTable(); await renderTimeCapsulesList(); renderConverterUI(); LedgerState.isInitialized = true; return true; }; /** * تصدير وحدة المحفظة */ global.FritreeWallet = { init: initWalletModule, signReceipt: signTransactionReceipt, verifyReceipt: verifyTransactionReceipt, auditHistory: auditTransactionHistory, renderLedgerTable, renderCapsules: renderTimeCapsulesList, renderConverter: renderConverterUI, executeSwap: executePointsSwap }; if (typeof document !== 'undefined') { if (!initWalletModule()) { document.addEventListener('DOMContentLoaded', initWalletModule); window.addEventListener('load', initWalletModule); } } })(typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : this);