ChristopherJKoen's picture
Manual changes saved
102ff79 verified
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>RepEx - Report Express | Review & Setup</title>
<link rel="stylesheet" href="style.css" />
<script src="https://cdn.tailwindcss.com"></script>
<script defer src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>
<style>
img { -webkit-print-color-adjust: exact; print-color-adjust: exact; }
</style>
</head>
<body class="bg-gray-50 min-h-screen">
<main class="max-w-4xl mx-auto my-8 bg-white shadow-sm ring-1 ring-gray-200 rounded-xl p-6 md:p-8">
<!-- Header -->
<header class="mb-8 border-b border-gray-200 pb-4">
<div class="grid grid-cols-[auto,1fr,auto] items-center gap-4">
<div class="flex items-center">
<img
src="https://huggingface.co/spaces/ChristopherJKoen/docusnap-report-wizard/resolve/main/images/Picture3.png"
alt="Company logo"
class="h-12 w-auto object-contain"
loading="eager"
/>
</div>
<div class="text-center">
<h1 class="text-2xl md:text-3xl font-bold text-gray-900 whitespace-nowrap">
RepEx - Report Express
</h1>
<p class="text-gray-600 whitespace-nowrap">
Review uploads → pick examples → continue to report viewer
</p>
</div>
<div class="flex justify-end">
<span class="inline-flex items-center gap-2 rounded-lg border border-gray-200 bg-gray-50 px-3 py-2 text-xs font-semibold text-gray-700">
<i data-feather="check-circle" class="h-4 w-4"></i>
Uploads processed
</span>
</div>
</div>
</header>
<!-- Orientation -->
<section class="mb-8" aria-labelledby="what-next">
<h2 id="what-next" class="text-xl font-semibold text-gray-800 border-b border-gray-200 pb-2 mb-4">
What happens on this page
</h2>
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
<div class="rounded-lg border border-gray-200 bg-gray-50 p-4">
<div class="inline-flex h-10 w-10 items-center justify-center rounded-full bg-blue-50 border border-blue-100 mb-3">
<i data-feather="image" class="h-5 w-5 text-blue-700"></i>
</div>
<h3 class="font-semibold text-gray-900 mb-1">Select example photos</h3>
<p class="text-sm text-gray-600">
Choose which uploaded images should appear as example figures in the report.
</p>
</div>
<div class="rounded-lg border border-gray-200 bg-gray-50 p-4">
<div class="inline-flex h-10 w-10 items-center justify-center rounded-full bg-emerald-50 border border-emerald-100 mb-3">
<i data-feather="file-text" class="h-5 w-5 text-emerald-700"></i>
</div>
<h3 class="font-semibold text-gray-900 mb-1">Confirm documents</h3>
<p class="text-sm text-gray-600">
Ensure supporting PDFs/DOCX are correct (and later attach to export if needed).
</p>
</div>
<div class="rounded-lg border border-gray-200 bg-gray-50 p-4">
<div class="inline-flex h-10 w-10 items-center justify-center rounded-full bg-amber-50 border border-amber-100 mb-3">
<i data-feather="table" class="h-5 w-5 text-amber-700"></i>
</div>
<h3 class="font-semibold text-gray-900 mb-1">Use Excel/CSV data</h3>
<p class="text-sm text-gray-600">
If Excel/CSV exists, it will populate report data areas automatically in later steps.
</p>
</div>
</div>
</section>
<!-- Review uploads -->
<section class="mb-8" aria-labelledby="review-uploads">
<h2 id="review-uploads" class="text-xl font-semibold text-gray-800 border-b border-gray-200 pb-2 mb-6">
Review uploaded files
</h2>
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
<!-- Photos -->
<div class="lg:col-span-2">
<div class="flex items-center justify-between mb-3">
<h3 class="text-lg font-semibold text-gray-900">Photos</h3>
<span id="photoCount" class="text-sm font-semibold text-gray-600">0 files</span>
</div>
<div class="rounded-lg border border-gray-200 bg-white p-4">
<p class="text-sm text-gray-600 mb-3">
Select images to use as example figures in the report.
<span class="font-semibold text-gray-800">Recommended:</span> 2–6 images.
</p>
<div id="photoGrid" class="grid grid-cols-2 md:grid-cols-3 gap-3">
<!-- populated by JS -->
</div>
<div class="mt-4 flex flex-wrap items-center justify-between gap-3">
<div class="text-sm text-gray-600">
Selected for report: <span id="photoSelected" class="font-semibold text-gray-900">0</span>
</div>
<div class="flex gap-2">
<button id="selectAllPhotos" type="button"
class="inline-flex items-center gap-2 rounded-lg border border-gray-200 bg-white px-3 py-2 text-sm font-semibold text-gray-800 hover:bg-gray-50 transition">
<i data-feather="check-square" class="h-4 w-4"></i>
Select all
</button>
<button id="clearPhotos" type="button"
class="inline-flex items-center gap-2 rounded-lg border border-gray-200 bg-white px-3 py-2 text-sm font-semibold text-gray-800 hover:bg-gray-50 transition">
<i data-feather="square" class="h-4 w-4"></i>
Clear
</button>
</div>
</div>
</div>
</div>
<!-- Documents + Data files -->
<div class="space-y-6">
<!-- Documents -->
<div>
<div class="flex items-center justify-between mb-3">
<h3 class="text-lg font-semibold text-gray-900">Documents</h3>
<span id="docCount" class="text-sm font-semibold text-gray-600">0 files</span>
</div>
<div class="rounded-lg border border-gray-200 bg-white p-4">
<ul id="docList" class="space-y-2 text-sm text-gray-700">
<!-- populated by JS -->
</ul>
<p id="docHint" class="text-xs text-gray-500 mt-3">
PDFs/DOCX appear here after processing.
</p>
</div>
</div>
<!-- Data files -->
<div>
<div class="flex items-center justify-between mb-3">
<h3 class="text-lg font-semibold text-gray-900">Data files</h3>
<span id="dataCount" class="text-sm font-semibold text-gray-600">0 files</span>
</div>
<div class="rounded-lg border border-gray-200 bg-white p-4">
<div id="dataBox" class="text-sm text-gray-700">
<!-- populated by JS -->
</div>
<p class="text-xs text-gray-500 mt-3">
If present, these files will populate report tables/fields automatically.
</p>
</div>
</div>
</div>
</div>
</section>
<!-- Continue -->
<section class="mb-4" aria-label="Continue to report viewer">
<div class="rounded-lg border border-gray-200 bg-gray-50 p-4 flex flex-col sm:flex-row gap-3 sm:items-center sm:justify-between">
<div class="text-sm text-gray-600">
Next step:
<span id="readyStatus" class="font-semibold text-amber-700">Choose report example images to continue…</span>
</div>
<button
id="continueBtn"
type="button"
class="inline-flex items-center justify-center gap-2 rounded-lg bg-emerald-600 px-5 py-2.5 text-white font-semibold hover:bg-emerald-700 transition disabled:opacity-50 disabled:cursor-not-allowed"
disabled
>
<i data-feather="arrow-right" class="h-5 w-5"></i>
Continue to Report Viewer
</button>
</div>
<p class="text-xs text-gray-500 mt-3">
Note: This page assumes uploads were completed on a previous “Processing” page.
</p>
</section>
<!-- Footer -->
<footer class="mt-12 text-center text-xs text-gray-500">
<p>Prosento - © 2026 All Rights Reserved</p>
<p class="mt-1">Workflow: Processing → Review uploads → Report viewer → Edit → Export</p>
</footer>
</main>
<script>
document.addEventListener('DOMContentLoaded', () => {
// Feather icons
if (window.feather && typeof window.feather.replace === 'function') {
window.feather.replace();
}
// ---- Simulated "uploads processed" payload ----
// Replace this with the real payload passed from the progress page (e.g., localStorage, URL params, backend session).
const processedUploads = {
photos: [
{ name: 'photo_01.jpg', url: 'https://huggingface.co/spaces/ChristopherJKoen/minefix-simm-inspector/resolve/main/images/Picture2.png' },
{ name: 'photo_02.jpg', url: 'https://huggingface.co/spaces/ChristopherJKoen/minefix-simm-inspector/resolve/main/images/Screenshot%202026-02-02%20100102.png' },
{ name: 'photo_03.jpg', url: 'https://huggingface.co/spaces/ChristopherJKoen/minefix-simm-inspector/resolve/main/images/Picture2.png' }
],
documents: [
{ name: 'inspection_notes.pdf', type: 'PDF' },
{ name: 'supporting_docs.docx', type: 'DOCX' }
],
dataFiles: [
{ name: 'report_data.xlsx', type: 'XLSX' }
]
};
// ---- State ----
const state = {
selectedPhotoIds: new Set(),
};
// ---- Elements ----
const photoGrid = document.getElementById('photoGrid');
const photoCount = document.getElementById('photoCount');
const photoSelected = document.getElementById('photoSelected');
const selectAllPhotosBtn = document.getElementById('selectAllPhotos');
const clearPhotosBtn = document.getElementById('clearPhotos');
const docList = document.getElementById('docList');
const docCount = document.getElementById('docCount');
const docHint = document.getElementById('docHint');
const dataBox = document.getElementById('dataBox');
const dataCount = document.getElementById('dataCount');
const readyStatus = document.getElementById('readyStatus');
const continueBtn = document.getElementById('continueBtn');
function renderUploads() {
// Photos
const photos = processedUploads.photos || [];
photoCount.textContent = `${photos.length} file${photos.length === 1 ? '' : 's'}`;
photoGrid.innerHTML = photos.map((p, idx) => {
const id = `photo-${idx}`;
return `
<label class="group cursor-pointer">
<input type="checkbox" class="sr-only photoCheck" data-photo-id="${id}">
<div class="rounded-lg border border-gray-200 bg-gray-50 overflow-hidden group-has-[:checked]:ring-2 group-has-[:checked]:ring-emerald-200 group-has-[:checked]:border-emerald-300 transition">
<div class="relative">
<img src="${p.url}" alt="${p.name}" class="h-28 w-full object-cover" loading="eager">
<div class="absolute top-2 right-2 inline-flex items-center justify-center rounded-full bg-white/90 border border-gray-200 p-1.5 text-gray-700 group-has-[:checked]:bg-emerald-50 group-has-[:checked]:border-emerald-200 group-has-[:checked]:text-emerald-700">
<i data-feather="check" class="h-4 w-4"></i>
</div>
</div>
<div class="p-2">
<div class="text-xs font-semibold text-gray-900 truncate">${p.name}</div>
<div class="text-xs text-gray-500">Click to select for report</div>
</div>
</div>
</label>
`;
}).join('');
// Documents
const docs = processedUploads.documents || [];
docCount.textContent = `${docs.length} file${docs.length === 1 ? '' : 's'}`;
docList.innerHTML = docs.length
? docs.map(d => `
<li class="flex items-center justify-between gap-3 rounded-lg border border-gray-200 bg-gray-50 px-3 py-2">
<div class="flex items-center gap-2 min-w-0">
<i data-feather="file-text" class="h-4 w-4 text-gray-600"></i>
<span class="truncate text-gray-800">${d.name}</span>
</div>
<span class="text-xs font-semibold text-gray-600">${d.type}</span>
</li>
`).join('')
: `<li class="text-sm text-gray-500">No supporting documents detected.</li>`;
docHint.style.display = docs.length ? 'none' : 'block';
// Data files
const dataFiles = processedUploads.dataFiles || [];
dataCount.textContent = `${dataFiles.length} file${dataFiles.length === 1 ? '' : 's'}`;
dataBox.innerHTML = dataFiles.length
? dataFiles.map(f => `
<div class="rounded-lg border border-gray-200 bg-gray-50 p-3 text-sm text-gray-700 mb-2 last:mb-0">
<div class="flex items-center justify-between gap-3">
<div class="flex items-center gap-2 min-w-0">
<i data-feather="table" class="h-4 w-4 text-amber-700"></i>
<span class="truncate font-semibold text-gray-900">${f.name}</span>
</div>
<span class="text-xs font-semibold text-gray-600">${f.type}</span>
</div>
<div class="text-xs text-gray-600 mt-1">
Will populate report data areas (tables/fields).
</div>
</div>
`).join('')
: `
<div class="rounded-lg border border-gray-200 bg-gray-50 p-3 text-sm text-gray-600">
<div class="font-semibold text-gray-800 mb-1">No Excel/CSV detected</div>
If you upload a CSV or Excel file, RepEx can auto-populate report data fields.
</div>
`;
// Icons for dynamic content
if (window.feather && typeof window.feather.replace === 'function') {
window.feather.replace();
}
}
function updateSelectionState() {
photoSelected.textContent = String(state.selectedPhotoIds.size);
const canContinue = state.selectedPhotoIds.size > 0;
continueBtn.disabled = !canContinue;
if (!canContinue) {
readyStatus.textContent = 'Choose report example images to continue…';
readyStatus.className = 'font-semibold text-amber-700';
} else {
readyStatus.textContent = 'Ready. Continue to report viewer.';
readyStatus.className = 'font-semibold text-emerald-700';
}
}
// Init render
renderUploads();
updateSelectionState();
// Photo selection tracking
photoGrid.addEventListener('change', (e) => {
const cb = e.target.closest('.photoCheck');
if (!cb) return;
const id = cb.dataset.photoId;
if (cb.checked) state.selectedPhotoIds.add(id);
else state.selectedPhotoIds.delete(id);
updateSelectionState();
});
selectAllPhotosBtn.addEventListener('click', () => {
photoGrid.querySelectorAll('.photoCheck').forEach(cb => {
cb.checked = true;
state.selectedPhotoIds.add(cb.dataset.photoId);
});
updateSelectionState();
});
clearPhotosBtn.addEventListener('click', () => {
photoGrid.querySelectorAll('.photoCheck').forEach(cb => (cb.checked = false));
state.selectedPhotoIds.clear();
updateSelectionState();
});
// Continue → go to report-viewer.html and pass selections
continueBtn.addEventListener('click', () => {
if (state.selectedPhotoIds.size === 0) return;
const selectedIndices = Array.from(state.selectedPhotoIds)
.map(id => Number(id.replace('photo-', '')))
.filter(n => Number.isFinite(n));
const payload = {
// what the viewer might need later
selectedPhotoIndices: selectedIndices,
uploads: processedUploads,
createdAt: new Date().toISOString(),
};
localStorage.setItem('repex_report_payload', JSON.stringify(payload));
window.location.href = 'report-viewer.html';
});
});
</script>
</body>
</html>