File size: 4,826 Bytes
70d9e6c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
bec7397
 
 
 
 
 
 
70d9e6c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
bec7397
 
79b0691
 
 
 
bec7397
70d9e6c
 
 
 
 
 
bec7397
 
79b0691
bec7397
 
79b0691
70d9e6c
 
 
 
 
 
 
 
 
 
 
 
 
bec7397
70d9e6c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
/** Standalone report page at /dda/reports/{runId} (FR-05). */

function parseReportRunId() {
  const m = window.location.pathname.match(/\/dda\/reports\/(\d+)/);
  return m ? parseInt(m[1], 10) : null;
}

function showReportError(msg) {
  const el = document.getElementById('report-error');
  if (!el) return;
  el.textContent = msg;
  el.classList.remove('hidden');
}

function formatCoord(v) {
  if (v == null || v === '') return '—';
  const n = Number(v);
  return Number.isFinite(n) ? n.toFixed(5) : '—';
}

function regionLatLng(r) {
  const ll = r.latLng || {};
  const lat = r.latitude ?? ll.lat;
  const lng = r.longitude ?? ll.lng;
  return { lat, lng };
}

async function loadReportPage() {
  const runId = parseReportRunId();
  const loading = document.getElementById('report-loading');
  const content = document.getElementById('report-content');
  if (!runId) {
    if (loading) loading.innerHTML = '<p class="dim">Invalid report URL.</p>';
    return;
  }

  try {
    const data = await ddaApi('GET', `/api/dda/reports/${runId}`);
    if (loading) loading.classList.add('hidden');
    if (content) content.classList.remove('hidden');

    document.getElementById('report-title').textContent = data.title || `Run #${runId}`;
    const loc = [data.village, data.zone].filter(Boolean).join(', ') || '—';
    document.getElementById('report-meta').textContent =
      `${data.method || '—'} · ${loc} · ${data.createdAt || ''}`;

    const stats = data.statistics || {};
    document.getElementById('report-stats').innerHTML = `
      <div class="dda-stat"><span class="label">Change</span><span class="value">${(stats.changePercentage ?? 0).toFixed(2)}%</span></div>
      <div class="dda-stat"><span class="label">Changed px</span><span class="value">${(stats.changedPixels ?? 0).toLocaleString()}</span></div>
      <div class="dda-stat"><span class="label">Regions</span><span class="value">${data.regionsCount ?? (data.regions || []).length}</span></div>`;

    const overlay = document.getElementById('report-overlay');
    if (overlay) {
      if (data.overlayBase64Png) {
        overlay.src = `data:image/png;base64,${data.overlayBase64Png}`;
      } else if (data.overlayUrl) {
        overlay.src = data.overlayUrl;
      } else {
        overlay.alt = 'No overlay available';
      }
    }

    const tbody = document.getElementById('report-regions-body');
    const regions = data.regions || [];
    if (tbody) {
      tbody.innerHTML = regions.length
        ? regions.map((r) => {
            const { lat, lng } = regionLatLng(r);
            const hasCoords = Number.isFinite(Number(lat)) && Number.isFinite(Number(lng));
            const mapsUrl = hasCoords
              ? `https://www.google.com/maps/search/?api=1&query=${lat},${lng}`
              : null;
            return `
            <tr>
              <td>${r.id ?? ''}</td>
              <td>${r.ddaChangeType || r.objectType || '—'}</td>
              <td>${r.internalObjectType || r.objectType || '—'}</td>
              <td>${((r.confidence ?? 0) * 100).toFixed(0)}%</td>
              <td>${(r.area ?? 0).toLocaleString()}</td>
              <td>${formatCoord(lat)}</td>
              <td>${formatCoord(lng)}</td>
              <td>${mapsUrl ? `<a class="btn btn-secondary btn-sm" href="${mapsUrl}" target="_blank" rel="noopener">Map</a>` : '—'}</td>
            </tr>`;
          }).join('')
        : '<tr><td colspan="8" class="dim">No regions detected.</td></tr>';
    }

    const pdfBtn = document.getElementById('report-pdf-btn');
    if (pdfBtn) {
      pdfBtn.disabled = false;
      pdfBtn.onclick = () => { window.location.href = `/api/dda/reports/${runId}/pdf`; };
    }

    const viewBtn = document.getElementById('report-view-btn');
    if (viewBtn) {
      viewBtn.disabled = false;
      viewBtn.onclick = () => {
        try { sessionStorage.setItem('dda_open_run', String(runId)); } catch (_) {}
        window.location.href = '/?tab=reports';
      };
    }

    window._reportPageData = data;
  } catch (err) {
    if (loading) loading.classList.add('hidden');
    showReportError(err.message || 'Could not load report.');
  }
}

document.getElementById('report-email-btn')?.addEventListener('click', async () => {
  const runId = parseReportRunId();
  const input = document.getElementById('report-email');
  const msg = document.getElementById('report-email-msg');
  const email = (input?.value || '').trim();
  if (!email) {
    if (msg) msg.textContent = 'Enter an email address.';
    return;
  }
  try {
    const res = await ddaApi('POST', `/api/dda/reports/${runId}/notify`, {
      body: JSON.stringify({ email }),
    });
    if (msg) msg.textContent = res.message || 'Sent.';
  } catch (err) {
    if (msg) msg.textContent = err.message || 'Send failed.';
  }
});

loadReportPage();