Files
maps-saas/apps/dashboard/js/refinement.js
T
2026-04-15 19:56:49 +03:00

119 lines
4.4 KiB
JavaScript

/**
* 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();
try {
const res = await fetch('/api/map-refinement/candidates?status=PENDING', { headers });
if (res.ok) {
refinement.state.candidates = await res.json();
refinement.renderTable();
}
} catch (error) {
console.error('Failed to fetch candidates', error);
}
},
renderTable: () => {
const tbody = document.getElementById('refinement-table-body');
if (!tbody) return;
if (refinement.state.candidates.length === 0) {
tbody.innerHTML = `
<tr>
<td colspan="5" class="py-20 text-center text-slate-500">
<div class="flex flex-col items-center gap-4">
<i data-lucide="map-pin" class="w-8 h-8 opacity-20"></i>
<p>No pending location suggestions.</p>
</div>
</td>
</tr>
`;
lucide.createIcons();
return;
}
tbody.innerHTML = refinement.state.candidates.map(c => `
<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>
</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>
<td class="px-8 py-6 text-right space-x-2">
<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>
<button onclick="refinement.approve('${c.id}')" class="p-2.5 rounded-xl bg-emerald-500/10 text-emerald-400 hover:bg-emerald-500/20 transition-all border border-emerald-500/20 shadow-lg shadow-emerald-500/10" title="Approve">
<i data-lucide="check" class="w-4 h-4"></i>
</button>
</td>
</tr>
`).join('');
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`, {
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/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);
}
}
};