241 lines
11 KiB
JavaScript
241 lines
11 KiB
JavaScript
'use strict';
|
|
// Organization Management — Ports, Companies, BuoyOwnership
|
|
|
|
let _orgPorts = [];
|
|
let _orgCompanies = [];
|
|
|
|
// ── Open modal ────────────────────────────────────────────────────────────────
|
|
window.openOrgModal = async function(tab = 'otab-ports') {
|
|
_showModal('modal-org');
|
|
_activateOrgTab(tab);
|
|
await _loadOrgPorts();
|
|
await _loadOrgCompanies();
|
|
};
|
|
|
|
function _activateOrgTab(id) {
|
|
document.querySelectorAll('.otab-panel').forEach(p => p.classList.add('hidden'));
|
|
document.querySelectorAll('.stab[data-otab]').forEach(b => b.classList.remove('active'));
|
|
document.getElementById(id)?.classList.remove('hidden');
|
|
document.querySelector(`.stab[data-otab="${id}"]`)?.classList.add('active');
|
|
}
|
|
|
|
document.querySelectorAll('.stab[data-otab]').forEach(btn => {
|
|
btn.addEventListener('click', () => _activateOrgTab(btn.dataset.otab));
|
|
});
|
|
|
|
// ── Auth header helper ────────────────────────────────────────────────────────
|
|
function _ah() {
|
|
return { 'Content-Type': 'application/json', Authorization: `Bearer ${window.Auth?.token()}` };
|
|
}
|
|
|
|
// ── PORTS ─────────────────────────────────────────────────────────────────────
|
|
async function _loadOrgPorts() {
|
|
try {
|
|
const r = await fetch(`${API}/org/ports`, { headers: _ah() });
|
|
_orgPorts = await r.json();
|
|
_renderPorts();
|
|
// populate company port selector
|
|
const sel = document.getElementById('oc-port');
|
|
sel.innerHTML = '<option value="">— Select port —</option>' +
|
|
_orgPorts.map(p => `<option value="${p.id}">${p.name}</option>`).join('');
|
|
} catch (e) {
|
|
document.getElementById('org-ports-body').innerHTML =
|
|
`<tr><td colspan="6" style="color:var(--red)">Error: ${e.message}</td></tr>`;
|
|
}
|
|
}
|
|
|
|
function _renderPorts() {
|
|
const tbody = document.getElementById('org-ports-body');
|
|
tbody.innerHTML = _orgPorts.map(p => `
|
|
<tr>
|
|
<td>${p.name}</td>
|
|
<td class="mono" style="font-size:0.7rem">${p.center_lat?.toFixed(4) ?? '--'}, ${p.center_lon?.toFixed(4) ?? '--'}</td>
|
|
<td>${p.default_zoom}</td>
|
|
<td style="font-size:0.7rem;color:var(--text-muted)">${p.chart_name || '--'}</td>
|
|
<td><span style="color:${p.activo ? 'var(--green)' : 'var(--red)'}">${p.activo ? 'ACTIVE' : 'OFF'}</span></td>
|
|
<td>
|
|
<button class="chart-row-btn" onclick="_editPort('${p.id}')">EDIT</button>
|
|
</td>
|
|
</tr>`).join('');
|
|
}
|
|
|
|
document.getElementById('btn-port-add')?.addEventListener('click', async () => {
|
|
const name = document.getElementById('op-name').value.trim();
|
|
const lat = parseFloat(document.getElementById('op-lat').value);
|
|
const lon = parseFloat(document.getElementById('op-lon').value);
|
|
const zoom = parseFloat(document.getElementById('op-zoom').value) || 12;
|
|
const chart = document.getElementById('op-chart').value.trim();
|
|
const st = document.getElementById('org-ports-status');
|
|
if (!name) { st.textContent = 'Port name is required.'; return; }
|
|
try {
|
|
const r = await fetch(`${API}/org/ports`, {
|
|
method: 'POST', headers: _ah(),
|
|
body: JSON.stringify({ name, center_lat: isNaN(lat)?null:lat, center_lon: isNaN(lon)?null:lon,
|
|
default_zoom: zoom, chart_name: chart || null })
|
|
});
|
|
if (!r.ok) throw new Error((await r.json()).detail);
|
|
st.textContent = `Port "${name}" added.`;
|
|
document.getElementById('op-name').value = '';
|
|
await _loadOrgPorts();
|
|
} catch (e) { st.textContent = `Error: ${e.message}`; }
|
|
});
|
|
|
|
window._editPort = async function(portId) {
|
|
const p = _orgPorts.find(x => x.id === portId);
|
|
if (!p) return;
|
|
const name = prompt('Port name:', p.name);
|
|
if (!name) return;
|
|
const chart = prompt('Chart folder (leave blank to keep):', p.chart_name || '');
|
|
try {
|
|
await fetch(`${API}/org/ports/${portId}`, {
|
|
method: 'PUT', headers: _ah(),
|
|
body: JSON.stringify({ name, chart_name: chart || null })
|
|
});
|
|
await _loadOrgPorts();
|
|
} catch (e) { alert('Error: ' + e.message); }
|
|
};
|
|
|
|
// ── COMPANIES ─────────────────────────────────────────────────────────────────
|
|
async function _loadOrgCompanies() {
|
|
try {
|
|
const r = await fetch(`${API}/org/companies`, { headers: _ah() });
|
|
_orgCompanies = await r.json();
|
|
_renderCompanies();
|
|
// populate ownership selectors
|
|
const sels = [document.getElementById('ow-filter-company'),
|
|
document.getElementById('ow-company-sel')];
|
|
sels.forEach(sel => {
|
|
if (!sel) return;
|
|
const val = sel.value;
|
|
sel.innerHTML = '<option value="">— All companies —</option>' +
|
|
_orgCompanies.map(c => `<option value="${c.id}">${c.name}</option>`).join('');
|
|
sel.value = val;
|
|
});
|
|
} catch (e) {
|
|
document.getElementById('org-companies-body').innerHTML =
|
|
`<tr><td colspan="6" style="color:var(--red)">Error: ${e.message}</td></tr>`;
|
|
}
|
|
}
|
|
|
|
function _renderCompanies() {
|
|
const portMap = Object.fromEntries(_orgPorts.map(p => [p.id, p.name]));
|
|
const tbody = document.getElementById('org-companies-body');
|
|
tbody.innerHTML = _orgCompanies.map(c => `
|
|
<tr>
|
|
<td>${c.name}</td>
|
|
<td>${portMap[c.port_id] || '--'}</td>
|
|
<td class="mono" style="font-size:0.7rem">${c.contact_email || '--'}</td>
|
|
<td style="font-size:0.7rem">${c.contact_phone || '--'}</td>
|
|
<td><span style="color:${c.activa ? 'var(--green)' : 'var(--red)'}">${c.activa ? 'ACTIVE' : 'OFF'}</span></td>
|
|
<td><button class="chart-row-btn" onclick="_editCompany('${c.id}')">EDIT</button></td>
|
|
</tr>`).join('');
|
|
}
|
|
|
|
document.getElementById('btn-company-add')?.addEventListener('click', async () => {
|
|
const name = document.getElementById('oc-name').value.trim();
|
|
const portId = document.getElementById('oc-port').value;
|
|
const email = document.getElementById('oc-email').value.trim();
|
|
const phone = document.getElementById('oc-phone').value.trim();
|
|
const st = document.getElementById('org-companies-status');
|
|
if (!name) { st.textContent = 'Company name is required.'; return; }
|
|
try {
|
|
const r = await fetch(`${API}/org/companies`, {
|
|
method: 'POST', headers: _ah(),
|
|
body: JSON.stringify({ name, port_id: portId || null,
|
|
contact_email: email || null, contact_phone: phone || null })
|
|
});
|
|
if (!r.ok) throw new Error((await r.json()).detail);
|
|
st.textContent = `Company "${name}" added.`;
|
|
document.getElementById('oc-name').value = '';
|
|
await _loadOrgCompanies();
|
|
} catch (e) { st.textContent = `Error: ${e.message}`; }
|
|
});
|
|
|
|
window._editCompany = async function(companyId) {
|
|
const c = _orgCompanies.find(x => x.id === companyId);
|
|
if (!c) return;
|
|
const name = prompt('Company name:', c.name);
|
|
if (!name) return;
|
|
const portId = prompt('Port ID (leave blank to keep):', c.port_id || '');
|
|
try {
|
|
await fetch(`${API}/org/companies/${companyId}`, {
|
|
method: 'PUT', headers: _ah(),
|
|
body: JSON.stringify({ name, port_id: portId || null })
|
|
});
|
|
await _loadOrgCompanies();
|
|
} catch (e) { alert('Error: ' + e.message); }
|
|
};
|
|
|
|
// ── BUOY OWNERSHIP ────────────────────────────────────────────────────────────
|
|
document.getElementById('btn-ow-load')?.addEventListener('click', _loadOwnership);
|
|
|
|
async function _loadOwnership() {
|
|
const companyId = document.getElementById('ow-filter-company').value;
|
|
if (!companyId) {
|
|
document.getElementById('org-ownership-body').innerHTML =
|
|
'<tr><td colspan="5" style="color:var(--text-muted)">Select a company first.</td></tr>';
|
|
return;
|
|
}
|
|
try {
|
|
const r = await fetch(`${API}/org/companies/${companyId}/buoys`, { headers: _ah() });
|
|
const rows = await r.json();
|
|
const cName = _orgCompanies.find(c => c.id === companyId)?.name || companyId;
|
|
document.getElementById('org-ownership-body').innerHTML = rows.length ? rows.map(row => `
|
|
<tr>
|
|
<td>${cName}</td>
|
|
<td>${row.aid_nombre || '--'}</td>
|
|
<td class="mono">${row.mmsi || '--'}</td>
|
|
<td style="font-size:0.7rem;color:var(--text-muted)">${row.notas || '--'}</td>
|
|
<td>
|
|
<button class="chart-row-btn danger" onclick="_removeOwnership('${companyId}','${row.id}')">REMOVE</button>
|
|
</td>
|
|
</tr>`).join('')
|
|
: '<tr><td colspan="5" style="color:var(--text-muted)">No buoys assigned to this company.</td></tr>';
|
|
} catch (e) {
|
|
document.getElementById('org-ownership-body').innerHTML =
|
|
`<tr><td colspan="5" style="color:var(--red)">Error: ${e.message}</td></tr>`;
|
|
}
|
|
}
|
|
|
|
window._removeOwnership = async function(companyId, ownershipId) {
|
|
if (!confirm('Remove this buoy assignment?')) return;
|
|
try {
|
|
const r = await fetch(`${API}/org/companies/${companyId}/buoys/${ownershipId}`, {
|
|
method: 'DELETE', headers: _ah()
|
|
});
|
|
if (!r.ok) throw new Error((await r.json()).detail);
|
|
// Refresh cache on server
|
|
await fetch(`${API}/org/refresh`, { method: 'POST', headers: _ah() });
|
|
await _loadOwnership();
|
|
} catch (e) { alert('Error: ' + e.message); }
|
|
};
|
|
|
|
document.getElementById('btn-ow-assign')?.addEventListener('click', async () => {
|
|
const companyId = document.getElementById('ow-company-sel').value;
|
|
const aidId = document.getElementById('ow-aid-id').value.trim();
|
|
const mmsi = document.getElementById('ow-mmsi').value.trim();
|
|
const notas = document.getElementById('ow-notes').value.trim();
|
|
const st = document.getElementById('org-ownership-status');
|
|
if (!companyId) { st.textContent = 'Select a company.'; return; }
|
|
if (!aidId && !mmsi) { st.textContent = 'Provide an Aid ID or MMSI.'; return; }
|
|
try {
|
|
const r = await fetch(`${API}/org/companies/${companyId}/buoys`, {
|
|
method: 'POST', headers: _ah(),
|
|
body: JSON.stringify({ aid_id: aidId || null, mmsi: mmsi || null, notas: notas || null })
|
|
});
|
|
if (!r.ok) throw new Error((await r.json()).detail);
|
|
// Refresh cache on server
|
|
await fetch(`${API}/org/refresh`, { method: 'POST', headers: _ah() });
|
|
st.textContent = 'Buoy assigned.';
|
|
document.getElementById('ow-aid-id').value = '';
|
|
document.getElementById('ow-mmsi').value = '';
|
|
// Auto-load the company we just assigned
|
|
document.getElementById('ow-filter-company').value = companyId;
|
|
await _loadOwnership();
|
|
} catch (e) { st.textContent = `Error: ${e.message}`; }
|
|
});
|
|
|
|
// ── Close buttons ─────────────────────────────────────────────────────────────
|
|
document.getElementById('btn-close-org')?.addEventListener('click', () => _hideModal('modal-org'));
|
|
document.getElementById('btn-close-org2')?.addEventListener('click', () => _hideModal('modal-org'));
|