2026-04-16-1
This commit is contained in:
@@ -14,14 +14,36 @@ const refinement = {
|
||||
|
||||
fetchCandidates: async () => {
|
||||
const headers = auth.getAuthHeader();
|
||||
const url = '/api/map-refinement/places/candidates?status=PENDING';
|
||||
console.log('🔍 [PlaceAudit] Fetching:', url);
|
||||
console.log('🔑 [PlaceAudit] Auth headers:', JSON.stringify(headers));
|
||||
|
||||
const tbody = document.getElementById('refinement-table-body');
|
||||
|
||||
try {
|
||||
const res = await fetch('/api/map-refinement/candidates?status=PENDING', { headers });
|
||||
const res = await fetch(url, { headers });
|
||||
console.log('📡 [PlaceAudit] Response status:', res.status);
|
||||
|
||||
if (res.ok) {
|
||||
refinement.state.candidates = await res.json();
|
||||
console.log('✅ [PlaceAudit] Loaded', refinement.state.candidates.length, 'candidates');
|
||||
refinement.renderTable();
|
||||
} else {
|
||||
const errorText = await res.text();
|
||||
console.error('❌ [PlaceAudit] API Error:', res.status, errorText);
|
||||
if (tbody) {
|
||||
tbody.innerHTML = `<tr><td colspan="5" class="py-20 text-center text-red-400 font-bold">
|
||||
API Error ${res.status}: ${errorText.substring(0, 100)}
|
||||
</td></tr>`;
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch candidates', error);
|
||||
console.error('❌ [PlaceAudit] Network Error:', error);
|
||||
if (tbody) {
|
||||
tbody.innerHTML = `<tr><td colspan="5" class="py-20 text-center text-red-400 font-bold">
|
||||
Network Error: ${error.message}
|
||||
</td></tr>`;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -48,18 +70,19 @@ const refinement = {
|
||||
<tr class="hover:bg-white/[0.02] transition-colors border-b border-white/[0.03]">
|
||||
<td class="px-8 py-6">
|
||||
<div class="font-bold text-white">${c.name_ar || c.name}</div>
|
||||
<div class="text-[10px] text-slate-500 uppercase font-bold mt-1">${c.country}</div>
|
||||
<div class="text-[10px] text-blue-400 font-extrabold uppercase mt-1">ID: ${c.id}</div>
|
||||
</td>
|
||||
<td class="px-8 py-6">
|
||||
<span class="px-2 py-1 rounded-lg bg-blue-500/10 text-blue-400 text-[10px] font-black uppercase tracking-wider">${c.category || 'General'}</span>
|
||||
</td>
|
||||
<td class="px-8 py-6 font-mono text-xs text-slate-400">
|
||||
${parseFloat(c.latitude).toFixed(5)}, ${parseFloat(c.longitude).toFixed(5)}
|
||||
</td>
|
||||
<td class="px-8 py-6 text-sm text-slate-400 font-medium">
|
||||
${c.submittedBy || 'System User'}
|
||||
<td class="px-8 py-6">
|
||||
<div class="text-sm text-slate-300 font-medium">${c.governorate_name || 'Unknown Region'}</div>
|
||||
<div class="text-[11px] text-slate-500 mt-1">${c.neighborhood_name || 'Unknown Neighborhood'}</div>
|
||||
</td>
|
||||
<td class="px-8 py-6 text-right space-x-2">
|
||||
<button onclick="refinement.showMapModal('${c.latitude}', '${c.longitude}', '${c.name_ar || c.name}')" class="p-2.5 rounded-xl bg-blue-500/10 text-blue-400 hover:bg-blue-500/20 transition-all" title="View on Google Maps">
|
||||
<i data-lucide="eye" class="w-4 h-4"></i>
|
||||
</button>
|
||||
<button onclick="refinement.reject('${c.id}')" class="p-2.5 rounded-xl bg-red-500/10 text-red-400 hover:bg-red-500/20 transition-all" title="Reject">
|
||||
<i data-lucide="x" class="w-4 h-4"></i>
|
||||
</button>
|
||||
@@ -73,12 +96,54 @@ const refinement = {
|
||||
lucide.createIcons();
|
||||
},
|
||||
|
||||
showMapModal: (lat, lng, name) => {
|
||||
// Remove existing modal if any
|
||||
const existing = document.getElementById('map-preview-modal');
|
||||
if (existing) existing.remove();
|
||||
|
||||
const modal = document.createElement('div');
|
||||
modal.id = 'map-preview-modal';
|
||||
modal.className = 'fixed inset-0 z-[100] flex items-center justify-center p-4 bg-slate-950/80 backdrop-blur-sm animate-in fade-in duration-300';
|
||||
modal.innerHTML = `
|
||||
<div class="bg-[#101014] border border-white/10 rounded-[2.5rem] w-full max-w-5xl overflow-hidden shadow-2xl animate-in zoom-in-95 duration-300">
|
||||
<div class="px-8 py-6 border-b border-white/5 flex justify-between items-center bg-white/[0.02]">
|
||||
<div>
|
||||
<h3 class="text-xl font-bold text-white">${name}</h3>
|
||||
<p class="text-xs text-slate-500 font-mono mt-1">${lat}, ${lng}</p>
|
||||
</div>
|
||||
<button onclick="document.getElementById('map-preview-modal').remove()" class="p-2 hover:bg-white/10 rounded-full transition-colors">
|
||||
<i data-lucide="x" class="w-6 h-6 text-slate-400"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div class="aspect-video w-full bg-slate-900">
|
||||
<iframe
|
||||
width="100%"
|
||||
height="100%"
|
||||
frameborder="0"
|
||||
scrolling="no"
|
||||
marginheight="0"
|
||||
marginwidth="0"
|
||||
src="https://maps.google.com/maps?q=${lat},${lng}&t=k&z=19&ie=UTF8&iwloc=&output=embed">
|
||||
</iframe>
|
||||
</div>
|
||||
<div class="px-8 py-6 bg-white/[0.01] flex justify-between items-center">
|
||||
<p class="text-xs text-slate-500 font-medium">Verify location visual details against satellite imagery</p>
|
||||
<a href="https://www.google.com/maps/search/?api=1&query=${lat},${lng}" target="_blank" class="px-4 py-2 bg-blue-600/10 text-blue-400 rounded-lg text-xs font-bold hover:bg-blue-600/20 transition-all border border-blue-500/10">
|
||||
Open in Full Google Maps
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
document.body.appendChild(modal);
|
||||
lucide.createIcons();
|
||||
},
|
||||
|
||||
approve: async (id) => {
|
||||
if (!confirm('Are you sure you want to approve this location and add it to the production map?')) return;
|
||||
|
||||
const headers = auth.getAuthHeader();
|
||||
try {
|
||||
const res = await fetch(`/api/map-refinement/candidates/${id}/approve`, {
|
||||
const res = await fetch(`/api/map-refinement/places/candidates/${id}/approve`, {
|
||||
method: 'PATCH',
|
||||
headers
|
||||
});
|
||||
@@ -98,7 +163,7 @@ const refinement = {
|
||||
|
||||
const headers = auth.getAuthHeader();
|
||||
try {
|
||||
const res = await fetch(`/api/map-refinement/candidates/${id}/reject`, {
|
||||
const res = await fetch(`/api/map-refinement/places/candidates/${id}/reject`, {
|
||||
method: 'PATCH',
|
||||
headers: {
|
||||
...headers,
|
||||
|
||||
Reference in New Issue
Block a user