cdh-merger/app/templates/index.html
2025-06-18 13:02:36 +02:00

167 lines
6.0 KiB
HTML

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>CDH Merger</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="https://unpkg.com/tabulator-tables@5.4.4/dist/css/tabulator.min.css" rel="stylesheet">
<style>
body { padding: 2rem; background: #f8f9fa; }
#table-container { height: 800px; width: 100%; overflow-x: auto;}
#table { width: 100%; }
/* Loading Overlay */
#loadingOverlay {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background: rgba(0, 0, 0, 0.5);
display: none;
align-items: center;
justify-content: center;
z-index: 9999;
}
/* Ensure toolbar stretches full width */
#toolbar { width: 100%; }
</style>
</head>
<body>
<div class="container-fluid px-0">
<h1 class="mb-4 ps-3">CDH Merger</h1>
<!-- Toolbar -->
<div class="d-flex flex-wrap align-items-center mb-3 px-3" id="toolbar">
<form id="upload-form" class="d-flex align-items-center me-3">
<input type="file" name="files" multiple class="form-control form-control-sm me-2">
<button type="submit" class="btn btn-primary btn-sm">Upload</button>
</form>
<button id="download-excel" class="btn btn-success btn-sm me-3">Excel Download</button>
<button id="clear-session" class="btn btn-warning btn-sm me-3">Daten löschen</button>
<div class="d-flex align-items-center">
<label for="table-select" class="form-label me-2 mb-0">Table:</label>
<select id="table-select" class="form-select form-select-sm">
<option value="stripe_import">Stripe Import</option>
<option value="raisenow_import">RaiseNow Import</option>
<option value="merged">Merged</option>
<option value="stripe_only">Stripe Only</option>
<option value="raisenow_only">RaiseNow Only</option>
<option value="export">Export</option>
</select>
</div>
</div>
<!-- Table -->
<div id="table-container" class="border rounded shadow-sm px-3">
<div id="table"></div>
</div>
</div>
<!-- Loading Overlay -->
<div id="loadingOverlay">
<div class="text-center text-white">
<div class="spinner-border" role="status" style="width: 4rem; height: 4rem;"><span class="visually-hidden">Loading...</span></div>
<p class="mt-3">Loading, please wait...</p>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<script src="https://unpkg.com/tabulator-tables@5.4.4/dist/js/tabulator.min.js"></script>
<script>
const uploadForm = document.getElementById('upload-form');
const tableSelect = document.getElementById('table-select');
const downloadBtn = document.getElementById('download-excel');
const clearBtn = document.getElementById('clear-session');
const loadingOverlay = document.getElementById('loadingOverlay');
let table;
function showLoading() { loadingOverlay.style.display = 'flex'; }
function hideLoading() { loadingOverlay.style.display = 'none'; }
uploadForm.addEventListener('submit', async e => {
e.preventDefault(); showLoading();
try {
const fd = new FormData(uploadForm);
const resp = await fetch('/upload', { method: 'POST', body: fd });
const res = await resp.json();
if (resp.ok) await loadTable(tableSelect.value);
else alert(res.error || 'Upload failed');
} catch (err) {
console.error(err); alert('An error occurred');
} finally { hideLoading(); }
});
tableSelect.addEventListener('change', () => loadTable(tableSelect.value));
downloadBtn.addEventListener('click', async () => {
showLoading();
try {
const resp = await fetch('/download');
if (!resp.ok) throw new Error('Download failed');
const blob = await resp.blob();
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
const disposition = resp.headers.get('Content-Disposition') || '';
const match = disposition.match(/filename="?([^";]+)"?/);
a.download = match ? match[1] : 'tables.xlsx';
document.body.appendChild(a);
a.click();
a.remove();
URL.revokeObjectURL(url);
} catch (err) {
console.error(err); alert(err.message);
} finally { hideLoading(); }
});
clearBtn.addEventListener('click', async () => {
if (!confirm('Are you sure you want to clear the server session? This will reset all loaded data.')) return;
showLoading();
try {
const resp = await fetch('/clear_session', { method: 'POST' });
const res = await resp.json();
if (!resp.ok) throw new Error(res.error || 'Failed to clear session');
// Reset UI
tableSelect.value = 'stripe_import';
if (table) table.destroy();
table = null;
alert('Session cleared successfully.');
} catch (err) {
console.error(err); alert(err.message);
} finally {
hideLoading();
}
});
async function loadTable(name) {
showLoading();
try {
const resp = await fetch(`/get_table?table=${encodeURIComponent(name)}`);
const json = await resp.json();
if (!resp.ok) { alert(json.error || 'Error loading'); return; }
if (!Array.isArray(json.data) || !json.data.length) { alert('No data for this table'); return; }
const cols = json.columns.map(c => ({ title: c, field: c, headerFilter: true }));
const opts = {
data: json.data,
layout: 'fitData',
height: '100%',
columns: cols,
};
if (table) table.destroy();
table = new Tabulator('#table', opts);
} catch (err) {
console.error(err); alert('Failed to load table data');
} finally { hideLoading(); }
}
// initialize
loadTable(tableSelect.value);
</script>
</body>
</html>