Rapport-Laravel/resources/views/team2unitsreport/export.blade.php

130 lines
5.3 KiB
PHP

@extends('layouts.vertical-individual', ['page_title' => $title ?? 'Ciphaler / SB Units Report Export'])
@section('css')
<style>
#team2-units-export-loader {
align-items: center;
display: flex;
flex-direction: column;
gap: 16px;
justify-content: center;
min-height: 320px;
text-align: center;
}
#team2-units-export-loader img {
height: 64px;
width: 64px;
}
</style>
@endsection
@section('content')
<div class="row mb-3">
<div class="col-12">
<h4 class="page-title">{{ $title }}</h4>
<p class="text-muted mb-0">Preparing your CSV export. This may take several minutes for the full dataset.</p>
@if (!empty($search))
<p class="text-muted mb-0 small">Filter: "{{ $search }}"</p>
@endif
</div>
</div>
<div class="card">
<div class="card-body">
<div id="team2-units-export-loader" aria-live="polite" aria-busy="true">
<img src="/images/loader-large.gif" alt="">
<div>
<strong id="team2-export-status-text">Starting export...</strong>
<p class="text-muted mb-0 small" id="team2-export-status-detail"></p>
</div>
<a href="{{ $base_url }}/report?{{ http_build_query(array_filter(['type' => $type ?? null, 'search' => $search !== '' ? $search : null, 'token' => !empty($token ?? '') ? $token : null])) }}" class="btn btn-outline-secondary btn-sm d-none" id="team2-export-back">Back to report</a>
<a href="#" class="btn btn-dark btn-sm d-none" id="team2-export-download" target="_blank" rel="noopener">Download CSV</a>
</div>
</div>
</div>
@endsection
@section('script-bottom')
<script>
(function () {
const exportId = @json($export_id);
const statusUrl = @json($base_url . '/exportStatus');
const accessToken = @json($token ?? '');
const statusText = document.getElementById('team2-export-status-text');
const statusDetail = document.getElementById('team2-export-status-detail');
const downloadBtn = document.getElementById('team2-export-download');
const backBtn = document.getElementById('team2-export-back');
const loader = document.getElementById('team2-units-export-loader');
let pollTimer = null;
function stopPolling() {
if (pollTimer) {
clearInterval(pollTimer);
pollTimer = null;
}
loader.setAttribute('aria-busy', 'false');
}
function showFailure(message) {
stopPolling();
statusText.textContent = 'Export failed';
statusDetail.textContent = message || 'Please try again.';
backBtn.classList.remove('d-none');
}
function showReady(url, rowCount) {
stopPolling();
statusText.textContent = 'Export ready';
statusDetail.textContent = rowCount > 0
? 'Download will start automatically (' + rowCount.toLocaleString() + ' rows).'
: 'Your CSV is ready to download.';
downloadBtn.href = url;
downloadBtn.classList.remove('d-none');
backBtn.classList.remove('d-none');
window.location.href = url;
}
function pollStatus() {
let pollUrl = statusUrl + '?export_id=' + encodeURIComponent(exportId);
if (accessToken) {
pollUrl += '&token=' + encodeURIComponent(accessToken);
}
fetch(pollUrl, {
headers: { 'Accept': 'application/json' },
credentials: 'same-origin',
})
.then(function (response) {
return response.json().then(function (body) {
return { ok: response.ok, body: body };
});
})
.then(function (result) {
const data = result.body || {};
if (!result.ok || data.status === 'failed') {
showFailure(data.message || 'Export failed.');
return;
}
if (data.status === 'ready' && data.url) {
showReady(data.url, data.row_count || data.rows || 0);
return;
}
const rows = data.rows || data.row_count || 0;
statusText.textContent = 'Preparing export...';
statusDetail.textContent = rows > 0
? rows.toLocaleString() + ' rows exported so far.'
: 'Collecting report data...';
})
.catch(function () {
showFailure('Could not check export status.');
});
}
pollStatus();
pollTimer = setInterval(pollStatus, 3000);
})();
</script>
@endsection