pif / app /templates /admin /data_refresh.html
pramodmisra's picture
v2.1: SWIA rebrand, bell-ringer + accounting email removal, House Standard split, domain self-signup, superadmin self-service
8933003
Raw
History Blame Contribute Delete
3.58 kB
{% extends "base.html" %}
{% block title %}Data Refresh — Admin{% endblock %}
{% block content %}
<div class="space-y-4">
<a href="/admin/?token={{ token }}" class="text-sm text-gray-400 hover:text-gray-600">← Admin Panel</a>
<h1 class="text-2xl font-bold sw-blue-text">Data Refresh</h1>
<p class="text-gray-500 text-sm">
Upload <code>refresh_data.json</code> exported from the BigQuery → producers/clients pipeline.
Existing entries are upserted by <code>code</code> / <code>lookup_code</code>; rows missing from
the upload are marked inactive (data preserved).
</p>
<div class="bg-white rounded-lg shadow p-5 grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<h3 class="font-semibold sw-blue-text mb-2">Current state</h3>
<ul class="text-sm text-gray-600 space-y-1">
<li>Active producers: <span class="font-bold sw-blue-text">{{ active_producers }}</span></li>
<li>Active clients: <span class="font-bold sw-blue-text">{{ active_clients }}</span></li>
</ul>
</div>
<div>
<h3 class="font-semibold sw-blue-text mb-2">Expected JSON shape</h3>
<pre class="text-xs bg-gray-50 border border-gray-200 rounded p-3 overflow-x-auto"><code>{
"producers": [
{"code": "DOEJA1", "prefix": "DOEJA", "suffix": 1, "name": "Jane Doe"}
],
"clients": [
{"lookup_code": "ACMECO-01", "name": "Acme Corp"}
]
}</code></pre>
</div>
</div>
<div class="bg-white rounded-lg shadow p-5">
<h3 class="font-semibold sw-blue-text mb-2">Upload</h3>
<input type="file" id="file_input" accept="application/json,.json"
class="w-full text-sm text-gray-600 file:mr-3 file:py-2 file:px-4 file:rounded file:border-0 file:bg-blue-50 file:text-blue-700 hover:file:bg-blue-100">
<button onclick="uploadRefresh()"
class="mt-3 bg-green-600 text-white px-6 py-2 rounded-lg text-sm font-semibold hover:bg-green-700 transition">
Run Refresh
</button>
<span id="status" class="ml-3 text-sm"></span>
</div>
</div>
{% endblock %}
{% block scripts %}
<script>
const authToken = '{{ token }}';
async function uploadRefresh() {
const fileInput = document.getElementById('file_input');
const status = document.getElementById('status');
if (!fileInput.files || !fileInput.files[0]) {
status.textContent = 'Choose a JSON file first.';
status.className = 'ml-3 text-sm text-red-600';
return;
}
status.textContent = 'Uploading…';
status.className = 'ml-3 text-sm text-gray-500';
const fd = new FormData();
fd.append('file', fileInput.files[0]);
try {
const resp = await fetch('/admin/api/data-refresh', {
method: 'POST',
headers: {'Authorization': 'Bearer ' + authToken},
body: fd,
});
const data = await resp.json();
if (data.success) {
status.textContent = '✅ ' + data.producers_imported + ' producers, ' +
data.clients_imported + ' clients imported. Reloading…';
status.className = 'ml-3 text-sm text-green-600';
setTimeout(() => location.reload(), 1500);
} else {
status.textContent = '❌ ' + (data.error || 'Failed');
status.className = 'ml-3 text-sm text-red-600';
}
} catch (e) {
status.textContent = '❌ ' + e.message;
status.className = 'ml-3 text-sm text-red-600';
}
}
</script>
{% endblock %}