Working version before modification.
This commit is contained in:
+126
-34
@@ -5,44 +5,136 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta name="theme-color" content="#f3efe6" />
|
||||
<title>Check List Portal</title>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet" />
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" />
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css" rel="stylesheet" />
|
||||
<link rel="stylesheet" href="/styles.css" />
|
||||
</head>
|
||||
<body class="portal-body">
|
||||
<!--
|
||||
The portal intentionally acts as a simple role chooser rather than a real
|
||||
authentication page. It separates user and admin entry points in the PoC
|
||||
without committing the project to a security model too early.
|
||||
-->
|
||||
<main class="portal-shell">
|
||||
<section class="portal-hero panel">
|
||||
<p class="eyebrow">Check List Access</p>
|
||||
<h1>Choose workspace</h1>
|
||||
<p class="portal-copy">
|
||||
Use the operator workspace for quality reports and the administrator workspace for configuration.
|
||||
</p>
|
||||
</section>
|
||||
<body class="portal-body d-flex align-items-center justify-content-center min-vh-100">
|
||||
<main class="container" style="max-width: 720px;">
|
||||
<div class="text-center mb-4">
|
||||
<p class="text-uppercase text-muted small fw-semibold mb-1">Check List Access</p>
|
||||
<h1 class="fw-bold">Choose workspace</h1>
|
||||
<p class="text-muted">Select a user, then open the operator or administrator workspace.</p>
|
||||
</div>
|
||||
|
||||
<section class="portal-grid">
|
||||
<!-- Direct operator entry for report creation and local draft work. -->
|
||||
<a class="portal-card panel" href="/user">
|
||||
<p class="summary-label">User area</p>
|
||||
<h2>Operator workspace</h2>
|
||||
<p class="portal-copy">
|
||||
Create reports, work offline, attach images, and manage local drafts.
|
||||
</p>
|
||||
<span class="button button-primary portal-button">Open user area</span>
|
||||
</a>
|
||||
<!-- User selection -->
|
||||
<div class="card mb-4">
|
||||
<div class="card-body">
|
||||
<label for="portalUserSelect" class="form-label fw-semibold">Select User</label>
|
||||
<select id="portalUserSelect" class="form-select">
|
||||
<option value="">— Choose a user to see their tasks —</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Direct administrator entry for centrally managed configuration. -->
|
||||
<a class="portal-card panel" href="/admin">
|
||||
<p class="summary-label">Admin area</p>
|
||||
<h2>Administrator workspace</h2>
|
||||
<p class="portal-copy">
|
||||
Maintain image requirements and other centrally managed configuration.
|
||||
</p>
|
||||
<span class="button button-secondary portal-button">Open admin area</span>
|
||||
</a>
|
||||
</section>
|
||||
<div class="row g-3">
|
||||
<!-- Operator workspace -->
|
||||
<div class="col-md-6">
|
||||
<a id="portalUserLink" class="card text-decoration-none h-100 portal-card" href="#">
|
||||
<div class="card-body text-center">
|
||||
<i class="bi bi-clipboard-check fs-1 text-primary mb-2 d-block"></i>
|
||||
<p class="text-muted small mb-1">User area</p>
|
||||
<h5 class="fw-bold">Operator workspace</h5>
|
||||
<p class="text-muted small">Process assigned tasks, attach images, save reports.</p>
|
||||
<span class="btn btn-primary btn-sm mt-2">Open user area</span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- Administrator workspace -->
|
||||
<div class="col-md-6">
|
||||
<a class="card text-decoration-none h-100 portal-card" href="/admin">
|
||||
<div class="card-body text-center">
|
||||
<i class="bi bi-gear fs-1 text-secondary mb-2 d-block"></i>
|
||||
<p class="text-muted small mb-1">Admin area</p>
|
||||
<h5 class="fw-bold">Administrator workspace</h5>
|
||||
<p class="text-muted small">Manage settings, users, sites, templates, and tasks.</p>
|
||||
<span class="btn btn-outline-secondary btn-sm mt-2">Open admin area</span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Data cleanup -->
|
||||
<div class="card mt-4">
|
||||
<div class="card-body d-flex align-items-center justify-content-between">
|
||||
<div>
|
||||
<h6 class="fw-semibold mb-1"><i class="bi bi-trash3 me-1"></i>Data Cleanup</h6>
|
||||
<p class="text-muted small mb-0">Remove all localStorage data and reset the application.</p>
|
||||
</div>
|
||||
<button id="cleanupBtn" class="btn btn-outline-danger btn-sm">Clear all data</button>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<script>
|
||||
// Populate user dropdown from server API
|
||||
(function() {
|
||||
const sel = document.getElementById('portalUserSelect');
|
||||
const userLink = document.getElementById('portalUserLink');
|
||||
|
||||
/* Prevent opening user area without selecting a user */
|
||||
userLink.addEventListener('click', (e) => {
|
||||
if (!sel.value) {
|
||||
e.preventDefault();
|
||||
sel.focus();
|
||||
sel.classList.add('is-invalid');
|
||||
setTimeout(() => sel.classList.remove('is-invalid'), 2000);
|
||||
}
|
||||
});
|
||||
|
||||
async function populateUsers() {
|
||||
try {
|
||||
const resp = await fetch('/api/v1/admin/users', { headers: { Accept: 'application/json' } });
|
||||
if (!resp.ok) throw new Error('Failed to load users');
|
||||
const data = await resp.json();
|
||||
const users = data.items || [];
|
||||
sel.innerHTML = '<option value="">— Choose a user to see their tasks —</option>';
|
||||
users.forEach(u => {
|
||||
const opt = document.createElement('option');
|
||||
opt.value = u.id;
|
||||
opt.textContent = `${u.name} ${u.familyName} (${u.email}) — ${u.role}`;
|
||||
sel.appendChild(opt);
|
||||
});
|
||||
const saved = localStorage.getItem('portal_selected_user');
|
||||
if (saved) sel.value = saved;
|
||||
updateUserLink();
|
||||
} catch (err) {
|
||||
console.warn('Could not load users from server:', err.message);
|
||||
}
|
||||
}
|
||||
|
||||
sel.addEventListener('change', () => {
|
||||
localStorage.setItem('portal_selected_user', sel.value);
|
||||
updateUserLink();
|
||||
});
|
||||
|
||||
function updateUserLink() {
|
||||
const uid = sel.value;
|
||||
userLink.href = uid ? `/user?userId=${encodeURIComponent(uid)}` : '#';
|
||||
}
|
||||
|
||||
populateUsers();
|
||||
|
||||
/* Re-populate when navigating back (fixes stale data after bfcache) */
|
||||
window.addEventListener('pageshow', (e) => { if (e.persisted) populateUsers(); });
|
||||
|
||||
// Cleanup button
|
||||
document.getElementById('cleanupBtn').addEventListener('click', () => {
|
||||
if (!confirm('This will remove ALL application data (cached data, settings). Continue?')) return;
|
||||
localStorage.removeItem('portal_selected_user');
|
||||
localStorage.removeItem('user_language');
|
||||
// Clear IndexedDB
|
||||
indexedDB.databases().then(dbs => {
|
||||
dbs.forEach(db => indexedDB.deleteDatabase(db.name));
|
||||
}).catch(() => {});
|
||||
alert('All data cleared. Page will reload.');
|
||||
location.reload();
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user