/** * Map Refinement (Place Audit) logic */ const refinement = { state: { candidates: [] }, init: async () => { console.log('📍 Initializing Map Refinement Logic...'); await refinement.fetchCandidates(); }, 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(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 = ` API Error ${res.status}: ${errorText.substring(0, 100)} `; } } } catch (error) { console.error('❌ [PlaceAudit] Network Error:', error); if (tbody) { tbody.innerHTML = ` Network Error: ${error.message} `; } } }, renderTable: () => { const tbody = document.getElementById('refinement-table-body'); if (!tbody) return; if (refinement.state.candidates.length === 0) { tbody.innerHTML = `

No pending location suggestions.

`; lucide.createIcons(); return; } try { tbody.innerHTML = refinement.state.candidates.map(c => { const trustColor = c.confidence_score >= 80 ? 'emerald' : (c.confidence_score >= 50 ? 'amber' : 'slate'); const trustText = c.confidence_score >= 80 ? 'High Trust' : (c.confidence_score >= 50 ? 'Partial Match' : 'Unverified'); // Safety checks for coordinates const lat = typeof c.latitude === 'number' ? c.latitude.toFixed(4) : 'N/A'; const lng = typeof c.longitude === 'number' ? c.longitude.toFixed(4) : 'N/A'; return `
${c.name_ar || c.name || 'Untitled'}
${c.category || 'Location'}
${c.verified_name || 'No external match'}
${trustText} (${c.confidence_score || 0}%)
${lat}, ${lng}
${c.neighborhood_name || 'Unknown Neighborhood'}
`; }).join(''); lucide.createIcons(); } catch (error) { console.error('❌ [PlaceAudit] Rendering error:', error); tbody.innerHTML = `Rendering Error: See console for details`; } }, 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 = `

${name}

${lat}, ${lng}

Verify location visual details against satellite imagery

Open in Full Google Maps
`; 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/places/candidates/${id}/approve`, { method: 'PATCH', headers }); if (res.ok) { await refinement.fetchCandidates(); } else { alert('Approval failed.'); } } catch (error) { console.error(error); } }, reject: async (id) => { const reason = prompt('Please enter a reason for rejection:'); if (reason === null) return; const headers = auth.getAuthHeader(); try { const res = await fetch(`/api/map-refinement/places/candidates/${id}/reject`, { method: 'PATCH', headers: { ...headers, 'Content-Type': 'application/json' }, body: JSON.stringify({ reason }) }); if (res.ok) { await refinement.fetchCandidates(); } else { alert('Rejection failed.'); } } catch (error) { console.error(error); } } };