أجواء
رقم واتساب غير موثّقيمكنك الدخول، لكن التبليغ يتطلب توثيق الرقم.0?’يمكنك طلب رابط جديد بعد’:’يمكنك طلب الرابط الآن’}${waiting>0?formatPhoneCountdown(waiting):’متاح’}
${adminEscape(reviewLabel)}`; } const shell=document.querySelector(‘.report-shell’);if(shell)shell.scrollTo({top:0,behavior:force?’auto’:’smooth’}); if(stage===1&&state.maps.mini)setTimeout(()=>state.maps.mini.invalidateSize(),80); return true; }
async function handleReportSubmit(e){ e.preventDefault();
showConfirmModal(“هل أنت متأكد من إرسال هذا التقرير؟”, async ()=> { const data=Object.fromEntries(new FormData(e.target).entries()); data.lat=document.getElementById(‘lat’).value;data.lon=document.getElementById(‘lon’).value;
if (data.type===‘assault_mode’) { if (!data.assault_subtype) { showAppModal(‘خطأ’, “يرجى تحديد نوع الاعتداء”, ‘error’); return; } data.type=data.assault_subtype; delete data.assault_subtype; }
const circ=document.querySelector(‘input[value=”circular”]’).checked; data.is_circular_flight=circ?1:0; if(document.querySelector(‘input[value=”direction”]’).checked){const class=document.querySelector(‘input[name=”aircraft_direction”]:checked’);if(dir)data.aircraft_direction=dir.value;} if(!data.lat){showAppModal(‘خطأ’, “حدد الموقع”, ‘error’);return;} if(!data.city || data.city.trim()===“”) { showAppModal(‘خطأ’, “يرجى تحديد المنطقة (اسم القرية أو المدينة)!”, ‘error’); return; }
try{const res=await fetch(`${API_URL}?action=add_report`,{method:’POST’,body:JSON.stringify(data)});const result=await res.json();if(res.ok){showAppModal(‘وصل بلاغك’, “ظهر البلاغ كبلاغ منفرد، وسيتحوّل إلى متقاطع جماعياً عند ورود بلاغ مستقل قريب.”, ‘success’);e.target.reset();document.getElementById(‘lat’).value=””;document.getElementById(‘lon’).value=””;document.getElementById(‘selected-location-name’).textContent=”لم تحدد موقعاً بعد”;delete document.getElementById(‘selected-location-name’).dataset.state;toggleReportStage(1,true);router.navigate(‘home’);}else showAppModal(‘تعذر الإرسال’, result.error||”فشل الإرسال”, ‘error’);}catch(x){showAppModal(‘خطأ’, “خطأ في الاتصال”, ‘error’);} }); }
// — STATS OVERHAUL LOGIC — state.statsData=null; state.statsPeriod=‘daily’; state.statsMapMode=”markers”; // ‘markers’ | ‘heat’ state.statsHeatPoints=[]; state.statsCurrentFilter=”all”;
function stepStatsDate(days) { const input=document.getElementById(‘stats-date’); const curVal=input.value || getBeirutDateString(); const d=new Date(curVal); d.setDate(d.getDate() + days); input.value=d.toISOString().split(‘T’)[0]; loadStats(); }
function setStatsToday() { const input=document.getElementById(‘stats-date’); input.value=getBeirutDateString(); loadStats(); }
function switchStatsPeriod(period) { state.statsPeriod=period; document.querySelectorAll(‘.period-btn’).forEach(b=> { b.classList.toggle(‘active’, b.dataset.period===period); }); updateStatsKPIs(); }
function updateStatsKPIs() { if(!state.statsData) return; const p=state.statsPeriod; let tot=state.statsData.totals; if(p===‘weekly’) tot=state.statsData.weekly_totals; if(p===‘monthly’) tot=state.statsData.monthly_totals; if(!tot) tot={};
const totalCount=parseInt(tot.total || 0, 10); const uav=parseInt(tot.uav || 0, 10); const fighter=parseInt(tot.fighter || 0, 10); const shelling=parseInt(tot.shelling || 0, 10); const drone=parseInt(tot.drone || 0, 10); const heli=parseInt(tot.helicopter || 0, 10);
totalCount > 0 ? `${Math.round((v / totalCount) * 100)}%` : ‘0%’;
document.getElementById(‘kpi-uav’).innerText=uav; document.getElementById(‘kpi-uav-pct’).innerText=calcPct(uav); document.getElementById(‘kpi-uav-bar’).style.width=calcPct(uav);
document.getElementById(‘kpi-fighter’).innerText=fighter; document.getElementById(‘kpi-fighter-pct’).innerText=calcPct(fighter); document.getElementById(‘kpi-fighter-bar’).style.width=calcPct(fighter);
document.getElementById(‘kpi-shelling’).innerText=shelling; document.getElementById(‘kpi-shelling-pct’).innerText=calcPct(shelling); document.getElementById(‘kpi-shelling-bar’).style.width=calcPct(shelling);
document.getElementById(‘kpi-drone’).innerText=drone; document.getElementById(‘kpi-drone-pct’).innerText=calcPct(drone); document.getElementById(‘kpi-drone-bar’).style.width=calcPct(drone);
document.getElementById(‘kpi-helicopter’).innerText=heli; document.getElementById(‘kpi-helicopter-pct’).innerText=calcPct(heli); document.getElementById(‘kpi-helicopter-bar’).style.width=calcPct(heli);
const periodLabel=p===‘daily’ ? ‘اليوم’ : (p===‘weekly’ ? ‘آخر 7 أيام’ : ‘هذا الشهر’); document.getElementById(‘stats-total-badge’).innerText=`${totalCount} بلاغ (${periodLabel})`; }
function setStatsMapMode(mode) { state.statsMapMode=mode; const btnMarkers=document.getElementById(‘btn-mode-markers’); const btnHeat=document.getElementById(‘btn-mode-heat’); if(btnMarkers) btnMarkers.classList.toggle(‘active’, mode===‘markers’); if(btnHeat) btnHeat.classList.toggle(‘active’, mode===‘heat’);
const labelEl=document.getElementById(‘stats-map-mode-label’); if(!state.maps.stats) return;
if(mode===‘heat’) { // Remove icon markers state.statsMarkers.forEach(m=> state.maps.stats.removeLayer(m)); // Add heat layer if(!state.heatLayer && state.statsHeatPoints.length > 0) { state.heatLayer=L.heatLayer(state.statsHeatPoints, { radius: 32, blur: 24, maxZoom: 16, minOpacity: 0.45, gradient: { 0.2: ‘#38bdf8’, 0.4: ‘#10b981’, 0.6: ‘#eab308’, 0.8: ‘#f97316’, 1.0: ‘#ef4444’ } }); } if(state.heatLayer) state.heatLayer.addTo(state.maps.stats); if(labelEl) labelEl.innerHTML=‘ خريطة الكثافة الحرارية (Heatmap)’; } else { // Remove heat layer if(state.heatLayer) state.maps.stats.removeLayer(state.heatLayer); // Re-add icon markers state.statsMarkers.forEach(m=> m.addTo(state.maps.stats)); if(labelEl) labelEl.innerHTML=‘ عرض الرموز المباشرة’; } }
function recenterStatsMap() { if(state.maps.stats) { state.maps.stats.setView([33.8547, 35.8623], 9); } }
function filterStatsList(type) { state.statsCurrentFilter=type; document.querySelectorAll(‘#stats-type-filter .filter-chip’).forEach(c=> { c.classList.toggle(‘active’, c.dataset.type===type); }); renderStatsList(); }
function renderStatsList() { if(!state.statsData || !state.statsData.details) return; const filter=state.statsCurrentFilter; const rows=state.statsData.details.filter(r=> { if(filter===‘all’) return true; if(filter===‘shelling’) return assaultTypes.includes(r.type); if(filter===‘uav’) return [‘uav’, ‘raid_drone’, ‘bomb_drone’].includes(r.type); if(filter===‘fighter’) return [‘fighter’, ‘raid_fighter’].includes(r.type); return r.type===filter; });
const tb=document.getElementById(‘stats-table-body’); const mobList=document.getElementById(‘stats-mobile-list’); if(tb) tb.innerHTML=”; if(mobList) mobList.innerHTML=”;
if(rows.length===0) { if(tb) tb.innerHTML=‘
لا توجد بلاغات مسجلة لهذا النوع في هذا اليوم‘; if(mobList) mobList.innerHTML=‘لا توجد بلاغات مسجلة لهذا النوع في هذا اليوم
‘; return; }
rows.forEach(r=> { const c=assaultTypes.includes(r.type) ? ‘text-shelling font-bold’ : (r.type===’uav’?’text-danger font-bold’:(r.type===’fighter’?’text-accent font-bold’:’text-warning font-bold’)); const s=translate.source[r.report_source] || ‘سماع’; const sIcon=r.report_source===‘visual’ ? ‘‘ : ‘‘; const timeStr=formatBeirutTime(r.created_at); const cityName=adminEscape(r.city_name || ‘منطقة غير محددة’); const typeLabel=translate.type[r.type] || r.type;
// Desktop Table Row if(tb) { tb.innerHTML +=`
${timeStr} ${cityName} ${eventIconMarkup(r.type,’table-event-icon’)}${typeLabel} ${sIcon} ${s} ${!isNaN(parseFloat(r.lat)) ? ` عرض` : ‘-‘}`; }
// Mobile Card Item if(mobList) { mobList.innerHTML +=`
${eventIconMarkup(r.type, ‘w-7 h-7 object-contain drop-shadow-sm’)}
${typeLabel} • ${sIcon} ${s}
${cityName}
${timeStr} ${!isNaN(parseFloat(r.lat)) ? ` الخريطة` : ”}
`; } }); }
function focusStatsReport(lat, lon) { if(state.maps.stats) { state.maps.stats.setView([lat, lon], 12, { animate: true }); const card=document.querySelector(‘.stats-map-card’); if(card) window.scrollTo({ top: card.offsetTop – 60, behavior: ‘smooth’ }); } }
const arabicDays=[‘الأحد’, ‘الاثنين’, ‘الثلاثاء’, ‘الأربعاء’, ‘الخميس’, ‘الجمعة’, ‘السبت’];
async function loadStats(){ const d=document.getElementById(‘stats-date’).value || getBeirutDateString(); const dateBadge=document.getElementById(‘stats-map-date’); if(dateBadge) dateBadge.innerText=d;
// Single Unified Map if(!state.maps.stats) { state.maps.stats=L.map(‘stats-map’, { zoomControl: false, zoomSnap: 0.5, scrollWheelZoom: false // Prevent touch/wheel trapping }).setView([33.8547, 35.8623], 9);
L.tileLayer(‘ {s}.tile.openstreetmap.org/{z}/{x}/{y}.png’, { className: ‘ajwa-soft-tiles’, maxZoom: 19, attribution: ‘© OpenStreetMap’ }).addTo(state.maps.stats);
L.control.zoom({ position: ‘topright’ }).addTo(state.maps.stats); }
try { const r=await fetch(`${API_URL}?action=get_stats&class=${d}&t=${Date.now()}`); const j=await r.json(); state.statsData=j;
// Update date subtitle const dateObj=new Date(d); const dayName=!isNaN(dateObj.getTime()) ? arabicDays[dateObj.getDay()] : ”; const subEl=document.getElementById(‘period-sub-daily’); if(subEl) subEl.innerText=dayName;
// Update KPIs updateStatsKPIs();
// Clear markers state.statsMarkers.forEach(mk=> state.maps.stats.removeLayer(mk)); state.statsMarkers=[]; state.statsHeatPoints=[];
let geoReportsCount=0; j.details.forEach(r=> { const timeStr=formatBeirutTime(r.created_at); if(!isNaN(parseFloat(r.lat))) { geoReportsCount++; const ic=L.divIcon({ html: `${eventIconMarkup(r.type,’map-event-icon’)}
`, className: ‘custom-div-icon’, iconSize: [32,32], iconAnchor: [16,16] }); const marker=L.marker([r.lat, r.lon], {icon: ic}).bindPopup(`${translate.type[r.type] || r.type}${r.city_name || ”}${timeStr}`); state.statsMarkers.push(marker);
let intensity=0.55; if(assaultTypes.includes(r.type)) intensity=1.0; state.statsHeatPoints.push([r.lat, r.lon, intensity]); } });
const countEl=document.getElementById(‘stats-map-count-badge’); if(countEl) countEl.innerText=`${geoReportsCount} حدث محدد جغرافياً`;
// Set map layer based on current mode (default: markers, heatmap only on-demand) setStatsMapMode(state.statsMapMode); if(state.statsMarkers && state.statsMarkers.length > 0) { try { const group=L.featureGroup(state.statsMarkers); state.maps.stats.fitBounds(group.getBounds().pad(0.25)); } catch(e) {} } else if(state.maps.stats) { state.maps.stats.setView([33.8547, 35.8623], 9); }
// Render activity list renderStatsList();
// Format Chart.js Activity curve if(j.chart && j.chart.length > 0) { const chartLabels=j.chart.map(i=> { try { const dt=new Date(i.date); return `${arabicDays[dt.getDay()]} ${dt.getDate()}`; } catch(e) { return i.date; } }); const chartValues=j.chart.map(i=> i.count); const peak=Math.max(…chartValues, 0); const peakBadge=document.getElementById(‘chart-peak-badge’); if(peakBadge) peakBadge.innerText=`أعلى نشاط: ${peak} بلاغ`;
if(state.chart) state.chart.destroy(); const canvas=document.getElementById(‘statsChart’); if(canvas) { const ctx=canvas.getContext(‘2d’); const gradient=ctx.createLinearGradient(0, 0, 0, 240); gradient.addColorStop(0, ‘rgba(56, 189, 248, 0.45)’); gradient.addColorStop(1, ‘rgba(56, 189, 248, 0.0)’);
state.chart=new Chart(ctx, { type: ‘line’, data: { labels: chartLabels, datasets: [{ label: ‘عدد البلاغات’, data: chartValues, borderColor: ‘#38bdf8’, borderWidth: 3, backgroundColor: gradient, fill: true, tension: 0.35, pointBackgroundColor: ‘#38bdf8’, pointBorderColor: ‘#0f172a’, pointBorderWidth: 2, pointRadius: 4, pointHoverRadius: 6 }] }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { display: false }, tooltip: { backgroundColor: ‘#0f172a’, titleColor: ‘#38bdf8’, bodyColor: ‘#ffffff’, borderColor: ‘#334155’, borderWidth: 1, padding: 10, displayColors: false, callbacks: { label: (context)=> ` ${context.parsed.y} بلاغ مسجل` } } }, scales: { y: { beginAtZero: true, grid: { color: ‘rgba(255, 255, 255, 0.06)’ }, ticks: { color: ‘#94a3b8’, font: { size: 10 } } }, x: { grid: { display: false }, ticks: { color: ‘#94a3b8’, font: { size: 11, weight: ‘bold’ } } } } } }); } } } catch(x){ console.error(“loadStats error:”, x); } }
async function generateAISummary(){ if (!state.user || state.user.is_active !=1) return; document.getElementById(‘modal-ai-analysis’).classList.remove(‘hidden’); document.getElementById(‘ai-analysis-content’).innerHTML=’جاري التحليل…
‘; try { const d=document.getElementById(‘stats-date’).value || getBeirutDateString(); const r=await fetch(`${API_URL}?action=get_stats&class=${d}&t=${Date.now()}`); const j=await r.json(); const c=`التاريخ: ${d}nإجمالي: ${j.totals.total}nالمناطق: ${j.details.slice(0,10).map(x=>x.city_name).join(‘, ‘)}`; const s=await callGemini(“لخص الوضع”, c, d); document.getElementById(‘ai-analysis-content’).innerHTML=marked.parse(s); } catch(x) { document.getElementById(‘ai-analysis-content’).innerHTML=‘فشل في التحليل’; } }
async function callGemini(p, c, d=null) { if(!aiEnabled) return “غير مفعل”; const payload={ prompt: p, context: c }; if(d) payload.date=d; const r=await fetch(`${API_URL}?action=ask_ai`, { method: ‘POST’, body: JSON.stringify(payload) }); const j=await r.json(); return j.response || “خطأ”; }
const adminEscape=value=>String(value??”).replace(/[&”‘]/g,c=>({‘&’:’&’,'’,'”‘:'”‘,”‘”:”’}[c])); const adminSearchText=value=>String(value??”).toLowerCase().trim(); async function refreshAdmin(){ const refreshButtons=document.querySelectorAll(‘#view-admin button[onclick=”refreshAdmin()”]’);refreshButtons.forEach(button=>button.disabled=true); try{ const r=await fetch(`${API_URL}?action=admin_dashboard&admin_id=${state.user.id}&t=${Date.now()}`,{cache:’no-store’});const j=await r.json(); if(!r.ok||!Array.isArray(j.users)||!Array.isArray(j.reports))throw new Error(j.error||’تعذر تحميل بيانات الإدارة’); state.adminData=j; const userIds=new Set(j.users.map(item=>item.id)),reportIds=new Set(j.reports.map(item=>item.id)); state.adminSelection.users.forEach(id=>{if(!userIds.has(id))state.adminSelection.users.delete(id);});state.adminSelection.reports.forEach(id=>{if(!reportIds.has(id))state.adminSelection.reports.delete(id);}); document.getElementById(‘admin-total-users’).textContent=j.users.length;document.getElementById(‘admin-total-reports’).textContent=j.reports.length;document.getElementById(‘admin-total-reports-detail’).textContent=`${j.reports.filter(report=>Number(report.is_active)!==0).length} ظاهر · ${j.reports.filter(report=>Number(report.is_active)===0).length} مخفي`;document.getElementById(‘admin-banned-users’).textContent=j.users.filter(u=>Number(u.is_banned)===1).length;document.getElementById(‘admin-verified-users’).textContent=j.users.filter(u=>u.phone_verified_at).length; document.getElementById(‘admin-users-tab-count’).textContent=j.users.length;document.getElementById(‘admin-reports-tab-count’).textContent=j.reports.length;document.getElementById(‘admin-push-count’).textContent=j.push_count||0; renderAdminTables(); }catch(error){showAppModal(‘تعذر التحديث’,error.message||’فشل تحميل لوحة الإدارة’,’error’);} finally{refreshButtons.forEach(button=>button.disabled=false);} }
function switchAdminTab(tab){ state.adminTab=tab; document.getElementById(‘admin-users’).classList.toggle(‘hidden’,tab!==’users’);document.getElementById(‘admin-reports’).classList.toggle(‘hidden’,tab!==’reports’);document.getElementById(‘admin-settings’).classList.toggle(‘hidden’,tab!==’settings’); document.getElementById(‘admin-toolbar’).classList.toggle(‘hidden’,tab===’settings’);document.getElementById(‘admin-user-filters’).classList.toggle(‘hidden’,tab!==’users’);document.getElementById(‘admin-report-filters’).classList.toggle(‘hidden’,tab!==’reports’); [‘users’,’reports’,’settings’].forEach(name=>{const button=document.getElementById(`btn-admin-${name}`);button.classList.toggle(‘is-active’,name===tab);button.setAttribute(‘aria-selected’,String(name===tab));}); const search=document.getElementById(‘admin-search’);if(search)search.placeholder=tab===’reports’?’ابحث بالمنطقة أو المبلّغ’:’ابحث بالاسم أو البريد أو الهاتف’; if(tab===’settings’){document.getElementById(‘admin-bulk-bar’).classList.add(‘hidden’);loadAdminSettings();}else renderAdminTables(); } function adminFiltersChanged(){state.pagination.adminUsers=1;state.pagination.adminReports=1;renderAdminTables();} function clearAdminSearch(){const input=document.getElementById(‘admin-search’);input.value=””;input.focus();adminFiltersChanged();} function resetAdminFilters(){ document.getElementById(‘admin-search’).value=””;[‘admin-filter-users’,’admin-filter-verification’,’admin-filter-reports’,’admin-filter-source’,’admin-filter-report-status’,’admin-filter-date’].forEach(id=>{const input=document.getElementById(id);if(input)input.value=”all”;});adminFiltersChanged(); } async function loadAdminSettings(){try{const r=await fetch(`${API_URL}?action=get_admin_settings`);const j=await r.json();const input=document.getElementById(‘admin-gemini-key’);input.value=””;input.placeholder=j.gemini_configured?’المفتاح محفوظ — أدخل مفتاحاً جديداً لاستبداله’:’أدخل مفتاح Gemini’;}catch(x){}} async function saveAdminSettings(){const k=document.getElementById(‘admin-gemini-key’).value;try{const r=await fetch(`${API_URL}?action=update_settings`,{method:’POST’,body:JSON.stringify({admin_id:state.user.id,gemini_key:k})});if(r.ok){showAppModal(‘تم’, “تم حفظ الإعدادات”, ‘success’);fetchConfig();}else showAppModal(‘خطأ’, “فشل الحفظ”, ‘error’);}catch(x){}} function toggleKeyVisibility(){const i=document.getElementById(‘admin-gemini-key’);i.type=i.type===’password’?’text’:’password’;}
function renderPaginationControls(totalItems, itemsPerPage, currentPage, context) { const totalPages=Math.ceil(totalItems / itemsPerPage); if(totalPages { let va=a[sortConfig.col], vb=b[sortConfig.col]; if (typeof va===‘string’) va=va.toLowerCase(); if (typeof vb===‘string’) vb=vb.toLowerCase(); if (va vb) return sortConfig.dir===‘asc’ ? 1 : -1; return 0; }); }
function adminSort(context, col) { const current=state.adminSort[context]; if(current.col===col) current.dir=current.dir===‘asc’ ? ‘desc’ : ‘asc’; else { current.col=col; current.class=”asc”; } renderAdminTables(); }
function filteredAdminUsers(){ const query=adminSearchText(document.getElementById(‘admin-search’).value),status=document.getElementById(‘admin-filter-users’).value,verification=document.getElementById(‘admin-filter-verification’).value; let users=state.adminData.users.filter(user=>[user.username,user.email,user.phone_number,user.registration_ip].some(value=>adminSearchText(value).includes(query))); if(status===’active’)users=users.filter(user=>Number(user.is_active)===1&&Number(user.is_banned)===0);if(status===’banned’)users=users.filter(user=>Number(user.is_banned)===1);if(status===’inactive’)users=users.filter(user=>Number(user.is_active)===0); if(verification===’phone’)users=users.filter(user=>user.phone_verified_at);if(verification===’email’)users=users.filter(user=>user.email_verified_at);if(verification===’unverified’)users=users.filter(user=>!user.phone_verified_at&&!user.email_verified_at); return sortData(users,state.adminSort.users); } function filteredAdminReports(){ const query=adminSearchText(document.getElementById(‘admin-search’).value),type=document.getElementById(‘admin-filter-reports’).value,source=document.getElementById(‘admin-filter-source’).value,status=document.getElementById(‘admin-filter-report-status’).value,period=document.getElementById(‘admin-filter-date’).value; let reports=state.adminData.reports.filter(report=>[report.city_name,report.username,translate.type[report.type],report.type].some(value=>adminSearchText(value).includes(query))); if(type!==’all’)reports=reports.filter(report=>type===’assault’?assaultTypes.includes(report.type):report.type===type);if(source!==’all’)reports=reports.filter(report=>(report.report_source===’audio’?’auditory’:report.report_source)===source); if(status===’active’)reports=reports.filter(report=>Number(report.is_active)!==0);if(status===’inactive’)reports=reports.filter(report=>Number(report.is_active)===0); if(period!==’all’){const days=period===’today’?0:period===’7d’?6:29;const cutoff=new Date();cutoff.setHours(0,0,0,0);cutoff.setDate(cutoff.getDate()-days);reports=reports.filter(report=>{const parsed=new Date(String(report.created_at||”).replace(‘ ‘,’T’));return !Number.isNaN(parsed.getTime())&&parsed>=cutoff;});} return sortData(reports,state.adminSort.reports); }
function renderAdminTables(){ if(!state.adminData||!Array.isArray(state.adminData.users)||!Array.isArray(state.adminData.reports))return; const itemsPerPage=parseInt(document.getElementById(‘admin-rows’).value); const users=filteredAdminUsers(); const userPages=Math.max(1,Math.ceil(users.length/itemsPerPage));state.pagination.adminUsers=Math.min(state.pagination.adminUsers,userPages);const usersPage=state.pagination.adminUsers; const usersSlice=users.slice((usersPage – 1) * itemsPerPage, usersPage * itemsPerPage); state.adminVisibleIds.users=usersSlice.filter(user=>user.role!==’admin’).map(user=>user.id); const ub=document.getElementById(‘admin-users-body’); ub.innerHTML=”; if(!usersSlice.length)ub.innerHTML=’
لا توجد حسابات مطابقةغيّر الفلاتر أو امسح عبارة البحث.‘; usersSlice.forEach(u=>{ const isAdmin=u.role===’admin’,checked=state.adminSelection.users.has(u.id);let status=””;if(Number(u.is_banned)===1)status=”محظور”;else if(Number(u.is_active)===1)status=”نشط”;else status=”غير مفعل”; const phoneVerification=`${u.phone_verified_at?’واتساب موثق’:’واتساب غير موثق’}${(!u.phone_verified_at&&u.phone_number&&!isAdmin)?`إرسال الرابط`:”}`; const verification=`${phoneVerification}${u.email_verified_at?’بريد موثق’:’بريد غير موثق’}`; const actions=isAdmin?’مدير النظام’:`${Number(u.is_active)===1?’تعطيل’:’تفعيل’}${Number(u.is_banned)===1?’فك الحظر’:’حظر’}كلمة المرورحذف`; ub.innerHTML+=`
${isAdmin?’‘:“} ${adminEscape(String(u.username||’?’).trim().charAt(0)||’?’)}${adminEscape(u.username)}${adminEscape(u.registration_ip||’IP غير متاح’)} · ${adminEscape(String(u.created_at||”).split(‘ ‘)[0])} ${adminEscape(u.email)}${adminEscape(u.phone_number||’لا يوجد رقم’)}${verification} ${status} ${Number(u.report_count)||0}${actions}
`; }); document.getElementById(‘admin-users-pagination’).innerHTML=renderPaginationControls(users.length, itemsPerPage, usersPage, ‘users’); document.getElementById(‘admin-users-result-count’).textContent=`عرض ${usersSlice.length} من ${users.length} عضواً`;
const reports=filteredAdminReports();const reportPages=Math.max(1,Math.ceil(reports.length/itemsPerPage));state.pagination.adminReports=Math.min(state.pagination.adminReports,reportPages);const reportsPage=state.pagination.adminReports; const reportsSlice=reports.slice((reportsPage – 1) * itemsPerPage, reportsPage * itemsPerPage); state.adminVisibleIds.reports=reportsSlice.map(report=>report.id); const rb=document.getElementById(‘admin-reports-body’); rb.innerHTML=”; if(!reportsSlice.length)rb.innerHTML=’
لا توجد بلاغات مطابقةغيّر النوع أو المصدر أو الفترة.‘; reportsSlice.forEach(r=>{ const c=assaultTypes.includes(r.type) ? ‘text-shelling’ : (r.type===’uav’?’text-danger’:(r.type===’fighter’?’text-accent’:’text-warning’)); const time=formatBeirutTime(r.created_at); const date=formatBeirutDateTime(r.created_at).split(‘,’)[0]; const checked=state.adminSelection.reports.has(r.id),sourceLabel=(r.report_source===’visual’?’مشاهدة’:’سماع’),reportActive=Number(r.is_active)!==0; rb.innerHTML+=`
${eventIconMarkup(r.type,’table-event-icon’)}${adminEscape(translate.type[r.type]||r.type)}${reportActive?’ظاهر للعامة’:’مخفي’}${adminEscape(String(r.id).slice(0,8))} ${adminEscape(r.city_name||’منطقة غير محددة’)}${sourceLabel} ${adminEscape(r.username||’مجهول’)} ${adminEscape(time)}${adminEscape(date)}${reportActive?’إخفاء’:’إظهار’}تعديلحذف
`; }); document.getElementById(‘admin-reports-pagination’).innerHTML=renderPaginationControls(reports.length, itemsPerPage, reportsPage, ‘reports’); document.getElementById(‘admin-reports-result-count’).textContent=`عرض ${reportsSlice.length} من ${reports.length} بلاغاً`; document.querySelectorAll(‘[data-sort-context]’).forEach(icon=>{const config=state.adminSort[icon.dataset.sortContext],active=config.col===icon.dataset.sortCol;icon.className=`sort-icon fa-solid ${active?(config.class===’asc’?’fa-sort-up’:’fa-sort-down’):’fa-sort’}${active?’ sort-active’:”}`;}); [‘users’,’reports’].forEach(context=>{const all=document.getElementById(`admin-select-all-${context}`),ids=state.adminVisibleIds[context];if(all){all.checked=ids.length>0&&ids.every(id=>state.adminSelection[context].has(id));all.indeterminate=ids.some(id=>state.adminSelection[context].has(id))&&!all.checked;}}); updateAdminBulkBar(); }
function toggleAdminSelection(context,id,checked){if(checked)state.adminSelection[context].add(id);else state.adminSelection[context].delete(id);const all=document.getElementById(`admin-select-all-${context}`),ids=state.adminVisibleIds[context];if(all){all.checked=ids.length>0&&ids.every(item=>state.adminSelection[context].has(item));all.indeterminate=ids.some(item=>state.adminSelection[context].has(item))&&!all.checked;}updateAdminBulkBar();} function toggleAdminPageSelection(context,checked){state.adminVisibleIds[context].forEach(id=>checked?state.adminSelection[context].add(id):state.adminSelection[context].delete(id));renderAdminTables();} function clearAdminSelection(){if(state.adminTab===’users’||state.adminTab===’reports’)state.adminSelection[state.adminTab].clear();renderAdminTables();} function updateAdminBulkBar(){const context=state.adminTab,count=(context===’users’||context===’reports’)?state.adminSelection[context].size:0,bar=document.getElementById(‘admin-bulk-bar’);bar.classList.toggle(‘hidden’,count===0||context===’settings’);document.getElementById(‘admin-selection-count’).textContent=count;document.getElementById(‘admin-user-bulk-actions’).classList.toggle(‘hidden’,context!==’users’);document.getElementById(‘admin-report-bulk-actions’).classList.toggle(‘hidden’,context!==’reports’);} function bulkAdminAction(operation){const context=operation.endsWith(‘_reports’)?’reports’:’users’,ids=[…state.adminSelection[context]];if(!ids.length)return;const labels={activate_users:’تفعيل الحسابات المحددة’,deactivate_users:’تعطيل الحسابات المحددة’,ban_users:’حظر الحسابات المحددة’,unban_users:’فك حظر الحسابات المحددة’,delete_users:’حذف الحسابات المحددة نهائياً’,activate_reports:’إظهار البلاغات المحددة للعامة’,deactivate_reports:’إخفاء البلاغات المحددة عن العامة’,delete_reports:’حذف البلاغات المحددة نهائياً’};showConfirmModal(`هل تريد ${labels[operation]}؟`,async()=>{try{const response=await fetch(`${API_URL}?action=admin_bulk_action`,{method:’POST’,body:JSON.stringify({type:operation,target_ids:ids})});const result=await response.json();if(!response.ok)throw new Error(result.error||’فشل تنفيذ الإجراء’);state.adminSelection[context].clear();await refreshAdmin();showAppModal(‘تم التنفيذ’,`تم تحديث ${result.affected||ids.length} عنصراً`,’success’);}catch(error){showAppModal(‘تعذر التنفيذ’,error.message,’error’);}});}
async function openUserModal(uid){ const u=state.adminData.users.find(x=>x.id===uid);if(!u)return; toggleModal(‘modal-user’, true); document.getElementById(‘modal-user-content’).innerHTML=‘
جاري التحميل…
‘;
try { const r=await fetch(`${API_URL}?action=get_user_reports&target_id=${uid}&t=${Date.now()}`); const j=await r.json(); const reps=j.data||[]; document.getElementById(‘modal-user-content’).innerHTML=`
IP
${u.registration_ip||’-‘}
تاريخ الانضمام
${u.created_at.split(‘ ‘)[0]}
آخر التقارير
النوع المنطقة الوقت ${reps.map(x=>` ${translate.type[x.type]} ${x.city_name} ${formatBeirutDateTime(x.created_at)}`).join(”)}
`; } catch(e) { document.getElementById(‘modal-user-content’).innerHTML=‘
فشل تحميل البيانات
‘; } } async function adminAction(t,tid){ showConfirmModal(“هل أنت متأكد من هذا الإجراء؟”, async ()=> { try{const response=await fetch(`${API_URL}?action=admin_action`,{method:’POST’,body:JSON.stringify({admin_id:state.user.id,target_id:tid,type:t})});const result=await response.json();if(!response.ok)throw new Error(result.error||’فشل تنفيذ الإجراء’);await refreshAdmin();showAppModal(‘تم’,’تم تنفيذ الإجراء بنجاح’,’success’);}catch(error){showAppModal(‘تعذر التنفيذ’,error.message,’error’);} }); }
async function adminResendPhoneActivation(userId,button){ const original=button.innerHTML; button.disabled=true; button.innerHTML=’جارٍ الإرسال’; try{ const response=await fetch(`${API_URL}?action=admin_action`,{method:’POST’,body:JSON.stringify({admin_id:state.user.id,target_id:userId,type:’resend_phone_activation’})}); const result=await response.json(); if(!response.ok)throw new Error(result.error||’تعذر إرسال رابط التوثيق’); showAppModal(‘تم الإرسال’,result.message||’تم إرسال رابط التوثيق عبر واتساب’,’success’); }catch(error){showAppModal(‘تعذر الإرسال’,error.message,’error’);} finally{button.disabled=false;button.innerHTML=original;} }
function openEditReportModal(reportId) { const report=state.adminData.reports.find(r=> r.id===reportId); if(!report) return; document.getElementById(‘edit-report-id’).value=report.id; document.getElementById(‘edit-report-type’).value=report.type; document.getElementById(‘edit-report-city’).value=report.city_name; document.getElementById(‘edit-report-source’).value=report.report_source || ‘visual’; toggleModal(‘modal-edit-report’, true); }
async function submitEditReport(e) { e.preventDefault(); const formData=new FormData(e.target); const data=Object.fromEntries(formData.entries()); data.admin_id=state.user.id; try { const res=await fetch(`${API_URL}?action=edit_report`, { method: ‘POST’, body: JSON.stringify(data) }); const j=await res.json(); if (res.ok) { showAppModal(‘نجاح’, “تم التعديل”, ‘success’); toggleModal(‘modal-edit-report’, false); refreshAdmin(); } else { showAppModal(‘خطأ’, j.error, ‘error’); } } catch (err) { showAppModal(‘خطأ’, “فشل الاتصال”, ‘error’); } }
window.addEventListener(‘load’, async ()=> { // 1. تهيئة الخريطة إذا كانت موجودة try { if(!state.maps.main && document.getElementById(‘map’)) { state.maps.main=L.map(‘map’, {zoomControl:false,zoomSnap:.25}).setView([33.8547,35.8623], 9); L.tileLayer(‘ {s}.tile.openstreetmap.org/{z}/{x}/{y}.png’, { className: ‘ajwa-soft-tiles’, maxZoom:19, attribution:’© OpenStreetMap’ }).addTo(state.maps.main); L.control.zoom({position:’bottomleft’}).addTo(state.maps.main); } } catch(e) { console.error(“Map Init Error”, e); }
insertFooters(); updateAuthUI();
const u=new URLSearchParams(window.location.search); const action=u.get(‘action’);
// 2. معالجة تفعيل البريد الإلكتروني if(action===‘activate_verify’){ try { const r=await fetch(`${API_URL}?action=activate_account`, { method:’POST’, body:JSON.stringify({token:u.get(‘token’)}) }); const j=await r.json(); showAppModal(‘تنبيه’, j.message || j.error, r.ok?’success’:’error’); if(r.ok) router.navigate(‘auth’); } catch(x) { showAppModal(‘خطأ’, “فشل الاتصال”, ‘error’); } }
// 3. معالجة تفعيل الهاتف (الواتساب) – الكود الجديد else if(action===‘activate_phone’){ try { const r=await fetch(`${API_URL}?action=activate_phone`, { method:’POST’, body:JSON.stringify({token:u.get(‘token’)}) }); const j=await r.json();
// عرض رسالة مناسبة حسب النتيجة if(r.ok) { showAppModal(‘تفعيل الهاتف’, j.message, ‘success’); router.navigate(‘auth’); // الذهاب لصفحة تسجيل الدخول } else { showAppModal(‘تنبيه’, j.error || “رابط التفعيل غير صالح أو منتهي الصلاحية”, ‘error’); router.navigate(‘home’); } } catch(x) { showAppModal(‘خطأ’, “فشل الاتصال بالخادم”, ‘error’); router.navigate(‘home’); } }
// 4. الوضع الطبيعي (الذهاب للرئيسية) else { const initialView=window.location.hash.slice(1); router.navigate(document.getElementById(`view-${initialView}`)?initialView:’home’); } window.addEventListener(‘hashchange’, ()=> { const hv=window.location.hash.slice(1); if(hv && document.getElementById(`view-${hv}`)) { router.navigate(hv); } });
// 5. التحقق من وجود إحداثيات في الرابط (للمشاركة) const latParam=u.get(‘lat’); const lonParam=u.get(‘lon’); if (latParam && lonParam && Number.isFinite(Number(latParam)) && Number.isFinite(Number(lonParam)) && Math.abs(Number(latParam)) prompt.classList.add(‘show’), 5000); } } function closePushPrompt() { const p=document.getElementById(‘push-prompt’); if(p) p.classList.remove(‘show’); }
async function subscribeToPush() { if (!vapidPublicKey) return showAppModal(‘خطأ’, “خطأ في إعدادات الخادم”, ‘error’); if (‘serviceWorker’ in navigator) { try { const registration=await navigator.serviceWorker.ready; const subscription=await registration.pushManager.subscribe({ userVisibleOnly: true, applicationServerKey: urlBase64ToUint8Array(vapidPublicKey) }); const region=document.getElementById(‘push-region’)?.value||localStorage.getItem(‘ajwa_push_region’)||’all’; const payload=subscription.toJSON();payload.region=region;localStorage.setItem(‘ajwa_push_region’,region); await fetch(`${API_URL}?action=subscribe_push`, { method: ‘POST’, body: JSON.stringify(payload) }); showAppModal(‘تم’, region===’all’?”تم تفعيل تنبيهات كل لبنان “:`تم تفعيل تنبيهات ${region} `, ‘success’); const icon=document.getElementById(‘notif-btn-icon’); if(icon) icon.className=“fa-solid fa-bell text-yellow-400 text-lg”; closePushPrompt(); } catch (err) { console.error(err); showAppModal(‘خطأ’, “فشل التفعيل. تأكد من إعطاء الصلاحية.”, ‘error’); } } }
async function togglePushSubscription() { if (‘serviceWorker’ in navigator) { const reg=await navigator.serviceWorker.ready; const sub=await reg.pushManager.getSubscription(); if (sub) { showConfirmModal(“هل تريد إيقاف التنبيهات؟”, async ()=> { await sub.unsubscribe(); await fetch(`${API_URL}?action=unsubscribe_push`, {method:’POST’, body:JSON.stringify({endpoint: sub.endpoint})}); document.getElementById(‘notif-btn-icon’).className=“fa-regular fa-bell text-gray-400 text-lg”; showAppModal(‘تم’, “تم إيقاف التنبيهات.”, ‘success’); }); } else { subscribeToPush(); } } }
المصدر: ajwa2.comمشاهدة أجواء لبنان خريطة البلاغات والمتابعة المباشرة عاجل
يذكر بـأن الموضوع التابع لـ أجواء لبنان خريطة البلاغات والمتابعة المباشرة عاجل قد تم نشرة ومتواجد على قد تم نشرة اليوم ( ) ومتواجد على بتوقيت بيروت_ beiruttime ( لبنان ) وقد قام فريق التحرير في برس بي بالتاكد منه وربما تم التعديل علية وربما قد يكون تم نقله بالكامل اوالاقتباس منه ويمكنك قراءة ومتابعة مستجدادت هذا الخبر او الموضوع من مصدره الاساسي.
التفاصيل من المصدر - اضغط هنا :::
وختاما نتمنى ان نكون قد قدمنا لكم من موقع Pressbee تفاصيل ومعلومات، أجواء لبنان .. خريطة البلاغات والمتابعة المباشرة عاجل.
في الموقع ايضا :