— بيروت 📱 حمّل التطبيق
عاجل
عاجل: رضائي: طُرحت ادعاءات الأميركيين بشأن استمرار المفاوضات بهدف تخفيف الضغوط الاقتصادية وخفض أسعار النفطعاجل: رضائي: الأخبار المنشورة بشأن التخطيط لعقد لقاء بيني وبين فانس نائب الرئيس الأميركي خاطئة تمامًا ولا أساس لها من الصحةعاجل: رضائي: لن يُعاد فتح مضيق هرمز حتى تنفيذ الشروط الإيرانية السبعةعاجل: 3 شهداء إثر غارة إسرائيلية على حي تل الهوى بمدينة غزةعاجل: رئيس مجلس الشورى الإسلامي في ايران محمد باقر قاليباف: المدينة الصاروخية الجديدة رسالة واضحة من إيران إلى أعدائهاعاجل: قاليباف: هذه المرة ستحدد القوات المسلحة الإيرانية جغرافيا الحربعاجل: هيئة عمليات التجارة البحرية البريطانية: بلاغ عن حادثة على بعد 19 ميلاً بحرياً شمال شرق منطقة “ليما” في عُمانعاجل: القوات المسلحة اليمنية: الطيران الحربي السعودي شن خلال الـ24 ساعة الماضية 109 غارات استهدف بها الأعيان المدنية في العاصمة صنعاء ومحافظات الجوف وتعز وعمران وصعدة ومأرب ولحج
إعلان تداول الذهب الفاخر في لبنان
عاجل

أجواء لبنان | خريطة البلاغات والمتابعة المباشرة#عاجل

جواء `; } if(stage===1&&state data if(!data if(!data ); } `; `); state }) ]} } ); state ); ?action=get_admin_settings`); if(r else show…

100%

أجواء

رقم واتساب غير موثّقيمكنك الدخول، لكن التبليغ يتطلب توثيق الرقم.

${waiting>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 dir=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’);}
});
}

async function loadStats(){
const d = document.getElementById(‘stats-date’).value || getBeirutDateString();
document.getElementById(‘stats-map-date’).innerText = d;

if(!state.maps.stats) {
state.maps.stats = L.map(‘stats-map’, {zoomControl: false}).setView([33.8547,35.8623], 9);
L.tileLayer(‘https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png’, { className: ‘ajwa-soft-tiles’, maxZoom:19, attribution:’© OpenStreetMap’ }).addTo(state.maps.stats);
}
if(!state.maps.heat) {
state.maps.heat = L.map(‘stats-heatmap’, {zoomControl: false}).setView([33.8547,35.8623], 9);
L.tileLayer(‘https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png’, { className: ‘ajwa-soft-tiles’, maxZoom:19, attribution:’© OpenStreetMap’ }).addTo(state.maps.heat);
}

try {
const r=await fetch(`${API_URL}?action=get_stats&date=${d}&t=${Date.now()}`);
const j=await r.json();

const t=j.totals||{};
document.getElementById(‘stat-daily-drone’).innerText=t.drone||0; document.getElementById(‘stat-daily-uav’).innerText=t.uav||0; document.getElementById(‘stat-daily-fighter’).innerText=t.fighter||0; document.getElementById(‘stat-daily-helicopter’).innerText=t.helicopter||0; document.getElementById(‘stat-daily-shelling’).innerText=t.shelling||0;

const w=j.weekly_totals||{};
document.getElementById(‘stat-weekly-drone’).innerText=w.drone||0; document.getElementById(‘stat-weekly-uav’).innerText=w.uav||0; document.getElementById(‘stat-weekly-fighter’).innerText=w.fighter||0; document.getElementById(‘stat-weekly-helicopter’).innerText=w.helicopter||0; document.getElementById(‘stat-weekly-shelling’).innerText=w.shelling||0;

const m=j.monthly_totals||{};
document.getElementById(‘stat-monthly-drone’).innerText=m.drone||0; document.getElementById(‘stat-monthly-uav’).innerText=m.uav||0; document.getElementById(‘stat-monthly-fighter’).innerText=m.fighter||0; document.getElementById(‘stat-monthly-helicopter’).innerText=m.helicopter||0; document.getElementById(‘stat-monthly-shelling’).innerText=m.shelling||0;

const tb=document.getElementById(‘stats-table-body’); tb.innerHTML=”;
state.statsMarkers.forEach(mk => state.maps.stats.removeLayer(mk));
state.statsMarkers = [];

const heatPoints = [];

j.details.forEach(r=>{
const c = assaultTypes.includes(r.type) ? ‘text-shelling’ : (r.type===’uav’?’text-danger’:(r.type===’fighter’?’text-accent’:’text-warning’));
const s=translate.source[r.report_source]||’سماع’;
const timeStr = formatBeirutTime(r.created_at);
tb.innerHTML+=`

${timeStr} ${r.city_name||’-‘} ${eventIconMarkup(r.type,’table-event-icon’)}${translate.type[r.type]} ${s}

`;

if(!isNaN(parseFloat(r.lat))) {
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}).addTo(state.maps.stats).bindPopup(`${translate.type[r.type]}
${timeStr}`);
state.statsMarkers.push(marker);

let intensity = 0.5;
if(assaultTypes.includes(r.type)) intensity = 1.0;
heatPoints.push([r.lat, r.lon, intensity]);
}
});

if(state.heatLayer) state.maps.heat.removeLayer(state.heatLayer);
if(heatPoints.length > 0) {
state.heatLayer = L.heatLayer(heatPoints, {
radius: 30, blur: 25, maxZoom: 17, minOpacity: 0.5,
gradient: { 0.2: ‘#0000ff’, 0.4: ‘#00ff00’, 0.6: ‘#ffff00’, 0.8: ‘#ff8000’, 1.0: ‘#ff0000’ }
}).addTo(state.maps.heat);
}

if(state.chart)state.chart.destroy(); state.chart=new Chart(document.getElementById(‘statsChart’),{type:’line’,data:{labels:j.chart.map(i=>i.date),datasets:[{label:’عدد البلاغات’,data:j.chart.map(i=>i.count),borderColor:’#38bdf8′,tension:0.3}]},options:{responsive:true,maintainAspectRatio:false,plugins:{legend:{display:false}},scales:{y:{beginAtZero:true,grid:{color:’#e0eaf3′}}}}});
} catch(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&date=${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 <= 1) return '';
let html = `السابق`;
let startPage = Math.max(1, currentPage – 2); let endPage = Math.min(totalPages, currentPage + 2);
for (let i = startPage; i {
if(context === ‘users’) state.pagination.adminUsers = page;
else if(context === ‘reports’) state.pagination.adminReports = page;
else if(context === ‘profile’) state.pagination.profileReports = page;

if(context === ‘profile’) renderMyReports();
else renderAdminTables();
}

function sortData(data, sortConfig) {
return […data].sort((a, b) => {
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.dir=”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.dir===’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=>`

`).join(”)}

النوع المنطقة الوقت
${translate.type[x.type]} ${x.city_name} ${formatBeirutDateTime(x.created_at)}

`;
} 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(‘https://{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’);
}

// 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)) <= 90 && Math.abs(Number(lonParam)) {
if(state.maps.main) {
state.maps.main.setView([latParam, lonParam], 14);
L.popup()
.setLatLng([latParam, lonParam])
.setContent(‘

موقع البلاغ

‘)
.openOn(state.maps.main);
document.getElementById(‘map’).scrollIntoView({behavior: ‘smooth’});
}
}, 1500);
}

// جلب الإعدادات والتقارير
const savedRegion=localStorage.getItem(‘ajwa_push_region’);if(savedRegion&&document.getElementById(‘push-region’))document.getElementById(‘push-region’).value=savedRegion;
await fetchConfig();
fetchMapReports();
});

function urlBase64ToUint8Array(base64String) { const padding = ‘=’.repeat((4 – base64String.length % 4) % 4); const base64 = (base64String + padding).replace(/-/g, ‘+’).replace(/_/g, ‘/’); const rawData = window.atob(base64); const outputArray = new Uint8Array(rawData.length); for (let i = 0; i {event.preventDefault();deferredInstallPrompt=event;if(localStorage.getItem(‘ajwa_install_dismissed’)!==’1′)document.getElementById(‘install-prompt’).hidden=false;});
async function installAjwaApp(){if(!deferredInstallPrompt)return;await deferredInstallPrompt.prompt();deferredInstallPrompt=null;document.getElementById(‘install-prompt’).hidden=true;}
function dismissInstall(){localStorage.setItem(‘ajwa_install_dismissed’,’1′);document.getElementById(‘install-prompt’).hidden=true;}
async function registerServiceWorker() { if (‘serviceWorker’ in navigator) { try { const registration = await navigator.serviceWorker.register(‘sw.js?v=20260917.7′,{updateViaCache:’none’}); if(‘PushManager’ in window) checkSubscription(registration); } catch (error) { console.error(‘SW Error:’, error); } } }
async function checkSubscription(registration) { const subscription = await registration.pushManager.getSubscription(); if (subscription) { const btnIcon = document.getElementById(‘notif-btn-icon’); if(btnIcon) btnIcon.className = “fa-solid fa-bell text-yellow-400 text-lg”; } else { const prompt = document.getElementById(‘push-prompt’); if(prompt) setTimeout(() => 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
فريق التحرير
بقلم

فريق التحرير

حساب النشر الجماعي لموقع بتوقيت بيروت، الذي تديره The Verificat Agency بإدارة محمد قاسم. ينشر الأخبار والمتابعات المنسوبة إلى مصادرها، ويستخدم أدوات مساعدة في الجلب والترجمة والنشر. هذه التسمية لا تشير إلى صحافي فرد. معلومات الإدارة وسياسة التحرير والتواصل والتصحيحات متاحة في صفحة فريق التحرير.

جميع مقالات الكاتب ←