feat(fusion_clock): always-available kiosk photo action + compact manager PIN pad
NFC kiosk: - Add "📷 Photo" action to every Manage-page employee row and to the post-enroll result card, so a manager can set/replace a profile photo at any time (previously only surfaced when the employee had no image). - Slim the Manager PIN pad: dedicated --pin panel variant (max-width 360px, reduced padding) with a tighter numpad, removing the oversized whitespace. Deployed live to entech (LXC 111) as 19.0.3.11.0. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
{
|
{
|
||||||
'name': 'Fusion Clock',
|
'name': 'Fusion Clock',
|
||||||
'version': '19.0.3.10.0',
|
'version': '19.0.3.11.0',
|
||||||
'category': 'Human Resources/Attendances',
|
'category': 'Human Resources/Attendances',
|
||||||
'summary': 'Complete Employee T&A with Geofencing, Shifts, Penalties, Overtime, Kiosk, Dashboard & Payroll Export',
|
'summary': 'Complete Employee T&A with Geofencing, Shifts, Penalties, Overtime, Kiosk, Dashboard & Payroll Export',
|
||||||
'description': """
|
'description': """
|
||||||
|
|||||||
@@ -306,7 +306,7 @@
|
|||||||
let pin = "";
|
let pin = "";
|
||||||
stateContainer.innerHTML = `
|
stateContainer.innerHTML = `
|
||||||
<div class="nfc-kiosk__enroll-overlay">
|
<div class="nfc-kiosk__enroll-overlay">
|
||||||
<div class="nfc-kiosk__enroll-panel">
|
<div class="nfc-kiosk__enroll-panel nfc-kiosk__enroll-panel--pin">
|
||||||
<h2>${escapeHtml(opts.title || "Enter PIN")}</h2>
|
<h2>${escapeHtml(opts.title || "Enter PIN")}</h2>
|
||||||
<div class="pin-display" id="nfc_pin_display"></div>
|
<div class="pin-display" id="nfc_pin_display"></div>
|
||||||
<div class="numpad">
|
<div class="numpad">
|
||||||
@@ -415,6 +415,7 @@
|
|||||||
? `<button class="m-btn m-danger" data-act="delok" data-id="${e.id}">Confirm delete</button>
|
? `<button class="m-btn m-danger" data-act="delok" data-id="${e.id}">Confirm delete</button>
|
||||||
<button class="m-btn" data-act="delno" data-id="${e.id}">Cancel</button>`
|
<button class="m-btn" data-act="delno" data-id="${e.id}">Cancel</button>`
|
||||||
: `<button class="m-btn" data-act="assign" data-id="${e.id}" data-name="${escapeHtml(e.name)}">${e.card_uid ? "Re-tag" : "Assign"}</button>
|
: `<button class="m-btn" data-act="assign" data-id="${e.id}" data-name="${escapeHtml(e.name)}">${e.card_uid ? "Re-tag" : "Assign"}</button>
|
||||||
|
<button class="m-btn" data-act="photo" data-id="${e.id}" data-name="${escapeHtml(e.name)}">📷 Photo</button>
|
||||||
${e.card_uid ? `<button class="m-btn" data-act="clear" data-id="${e.id}">Clear tag</button>` : ""}
|
${e.card_uid ? `<button class="m-btn" data-act="clear" data-id="${e.id}">Clear tag</button>` : ""}
|
||||||
<button class="m-btn m-danger" data-act="del" data-id="${e.id}">Delete</button>`;
|
<button class="m-btn m-danger" data-act="del" data-id="${e.id}">Delete</button>`;
|
||||||
return `<div class="manager-row">
|
return `<div class="manager-row">
|
||||||
@@ -430,6 +431,8 @@
|
|||||||
enrollSelectedEmployee = { id, name: btn.dataset.name };
|
enrollSelectedEmployee = { id, name: btn.dataset.name };
|
||||||
pendingEnrollUid = null;
|
pendingEnrollUid = null;
|
||||||
renderEnroll({ phase: "tap" });
|
renderEnroll({ phase: "tap" });
|
||||||
|
} else if (act === "photo") {
|
||||||
|
openPhotoCapture(id, btn.dataset.name, () => renderEnroll({ phase: "manager" }));
|
||||||
} else if (act === "clear") {
|
} else if (act === "clear") {
|
||||||
try { await postJson("/fusion_clock/kiosk/nfc/clear_tag", { employee_id: id, enroll_password: enrollPassword }); } catch (e) {}
|
try { await postJson("/fusion_clock/kiosk/nfc/clear_tag", { employee_id: id, enroll_password: enrollPassword }); } catch (e) {}
|
||||||
refresh();
|
refresh();
|
||||||
@@ -566,14 +569,14 @@
|
|||||||
<div class="nfc-kiosk__enroll-panel" style="text-align:center">
|
<div class="nfc-kiosk__enroll-panel" style="text-align:center">
|
||||||
<h2 style="color:${ok ? "var(--nfc-success)" : "var(--nfc-error)"}">${msg}</h2>
|
<h2 style="color:${ok ? "var(--nfc-success)" : "var(--nfc-error)"}">${msg}</h2>
|
||||||
<div class="actions" style="justify-content:center">
|
<div class="actions" style="justify-content:center">
|
||||||
${ok && payload.needs_photo && payload.employee_id ? `<button class="confirm" id="enroll_photo">📷 Take photo</button>` : ""}
|
${ok && payload.employee_id ? `<button class="confirm" id="enroll_photo">📷 Take photo</button>` : ""}
|
||||||
<button class="confirm" id="enroll_another">Enroll another</button>
|
<button class="confirm" id="enroll_another">Enroll another</button>
|
||||||
<button class="cancel" id="enroll_done">Done</button>
|
<button class="cancel" id="enroll_done">Done</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
if (ok && payload.needs_photo && payload.employee_id) {
|
if (ok && payload.employee_id) {
|
||||||
document.getElementById("enroll_photo").addEventListener("click", () => {
|
document.getElementById("enroll_photo").addEventListener("click", () => {
|
||||||
openPhotoCapture(payload.employee_id, payload.employee_name, () => {
|
openPhotoCapture(payload.employee_id, payload.employee_name, () => {
|
||||||
if (enrollPassword) renderEnroll({ phase: "manager" }); else exitEnrollMode();
|
if (enrollPassword) renderEnroll({ phase: "manager" }); else exitEnrollMode();
|
||||||
|
|||||||
@@ -512,6 +512,9 @@ html:has(#nfc_kiosk_root) {
|
|||||||
max-height: 92vh;
|
max-height: 92vh;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
|
|
||||||
|
// Compact PIN-pad variant — narrower + tighter than the wide list panels
|
||||||
|
&--pin { width: auto; max-width: 360px; padding: 1.5rem 1.5rem 1.25rem; }
|
||||||
|
|
||||||
h2 {
|
h2 {
|
||||||
font-size: 1.5rem;
|
font-size: 1.5rem;
|
||||||
margin: 0 0 1.5rem;
|
margin: 0 0 1.5rem;
|
||||||
@@ -522,12 +525,12 @@ html:has(#nfc_kiosk_root) {
|
|||||||
.numpad {
|
.numpad {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(3, 1fr);
|
grid-template-columns: repeat(3, 1fr);
|
||||||
gap: 0.75rem;
|
gap: 0.5rem;
|
||||||
margin: 1rem 0;
|
margin: 0.5rem 0 0.75rem;
|
||||||
|
|
||||||
button {
|
button {
|
||||||
font-size: 1.7rem;
|
font-size: 1.45rem;
|
||||||
padding: 1.1rem 0;
|
padding: 0.7rem 0;
|
||||||
background: rgba(255,255,255,0.05);
|
background: rgba(255,255,255,0.05);
|
||||||
color: var(--nfc-text);
|
color: var(--nfc-text);
|
||||||
border: 1px solid rgba(255,255,255,0.1);
|
border: 1px solid rgba(255,255,255,0.1);
|
||||||
|
|||||||
Reference in New Issue
Block a user