| |
| |
| |
| |
|
|
|
|
| (global => {
|
| 'use strict';
|
|
|
| let isTermSuspended = false;
|
| let isUiSyncActive = false;
|
| let isFbSyncing = false;
|
| let lastFbSyncTimestamp = 0;
|
| let alivePort = null;
|
| let campaignTimerInterval = null;
|
| let campaignStartTime = null;
|
| let totalCooldownSeconds = 0;
|
| let completedStepsCount = 0;
|
| let lastLaunchedCampaignId = null;
|
| const activeCampaignsMetrics = new Map();
|
|
|
| function silentTrap(err) {
|
| return null;
|
| }
|
|
|
| |
| |
|
|
| const establishPersistentKeepAlive = () => {
|
| try {
|
| if (typeof chrome !== 'undefined' && chrome.runtime && chrome.runtime.connect) {
|
| alivePort = chrome.runtime.connect({ name: "fritree-keep-alive" });
|
| alivePort.onDisconnect.addListener(() => {
|
| setTimeout(establishPersistentKeepAlive, 500);
|
| });
|
| }
|
| } catch (e) {
|
| silentTrap(e);
|
| }
|
| };
|
|
|
| setInterval(() => {
|
| try {
|
| if (alivePort) {
|
| alivePort.postMessage({ ping: true });
|
| } else {
|
| establishPersistentKeepAlive();
|
| }
|
| } catch (e) {
|
| establishPersistentKeepAlive();
|
| }
|
| }, 2000);
|
|
|
| function formatHHMMSS(totalSeconds) {
|
| try {
|
| const hrs = Math.floor(totalSeconds / 3600);
|
| const mins = Math.floor((totalSeconds % 3600) / 60);
|
| const secs = totalSeconds % 60;
|
| return [
|
| String(hrs).padStart(2, '0'),
|
| String(mins).padStart(2, '0'),
|
| String(secs).padStart(2, '0')
|
| ].join(':');
|
| } catch (e) {
|
| silentTrap(e);
|
| return "00:00:00";
|
| }
|
| }
|
|
|
| const setDomTextSafely = (elementId, value) => {
|
| try {
|
| const element = document.getElementById(elementId);
|
| if (element) {
|
| element.textContent = value;
|
| return true;
|
| }
|
| return false;
|
| } catch (e) {
|
| silentTrap(e);
|
| return false;
|
| }
|
| };
|
|
|
| const startCampaignTrackingTimers = () => {
|
| try {
|
| campaignStartTime = Date.now();
|
| totalCooldownSeconds = 0;
|
| completedStepsCount = 0;
|
| setDomTextSafely('ctldyt8www', '00:00:00');
|
| setDomTextSafely('idrsed82qy', '00:00:00');
|
| setDomTextSafely('e8fmmjhyng', '0 ثانية');
|
|
|
| if (campaignTimerInterval) clearInterval(campaignTimerInterval);
|
| campaignTimerInterval = setInterval(() => {
|
| try {
|
| if (!campaignStartTime) return;
|
| const elapsedMs = Date.now() - campaignStartTime;
|
| const elapsedSeconds = Math.floor(elapsedMs / 1000);
|
| setDomTextSafely('ctldyt8www', formatHHMMSS(elapsedSeconds));
|
| } catch (err) {
|
| silentTrap(err);
|
| }
|
| }, 500);
|
| } catch (e) {
|
| silentTrap(e);
|
| }
|
| };
|
|
|
| const stopCampaignTrackingTimers = () => {
|
| try {
|
| if (campaignTimerInterval) {
|
| clearInterval(campaignTimerInterval);
|
| campaignTimerInterval = null;
|
| }
|
| } catch (e) {
|
| silentTrap(e);
|
| }
|
| };
|
|
|
| |
| |
|
|
| const buildSchedulerPaneLayout = () => {
|
| const contentArea = document.getElementById('s7ihkirolg');
|
| if (!contentArea) return false;
|
|
|
| const host = document.getElementById('fritree-dynamic-panes-host') || contentArea;
|
| let pane = document.getElementById('ss7cgkeahf');
|
| if (pane) {
|
| if (pane.parentElement !== host) {
|
| host.appendChild(pane);
|
| }
|
| return true;
|
| }
|
|
|
| pane = document.createElement('section');
|
| pane.className = 'rjiai07g77';
|
| pane.id = 'ss7cgkeahf';
|
| pane.innerHTML = `
|
| <div class="d5tp7way8h zcjbe1otmg" style="margin: 0; padding: clamp(14px, 1.8vw, 24px); border-radius: var(--radius-xl); border: 1px solid var(--border); direction: rtl; text-align: right; background: var(--bg-card); box-sizing: border-box;">
|
| <div style="display: flex; justify-content: space-between; align-items: center; border-bottom: 1px solid var(--border); padding-bottom: 14px; margin-bottom: 18px; flex-wrap: wrap; gap: 10px;">
|
| <div>
|
| <h2 style="font-size: clamp(15px, 1.2vw, 18px); font-weight: 900; display: flex; align-items: center; gap: 8px; margin: 0; color: var(--text-main);">
|
| <i class="fa-solid fa-calendar-plus" style="color: #3b82f6;"></i>
|
| <span>مركز إدارة وطابور الحملات المجدولة</span>
|
| </h2>
|
| <p style="font-size: 11px; color: var(--text-muted); margin-top: 4px; font-weight: 700;">
|
| <i class="fa-solid fa-clock"></i>
|
| <span>أتمتة إطلاق الحملات التسويقية في مواعيد محددة بدقة على فيسبوك وواتساب.</span>
|
| </p>
|
| </div>
|
| </div>
|
|
|
| <!-- نموذج إنشاء وتثبيت حملة مجدولة جديدة -->
|
| <div style="border: 1px solid var(--border); border-radius: var(--radius-lg); padding: clamp(12px, 1.4vw, 18px); margin-bottom: 16px; background: var(--bg-subtle); box-sizing: border-box;">
|
| <h3 style="font-size: 13.5px; font-weight: 900; margin: 0 0 12px 0; display: flex; align-items: center; gap: 6px; border-bottom: 1px solid var(--border); padding-bottom: 8px; color: var(--text-main);">
|
| <i class="fa-solid fa-calendar-check" style="color: var(--primary);"></i> <span>إنشاء وتثبيت موعد حملة مجدولة جديدة</span>
|
| </h3>
|
| <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(clamp(180px, 20vw, 280px), 1fr)); gap: 10px; margin-bottom: 10px;">
|
| <div class="d0uttwsjz2" style="margin: 0;">
|
| <label style="font-size: 11px; font-weight: 700;"><i class="fa-solid fa-heading"></i> <span>اسم أو عنوان الحملة:</span></label>
|
| <input type="text" id="sched-create-name" class="xy26ymifmf" placeholder="مثال: حملة عروض نهاية الأسبوع..." style="padding: 8px 10px;">
|
| </div>
|
| <div class="d0uttwsjz2" style="margin: 0;">
|
| <label style="font-size: 11px; font-weight: 700;"><i class="fa-solid fa-shapes"></i> <span>المنصة المستهدفة:</span></label>
|
| <select id="sched-create-platform" class="xy26ymifmf" style="padding: 8px 10px; font-weight: 700;">
|
| <option value="facebook" selected>منصة فيسبوك (Facebook Groups)</option>
|
| <option value="whatsapp">منصة واتساب (WhatsApp Broadcast)</option>
|
| </select>
|
| </div>
|
| <div class="d0uttwsjz2" style="margin: 0;">
|
| <label style="font-size: 11px; font-weight: 700;"><i class="fa-solid fa-clock"></i> <span>تاريخ ووقت الانطلاق:</span></label>
|
| <input type="datetime-local" id="sched-create-datetime" class="xy26ymifmf" style="padding: 6px 8px; font-size: 11px;">
|
| </div>
|
| </div>
|
|
|
| <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(clamp(260px, 30vw, 1fr), 1fr)); gap: 10px; margin-bottom: 10px;">
|
| <div class="d0uttwsjz2" style="margin: 0;">
|
| <label style="font-size: 11px; font-weight: 700;"><i class="fa-solid fa-message"></i> <span>نص رسالة أو منشور الحملة:</span></label>
|
| <textarea id="sched-create-text" class="f0ngq4vbzj" style="height: 75px; min-height: 60px;" placeholder="اكتب نص المنشور أو الرسالة هنا..."></textarea>
|
| </div>
|
| <div style="display: flex; flex-direction: column; gap: 8px; justify-content: space-between;">
|
| <div class="d0uttwsjz2" style="margin: 0;">
|
| <label style="font-size: 11px; font-weight: 700;"><i class="fa-solid fa-layer-group"></i> <span>ربط بحزمة تدوير مخصصة (اختياري):</span></label>
|
| <select id="sched-create-group-select" class="xy26ymifmf" style="padding: 7px 10px; font-size: 11px;">
|
| <option value="">-- بدون ربط (استخدام النص المباشر) --</option>
|
| </select>
|
| </div>
|
| <button type="button" id="btn-submit-create-scheduled" class="itdnt14mss" style="padding: 10px; font-size: 12px; font-weight: 800; width: 100%; min-height: 36px;">
|
| <i class="fa-solid fa-calendar-plus"></i> <span>جدولة وإضافة لطابور الانتظار</span>
|
| </button>
|
| </div>
|
| </div>
|
| </div>
|
|
|
| <!-- جدول طابور الحملات المجدولة -->
|
| <div>
|
| <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px;">
|
| <h3 style="font-size: 13.5px; font-weight: 900; margin: 0; display: flex; align-items: center; gap: 6px; color: var(--text-main);">
|
| <i class="fa-solid fa-list-ol" style="color: var(--primary);"></i> <span>طابور الحملات المجدولة المسجلة</span>
|
| </h3>
|
| <span id="sched-queue-count-badge" style="font-size: 10.5px; font-weight: 800; background: var(--bg-subtle); color: var(--text-secondary); padding: 2px 8px; border-radius: var(--radius-pill); border: 1px solid var(--border); font-family: var(--font-code);">
|
| 0 حملات في الطابور
|
| </span>
|
| </div>
|
|
|
| <div class="diktqr0h64" style="max-height: 440px;">
|
| <table style="width: 100%; border-collapse: collapse; direction: rtl; text-align: right;">
|
| <thead>
|
| <tr>
|
| <th style="width: 25%; padding: 10px 12px;"><i class="fa-solid fa-bullseye"></i> <span>اسم وتفاصيل الحملة</span></th>
|
| <th style="width: 15%; text-align: center; padding: 10px 12px;"><i class="fa-solid fa-shapes"></i> <span>المنصة</span></th>
|
| <th style="width: 25%; padding: 10px 12px;"><i class="fa-solid fa-clock"></i> <span>موعد الإطلاق المجدول</span></th>
|
| <th style="width: 15%; text-align: center; padding: 10px 12px;"><i class="fa-solid fa-circle-info"></i> <span>الحالة</span></th>
|
| <th style="width: 20%; text-align: center; padding: 10px 12px;"><i class="fa-solid fa-sliders"></i> <span>الإجراءات</span></th>
|
| </tr>
|
| </thead>
|
| <tbody id="sched-queue-tbody">
|
| <tr>
|
| <td colspan="5" style="text-align: center; color: var(--text-muted); padding: 30px; font-size: 11.5px;">
|
| <i class="fa-solid fa-calendar-xmark" style="font-size: 24px; display: block; margin-bottom: 6px;"></i>
|
| <span>لا توجد أي حملات مجدولة مسجلة في طابور الانتظار حالياً.</span>
|
| </td>
|
| </tr>
|
| </tbody>
|
| </table>
|
| </div>
|
| </div>
|
| </div>
|
| `;
|
|
|
| host.appendChild(pane);
|
| renderScheduledQueueTable();
|
| bindSchedulerPaneEvents();
|
| return true;
|
| };
|
|
|
| const renderScheduledQueueTable = async () => {
|
| const tbody = document.getElementById('sched-queue-tbody');
|
| const countBadge = document.getElementById('sched-queue-count-badge');
|
| const groupSelect = document.getElementById('sched-create-group-select');
|
| if (!tbody || !global.FritreeStorage) return;
|
|
|
| const list = await global.FritreeStorage.get('scheduledCampaignsData', []) || [];
|
| if (countBadge) countBadge.textContent = `${list.length.toLocaleString('en-US')} حملات في الطابور`;
|
|
|
| if (groupSelect && global.FritreeRotation) {
|
| const groups = global.FritreeRotation.getGroups() || [];
|
| groupSelect.innerHTML = '<option value="">-- بدون ربط (استخدام النص المباشر) --</option>';
|
| groups.forEach(g => {
|
| const opt = document.createElement('option');
|
| opt.value = g.id;
|
| opt.textContent = `حزمة: ${g.name} (${(g.postIds || []).length} منشور)`;
|
| groupSelect.appendChild(opt);
|
| });
|
| }
|
|
|
| tbody.innerHTML = '';
|
| if (list.length === 0) {
|
| tbody.innerHTML = `
|
| <tr>
|
| <td colspan="5" style="text-align: center; color: var(--text-muted); padding: 30px; font-size: 11.5px;">
|
| <i class="fa-solid fa-calendar-xmark" style="font-size: 24px; display: block; margin-bottom: 6px; color: var(--border-strong);"></i>
|
| <span>لا توجد أي حملات مجدولة مسجلة في طابور الانتظار حالياً.</span>
|
| </td>
|
| </tr>
|
| `;
|
| return;
|
| }
|
|
|
| list.forEach(c => {
|
| const tr = document.createElement('tr');
|
| tr.style.cssText = 'border-bottom: 1px solid var(--border);';
|
|
|
| const isFb = c.platform === 'facebook';
|
| const platformBadge = isFb ?
|
| `<span style="background:var(--primary-light); color:var(--primary); border:1px solid var(--primary-border); font-size:9.5px; font-weight:800; padding:2px 8px; border-radius:var(--radius-pill);"><i class="fa-brands fa-facebook"></i> فيسبوك</span>` :
|
| `<span style="background:var(--wa-light); color:var(--wa-brand); border:1px solid var(--wa-border); font-size:9.5px; font-weight:800; padding:2px 8px; border-radius:var(--radius-pill);"><i class="fa-brands fa-whatsapp"></i> واتساب</span>`;
|
|
|
| let statusLabel = 'قيد الانتظار';
|
| let statusClass = 'go30y9mfgh pending';
|
|
|
| if (c.status === 'completed') {
|
| statusLabel = 'مكتملة بنجاح';
|
| statusClass = 'go30y9mfgh success';
|
| } else if (c.status === 'running') {
|
| statusLabel = 'جاري الإطلاق';
|
| statusClass = 'go30y9mfgh running';
|
| } else if (c.status === 'failed') {
|
| statusLabel = 'فشلت';
|
| statusClass = 'go30y9mfgh failed';
|
| }
|
|
|
| const targetInfo = isFb ?
|
| `الجروبات: ${(c.groupIds || []).length} جروب` :
|
| `المستلمين: ${(c.recipients || []).length} عميل`;
|
|
|
| tr.innerHTML = `
|
| <td style="padding: 10px 12px; font-weight: 700;">
|
| <div style="color:var(--text-main); font-size:12px;">${c.name || 'حملة مجدولة'}</div>
|
| <span style="font-size: 10px; color: var(--text-muted); font-weight: normal;">${targetInfo} ${c.postGroupId ? '| مرتبطة بحزمة تدوير' : ''}</span>
|
| </td>
|
| <td style="text-align: center; padding: 10px 12px;">${platformBadge}</td>
|
| <td style="padding: 10px 12px; font-size: 11px; font-weight: 700; direction: ltr; text-align: right; font-family: var(--font-code); color: var(--text-secondary);">
|
| <i class="fa-regular fa-clock" style="margin-right: 4px;"></i> ${new Date(c.scheduledTime).toLocaleString('en-US')}
|
| </td>
|
| <td style="text-align: center; padding: 10px 12px;">
|
| <span class="${statusClass}">
|
| ${statusLabel}
|
| </span>
|
| </td>
|
| <td style="text-align: center; padding: 10px 12px;">
|
| <div style="display: flex; gap: 4px; justify-content: center;">
|
| <button type="button" class="ipxi2jz4g0 btn-run-sched-now" data-sched-id="${c.id}" style="padding: 3px 8px; font-size: 10px; font-weight: 800; min-height: 28px;" title="إطلاق الحملة فوراً الآن">
|
| <i class="fa-solid fa-bolt" style="color: #f59e0b;"></i> <span>تشغيل</span>
|
| </button>
|
| <button type="button" class="btn-danger btn-delete-sched" data-sched-id="${c.id}" style="padding: 3px 8px; font-size: 10px; min-height: 28px;" title="إلغاء وحذف من الجدولة">
|
| <i class="fa-solid fa-trash"></i>
|
| </button>
|
| </div>
|
| </td>
|
| `;
|
|
|
| tr.querySelector('.btn-run-sched-now').onclick = async () => {
|
| if (confirm(`هل تريد إطلاق الحملة "${c.name}" فوراً الآن وتجاوز موعد الجدولة؟`)) {
|
| chrome.runtime.sendMessage({
|
| action: 'execute_scheduled_campaign_immediately',
|
| campaignId: c.id
|
| }, () => {
|
| renderScheduledQueueTable();
|
| if (global.syncWorkspaceUI) global.syncWorkspaceUI();
|
| });
|
| }
|
| };
|
|
|
| tr.querySelector('.btn-delete-sched').onclick = async () => {
|
| if (confirm(`هل تريد إلغاء وحذف الحملة المجدولة "${c.name}"؟`)) {
|
| let updatedList = await global.FritreeStorage.get('scheduledCampaignsData', []) || [];
|
| updatedList = updatedList.filter(item => item.id !== c.id);
|
| await global.FritreeStorage.set('scheduledCampaignsData', updatedList);
|
| renderScheduledQueueTable();
|
| }
|
| };
|
|
|
| tbody.appendChild(tr);
|
| });
|
| };
|
|
|
| const bindSchedulerPaneEvents = () => {
|
| const btnSubmitCreate = document.getElementById('btn-submit-create-scheduled');
|
| if (btnSubmitCreate) {
|
| btnSubmitCreate.onclick = async () => {
|
| const name = (document.getElementById('sched-create-name')?.value || '').trim();
|
| const platform = document.getElementById('sched-create-platform')?.value || 'facebook';
|
| const scheduledTime = document.getElementById('sched-create-datetime')?.value;
|
| const text = (document.getElementById('sched-create-text')?.value || '').trim();
|
| const postGroupId = document.getElementById('sched-create-group-select')?.value || '';
|
|
|
| if (!name) {
|
| alert('يرجى كتابة اسم واضح للحملة المجدولة!');
|
| return;
|
| }
|
| if (!scheduledTime || new Date(scheduledTime).getTime() <= Date.now()) {
|
| alert('يرجى تحديد تاريخ ووقت مستقبلي صالح لانطلاق الحملة!');
|
| return;
|
| }
|
|
|
| let targetGroupIds = [];
|
| let targetRecipients = [];
|
|
|
| if (platform === 'facebook') {
|
| targetGroupIds = global.FritreeFacebook ? global.FritreeFacebook.getSelectedIds() : [];
|
| if (targetGroupIds.length === 0) {
|
| const allFb = await global.FritreeStorage.get('local_groups', []);
|
| targetGroupIds = allFb.map(g => g.id);
|
| }
|
| if (targetGroupIds.length === 0) {
|
| alert('يرجى تحديد أو استيراد مجموعات فيسبوك أولاً لربطها بالحملة!');
|
| return;
|
| }
|
| } else {
|
| targetRecipients = global.FritreeWhatsApp ? global.FritreeWhatsApp.getRecipients() : [];
|
| if (targetRecipients.length === 0) {
|
| const allRecs = await global.FritreeStorage.get('local_wa_recipients_queue', []);
|
| targetRecipients = allRecs;
|
| }
|
| if (targetRecipients.length === 0) {
|
| alert('يرجى إضافة أو جلب مستلمي واتساب أولاً لربطهم بالحملة!');
|
| return;
|
| }
|
| }
|
|
|
| const newSchedItem = {
|
| id: 'sched_' + Date.now() + '_' + Math.random().toString(36).substr(2, 4),
|
| name: name,
|
| platform: platform,
|
| scheduledTime: scheduledTime,
|
| text: text,
|
| useGroupRotation: !!postGroupId,
|
| postGroupId: postGroupId,
|
| groupIds: targetGroupIds,
|
| recipients: targetRecipients,
|
| status: 'scheduled',
|
| createdAt: new Date().toISOString()
|
| };
|
|
|
| const currentList = await global.FritreeStorage.get('scheduledCampaignsData', []) || [];
|
| currentList.unshift(newSchedItem);
|
| await global.FritreeStorage.set('scheduledCampaignsData', currentList);
|
|
|
| if (global.FritreeCalendarStore && typeof global.FritreeCalendarStore.logActivity === 'function') {
|
| await global.FritreeCalendarStore.logActivity({
|
| title: `[حملة مجدولة] ${name}`,
|
| type: 'campaign',
|
| timestamp: scheduledTime,
|
| notes: `حملة تسويقية مجدولة على منصة ${platform === 'whatsapp' ? 'واتساب' : 'فيسبوك'}`
|
| });
|
| }
|
|
|
| alert(`تم بنجاح جدولة الحملة "${name}" لتنطلق تلقائياً بتاريخ: ${new Date(scheduledTime).toLocaleString('en-US')}`);
|
| document.getElementById('sched-create-name').value = '';
|
| document.getElementById('sched-create-text').value = '';
|
| renderScheduledQueueTable();
|
| };
|
| }
|
| };
|
|
|
| |
| |
|
|
| const syncWorkspaceUI = async () => {
|
| if (isUiSyncActive) return;
|
| isUiSyncActive = true;
|
| try {
|
| if (global.FritreeAppState && typeof global.FritreeAppState.loadDashboardState === 'function') {
|
| await global.FritreeAppState.loadDashboardState();
|
| }
|
| if (global.FritreeShellLayout && typeof global.FritreeShellLayout.updatePointsUI === 'function') {
|
| await global.FritreeShellLayout.updatePointsUI();
|
| }
|
| if (global.FritreeProgressionService && typeof global.FritreeProgressionService.renderTasksUI === 'function') {
|
| global.FritreeProgressionService.renderTasksUI();
|
| }
|
| if (global.FritreeAntibanRulesService && typeof global.FritreeAntibanRulesService.evaluateRisk === 'function') {
|
| await global.FritreeAntibanRulesService.evaluateRisk();
|
| }
|
| } catch (err) {
|
| silentTrap(err);
|
| } finally {
|
| isUiSyncActive = false;
|
| }
|
| };
|
|
|
| const startWorkspaceSecurityHeartbeat = () => {
|
| try {
|
| setInterval(async () => {
|
| try {
|
| await syncWorkspaceUI();
|
| await checkConnectedSessions();
|
| } catch (err) {
|
| silentTrap(err);
|
| }
|
| }, 3000);
|
| } catch (e) {
|
| silentTrap(e);
|
| }
|
| };
|
|
|
| const ensurePanesOrderInDOM = () => {
|
| const host = document.getElementById('fritree-dynamic-panes-host');
|
| const mainContent = document.getElementById('s7ihkirolg');
|
| const monitoringPanel = document.getElementById('cxyr0eirov');
|
| if (!host && mainContent && monitoringPanel) {
|
| document.querySelectorAll('.rjiai07g77').forEach(pane => {
|
| if (pane.parentElement === mainContent) {
|
| mainContent.insertBefore(pane, monitoringPanel);
|
| }
|
| });
|
| } else if (host) {
|
| document.querySelectorAll('.rjiai07g77').forEach(pane => {
|
| if (pane.parentElement !== host) {
|
| host.appendChild(pane);
|
| }
|
| });
|
| }
|
| };
|
|
|
| |
| |
| |
|
|
| const navigateToPane = async (targetId) => {
|
| try {
|
| if (targetId === 'pane-fb-group-health' || targetId === 'pane-fb-heatmap') {
|
| targetId = 'sf1xx5vcac';
|
| }
|
|
|
| if (targetId === 'qt3bcp0qq8' && global.FritreeStealthUI) {
|
| global.FritreeStealthUI.buildPane();
|
| global.FritreeStealthUI.loadForm();
|
| } else if (targetId === 'oboufoudrv' && global.FritreeBackupService) {
|
| global.FritreeBackupService.buildPane();
|
| global.FritreeBackupService.refreshBadges();
|
| } else if (targetId === 'ss7cgkeahf') {
|
| buildSchedulerPaneLayout();
|
| renderScheduledQueueTable();
|
| }
|
|
|
| ensurePanesOrderInDOM();
|
|
|
| document.querySelectorAll('.rjiai07g77').forEach(p => p.classList.remove('vn5qn7dmpk'));
|
| const targetPane = document.getElementById(targetId);
|
| if (targetPane) {
|
| targetPane.classList.add('vn5qn7dmpk');
|
| }
|
|
|
| if (targetId === 'gaap721x61' && global.FritreeCalendar) {
|
| if (typeof global.FritreeCalendar.init === 'function') await global.FritreeCalendar.init();
|
| if (typeof global.FritreeCalendar.render === 'function') await global.FritreeCalendar.render();
|
| } else if (targetId === 'ny517knjde' && global.FritreeContacts) {
|
| if (typeof global.FritreeContacts.refreshUI === 'function') global.FritreeContacts.refreshUI();
|
| } else if (targetId === 'i2ohy2hnfl' && global.FritreeRotation) {
|
| if (typeof global.FritreeRotation.renderPreviousPostsGrid === 'function') global.FritreeRotation.renderPreviousPostsGrid();
|
| if (typeof global.FritreeRotation.updateRotationIndicatorUI === 'function') global.FritreeRotation.updateRotationIndicatorUI();
|
| } else if (targetId === 'j2nzw12azj' && global.FritreeWallet) {
|
| if (typeof global.FritreeWallet.renderLedgerTable === 'function') await global.FritreeWallet.renderLedgerTable();
|
| if (typeof global.FritreeWallet.renderCapsules === 'function') await global.FritreeWallet.renderCapsules();
|
| } else if (targetId === 'xhcwhbkzqe' && global.FritreeHistory) {
|
| if (typeof global.FritreeHistory.refresh === 'function') global.FritreeHistory.refresh();
|
| } else if (targetId === 'dc1z57si9s' && global.FritreeStoreCalculator) {
|
| if (typeof global.FritreeStoreCalculator.updateCalculator === 'function') global.FritreeStoreCalculator.updateCalculator();
|
| }
|
|
|
| window.scrollTo({ top: 0, behavior: 'smooth' });
|
| await syncWorkspaceUI();
|
| } catch (e) {
|
| silentTrap(e);
|
| }
|
| };
|
|
|
| |
| |
|
|
| const executeHashRouter = () => {
|
| try {
|
| const hash = window.location.hash.slice(1);
|
| const validPanes = [
|
| 'h7qak5tprs', 'sf1xx5vcac', 'i2ohy2hnfl', 'sf8pufcpyl',
|
| 'ny517knjde', 'qt3bcp0qq8', 'j2nzw12azj', 'dc1z57si9s',
|
| 'xhcwhbkzqe', 'oboufoudrv', 'xrsxtjzo87', 'ss7cgkeahf',
|
| 'gaap721x61'
|
| ];
|
|
|
| if (validPanes.includes(hash)) {
|
| navigateToPane(hash);
|
| } else if (hash === 'pane-fb-group-health' || hash === 'pane-fb-heatmap') {
|
| window.location.hash = 'sf1xx5vcac';
|
| } else {
|
| window.location.hash = 'h7qak5tprs';
|
| }
|
| } catch (e) {
|
| silentTrap(e);
|
| }
|
| };
|
|
|
| |
| |
|
|
| const addLog = (payload, type = "info") => {
|
| try {
|
| if (isTermSuspended) return;
|
| const terminal = document.getElementById('r99bttinj8');
|
| if (!terminal) return;
|
|
|
| let msg = typeof payload === 'object' && payload !== null ? (payload.ar || payload.en || '') : String(payload);
|
| if (msg.toLowerCase().includes("error") || msg.toLowerCase().includes("failed") || msg.toLowerCase().includes("exception")) {
|
| msg = "درع الأمان: تم تحديث خطوات الإرسال التلقائي لحماية حسابك.";
|
| type = "warn";
|
| }
|
|
|
| const time = new Date().toLocaleTimeString('en-US');
|
| const line = document.createElement('div');
|
| line.className = 'xat4o6cs3m';
|
|
|
| const timeSpan = document.createElement('span');
|
| timeSpan.className = 'fe5xz6pikv';
|
| timeSpan.textContent = `[${time}]`;
|
|
|
| const msgSpan = document.createElement('span');
|
| let classType = 'ma43slkxth';
|
| let defaultIcon = '<i class="fa-solid fa-circle-info"></i> ';
|
|
|
| if (type === 'success') {
|
| classType = 'hjxwx50o9j';
|
| defaultIcon = '<i class="fa-solid fa-circle-check"></i> ';
|
| } else if (type === 'error') {
|
| classType = 'j640dqp9ki';
|
| defaultIcon = '<i class="fa-solid fa-triangle-exclamation"></i> ';
|
| } else if (type === 'warn') {
|
| classType = 'j271lhps8l';
|
| defaultIcon = '<i class="fa-solid fa-circle-exclamation"></i> ';
|
| } else if (type === 'security') {
|
| classType = 'hjxwx50o9j';
|
| defaultIcon = '<i class="fa-solid fa-shield-virus"></i> ';
|
| }
|
|
|
| const finalIcon = getDynamicIconForText(msg, defaultIcon);
|
| msgSpan.className = classType;
|
| msgSpan.innerHTML = `${finalIcon} <span>${msg}</span>`;
|
|
|
| line.appendChild(timeSpan);
|
| line.appendChild(msgSpan);
|
| terminal.appendChild(line);
|
| terminal.scrollTop = terminal.scrollHeight;
|
| } catch (e) {
|
| silentTrap(e);
|
| }
|
| };
|
|
|
| const getDynamicIconForText = (msg, defaultIcon) => {
|
| try {
|
| const text = (msg || '').toString().toLowerCase();
|
| if (text.includes('facebook') || text.includes('[facebook]') || text.includes('فيسبوك')) return '<i class="fa-brands fa-facebook"></i> ';
|
| if (text.includes('whatsapp') || text.includes('[whatsapp]') || text.includes('واتساب')) return '<i class="fa-brands fa-whatsapp"></i> ';
|
| if (text.includes('cooldown') || text.includes('wait') || text.includes('seconds') || text.includes('تبريد') || text.includes('انتظار') || text.includes('ثانية')) return '<i class="fa-solid fa-hourglass-half"></i> ';
|
| if (text.includes('campaign') || text.includes('broadcast') || text.includes('post') || text.includes('حملة') || text.includes('بث')) return '<i class="fa-solid fa-bullhorn" style="color:#3b82f6;"></i> ';
|
| if (text.includes('success') || text.includes('completed') || text.includes('dispatched') || text.includes('نجاح') || text.includes('بنجاح') || text.includes('اكتملت')) return '<i class="fa-solid fa-circle-check"></i> ';
|
| if (text.includes('failed') || text.includes('error') || text.includes('aborted') || text.includes('فشل') || text.includes('خطأ')) return '<i class="fa-solid fa-circle-xmark"></i> ';
|
| if (text.includes('security') || text.includes('integrity') || text.includes('shield') || text.includes('أمان') || text.includes('حظر') || text.includes('درع')) return '<i class="fa-solid fa-shield-halved"></i> ';
|
| if (text.includes('wallet') || text.includes('points') || text.includes('usd') || text.includes('balance') || text.includes('محفظة') || text.includes('رصيد') || text.includes('نقطة')) return '<i class="fa-solid fa-wallet"></i> ';
|
| if (text.includes('group') || text.includes('groups') || text.includes('مجموع')) return '<i class="fa-solid fa-users" style="color:#3b82f6;"></i> ';
|
| return defaultIcon;
|
| } catch (e) {
|
| silentTrap(e);
|
| return defaultIcon;
|
| }
|
| };
|
|
|
| |
| |
|
|
| const triggerFacebookGroupsSync = (isManual = false) => {
|
| if (isFbSyncing) return;
|
| const now = Date.now();
|
|
|
| if (!isManual && (now - lastFbSyncTimestamp < 60000)) return;
|
|
|
| isFbSyncing = true;
|
| lastFbSyncTimestamp = now;
|
|
|
| if (isManual) {
|
| addLog("جاري فحص وتوثيق جلسة فيسبوك ومزامنة المجموعات...", "info");
|
| }
|
|
|
| if (chrome && chrome.runtime && chrome.runtime.sendMessage) {
|
| chrome.runtime.sendMessage({ action: 'getGroups' }, async (response) => {
|
| isFbSyncing = false;
|
| if (response && response.success && response.groups && response.groups.length > 0) {
|
| if (global.FritreeFacebook && typeof global.FritreeFacebook.setGroups === 'function') {
|
| await global.FritreeFacebook.setGroups(response.groups, response.userId);
|
| }
|
| if (global.FritreeStorage) {
|
| await global.FritreeStorage.set('local_groups', response.groups);
|
| await global.FritreeStorage.set('userId', response.userId || 'fb_user');
|
| }
|
|
|
| const fbDashGroups = document.getElementById('ua07ivc7rv');
|
| if (fbDashGroups) fbDashGroups.innerHTML = `<i class="fa-solid fa-users"></i> <span>${response.groups.length.toLocaleString('en-US')}</span>`;
|
|
|
| const badge = document.getElementById('d769nsyxio');
|
| const statusText = document.getElementById('mbgc4irrsa');
|
| const startFbBtn = document.getElementById('q0ilg5gt03');
|
|
|
| if (badge) {
|
| badge.style.background = "var(--primary-light)";
|
| badge.style.borderColor = "var(--primary-border)";
|
| }
|
| if (statusText) {
|
| statusText.innerHTML = `<i class="fa-solid fa-plug-circle-check"></i> <span>فيسبوك متصل</span>`;
|
| statusText.style.color = "var(--primary)";
|
| }
|
| if (startFbBtn) startFbBtn.disabled = false;
|
|
|
| addLog(`تمت مزامنة [${response.groups.length.toLocaleString('en-US')}] مجموعة فيسبوك بنجاح!`, "success");
|
| } else {
|
| if (isManual) {
|
| addLog(response?.message || "يرجى تسجيل الدخول إلى فيسبوك في المتصفح لتوثيق الجلسة.", "warn");
|
| }
|
| }
|
| });
|
| } else {
|
| isFbSyncing = false;
|
| }
|
| };
|
|
|
| |
| |
|
|
| const checkConnectedSessions = async () => {
|
| try {
|
|
|
| if (global.FritreeStorage) {
|
| const storedFbGroups = await global.FritreeStorage.get('local_groups', []);
|
| if (storedFbGroups && storedFbGroups.length > 0) {
|
| const fbDashGroups = document.getElementById('ua07ivc7rv');
|
| if (fbDashGroups) fbDashGroups.innerHTML = `<i class="fa-solid fa-users"></i> <span>${storedFbGroups.length.toLocaleString('en-US')}</span>`;
|
| }
|
| }
|
|
|
| if (typeof chrome === 'undefined') return;
|
|
|
|
|
| if (chrome.cookies && chrome.cookies.getAll) {
|
| chrome.cookies.getAll({ domain: '.facebook.com', name: 'c_user' }, (cookies) => {
|
| let cUserVal = (cookies && cookies.length > 0) ? cookies[0].value : null;
|
| if (!cUserVal) {
|
| chrome.cookies.getAll({ name: 'c_user' }, (allC) => {
|
| const found = (allC || []).find(c => c.domain && c.domain.includes('facebook'));
|
| handleFacebookCookieResult(found ? found.value : null);
|
| });
|
| } else {
|
| handleFacebookCookieResult(cUserVal);
|
| }
|
| });
|
| } else {
|
|
|
| const storedFbGroups = global.FritreeStorage ? await global.FritreeStorage.get('local_groups', []) : [];
|
| if (storedFbGroups && storedFbGroups.length > 0) {
|
| handleFacebookCookieResult('pwa_synced_user');
|
| }
|
| }
|
|
|
|
|
| if (chrome.tabs && chrome.tabs.query) {
|
| chrome.tabs.query({ url: ['*://web.whatsapp.com/*', '*://*.whatsapp.com/*'] }, async (tabs) => {
|
| const hasTab = tabs && tabs.length > 0;
|
| const isWaStoredConnected = global.FritreeStorage ? await global.FritreeStorage.get('wa_connected', false) : false;
|
| const finalWaConnected = hasTab || isWaStoredConnected;
|
| updateWAUIStatus(finalWaConnected);
|
| });
|
| } else {
|
| const isWaStored = global.FritreeStorage ? await global.FritreeStorage.get('wa_connected', false) : false;
|
| updateWAUIStatus(isWaStored);
|
| }
|
| } catch (e) {
|
| silentTrap(e);
|
| }
|
| };
|
|
|
| const handleFacebookCookieResult = (cUserVal) => {
|
| const badge = document.getElementById('d769nsyxio');
|
| const startFbBtn = document.getElementById('q0ilg5gt03');
|
| const statusText = document.getElementById('mbgc4irrsa');
|
|
|
| if (cUserVal) {
|
| if (badge) {
|
| badge.style.background = "var(--primary-light)";
|
| badge.style.borderColor = "var(--primary-border)";
|
| }
|
| if (statusText) {
|
| statusText.innerHTML = `<i class="fa-solid fa-plug-circle-check"></i> <span>فيسبوك متصل</span>`;
|
| statusText.style.color = "var(--primary)";
|
| }
|
| if (startFbBtn) startFbBtn.disabled = false;
|
|
|
|
|
| triggerFacebookGroupsSync(false);
|
| } else {
|
| if (badge) {
|
| badge.style.background = "var(--danger-light)";
|
| badge.style.borderColor = "var(--danger-border)";
|
| }
|
| if (statusText) {
|
| statusText.innerHTML = `<i class="fa-solid fa-plug-circle-xmark"></i> <span>فيسبوك غير متصل</span>`;
|
| statusText.style.color = "var(--danger)";
|
| }
|
| }
|
| };
|
|
|
| const updateWAUIStatus = (connected) => {
|
| try {
|
| const badge = document.getElementById('hzo3r22pug');
|
| const startWaBtn = document.getElementById('ciqrxeqovl');
|
| const warningBanner = document.getElementById('ns1lig1nty');
|
| const statusText = document.getElementById('hii0s83z9e');
|
|
|
| if (badge) {
|
| if (connected) {
|
| badge.style.background = "var(--wa-light)";
|
| badge.style.borderColor = "var(--wa-border)";
|
| if (statusText) {
|
| statusText.innerHTML = `<i class="fa-solid fa-plug-circle-check"></i> <span>واتساب متصل</span>`;
|
| statusText.style.color = "var(--wa-brand)";
|
| }
|
| } else {
|
| badge.style.background = "var(--danger-light)";
|
| badge.style.borderColor = "var(--danger-border)";
|
| if (statusText) {
|
| statusText.innerHTML = `<i class="fa-solid fa-plug-circle-xmark"></i> <span>واتساب غير متصل</span>`;
|
| statusText.style.color = "var(--danger)";
|
| }
|
| }
|
| }
|
| if (startWaBtn) startWaBtn.disabled = !connected;
|
| if (warningBanner) warningBanner.style.display = connected ? 'none' : 'block';
|
| } catch (e) {
|
| silentTrap(e);
|
| }
|
| };
|
|
|
| |
| |
|
|
| const triggerFacebookCampaign = async () => {
|
| const selectedGroupIds = global.FritreeFacebook ? global.FritreeFacebook.getSelectedIds() : [];
|
| if (selectedGroupIds.length === 0) {
|
| alert('اختار مجموعة فيسبوك واحدة على الأقل لبدء الحملة!');
|
| return;
|
| }
|
|
|
| const isScheduleChecked = document.getElementById('k58hokq80h')?.checked || false;
|
| const scheduledTime = document.getElementById('b3qy01i1dm')?.value;
|
|
|
| if (isScheduleChecked) {
|
| if (!scheduledTime || new Date(scheduledTime).getTime() <= Date.now()) {
|
| alert('اختر تاريخاً ووقتاً مستقبلياً صالحاً لجدولة الحملة!');
|
| return;
|
| }
|
| const baseText = global.FritreeFacebookComposer ? global.FritreeFacebookComposer.getComposerText() : '';
|
| const images = global.FritreeFacebookComposer ? await global.FritreeFacebookComposer.getUploadedImages() : [];
|
| const delayConfig = global.FritreeFacebookComposer ? global.FritreeFacebookComposer.getDelayConfig() : { mode: 'random', minSeconds: 45, maxSeconds: 120 };
|
| const launchMode = document.getElementById('q2hxmk5c3l')?.value || 'tab';
|
|
|
| const newSchedItem = {
|
| id: 'sched_fb_' + Date.now() + '_' + Math.random().toString(36).substr(2, 4),
|
| name: `حملة فيسبوك مجدولة (${selectedGroupIds.length} مجموعة)`,
|
| platform: 'facebook',
|
| scheduledTime: scheduledTime,
|
| text: baseText,
|
| images: images,
|
| groupIds: selectedGroupIds,
|
| delayConfig: delayConfig,
|
| launchMode: launchMode,
|
| status: 'scheduled',
|
| createdAt: new Date().toISOString()
|
| };
|
|
|
| const currentList = await global.FritreeStorage.get('scheduledCampaignsData', []) || [];
|
| currentList.unshift(newSchedItem);
|
| await global.FritreeStorage.set('scheduledCampaignsData', currentList);
|
|
|
| alert(`تمت جدولة حملة فيسبوك بنجاح لتنطلق تلقائياً بتاريخ: ${new Date(scheduledTime).toLocaleString('en-US')}`);
|
| window.location.hash = 'ss7cgkeahf';
|
| return;
|
| }
|
|
|
| const fbPoints = global.FritreeDashboard ? global.FritreeDashboard.getFbPoints() : 0;
|
| if (fbPoints < 1) {
|
| handleInsufficientBalanceAbort('facebook');
|
| return;
|
| }
|
|
|
| let baseText = "";
|
| let images = [];
|
| let isLibraryMode = false;
|
| let payloadMap = {};
|
|
|
| const resetPublishButtonsOnFailure = () => {
|
| const btnStart = document.getElementById('q0ilg5gt03');
|
| const btnStop = document.getElementById('ctmo3psebt');
|
| const btnFreeze = document.getElementById('te6ue1mcua');
|
| if (btnStart) btnStart.disabled = false;
|
| if (btnStop) btnStop.disabled = true;
|
| if (btnFreeze) btnFreeze.disabled = true;
|
| };
|
|
|
| try {
|
| const isRotationActive = global.FritreeRotation ? global.FritreeRotation.isRotationActive() : false;
|
| if (isRotationActive) {
|
| isLibraryMode = true;
|
| addLog("جاري تجهيز وتوزيع المنشورات من مكتبة التدوير التلقائي...", "info");
|
| const activeMode = await global.FritreeStorage.get('local_rotation_mode', 'balanced');
|
| const availableIds = global.FritreeRotation.getPosts().map(p => p.id);
|
|
|
| if (availableIds.length === 0) {
|
| alert("وضع التدوير مفعل ولكن لا توجد منشورات نشطة محددة.");
|
| resetPublishButtonsOnFailure();
|
| return;
|
| }
|
|
|
| for (let idx = 0; idx < selectedGroupIds.length; idx++) {
|
| const gId = selectedGroupIds[idx];
|
| const postObj = global.FritreeRotation.selectNextPost(activeMode, availableIds);
|
| if (!postObj) {
|
| alert("لم يتم العثور على منشور نشط يطابق شروط التدوير الحالية.");
|
| resetPublishButtonsOnFailure();
|
| return;
|
| }
|
|
|
| payloadMap[gId] = {
|
| text: postObj.text || postObj.altText || '',
|
| images: postObj.mediaReferences || [],
|
| uuid: postObj.id
|
| };
|
| }
|
| } else {
|
| baseText = global.FritreeFacebookComposer ? global.FritreeFacebookComposer.getComposerText() : '';
|
| images = global.FritreeFacebookComposer ? await global.FritreeFacebookComposer.getUploadedImages() : [];
|
|
|
| if (!baseText && images.length === 0) {
|
| alert("لا يمكن نشر منشور فارغ! اكتب نصاً أو ارفع صورة أولاً.");
|
| resetPublishButtonsOnFailure();
|
| return;
|
| }
|
| }
|
|
|
| const delayConfig = global.FritreeFacebookComposer ? global.FritreeFacebookComposer.getDelayConfig() : { mode: 'random', minSeconds: 45, maxSeconds: 120 };
|
| const launchMode = document.getElementById('q2hxmk5c3l')?.value || 'tab';
|
|
|
| setDomTextSafely('uns2dhjlx2', selectedGroupIds.length);
|
| setDomTextSafely('yn082h7vxq', 0);
|
| setDomTextSafely('pe147sfejg', 0);
|
| setDomTextSafely('c2hyj1dsyf', 0);
|
|
|
| const campaignId = 'manual_fb_' + Date.now();
|
| lastLaunchedCampaignId = campaignId;
|
| const campaignName = 'حملة نشر يدوية فيسبوك';
|
| startCampaignTrackingTimers();
|
|
|
| const activeCampaignImages = [];
|
| for (const img of images) {
|
| const rawBlob = await global.FritreeStorage.get(`media_blob_${img.id}`);
|
| if (rawBlob) {
|
| await global.FritreeStorage.set(`media_blob_active_${campaignId}_${img.id}`, rawBlob);
|
| activeCampaignImages.push({ id: img.id, name: img.name, type: img.type });
|
| }
|
| }
|
|
|
| if (global.FritreeFacebookComposer) {
|
| await global.FritreeFacebookComposer.savePublishedPostToRecent(baseText, activeCampaignImages, selectedGroupIds);
|
| }
|
|
|
| chrome.runtime.sendMessage({
|
| action: "publishToMultipleGroups",
|
| campaignId,
|
| campaignName,
|
| groupIds: selectedGroupIds,
|
| text: baseText,
|
| images: activeCampaignImages,
|
| delayConfig,
|
| isLibraryMode,
|
| payloadMap,
|
| launchMode
|
| });
|
|
|
| const btnStart = document.getElementById('q0ilg5gt03');
|
| const btnPause = document.getElementById('ctmo3psebt');
|
| const btnFreeze = document.getElementById('te6ue1mcua');
|
|
|
| if (btnStart) btnStart.disabled = false;
|
| if (btnPause) {
|
| btnPause.disabled = false;
|
| btnPause.setAttribute('data-state', 'running');
|
| btnPause.innerHTML = '<i class="fa-solid fa-pause"></i> <span>إيقاف مؤقت للحملة</span>';
|
| }
|
| if (btnFreeze) btnFreeze.disabled = false;
|
|
|
| } catch (err) {
|
| silentTrap(err);
|
| resetPublishButtonsOnFailure();
|
| stopCampaignTrackingTimers();
|
| }
|
| };
|
|
|
| |
| |
|
|
| const triggerWhatsAppCampaign = async () => {
|
| const recipients = global.FritreeWhatsApp ? global.FritreeWhatsApp.getRecipients() : [];
|
| if (recipients.length === 0) {
|
| alert("قائمة مستلمي الواتساب فارغة. يرجى إضافة أرقام العملاء أولاً!");
|
| return;
|
| }
|
|
|
| const isScheduleChecked = document.getElementById('eve1rrjds1')?.checked || false;
|
| const scheduledTime = document.getElementById('xlz92zcfuh')?.value;
|
|
|
| if (isScheduleChecked) {
|
| if (!scheduledTime || new Date(scheduledTime).getTime() <= Date.now()) {
|
| alert('اختر تاريخاً ووقتاً مستقبلياً صالحاً لجدولة الرسائل!');
|
| return;
|
| }
|
| let text = global.FritreeWhatsAppComposer ? global.FritreeWhatsAppComposer.getComposerText() : '';
|
| const waComposerImages = global.FritreeWhatsAppComposer ? await global.FritreeWhatsAppComposer.getUploadedImages() : [];
|
| const delayConfig = global.FritreeWhatsAppComposer ? global.FritreeWhatsAppComposer.getDelayConfig() : { mode: "random", minSeconds: 60, maxSeconds: 150 };
|
| const launchMode = document.getElementById('cdeyq8k3xd')?.value || 'tab';
|
|
|
| const newSchedItem = {
|
| id: 'sched_wa_' + Date.now() + '_' + Math.random().toString(36).substr(2, 4),
|
| name: `حملة واتساب مجدولة (${recipients.length} مستلم)`,
|
| platform: 'whatsapp',
|
| scheduledTime: scheduledTime,
|
| text: text,
|
| images: waComposerImages,
|
| recipients: recipients,
|
| delayConfig: delayConfig,
|
| launchMode: launchMode,
|
| status: 'scheduled',
|
| createdAt: new Date().toISOString()
|
| };
|
|
|
| const currentList = await global.FritreeStorage.get('scheduledCampaignsData', []) || [];
|
| currentList.unshift(newSchedItem);
|
| await global.FritreeStorage.set('scheduledCampaignsData', currentList);
|
|
|
| alert(`تمت جدولة رسائل الواتساب بنجاح لتنطلق تلقائياً بتاريخ: ${new Date(scheduledTime).toLocaleString('en-US')}`);
|
| window.location.hash = 'ss7cgkeahf';
|
| return;
|
| }
|
|
|
| const waPoints = global.FritreeDashboard ? global.FritreeDashboard.getWaPoints() : 0;
|
| if (waPoints < 1) {
|
| handleInsufficientBalanceAbort('whatsapp');
|
| return;
|
| }
|
|
|
| let text = global.FritreeWhatsAppComposer ? global.FritreeWhatsAppComposer.getComposerText() : '';
|
| const waComposerImages = global.FritreeWhatsAppComposer ? await global.FritreeWhatsAppComposer.getUploadedImages() : [];
|
|
|
| if (!text && waComposerImages.length === 0) {
|
| alert("لا يمكن إرسال رسالة فارغة! اكتب نص الرسالة أو ارفق صور/فيديو أولاً.");
|
| return;
|
| }
|
|
|
| const btnStart = document.getElementById('ciqrxeqovl');
|
| const btnPause = document.getElementById('fne7jmd8cp');
|
| const btnFreeze = document.getElementById('nnsh4j5crx');
|
|
|
| try {
|
| const delayConfig = global.FritreeWhatsAppComposer ? global.FritreeWhatsAppComposer.getDelayConfig() : { mode: "random", minSeconds: 60, maxSeconds: 150 };
|
| const launchMode = document.getElementById('cdeyq8k3xd')?.value || 'tab';
|
|
|
| setDomTextSafely('n5kl1m8coi', recipients.length);
|
| setDomTextSafely('hig5lc1irj', 0);
|
|
|
| if (btnStart) btnStart.disabled = true;
|
| if (btnPause) {
|
| btnPause.disabled = false;
|
| btnPause.setAttribute('data-state', 'running');
|
| btnPause.innerHTML = '<i class="fa-solid fa-pause"></i> <span>إيقاف مؤقت للحملة</span>';
|
| }
|
| if (btnFreeze) btnFreeze.disabled = false;
|
|
|
| startCampaignTrackingTimers();
|
| const campaignId = 'manual_wa_' + Date.now();
|
| lastLaunchedCampaignId = campaignId;
|
|
|
| const activeCampaignImages = [];
|
| for (const img of waComposerImages) {
|
| const rawBlob = await global.FritreeStorage.get(`media_blob_${img.id}`);
|
| if (rawBlob) {
|
| await global.FritreeStorage.set(`media_blob_active_${campaignId}_${img.id}`, rawBlob);
|
| activeCampaignImages.push({ id: img.id, name: img.name, type: img.type });
|
| }
|
| }
|
|
|
| if (global.FritreeTextCompiler) {
|
| text = await global.FritreeTextCompiler.asyncParseVariables(text);
|
| }
|
|
|
| chrome.runtime.sendMessage({
|
| action: "start_wa_campaign",
|
| campaignId,
|
| recipients,
|
| text,
|
| media: activeCampaignImages,
|
| delayConfig,
|
| launchMode
|
| });
|
|
|
| } catch (err) {
|
| silentTrap(err);
|
| if (btnStart) btnStart.disabled = false;
|
| stopCampaignTrackingTimers();
|
| }
|
| };
|
|
|
| |
| |
|
|
| const handleFacebookProgress = (data) => {
|
| try {
|
| const campaignId = data.campaignId || 'legacy';
|
| const campaignName = data.campaignName || 'حملة فيسبوك نشطة';
|
| const current = data.current;
|
| const total = data.total;
|
| const gId = data.groupId;
|
| const status = data.status;
|
| const error = data.error;
|
| const postUrl = data.postUrl;
|
|
|
| const metrics = activeCampaignsMetrics.get(campaignId) || { success: 0, pending: 0, failed: 0 };
|
| if (status === 'success') metrics.success++;
|
| else if (status === 'pending') metrics.pending++;
|
| else if (status === 'failed') metrics.failed++;
|
| activeCampaignsMetrics.set(campaignId, metrics);
|
|
|
| if (status === 'success') {
|
| addLog(`[${campaignName}] تم نشر المنشور بنجاح داخل مجموعة فيسبوك: [${gId}].`, 'success');
|
| updateFacebookStatsCounter('success');
|
| addProofLinkRow(gId, 'Success', postUrl);
|
| if (global.FritreeProgressionService) global.FritreeProgressionService.progressTask('fb_post', 1);
|
| } else if (status === 'pending') {
|
| addLog(`[${campaignName}] تم النشر داخل مجموعة فيسبوك: [${gId}] ومعلق حالياً بانتظار موافقة الإدارة.`, 'warn');
|
| updateFacebookStatsCounter('pending');
|
| addProofLinkRow(gId, 'Pending Approval', postUrl || '#');
|
| if (global.FritreeProgressionService) global.FritreeProgressionService.progressTask('fb_post', 1);
|
| } else if (status === 'failed') {
|
| addLog(`[${campaignName}] فشل النشر داخل مجموعة فيسبوك: [${gId}].`, 'error');
|
| updateFacebookStatsCounter('failed');
|
| addProofLinkRow(gId, 'Restricted', null, error);
|
| }
|
|
|
| if (data.variantName && (status === 'success' || status === 'pending' || status === 'failed')) {
|
| if (global.FritreeRotationStore) global.FritreeRotationStore.incrementUsage(data.variantName, status);
|
| }
|
|
|
| const fill = document.getElementById('yuc3c21zr2');
|
| const pctLabel = document.getElementById('gu66d84s18');
|
| const pct = Math.round((current / total) * 100);
|
| if (fill) fill.style.width = `${pct}%`;
|
| if (pctLabel) pctLabel.textContent = `${pct}%`;
|
| } catch (e) {
|
| silentTrap(e);
|
| }
|
| };
|
|
|
| const updateFacebookStatsCounter = (type) => {
|
| try {
|
| if (type === 'success') {
|
| const el = document.getElementById('yn082h7vxq');
|
| if (el) el.innerHTML = `<i class="fa-solid fa-thumbs-up" style="font-size:15px; color:#10b981;"></i> ${parseInt(el.textContent || '0', 10) + 1}`;
|
| completedStepsCount++;
|
| } else if (type === 'pending') {
|
| const el = document.getElementById('pe147sfejg');
|
| if (el) el.innerHTML = `<i class="fa-solid fa-hourglass-half" style="font-size:15px; color:#f59e0b;"></i> ${parseInt(el.textContent || '0', 10) + 1}`;
|
| completedStepsCount++;
|
| } else if (type === 'failed') {
|
| const el = document.getElementById('c2hyj1dsyf');
|
| if (el) el.innerHTML = `<i class="fa-solid fa-triangle-exclamation" style="font-size:15px; color:#ef4444;"></i> ${parseInt(el.textContent || '0', 10) + 1}`;
|
| completedStepsCount++;
|
| }
|
| } catch (e) {
|
| silentTrap(e);
|
| }
|
| };
|
|
|
| const handleWhatsAppProgress = (data) => {
|
| try {
|
| const current = data.current;
|
| const total = data.total;
|
| const phone = data.phone;
|
| const name = data.name;
|
| const status = data.status;
|
| const error = data.error;
|
|
|
| if (status === 'success') {
|
| addLog(`تم إرسال الرسالة بنجاح لـ: ${name} (${phone}).`, 'success');
|
| const el = document.getElementById('hig5lc1irj');
|
| if (el) el.innerHTML = `<i class="fa-solid fa-paper-plane" style="font-size:15px; color:#00a884;"></i> ${parseInt(el.textContent || '0', 10) + 1}`;
|
| addProofLinkRow(phone, 'Success', `https://web.whatsapp.com/send?phone=${phone.replace(/[^0-9]/g, '')}`);
|
| if (global.FritreeProgressionService) global.FritreeProgressionService.progressTask('wa_send', 1);
|
| } else if (status === 'failed') {
|
| addLog(`فشل الإرسال لـ: ${name} (${phone}).`, 'error');
|
| addProofLinkRow(phone, 'Failed', null, error);
|
| }
|
|
|
| const pct = Math.round((current / total) * 100);
|
| const fill = document.getElementById('vsc6h9bses');
|
| const pctLabel = document.getElementById('z5eisfkgpg');
|
| if (fill) fill.style.width = `${pct}%`;
|
| if (pctLabel) pctLabel.textContent = `${pct}%`;
|
| } catch (e) {
|
| silentTrap(e);
|
| }
|
| };
|
|
|
| const addProofLinkRow = (target, stateText, proofUrl, errorMsg = '') => {
|
| try {
|
| const tbody = document.querySelector('#rne8yohkuk tbody');
|
| if (!tbody) return;
|
| const fallbackRow = document.getElementById('tslozgkksi');
|
| if (fallbackRow) fallbackRow.remove();
|
|
|
| const tr = document.createElement('tr');
|
| tr.style.borderBottom = '1px solid var(--border)';
|
| const tdTarget = document.createElement('td');
|
| tdTarget.style.cssText = 'font-weight: 700; padding: 8px 10px; font-family: var(--font-code); font-size: 11.5px;';
|
| tdTarget.textContent = target;
|
|
|
| const tdState = document.createElement('td');
|
| tdState.style.cssText = 'text-align: center; padding: 8px 10px;';
|
| const badge = document.createElement('span');
|
| let badgeClass = 'go30y9mfgh ';
|
| let displayState = stateText;
|
|
|
| if (stateText === 'Success') {
|
| badgeClass += 'success';
|
| displayState = 'ناجح';
|
| } else if (stateText === 'Pending Approval') {
|
| badgeClass += 'pending';
|
| displayState = 'قيد المراجعة';
|
| } else {
|
| badgeClass += 'failed';
|
| displayState = 'فشل';
|
| }
|
|
|
| badge.className = badgeClass;
|
| badge.textContent = displayState;
|
| tdState.appendChild(badge);
|
|
|
| const tdLink = document.createElement('td');
|
| tdLink.style.cssText = 'text-align: center; padding: 8px 10px;';
|
| if (proofUrl) {
|
| const link = document.createElement('a');
|
| link.href = proofUrl;
|
| link.target = '_blank';
|
| link.style.cssText = 'font-weight: 700; text-decoration: none; display: inline-flex; align-items: center; gap: 4px; color: var(--primary); font-size: 11px;';
|
| link.innerHTML = '<i class="fa-solid fa-up-right-from-square"></i> <span>فتح الرابط</span>';
|
| tdLink.appendChild(link);
|
| } else {
|
| const errSpan = document.createElement('span');
|
| errSpan.style.cssText = 'font-size: 10.5px; font-weight: 700; color: var(--danger);';
|
| errSpan.textContent = errorMsg || 'غير متاح';
|
| tdLink.appendChild(errSpan);
|
| }
|
|
|
| tr.appendChild(tdTarget);
|
| tr.appendChild(tdState);
|
| tr.appendChild(tdLink);
|
| tbody.appendChild(tr);
|
| } catch (e) {
|
| silentTrap(e);
|
| }
|
| };
|
|
|
| |
| |
|
|
| const bindBackgroundMessageTunnelListener = () => {
|
| try {
|
| if (typeof chrome !== 'undefined' && chrome.runtime && chrome.runtime.onMessage) {
|
| chrome.runtime.onMessage.addListener((message) => {
|
| try {
|
| if (message.action === 'publishProgress') {
|
| handleFacebookProgress(message);
|
| } else if (message.action === 'publishCountdown') {
|
| addLog(`فترة انتظار وتبريد: الخطوة القادمة ستبدأ خلال ${message.seconds} ثانية.`, 'warn');
|
| totalCooldownSeconds++;
|
| } else if (message.action === 'publishComplete') {
|
| addLog(`اكتملت حملة فيسبوك بنجاح!`, "success");
|
| stopCampaignTrackingTimers();
|
| syncWorkspaceUI();
|
| } else if (message.action === 'wa_send_progress') {
|
| handleWhatsAppProgress(message);
|
| } else if (message.action === 'wa_send_countdown') {
|
| addLog(`فترة انتظار وتبريد واتساب: ${message.seconds} ثانية...`, 'warn');
|
| totalCooldownSeconds++;
|
| } else if (message.action === 'wa_send_complete') {
|
| addLog("اكتملت حملة الواتساب بنجاح!", "success");
|
| stopCampaignTrackingTimers();
|
| syncWorkspaceUI();
|
| } else if (message.action === 'scheduled_list_updated') {
|
| renderScheduledQueueTable();
|
| } else if (message.action === 'CAMPAIGN_ABORTED_INSUFFICIENT_BALANCE') {
|
| handleInsufficientBalanceAbort(message.platform);
|
| }
|
| } catch (inner) {
|
| silentTrap(inner);
|
| }
|
| });
|
| }
|
| } catch (e) {
|
| silentTrap(e);
|
| }
|
| };
|
|
|
| const handleInsufficientBalanceAbort = async (platform) => {
|
| stopCampaignTrackingTimers();
|
| alert(`تنبيه: رصيد نقاط ${platform === 'facebook' ? 'فيسبوك' : 'واتساب'} غير كافٍ. يرجى الشحن من المتجر.`);
|
| window.location.hash = 'dc1z57si9s';
|
| };
|
|
|
| |
| |
|
|
| const bindDocumentClickDelegation = () => {
|
| document.addEventListener('click', (e) => {
|
| const targetElem = e.target.closest('[data-target]');
|
| if (targetElem) {
|
| const targetId = targetElem.getAttribute('data-target');
|
| if (targetId && !targetElem.closest('#q0ilg5gt03') && !targetElem.closest('#ciqrxeqovl')) {
|
| window.location.hash = targetId;
|
| }
|
| }
|
|
|
| if (e.target.closest('#b8imusheoz')) {
|
| window.location.hash = 'sf1xx5vcac';
|
| return;
|
| }
|
| if (e.target.closest('#nog5je6ddx')) {
|
| window.location.hash = 'sf8pufcpyl';
|
| return;
|
| }
|
| if (e.target.closest('#frtal49mqm')) {
|
| window.location.hash = 'j2nzw12azj';
|
| return;
|
| }
|
|
|
|
|
| if (e.target.closest('#d769nsyxio')) {
|
| triggerFacebookGroupsSync(true);
|
| return;
|
| }
|
|
|
| if (e.target.closest('#hzo3r22pug')) {
|
| if (chrome.tabs && chrome.tabs.create) {
|
| chrome.tabs.create({ url: 'https://web.whatsapp.com' }, () => {
|
| setTimeout(checkConnectedSessions, 3000);
|
| });
|
| } else {
|
| window.open('https://web.whatsapp.com', '_blank');
|
| setTimeout(checkConnectedSessions, 3000);
|
| }
|
| return;
|
| }
|
|
|
| if (e.target.closest('#n3jlayvv4s')) {
|
| window.location.hash = 'qt3bcp0qq8';
|
| return;
|
| }
|
|
|
| if (e.target.closest('#h4we1yzu71')) {
|
| if (global.FritreePacingUI && typeof global.FritreePacingUI.openModal === 'function') {
|
| global.FritreePacingUI.openModal('fb');
|
| }
|
| return;
|
| }
|
|
|
| if (e.target.closest('#wjdexzlzuv')) {
|
| const terminal = document.getElementById('r99bttinj8');
|
| if (terminal) terminal.innerHTML = '';
|
| addLog("تم مسح سجل الأوامر بنجاح.", "warn");
|
| return;
|
| }
|
|
|
| if (e.target.closest('#s24x8dpijy')) {
|
| isTermSuspended = !isTermSuspended;
|
| const btn = document.getElementById('s24x8dpijy');
|
| if (btn) {
|
| btn.innerHTML = isTermSuspended ? '<i class="fa-solid fa-play"></i>' : '<i class="fa-solid fa-pause"></i>';
|
| btn.title = isTermSuspended ? 'استئناف شاشة السجل' : 'إيقاف مؤقت لشاشة السجل';
|
| }
|
| addLog(isTermSuspended ? "تم إيقاف تحديث سجل الأوامر مؤقتاً." : "تم استئناف تحديث سجل الأوامر.", "info");
|
| return;
|
| }
|
|
|
| if (e.target.closest('#q0ilg5gt03')) {
|
| triggerFacebookCampaign();
|
| return;
|
| }
|
|
|
| if (e.target.closest('#ciqrxeqovl')) {
|
| triggerWhatsAppCampaign();
|
| return;
|
| }
|
|
|
| const pauseFbBtn = e.target.closest('#ctmo3psebt');
|
| if (pauseFbBtn && lastLaunchedCampaignId) {
|
| const currentState = pauseFbBtn.getAttribute('data-state') || 'running';
|
| if (currentState === 'running') {
|
| chrome.runtime.sendMessage({ action: 'pause_campaign', campaignId: lastLaunchedCampaignId });
|
| pauseFbBtn.setAttribute('data-state', 'paused');
|
| pauseFbBtn.innerHTML = '<i class="fa-solid fa-play"></i> <span>استئناف الحملة</span>';
|
| } else {
|
| chrome.runtime.sendMessage({ action: 'resume_campaign', campaignId: lastLaunchedCampaignId });
|
| pauseFbBtn.setAttribute('data-state', 'running');
|
| pauseFbBtn.innerHTML = '<i class="fa-solid fa-pause"></i> <span>إيقاف مؤقت للحملة</span>';
|
| }
|
| return;
|
| }
|
|
|
| const pauseWaBtn = e.target.closest('#fne7jmd8cp');
|
| if (pauseWaBtn && lastLaunchedCampaignId) {
|
| const currentState = pauseWaBtn.getAttribute('data-state') || 'running';
|
| if (currentState === 'running') {
|
| chrome.runtime.sendMessage({ action: 'pause_campaign', campaignId: lastLaunchedCampaignId });
|
| pauseWaBtn.setAttribute('data-state', 'paused');
|
| pauseWaBtn.innerHTML = '<i class="fa-solid fa-play"></i> <span>استئناف الحملة</span>';
|
| } else {
|
| chrome.runtime.sendMessage({ action: 'resume_campaign', campaignId: lastLaunchedCampaignId });
|
| pauseWaBtn.setAttribute('data-state', 'running');
|
| pauseWaBtn.innerHTML = '<i class="fa-solid fa-pause"></i> <span>إيقاف مؤقت للحملة</span>';
|
| }
|
| return;
|
| }
|
|
|
| if (e.target.closest('#te6ue1mcua') || e.target.closest('#nnsh4j5crx')) {
|
| if (confirm("هل أنت متأكد من إيقاف وتجميد الحملة النشطة نهائياً؟")) {
|
| chrome.runtime.sendMessage({ action: 'stop_campaign', campaignId: lastLaunchedCampaignId });
|
| stopCampaignTrackingTimers();
|
| }
|
| return;
|
| }
|
| });
|
| };
|
|
|
| |
| |
|
|
| const initOrchestrator = async () => {
|
| try {
|
| const mainContentArea = document.getElementById('s7ihkirolg');
|
| if (!mainContentArea) return false;
|
|
|
| buildSchedulerPaneLayout();
|
| if (global.FritreeStealthUI && typeof global.FritreeStealthUI.buildPane === 'function') {
|
| global.FritreeStealthUI.buildPane();
|
| }
|
| if (global.FritreeBackupService && typeof global.FritreeBackupService.buildPane === 'function') {
|
| global.FritreeBackupService.buildPane();
|
| }
|
|
|
| establishPersistentKeepAlive();
|
| bindDocumentClickDelegation();
|
| window.addEventListener('hashchange', executeHashRouter);
|
|
|
| await syncWorkspaceUI();
|
| executeHashRouter();
|
|
|
| await checkConnectedSessions();
|
| startWorkspaceSecurityHeartbeat();
|
| bindBackgroundMessageTunnelListener();
|
|
|
| global.addLog = addLog;
|
| global.syncWorkspaceUI = syncWorkspaceUI;
|
|
|
|
|
| setTimeout(() => {
|
| triggerFacebookGroupsSync(false);
|
| }, 800);
|
|
|
| addLog("تم تشغيل لوحة التحكم الموحدة ودروع التخفي والمزامنة الذاتية بنجاح!", "info");
|
| return true;
|
| } catch (e) {
|
| silentTrap(e);
|
| return false;
|
| }
|
| };
|
|
|
| |
| |
|
|
| global.FritreeOrchestrator = {
|
| init: initOrchestrator,
|
| addLog,
|
| syncUI: syncWorkspaceUI,
|
| checkSessions: checkConnectedSessions,
|
| syncFacebookGroups: triggerFacebookGroupsSync,
|
| triggerFB: triggerFacebookCampaign,
|
| triggerWA: triggerWhatsAppCampaign,
|
| buildSchedulerPane: buildSchedulerPaneLayout,
|
| renderScheduledQueue: renderScheduledQueueTable
|
| };
|
|
|
| if (typeof document !== 'undefined') {
|
| if (document.readyState === 'complete' || document.readyState === 'interactive') {
|
| initOrchestrator();
|
| } else {
|
| document.addEventListener('DOMContentLoaded', initOrchestrator);
|
| }
|
| }
|
|
|
| })(typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : this); |