
أجواء
${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+=`
`;
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+=`
`;
});
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+=`
${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]}
آخر التقارير
| النوع | المنطقة | الوقت |
|---|---|---|
| ${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(); }
}
}



