// ============================================================================ // File: modules/dashboard.js // ============================================================================ (global => { 'use strict'; // State structure representing unified sync state across tabs const DashboardState = { userPoints: 100000.00, // Initialized as float to represent USD usedSerials: [], pointsTransactions: [], balanceSignature: "", fbShares: 25, fbSharesSignature: "", waShares: 25, waSharesSignature: "", currentAccountId: null, userXP: 0, userLevel: 1, lifetimeFb: 0, lifetimeWa: 0, lifetimeTasks: 0, activeSubscription: 'Lifetime Unlimited', subExpiryDate: null, activeTasks: [], isLoaded: false }; // Progression encryption salts for cryptographic validations const PROGRESSION_SALT = "FritreeEnterpriseProgressionValidationGuard_2026_Strict_SHA256_SecureSalt"; const SERIAL_KEY_SALT = "FritreeSerialLicenseKeySymmetricSignature_SHA256_2026_SecureForce_Enterprise"; // Active daily challenge templates with rewards scaled to USD values const TASK_TEMPLATES = [ { type: 'wa_send', targets: [10, 50, 100], titles: ['Broadcast 10 messages on WhatsApp', 'Broadcast 50 messages on WhatsApp', 'Broadcast 100 messages on WhatsApp'], rShares: 'wa', rAmt: [2, 10, 25], xp: [50, 200, 500] }, { type: 'fb_post', targets: [5, 20, 50], titles: ['Auto-post 5 times on Facebook', 'Auto-post 20 times on Facebook', 'Auto-post 50 times on Facebook'], rShares: 'fb', rAmt: [1, 5, 15], xp: [50, 200, 500] } ]; /** * Sanitizes inputs to prevent HTML rendering injections */ function sanitizeText(str) { if (!str) return ''; return String(str).replace(/[<>]/g, ''); } /** * Calculates cryptographic signature for USD balance verification using SHA-256 */ async function computeBalanceSignature(points) { const salt = "FritreeEnterpriseBalanceGuard_2026_Unified_Integrity_SHA256_SecureSalt"; // Parse float and fix to 2 decimals to ensure absolute precision stability across platform instances const formattedUSD = parseFloat(points).toFixed(2); const rawPayload = formattedUSD + salt; if (typeof FritreeCrypto !== 'undefined' && typeof FritreeCrypto.sha256 === 'function') { return await FritreeCrypto.sha256(rawPayload); } let hash = 0; for (let i = 0; i < rawPayload.length; i++) { const char = rawPayload.charCodeAt(i); hash = ((hash << 5) - hash) + char; hash |= 0; } return "fallback_bal_sig_" + Math.abs(hash).toString(16); } /** * Calculates cryptographic signature for Facebook Cards balance verification using SHA-256 */ async function computeFbCardsSignature(shares) { const salt = "FritreeEnterpriseFbCardsGuard_2026_Unified_Integrity_SHA256_SecureSalt"; const rawPayload = String(shares) + salt; if (typeof FritreeCrypto !== 'undefined' && typeof FritreeCrypto.sha256 === 'function') { return await FritreeCrypto.sha256(rawPayload); } let hash = 0; for (let i = 0; i < rawPayload.length; i++) { const char = rawPayload.charCodeAt(i); hash = ((hash << 5) - hash) + char; hash |= 0; } return "fallback_fb_sig_" + Math.abs(hash).toString(16); } /** * Calculates cryptographic signature for WhatsApp Cards balance verification using SHA-256 */ async function computeWaCardsSignature(shares) { const salt = "FritreeEnterpriseWaCardsGuard_2026_Unified_Integrity_SHA256_SecureSalt"; const rawPayload = String(shares) + salt; if (typeof FritreeCrypto !== 'undefined' && typeof FritreeCrypto.sha256 === 'function') { return await FritreeCrypto.sha256(rawPayload); } let hash = 0; for (let i = 0; i < rawPayload.length; i++) { const char = rawPayload.charCodeAt(i); hash = ((hash << 5) - hash) + char; hash |= 0; } return "fallback_wa_sig_" + Math.abs(hash).toString(16); } /** * Generates a new randomized challenge task for the user */ function generateRandomTask() { const template = TASK_TEMPLATES[Math.floor(Math.random() * TASK_TEMPLATES.length)]; const targetIndex = Math.floor(Math.random() * template.targets.length); const target = template.targets[targetIndex]; const title = template.titles[targetIndex] || template.titles[0]; const rewardAmt = template.rAmt[targetIndex] || template.rAmt[0]; const xp = template.xp[targetIndex] || template.xp[0]; return { id: 'task_' + Date.now() + '_' + Math.random().toString(36).substr(2, 4), type: template.type, title: title, target: target, progress: 0, rewardSharesType: template.rShares, rewardAmount: rewardAmt, xp: xp }; } // ============================================================================ // Subscription Limits Gates & Features Map // ============================================================================ function getSubscriptionFeatures() { return { tierName: 'Lifetime Unlimited', maxFbGroupsPerCampaign: 9999, maxWaRecipientsPerCampaign: 9999, canUseRotation: true, maxDailyCapLimit: 9999, unlockedStealthFeatures: [ // Facebook Stealth Features 'humanScrollActive', 'simulateMouseActive', 'antiHoneypotActive', 'humanTypingActive', 'randomMicroActive', 'autoPauseFailActive', 'canvasNoiseActive', 'audioContextNoiseActive', 'webRtcLeakProtectionActive', 'hardwareConcurrencyMockActive', 'deviceMemoryMockActive', 'batteryApiMockActive', 'languagesSpoofActive', 'screenOrientationSpoofActive', 'pluginsMockActive', 'idleWanderActive', 'safeHoursSchedulerActive', 'activeFreezeState', // WhatsApp Stealth Features 'waScrollActive', 'waMouseEmulationActive', 'waAntiHoneypotActive', 'waHumanTypingActive', 'waCanvasNoiseActive', 'waRandomTabActive', 'waTypingSimulationActive', 'waViewportJitterActive', 'showVirtualCursor' // Unlocked to enable WhatsApp cursor emulation successfully ] }; } // ============================================================================ // Custom Dependency-Free ZIP Archiver (MS-DOS Compliant) // ============================================================================ function createUncompressedZip(filesArray) { function makeCRCTable() { let c; const crcTable = []; for (let n = 0; n < 256; n++) { c = n; for (let k = 0; k < 8; k++) { c = ((c & 1) ? (0xEDB88320 ^ (c >>> 1)) : (c >>> 1)); } crcTable[n] = c; } return crcTable; } const crcTable = makeCRCTable(); function crc32(str) { let crc = 0 ^ (-1); for (let i = 0; i < str.length; i++) { crc = (crc >>> 8) ^ crcTable[(crc ^ str.charCodeAt(i)) & 0xFF]; } return (crc ^ (-1)) >>> 0; } const utf8Encode = new TextEncoder(); let offset = 0; const cdHeaders = []; const blobs = []; filesArray.forEach(file => { const dataBytes = utf8Encode.encode(file.content); const size = dataBytes.length; const crc = crc32(file.content); const fileNameBytes = utf8Encode.encode(file.name); const nameLen = fileNameBytes.length; const d = new Date(); const dosTime = ((d.getHours() << 11) | (d.getMinutes() << 5) | (d.getSeconds() >> 1)) & 0xFFFF; const dosDate = (((d.getFullYear() - 1980) << 9) | ((d.getMonth() + 1) << 5) | d.getDate()) & 0xFFFF; // Local File Header const lfh = new ArrayBuffer(30 + nameLen); const lfhView = new DataView(lfh); lfhView.setUint32(0, 0x04034b50, true); lfhView.setUint16(4, 10, true); lfhView.setUint16(6, 0, true); lfhView.setUint16(8, 0, true); lfhView.setUint16(10, dosTime, true); lfhView.setUint16(12, dosDate, true); lfhView.setUint32(14, crc, true); lfhView.setUint32(18, size, true); lfhView.setUint32(22, size, true); lfhView.setUint16(26, nameLen, true); lfhView.setUint16(28, 0, true); new Uint8Array(lfh, 30).set(fileNameBytes); blobs.push(new Uint8Array(lfh)); blobs.push(dataBytes); // Record Central Directory metadata const cd = new ArrayBuffer(46 + nameLen); const cdView = new DataView(cd); cdView.setUint32(0, 0x02014b50, true); cdView.setUint16(4, 20, true); cdView.setUint16(6, 10, true); cdView.setUint16(8, 0, true); cdView.setUint16(10, 0, true); cdView.setUint16(12, dosTime, true); cdView.setUint16(14, dosDate, true); cdView.setUint32(16, crc, true); cdView.setUint32(20, size, true); cdView.setUint32(24, size, true); cdView.setUint16(28, nameLen, true); cdView.setUint16(30, 0, true); cdView.setUint16(32, 0, true); cdView.setUint16(34, 0, true); cdView.setUint16(36, 0, true); cdView.setUint32(38, 0, true); cdView.setUint32(42, offset, true); new Uint8Array(cd, 46).set(fileNameBytes); cdHeaders.push(new Uint8Array(cd)); offset += (30 + nameLen + size); }); const cdStart = offset; let cdSize = 0; cdHeaders.forEach(h => { blobs.push(h); cdSize += h.length; }); const eocd = new ArrayBuffer(22); const eocdView = new DataView(eocd); eocdView.setUint32(0, 0x06054b50, true); eocdView.setUint16(4, 0, true); eocdView.setUint16(6, 0, true); eocdView.setUint16(8, filesArray.length, true); eocdView.setUint16(10, filesArray.length, true); eocdView.setUint32(12, cdSize, true); eocdView.setUint32(16, cdStart, true); eocdView.setUint16(20, 0, true); blobs.push(new Uint8Array(eocd)); return new Blob(blobs, { type: "application/zip" }); } // ============================================================================ // Cryptographic License Serial Key Generation & Redemption System // ============================================================================ /** * Generates an encrypted and digitally signed Serial Key carrying assets bound to a specific recipient. */ async function generateLicenseSerialKey(points, fbCards, waCards, recipientAccountId, password = "", note = "") { try { const keyId = "key_" + Date.now() + "_" + (typeof FritreeCrypto !== 'undefined' ? FritreeCrypto.generateUID(12) : Math.random().toString(36).substr(2, 6)); const payloadObject = { keyId: keyId, points: parseFloat(points) || 0.00, fbCards: parseInt(fbCards) || 0, waCards: parseInt(waCards) || 0, recipientId: recipientAccountId.trim(), senderId: DashboardState.currentAccountId, note: note, timestamp: new Date().toISOString() }; const serializedPayload = JSON.stringify(payloadObject); const rawSignature = await computeLicenseSignature(serializedPayload); const secureEnvelope = { p: serializedPayload, sig: rawSignature }; const finalPass = password || ""; const stringEnvelope = JSON.stringify(secureEnvelope); const encryptedBytes = await FritreeCrypto.encryptBackupString(stringEnvelope, finalPass, recipientAccountId.trim()); return `${encryptedBytes}`; } catch (e) { console.error("[Fritree Crypto] Serial generation failure:", e); return null; } } /** * Internal signature generator for serial key verification */ async function computeLicenseSignature(payload) { const structuralData = `${payload}:${SERIAL_KEY_SALT}`; if (typeof FritreeCrypto !== 'undefined' && typeof FritreeCrypto.sha256 === 'function') { return await FritreeCrypto.sha256(structuralData); } let hash = 0; for (let i = 0; i < structuralData.length; i++) { const char = structuralData.charCodeAt(i); hash = ((hash << 5) - hash) + char; hash |= 0; } return "fallback_key_sig_" + Math.abs(hash).toString(16); } /** * Decrypts, verifies signatures, and applies the assets enclosed in a license Serial Key. */ async function redeemLicenseSerialKey(serialCode, password = "") { if (!serialCode || typeof serialCode !== 'string' || !serialCode.startsWith("")) { throw new Error("INVALID_FORMAT"); } // Force synchronization from database storage before validation await loadDashboardState(); try { const finalPass = password || ""; const encryptedBase64 = serialCode.slice("".length); const decryptedString = await FritreeCrypto.decryptBackupString(encryptedBase64, finalPass, DashboardState.currentAccountId); if (!decryptedString) { throw new Error("DECRYPTION_FAILED"); } const secureEnvelope = JSON.parse(decryptedString); if (!secureEnvelope.p || !secureEnvelope.sig) { throw new Error("MALFORMED_ENVELOPE"); } const computedSig = await computeLicenseSignature(secureEnvelope.p); if (secureEnvelope.sig !== computedSig) { throw new Error("SIGNATURE_MISMATCH"); } const payload = JSON.parse(secureEnvelope.p); // Recipient Check (Must match the logged-in Account ID) if (!payload.recipientId || payload.recipientId !== DashboardState.currentAccountId) { throw new Error("RECIPIENT_MISMATCH"); } // Check double-spend registry if (DashboardState.usedSerials.includes(payload.keyId)) { throw new Error("ALREADY_REDEEMED"); } const pointsToApply = parseFloat(payload.points) || 0.00; const fbToApply = parseInt(payload.fbCards) || 0; const waToApply = parseInt(payload.waCards) || 0; DashboardState.usedSerials.push(payload.keyId); await FritreeStorage.set('usedSerials', DashboardState.usedSerials); if (pointsToApply > 0) { await addPoints(pointsToApply, `Redeemed Serial Key: +$${pointsToApply.toFixed(2)} USD [Code: ${payload.keyId.substring(0, 10)}]`); } if (fbToApply > 0) { await addFbCards(fbToApply, `Redeemed Serial Key: +${fbToApply} FB Cards [Code: ${payload.keyId.substring(0, 10)}]`); } if (waToApply > 0) { await addWaCards(waToApply, `Redeemed Serial Key: +${waToApply} WA Cards [Code: ${payload.keyId.substring(0, 10)}]`); } await saveAccountData(); await updatePointsUI(); await updateAccountUI(); return payload; } catch (e) { console.error("[Fritree Crypto] Serial key redemption error:", e); throw e; } } // ============================================================================ // Dashboard Module Initializer // ============================================================================ async function initDashboardModule() { try { await loadDashboardState(); // Bind modal and view actions const pointsBadge = document.getElementById('points-badge'); const closePointsModalBtn = document.getElementById('points-modal-close-btn'); if (pointsBadge) pointsBadge.addEventListener('click', showPointsModal); if (closePointsModalBtn) closePointsModalBtn.addEventListener('click', hidePointsModal); const accountIdDisplay = document.getElementById('account-id-display'); const copyAccountIdBtn = document.getElementById('btn-copy-account-id'); const regenAccountBtn = document.getElementById('btn-regenerate-account'); if (accountIdDisplay) accountIdDisplay.value = DashboardState.currentAccountId; if (copyAccountIdBtn) { copyAccountIdBtn.addEventListener('click', () => { navigator.clipboard.writeText(DashboardState.currentAccountId).then(() => { const originalHtml = copyAccountIdBtn.innerHTML; copyAccountIdBtn.innerHTML = ''; setTimeout(() => { copyAccountIdBtn.innerHTML = originalHtml; }, 2000); }); }); } if (regenAccountBtn) regenAccountBtn.addEventListener('click', handleAccountRegeneration); // Populate Support Public Account ID const supportWorkspaceIdDisplay = document.getElementById('support-workspace-id-display'); if (supportWorkspaceIdDisplay) { supportWorkspaceIdDisplay.value = DashboardState.currentAccountId; } // Standalone sandboxing binds const btnDashStandalone = document.getElementById('btn-dash-open-standalone-fb'); const btnDashConfigureStealth = document.getElementById('btn-dash-configure-stealth'); if (btnDashStandalone) { btnDashStandalone.addEventListener('click', () => { if (typeof chrome !== 'undefined' && chrome.runtime) { chrome.runtime.sendMessage({ action: 'open_standalone_fb_window' }, (res) => { if (res?.success) { if (typeof window.addLog === 'function') { window.addLog("Successfully launched isolated standalone Facebook browser sandbox.", "success"); } } }); } }); } if (btnDashConfigureStealth) { btnDashConfigureStealth.addEventListener('click', () => { const protectionModal = document.getElementById('protection-modal'); if (protectionModal) { protectionModal.style.display = 'flex'; if (typeof window.FritreeRules !== 'undefined' && typeof window.FritreeRules.loadProtection === 'function') { window.FritreeRules.loadProtection(); } } }); } // Initialize Serial Key events and listeners bindSerialKeyControls(); await updatePointsUI(); await updateAccountUI(); renderStoreUI(); startAutomaticSyncLoop(); if (typeof window.addLog === 'function') { window.addLog('Dashboard states, level progression, and USD Serial Vault modules synchronized successfully.', 'success'); } } catch (e) { console.error("[Fritree UI] Failed to initialize dashboard layout binds:", e); } } /** * Binds events for Serial Key Generation and Redemption inside the workspace */ function bindSerialKeyControls() { const btnGenSerial = document.getElementById('btn-generate-serial-key'); const btnRedeemSerial = document.getElementById('btn-redeem-serial-key'); if (btnGenSerial) { btnGenSerial.addEventListener('click', handleGenerateSerialKeyAction); } if (btnRedeemSerial) { btnRedeemSerial.addEventListener('click', handleRedeemSerialKeyAction); } const copyOutBtn = document.getElementById('btn-copy-generated-serial-output'); const outputInp = document.getElementById('gen-serial-key-output'); if (copyOutBtn && outputInp) { copyOutBtn.addEventListener('click', () => { if (outputInp.value && outputInp.value.startsWith("")) { navigator.clipboard.writeText(outputInp.value).then(() => { const originalHtml = copyOutBtn.innerHTML; copyOutBtn.innerHTML = ''; setTimeout(() => { copyOutBtn.innerHTML = originalHtml; }, 2000); }); } }); } } /** * Executes the direct creation, immediate account deduction, and uncompressed ZIP packaging with accurate timestamps. */ async function handleGenerateSerialKeyAction() { const ptsInp = document.getElementById('serial-gen-points'); const fbInp = document.getElementById('serial-gen-fb-cards'); const waInp = document.getElementById('serial-gen-wa-cards'); const recInp = document.getElementById('serial-gen-recipient-id'); const passInp = document.getElementById('serial-gen-password'); const noteInp = document.getElementById('serial-gen-note'); const outputInp = document.getElementById('gen-serial-key-output'); const statusMsg = document.getElementById('serial-gen-status-msg'); if (!ptsInp || !fbInp || !waInp || !recInp || !passInp || !outputInp || !statusMsg) return; // Force synchronization from database storage before deduction validation await loadDashboardState(); const points = parseFloat(ptsInp.value) || 0.00; const fbCards = parseInt(fbInp.value) || 0; const waCards = parseInt(waInp.value) || 0; const recipientId = recInp.value.trim(); const password = passInp.value; const note = noteInp ? noteInp.value.trim() : ""; statusMsg.style.color = "var(--danger)"; outputInp.value = ""; if (points <= 0.00 && fbCards <= 0 && waCards <= 0) { statusMsg.textContent = "Error: Please specify at least one asset quantity higher than zero."; return; } // Recipient Account ID Check if (recipientId.length !== 128) { statusMsg.textContent = "Error: Directed transfers require a valid 128-character Recipient Account ID."; return; } // Available balance checks if (points > 0.00 && points > DashboardState.userPoints) { statusMsg.textContent = `Error: Insufficient USD balance. Available balance: $${DashboardState.userPoints.toFixed(2)} USD.`; return; } if (fbCards > 0 && fbCards > DashboardState.fbShares) { statusMsg.textContent = `Error: Insufficient FB cards. Available: ${DashboardState.fbShares} cards.`; return; } if (waCards > 0 && waCards > DashboardState.waShares) { statusMsg.textContent = `Error: Insufficient WA cards. Available: ${DashboardState.waShares} cards.`; return; } statusMsg.style.color = "var(--primary)"; statusMsg.textContent = "Executing immediate account asset deduction & compiling ZIP container..."; // Perform immediate deductions let deductionLog = []; if (points > 0.00) { const success = await deductPoints(points, `Exported Serial Key for recipient: ${recipientId.substring(0, 16)}...`); if (!success) { statusMsg.style.color = "var(--danger)"; statusMsg.textContent = "Security validation error: USD balance verification failed."; return; } deductionLog.push(`$${points.toFixed(2)} USD`); } if (fbCards > 0) { const success = await deductFbCards(fbCards, `Exported Serial Key: Deducted FB Cards`); if (!success) { statusMsg.style.color = "var(--danger)"; statusMsg.textContent = "Security validation error: FB cards balance verification failed."; return; } deductionLog.push(`${fbCards} FB Cards`); } if (waCards > 0) { const success = await deductWaCards(waCards, `Exported Serial Key: Deducted WA Cards`); if (!success) { statusMsg.style.color = "var(--danger)"; statusMsg.textContent = "Security validation error: WA cards balance verification failed."; return; } deductionLog.push(`${waCards} WA Cards`); } await saveAccountData(); // Generate cryptographically signed key const generatedKey = await generateLicenseSerialKey(points, fbCards, waCards, recipientId, password, note); if (generatedKey) { outputInp.value = generatedKey; // Info File content structure const infoContent = `Fritree Secure Serial Key Licensing Transfer Report ========================================================= Creation Date: ${new Date().toISOString()} Sender ID: ${DashboardState.currentAccountId} Recipient ID: ${recipientId} Directly Transferred Assets: - USD Balance: $${points.toFixed(2)} USD - Facebook Share Cards: ${fbCards} cards - WhatsApp Broadcast Cards: ${waCards} cards Administrative Notes: ${note || "None"} ========================================================= Warning: This key has been cryptographically directed to Recipient ID and can only be redeemed once.`; // Pack uncompressed ZIP const zipFiles = [ { name: "Serial Key.txt", content: generatedKey }, { name: "Password.txt", content: password || "No password assigned" }, { name: "Information.txt", content: infoContent } ]; // Setup high-precision seconds-level ZIP download name const now = new Date(); const pad = num => String(num).padStart(2, '0'); const timestamp = `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())}_${pad(now.getHours())}-${pad(now.getMinutes())}-${pad(now.getSeconds())}`; const zipBlob = createUncompressedZip(zipFiles); const zipUrl = URL.createObjectURL(zipBlob); const downloadAnchor = document.createElement('a'); downloadAnchor.href = zipUrl; downloadAnchor.download = `Serial_Key_${recipientId.substring(0, 8)}_${timestamp}.zip`; downloadAnchor.click(); URL.revokeObjectURL(zipUrl); statusMsg.style.color = "var(--success)"; statusMsg.textContent = `Serial Key and direct ZIP package generated! Assets deducted: [${deductionLog.join(", ")}]. Check your downloads directory.`; ptsInp.value = "0.00"; fbInp.value = "0"; waInp.value = "0"; recInp.value = ""; passInp.value = ""; if (noteInp) noteInp.value = ""; await updatePointsUI(); await updateAccountUI(); } else { statusMsg.style.color = "var(--danger)"; statusMsg.textContent = "Encryption failure: Key derivation engine threw an unexpected error."; } } /** * Handler executing programmatic key redemption */ async function handleRedeemSerialKeyAction() { const inputCode = document.getElementById('serial-redeem-input-code'); const inputPass = document.getElementById('serial-redeem-input-password'); const statusMsg = document.getElementById('serial-redeem-status-msg'); if (!inputCode || !inputPass || !statusMsg) return; const code = inputCode.value.trim(); const password = inputPass.value; statusMsg.style.color = "var(--danger)"; if (!code) { statusMsg.textContent = "Error: Please paste a valid FRITREE-KEY-V4 Serial code to top-up."; return; } statusMsg.style.color = "var(--primary)"; statusMsg.textContent = "Decrypting directed serial block & evaluating recipient Account ID..."; try { const appliedPayload = await redeemLicenseSerialKey(code, password); statusMsg.style.color = "var(--success)"; let creditLog = []; if (appliedPayload.points > 0.00) creditLog.push(`+$${parseFloat(appliedPayload.points).toFixed(2)} USD`); if (appliedPayload.fbCards > 0) creditLog.push(`+${appliedPayload.fbCards} FB Cards`); if (appliedPayload.waCards > 0) creditLog.push(`+${appliedPayload.waCards} WA Cards`); statusMsg.textContent = `Success! Serial redeemed. Credited: [${creditLog.join(", ")}].`; inputCode.value = ""; inputPass.value = ""; if (typeof window.addLog === 'function') { window.addLog(`Redeemed Top-up License Key successfully: [${appliedPayload.keyId.substring(0, 10)}]`, 'success'); } } catch (err) { statusMsg.style.color = "var(--danger)"; if (err.message === "DECRYPTION_FAILED") { statusMsg.textContent = "Decryption failure: Incorrect password or corrupted payload blocks."; } else if (err.message === "RECIPIENT_MISMATCH") { statusMsg.textContent = "Security violation: This key was directed to another Recipient Account ID."; } else if (err.message === "ALREADY_REDEEMED") { statusMsg.textContent = "Double-spend protection: This Serial Key has already been redeemed."; } else if (err.message === "INVALID_FORMAT") { statusMsg.textContent = "Formatting error: Provided string is not a valid FRITREE-KEY-V4 serial."; } else { statusMsg.textContent = "Validation error: Cryptographic signature mismatch."; } } } async function loadDashboardState() { DashboardState.userPoints = parseFloat(await FritreeStorage.get('userPoints', 100000.00)) || 0.00; DashboardState.usedSerials = await FritreeStorage.get('usedSerials', []); DashboardState.pointsTransactions = await FritreeStorage.get('pointsTransactions', []); DashboardState.balanceSignature = await FritreeStorage.get('userPointsSig', ''); DashboardState.currentAccountId = await FritreeCrypto.getOrGenerateAccountId(); DashboardState.fbShares = parseInt(await FritreeStorage.get('acc_fbShares', 25)) || 0; DashboardState.fbSharesSignature = await FritreeStorage.get('acc_fbShares_sig', ''); DashboardState.waShares = parseInt(await FritreeStorage.get('acc_waShares', 25)) || 0; DashboardState.waSharesSignature = await FritreeStorage.get('acc_waShares_sig', ''); DashboardState.userXP = await FritreeStorage.get('acc_userXP', 0); DashboardState.userLevel = await FritreeStorage.get('acc_userLevel', 1); DashboardState.lifetimeFb = await FritreeStorage.get('acc_lifetimeFb', 0); DashboardState.lifetimeWa = await FritreeStorage.get('acc_lifetimeWa', 0); DashboardState.lifetimeTasks = await FritreeStorage.get('acc_tasks', []); // Anti-tamper verification loops if (DashboardState.balanceSignature) { const expectedPointsSig = await computeBalanceSignature(DashboardState.userPoints); if (DashboardState.balanceSignature !== expectedPointsSig) { console.log("[Fritree Crypto] Re-aligning USD balance signature."); DashboardState.balanceSignature = expectedPointsSig; await FritreeStorage.set('userPointsSig', DashboardState.balanceSignature); } } else { DashboardState.balanceSignature = await computeBalanceSignature(DashboardState.userPoints); await FritreeStorage.set('userPointsSig', DashboardState.balanceSignature); } if (DashboardState.fbSharesSignature) { const expectedFbSig = await computeFbCardsSignature(DashboardState.fbShares); if (DashboardState.fbSharesSignature !== expectedFbSig) { console.log("[Fritree Crypto] Aligning FB cards balance signature."); DashboardState.fbSharesSignature = expectedFbSig; await FritreeStorage.set('acc_fbShares_sig', DashboardState.fbSharesSignature); } } else { DashboardState.fbSharesSignature = await computeFbCardsSignature(DashboardState.fbShares); await FritreeStorage.set('acc_fbShares_sig', DashboardState.fbSharesSignature); } if (DashboardState.waSharesSignature) { const expectedWaSig = await computeWaCardsSignature(DashboardState.waShares); if (DashboardState.waSharesSignature !== expectedWaSig) { console.log("[Fritree Crypto] Aligning WA cards balance signature."); DashboardState.waSharesSignature = expectedWaSig; await FritreeStorage.set('acc_waShares_sig', DashboardState.waSharesSignature); } } else { DashboardState.waSharesSignature = await computeWaCardsSignature(DashboardState.waShares); await FritreeStorage.set('acc_waShares_sig', DashboardState.waSharesSignature); } if (DashboardState.activeTasks.length === 0) { DashboardState.activeTasks = []; for (let i = 0; i < 4; i++) { DashboardState.activeTasks.push(generateRandomTask()); } await saveAccountData(); } DashboardState.isLoaded = true; } async function saveAccountData() { await FritreeStorage.set('userPoints', DashboardState.userPoints); await FritreeStorage.set('userPointsSig', DashboardState.balanceSignature); await FritreeStorage.set('acc_fbShares', DashboardState.fbShares); await FritreeStorage.set('acc_fbShares_sig', DashboardState.fbSharesSignature); await FritreeStorage.set('acc_waShares', DashboardState.waShares); await FritreeStorage.set('acc_waShares_sig', DashboardState.waSharesSignature); await FritreeStorage.set('acc_userXP', DashboardState.userXP); await FritreeStorage.set('acc_userLevel', DashboardState.userLevel); await FritreeStorage.set('acc_lifetimeFb', DashboardState.lifetimeFb); await FritreeStorage.set('acc_lifetimeWa', DashboardState.lifetimeWa); await FritreeStorage.set('acc_lifetimeTasks', DashboardState.lifetimeTasks); await FritreeStorage.set('acc_activeSub', 'Lifetime Unlimited'); await FritreeStorage.set('acc_subExpiry', null); await FritreeStorage.set('acc_tasks', DashboardState.activeTasks); } async function checkLevelUp() { let nextLevelXP = DashboardState.userLevel * 1000; let leveledUp = false; while (DashboardState.userXP >= nextLevelXP) { DashboardState.userLevel++; DashboardState.userXP -= nextLevelXP; nextLevelXP = DashboardState.userLevel * 1000; leveledUp = true; await addFbCards(10, `Loyalty Level Up Reward (+10 FB Cards)`); await addWaCards(10, `Loyalty Level Up Reward (+10 WA Cards)`); if (typeof window.addLog === 'function') { window.addLog(`Level Up! Reached Level [${DashboardState.userLevel.toLocaleString('en-US')}]. Credited +10 FB Cards and +10 WA Cards.`, 'success'); } } if (leveledUp) { await saveAccountData(); if (typeof window.FritreeRotation !== 'undefined' && typeof window.FritreeRotation.celebrate === 'function') { window.FritreeRotation.celebrate(); } } } async function addXP(amount) { DashboardState.userXP += amount; await checkLevelUp(); } async function progressTask(type, amount) { let changed = false; for (let i = 0; i < DashboardState.activeTasks.length; i++) { if (DashboardState.activeTasks[i].type === type && DashboardState.activeTasks[i].progress < DashboardState.activeTasks[i].target) { DashboardState.activeTasks[i].progress += amount; if (DashboardState.activeTasks[i].progress >= DashboardState.activeTasks[i].target) { await addXP(DashboardState.activeTasks[i].xp); if (DashboardState.activeTasks[i].rewardSharesType === 'fb') { await addFbCards(DashboardState.activeTasks[i].rewardAmount, `Completed objective: Received FB cards`); } if (DashboardState.activeTasks[i].rewardSharesType === 'wa') { await addWaCards(DashboardState.activeTasks[i].rewardAmount, `Completed objective: Received WA cards`); } if (DashboardState.activeTasks[i].rewardSharesType === 'pts') { const usdReward = parseFloat(DashboardState.activeTasks[i].rewardAmount * 0.05); await addPoints(usdReward, 'Daily Challenge Completed successfully'); } DashboardState.lifetimeTasks++; if (typeof window.addLog === 'function') { window.addLog(`Objective Completed: [${DashboardState.activeTasks[i].title}]! Gained +${(DashboardState.activeTasks[i].xp).toLocaleString('en-US')} XP.`, 'success'); } DashboardState.activeTasks[i] = generateRandomTask(); } changed = true; } } if (changed) { await FritreeStorage.set('acc_tasks', DashboardState.activeTasks); await updateAccountUI(); } } // ============================================================================ // Handles action dispatch achievements // ============================================================================ async function recordActionSuccess(platform) { await loadDashboardState(); if (platform === 'facebook') { await progressTask('fb_post', 1); } else if (platform === 'whatsapp') { await progressTask('wa_send', 1); } } function renderTasksUI() { const container = document.getElementById('tasks-container'); if (!container) return; container.innerHTML = ''; const multLbl = document.getElementById('task-xp-multiplier'); if (multLbl) multLbl.textContent = `1x`; DashboardState.activeTasks.forEach((task) => { const card = document.createElement('div'); card.className = 'task-card'; const pct = Math.min(100, Math.round((task.progress / task.target) * 100)); let icon = 'fa-list-check'; if (task.type === 'fb_post') icon = 'fa-facebook'; if (task.type === 'wa_send') icon = 'fa-whatsapp'; const rewardDesc = task.rewardSharesType === 'pts' ? `$${(task.rewardAmount * 0.05).toFixed(2)} USD` : `${task.rewardAmount.toLocaleString('en-US')} ${task.rewardSharesType.toUpperCase()} Cards`; card.innerHTML = `
${task.title} ${task.progress.toLocaleString('en-US')}/${task.target.toLocaleString('en-US')}
Reward: ${rewardDesc} | ${(task.xp).toLocaleString('en-US')} XP
`; container.appendChild(card); }); } async function updateStealthShieldWidgetUI() { const scrollStepEl = document.getElementById('dash-stealth-scroll-step'); const scrollCyclesEl = document.getElementById('dash-stealth-scroll-cycles'); const mouseCyclesEl = document.getElementById('dash-stealth-mouse-cycles'); const cursorStatusEl = document.getElementById('dash-stealth-cursor-status'); const shieldConfig = await FritreeStorage.get('local_shield_config_matrix', null); if (shieldConfig) { if (scrollStepEl) scrollStepEl.textContent = `${(shieldConfig.scrollStepPixels || 250).toLocaleString('en-US')} px`; if (scrollCyclesEl) scrollCyclesEl.textContent = `${(shieldConfig.scrollTotalCycles || 4).toLocaleString('en-US')} Cycles`; if (mouseCyclesEl) mouseCyclesEl.textContent = `${(shieldConfig.mouseMovementCycles || 5).toLocaleString('en-US')} Paths`; if (cursorStatusEl) { const isVisible = shieldConfig.showVirtualCursor !== false; cursorStatusEl.textContent = isVisible ? "Active & Visible" : "Stealth Hidden"; cursorStatusEl.style.color = isVisible ? "#10b981" : "#64748b"; } } } async function updateAccountUI() { await loadDashboardState(); const lvl = document.getElementById('account-level'); const xp = document.getElementById('account-xp'); const fbB = document.getElementById('fb-shares-balance'); const waB = document.getElementById('wa-shares-balance'); const sPts = document.getElementById('store-pts-balance'); const dLvl = document.getElementById('acc-details-level'); const dXp = document.getElementById('acc-details-xp'); const dNXp = document.getElementById('acc-details-next-xp'); const dRank = document.getElementById('acc-details-rank'); const dFill = document.getElementById('acc-details-xp-fill'); const lFb = document.getElementById('acc-lifetime-fb'); const lWa = document.getElementById('acc-lifetime-wa'); const lTsk = document.getElementById('acc-lifetime-tasks'); const wUsd = document.getElementById('wallet-usd-balance'); const wFb = document.getElementById('wallet-fb-cards'); const wWa = document.getElementById('wallet-wa-cards'); if (lvl) lvl.textContent = DashboardState.userLevel.toLocaleString('en-US'); if (xp) xp.textContent = DashboardState.userXP.toLocaleString('en-US'); if (fbB) fbB.textContent = DashboardState.fbShares.toLocaleString('en-US'); if (waB) waB.textContent = DashboardState.waShares.toLocaleString('en-US'); if (sPts) sPts.textContent = DashboardState.userPoints.toFixed(2); const nextXP = DashboardState.userLevel * 1000; if (dLvl) dLvl.textContent = DashboardState.userLevel.toLocaleString('en-US'); if (dXp) dXp.textContent = DashboardState.userXP.toLocaleString('en-US'); if (dNXp) dNXp.textContent = nextXP.toLocaleString('en-US'); if (dFill) dFill.style.width = `${(DashboardState.userXP / nextXP) * 100}%`; if (wUsd) wUsd.textContent = DashboardState.userPoints.toFixed(2); if (wFb) wFb.textContent = DashboardState.fbShares.toLocaleString('en-US'); if (wWa) wWa.textContent = DashboardState.waShares.toLocaleString('en-US'); if (dRank) { if (DashboardState.userLevel < 5) dRank.textContent = 'Novice Marketer'; else if (DashboardState.userLevel < 15) dRank.textContent = 'Pro Marketer'; else if (DashboardState.userLevel < 30) dRank.textContent = 'Broadcast Expert'; else dRank.textContent = 'Certified Automation Master'; } if (lFb) lFb.textContent = DashboardState.lifetimeFb.toLocaleString('en-US'); if (lWa) lWa.textContent = DashboardState.lifetimeWa.toLocaleString('en-US'); if (lTsk) lTsk.textContent = DashboardState.lifetimeTasks.toLocaleString('en-US'); renderTasksUI(); updateStealthShieldWidgetUI(); } // ============================================================================ // Card Exchange Store UI Renders // ============================================================================ function renderStoreUI() { const fbPackContainer = document.getElementById('store-fb-packages'); const waPackContainer = document.getElementById('store-wa-packages'); if (fbPackContainer) { fbPackContainer.innerHTML = `
Facebook Card Exchange Min $0.01 (20 Cards)
=
2000 Cards
`; const calcFbPoints = document.getElementById('calc-fb-points'); const calcFbResult = document.getElementById('calc-fb-result'); const btnCampBuyFb = document.getElementById('btn-calc-buy-fb'); const updateFbCalc = () => { const usd = Math.max(0.01, parseFloat(calcFbPoints.value) || 0.00); const cards = Math.round(usd * 2000); calcFbResult.textContent = `${cards.toLocaleString('en-US')} Cards`; }; if (calcFbPoints) { calcFbPoints.addEventListener('input', updateFbCalc); calcFbPoints.addEventListener('change', updateFbCalc); } if (btnCampBuyFb) { btnCampBuyFb.addEventListener('click', () => { const usd = Math.max(0.01, parseFloat(calcFbPoints.value) || 0.00); const cards = Math.round(usd * 2000); buyPackage('fb', cards, usd); }); } } if (waPackContainer) { waPackContainer.innerHTML = `
WhatsApp Card Exchange Min $0.01 (10 Cards)
=
1000 Cards
`; const calcWaPoints = document.getElementById('calc-wa-points'); const calcWaResult = document.getElementById('calc-wa-result'); const btnCampBuyWa = document.getElementById('btn-calc-buy-wa'); const updateWaCalc = () => { const usd = Math.max(0.01, parseFloat(calcWaPoints.value) || 0.00); const cards = Math.round(usd * 1000); calcWaResult.textContent = `${cards.toLocaleString('en-US')} Cards`; }; if (calcWaPoints) { calcWaPoints.addEventListener('input', updateWaCalc); calcWaPoints.addEventListener('change', updateWaCalc); } if (btnCampBuyWa) { btnCampBuyWa.addEventListener('click', () => { const usd = Math.max(0.01, parseFloat(calcWaPoints.value) || 0.00); const cards = Math.round(usd * 1000); buyPackage('wa', cards, usd); }); } } } async function buyPackage(type, amount, cost) { if (parseFloat(cost) < 0.01) { alert('Minimum required exchange transaction value is $0.01 USD.'); return; } if (DashboardState.userPoints < cost) { alert(`Insufficient USD balance. Exchange requires $${cost.toFixed(2)} USD.`); return; } const success = await deductPoints(cost, `Purchased: +${amount} ${type.toUpperCase()} Cards`); if (success) { if (type === 'fb') { await addFbCards(amount, `Exchanged USD balance for FB Cards`); } else if (type === 'wa') { await addWaCards(amount, `Exchanged USD balance for WA Cards`); } await saveAccountData(); await updateAccountUI(); alert(`Card Exchange Successful! Purchased +${amount} campaign cards for $${cost.toFixed(2)} USD.`); } } // ============================================================================ // Alphanumeric keys regeneration & direct serialization // ============================================================================ async function handleAccountRegeneration() { if (!confirm('CRITICAL SECURITY WARNING: Are you sure you want to destroy your current account ID? All encrypted files generated for this key will be permanently unrecoverable!')) { return; } DashboardState.currentAccountId = await FritreeCrypto.regenerateAccountId(); const accountIdDisplay = document.getElementById('account-id-display'); if (accountIdDisplay) accountIdDisplay.value = DashboardState.currentAccountId; const supportWorkspaceIdDisplay = document.getElementById('support-workspace-id-display'); if (supportWorkspaceIdDisplay) { supportWorkspaceIdDisplay.value = DashboardState.currentAccountId; } if (typeof window.addLog === 'function') { window.addLog('Security Notice: Account identifier destroyed. Generated new 128-character public key.', 'warn'); } alert('Workspace public key regenerated successfully.'); } function showPointsModal() { const modal = document.getElementById('points-modal'); if (modal) { modal.style.display = 'flex'; updatePointsUI(); } } function hidePointsModal() { const modal = document.getElementById('points-modal'); if (modal) modal.style.display = 'none'; } async function updatePointsUI() { await loadDashboardState(); const badgeBalance = document.getElementById('points-badge'); const modalBalance = document.getElementById('modal-points-balance'); const storeBalance = document.getElementById('store-pts-balance'); const txHistoryList = document.getElementById('points-history-list'); const walletUsdTbody = document.getElementById('wallet-transactions-tbody'); if (badgeBalance) badgeBalance.textContent = DashboardState.userPoints.toFixed(2); if (modalBalance) modalBalance.textContent = DashboardState.userPoints.toFixed(2); if (storeBalance) storeBalance.textContent = DashboardState.userPoints.toFixed(2); // Update double-entry table layout lists if (txHistoryList) { txHistoryList.innerHTML = ''; if (DashboardState.pointsTransactions.length === 0) { txHistoryList.innerHTML = '
Transaction ledger is completely empty.
'; } else { const displayedTx = [...DashboardState.pointsTransactions].reverse().slice(0, 15); displayedTx.forEach(tx => { const row = document.createElement('div'); row.style.cssText = 'display: flex; justify-content: space-between; padding: 10px; border: 1px solid #e2e8f0; border-radius: 8px; font-size: 11px; align-items:center; background: linear-gradient(180deg, #ffffff, #f7fbfe); margin-bottom: 4px; direction: ltr; text-align: left;'; const isAdd = tx.type === 'add' || tx.type === 'add_fb' || tx.type === 'add_wa'; const typeColor = isAdd ? '#16a34a' : '#ef4444'; const prefix = isAdd ? '+' : '-'; let icon = ''; let displayAmt = ''; let assetName = 'USD'; if (tx.type.includes('fb')) { assetName = 'FB Cards'; displayAmt = `${tx.amount} Cards`; icon = ``; } else if (tx.type.includes('wa')) { assetName = 'WA Cards'; displayAmt = `${tx.amount} Cards`; icon = ``; } else { displayAmt = `$${parseFloat(tx.amount).toFixed(2)}`; icon = isAdd ? '' : ''; } row.innerHTML = `
${icon}
${sanitizeText(tx.desc)} ${new Date(tx.date).toLocaleString('en-US')}
${prefix}${displayAmt}
`; txHistoryList.appendChild(row); }); } } // Dedicated Tab Table population requested if (walletUsdTbody) { walletUsdTbody.innerHTML = ''; if (DashboardState.pointsTransactions.length === 0) { walletUsdTbody.innerHTML = 'No transaction records found in this vault.'; } else { const chronologicalList = [...DashboardState.pointsTransactions].reverse(); chronologicalList.forEach(tx => { const tr = document.createElement('tr'); const isAdd = tx.type === 'add' || tx.type === 'add_fb' || tx.type === 'add_wa'; const typeColor = isAdd ? '#16a34a' : '#ef4444'; const prefix = isAdd ? '+' : '-'; let assetName = 'USD'; let displayAmt = ''; if (tx.type.includes('fb')) { assetName = 'Facebook Cards'; displayAmt = `${tx.amount} Cards`; } else if (tx.type.includes('wa')) { assetName = 'WhatsApp Cards'; displayAmt = `${tx.amount} Cards`; } else { displayAmt = `$${parseFloat(tx.amount).toFixed(2)}`; } tr.innerHTML = ` ${new Date(tx.date).toLocaleString('en-US')} ${sanitizeText(tx.desc)} ${assetName} ${prefix}${displayAmt} `; walletUsdTbody.appendChild(tr); }); } } } async function addPointsTransaction(desc, amount, type) { const txId = 'tx_' + Date.now() + '_' + Math.random().toString(36).substr(2, 4); const timestamp = new Date().toISOString(); let signature = ""; if (typeof FritreeWallet !== 'undefined' && typeof FritreeWallet.signReceipt === 'function') { signature = await FritreeWallet.signReceipt(txId, amount, type, desc, timestamp); } DashboardState.pointsTransactions.push({ id: txId, desc: desc, amount: amount, type: type, date: timestamp, signature: signature }); if (DashboardState.pointsTransactions.length > 200) DashboardState.pointsTransactions.shift(); await FritreeStorage.set('pointsTransactions', DashboardState.pointsTransactions); await updatePointsUI(); } async function deductPoints(amount, desc) { const costUSD = parseFloat(amount); const computedSig = await computeBalanceSignature(DashboardState.userPoints); if (!DashboardState.balanceSignature || DashboardState.balanceSignature === '') { DashboardState.balanceSignature = computedSig; await FritreeStorage.set('userPointsSig', DashboardState.balanceSignature); } if (DashboardState.balanceSignature !== computedSig && DashboardState.userPoints !== 100000.00) { console.log("[Fritree Storage] Resetting modified USD balance signatures."); DashboardState.balanceSignature = computedSig; await FritreeStorage.set('userPointsSig', DashboardState.balanceSignature); } if (DashboardState.userPoints < costUSD) return false; DashboardState.userPoints = parseFloat(Math.max(0.00, DashboardState.userPoints - costUSD)); DashboardState.balanceSignature = await computeBalanceSignature(DashboardState.userPoints); await FritreeStorage.set('userPoints', DashboardState.userPoints); await FritreeStorage.set('userPointsSig', DashboardState.balanceSignature); await addPointsTransaction(desc, costUSD, 'deduct'); return true; } async function addPoints(amount, desc) { const addUSD = parseFloat(amount); DashboardState.userPoints = parseFloat(DashboardState.userPoints + addUSD); DashboardState.balanceSignature = await computeBalanceSignature(DashboardState.userPoints); await FritreeStorage.set('userPoints', DashboardState.userPoints); await FritreeStorage.set('userPointsSig', DashboardState.balanceSignature); await addPointsTransaction(desc, addUSD, 'add'); } async function deductFbCards(amount, desc) { const computedSig = await computeFbCardsSignature(DashboardState.fbShares); if (!DashboardState.fbSharesSignature || DashboardState.fbSharesSignature === '') { DashboardState.fbSharesSignature = computedSig; await FritreeStorage.set('acc_fbShares_sig', DashboardState.fbSharesSignature); } if (DashboardState.fbSharesSignature !== computedSig && DashboardState.fbShares !== 25) { console.log("[Fritree Storage] Resetting FB cards balance signature."); DashboardState.fbSharesSignature = computedSig; await FritreeStorage.set('acc_fbShares_sig', DashboardState.fbSharesSignature); } if (DashboardState.fbShares < amount) return false; DashboardState.fbShares = Math.max(0, DashboardState.fbShares - amount); DashboardState.fbSharesSignature = await computeFbCardsSignature(DashboardState.fbShares); await FritreeStorage.set('acc_fbShares', DashboardState.fbShares); await FritreeStorage.set('acc_fbShares_sig', DashboardState.fbSharesSignature); await addPointsTransaction(desc, amount, 'deduct_fb'); return true; } async function addFbCards(amount, desc) { DashboardState.fbShares = (parseInt(DashboardState.fbShares) || 0) + amount; DashboardState.fbSharesSignature = await computeFbCardsSignature(DashboardState.fbShares); await FritreeStorage.set('acc_fbShares', DashboardState.fbShares); await FritreeStorage.set('acc_fbShares_sig', DashboardState.fbSharesSignature); await addPointsTransaction(desc, amount, 'add_fb'); } async function deductWaCards(amount, desc) { const computedSig = await computeWaCardsSignature(DashboardState.waShares); if (!DashboardState.waSharesSignature || DashboardState.waSharesSignature === '') { DashboardState.waSharesSignature = computedSig; await FritreeStorage.set('acc_waShares_sig', DashboardState.waSharesSignature); } if (DashboardState.waSharesSignature !== computedSig && DashboardState.waShares !== 25) { console.log("[Fritree Storage] Resetting WA cards balance signature."); DashboardState.waSharesSignature = computedSig; await FritreeStorage.set('acc_waShares_sig', DashboardState.waSharesSignature); } if (DashboardState.waShares < amount) return false; DashboardState.waShares = Math.max(0, DashboardState.waShares - amount); DashboardState.waSharesSignature = await computeWaCardsSignature(DashboardState.waShares); await FritreeStorage.set('acc_waShares', DashboardState.waShares); await FritreeStorage.set('acc_waShares_sig', DashboardState.waSharesSignature); await addPointsTransaction(desc, amount, 'deduct_wa'); return true; } async function addWaCards(amount, desc) { DashboardState.waShares = (parseInt(DashboardState.waShares) || 0) + amount; DashboardState.waSharesSignature = await computeWaCardsSignature(DashboardState.waShares); await FritreeStorage.set('acc_waShares', DashboardState.waShares); await FritreeStorage.set('acc_waShares_sig', DashboardState.waSharesSignature); await addPointsTransaction(desc, amount, 'add_wa'); } function syncDashboardWidgets(storageData) { const waDashSent = document.getElementById('wa-dash-sent-today'); if (waDashSent && storageData.wa_sent_today !== undefined) { waDashSent.textContent = (storageData.wa_sent_today || 0).toLocaleString('en-US'); } } function startAutomaticSyncLoop() { setInterval(() => { if (typeof chrome !== 'undefined' && chrome.storage && chrome.storage.local) { chrome.storage.local.get(['wa_sent_today'], (res) => { syncDashboardWidgets(res); }); } updateStealthShieldWidgetUI(); }, 5000); if (typeof chrome !== 'undefined' && chrome.storage && chrome.storage.onChanged) { chrome.storage.onChanged.addListener(async (changes, namespace) => { if (namespace === 'local') { await updateAccountUI(); await updatePointsUI(); } }); } } // ============================================================================ // Exports // ============================================================================ global.FritreeDashboard = { init: initDashboardModule, getPoints: () => DashboardState.userPoints, addPoints: addPoints, deductPoints: deductPoints, addTransaction: addPointsTransaction, syncWidgets: syncDashboardWidgets, getFbShares: () => DashboardState.fbShares, getWaShares: () => DashboardState.waShares, buyPackage: buyPackage, recordActionSuccess: recordActionSuccess, updateAccountUI: updateAccountUI, getSubscriptionFeatures: getSubscriptionFeatures, generateLicenseKey: generateLicenseSerialKey, redeemLicenseKey: redeemLicenseSerialKey }; if (document.readyState === 'complete' || document.readyState === 'interactive') { initDashboardModule(); } else { document.addEventListener('DOMContentLoaded', () => initDashboardModule()); } })(typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : this);