2026-09-30 23:12:51 +01:00
<!doctype html>
< html lang = "en" >
< head >
< meta charset = "utf-8" >
< meta name = "viewport" content = "width=device-width, initial-scale=1" >
< title > Fingerprint Agent · YOUreka Tools</ title >
2026-10-01 02:03:07 +01:00
< link rel = "stylesheet" href = "https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:wght@400;500;600;700&display=swap" >
< link rel = "stylesheet" href = "https://cdn.jsdelivr.net/npm/@carbon/styles@1.69.0/css/styles.min.css" >
2026-09-30 23:12:51 +01:00
< link rel = "stylesheet" href = "/assets/style.css" >
2026-10-01 04:08:09 +01:00
< link rel = "icon" type = "image/png" href = "/assets/youreka-favicon.png" >
2026-10-01 02:03:07 +01:00
< script src = "https://cdn.socket.io/4.4.0/socket.io.min.js" integrity = "sha384-1fOn6VtTq3PWwfsOrk45LnYcGosJwzMHv+Xh/Jx5303FVOXzEnw0EpLv30mtjmlj" crossorigin = "anonymous" ></ script >
2026-10-01 03:53:24 +01:00
< script type = "module" src = "https://1.www.s81c.com/common/carbon/web-components/version/v2.50.0/ui-shell.min.js" ></ script >
2026-10-01 04:08:09 +01:00
< script type = "module" src = "https://1.www.s81c.com/common/carbon/web-components/version/v2.50.0/modal.min.js" ></ script >
2026-10-01 02:03:07 +01:00
< script type = "module" src = "https://1.www.s81c.com/common/carbon/web-components/version/v2.50.0/button.min.js" ></ script >
< script type = "module" src = "https://1.www.s81c.com/common/carbon/web-components/version/v2.50.0/notification.min.js" ></ script >
< script type = "module" src = "https://1.www.s81c.com/common/carbon/web-components/version/v2.50.0/progress-bar.min.js" ></ script >
< script type = "module" src = "https://1.www.s81c.com/common/carbon/web-components/version/v2.50.0/tag.min.js" ></ script >
2026-09-30 23:12:51 +01:00
</ head >
2026-10-01 04:01:44 +01:00
< body class = "app cds--g100" >
2026-09-30 23:12:51 +01:00
< div id = "app" >
2026-10-01 03:53:24 +01:00
<!--app-header-->
2026-09-30 23:12:51 +01:00
< main class = "container" v-cloak v-if = "session" >
< div class = "page-head" >
< div >
< h1 > Fingerprint Agent</ h1 >
< p class = "sub" >
Enrollment wizard for staff fingerprints on this laptop
< span v-if = "agent.version" class = "faint" > · fpagent {{ agent.version }}</ span >
</ p >
</ div >
</ div >
2026-10-01 02:03:07 +01:00
< cds-inline-notification v-if = "notif.show" v-bind:kind = "notif.kind" v-bind:title = "notif.title"
v-bind:subtitle = "notif.subtitle" hide-close-button style = "margin-bottom: 1rem;" >
</ cds-inline-notification >
2026-09-30 23:12:51 +01:00
2026-10-01 02:03:07 +01:00
<!-- 1 · locate profile -->
2026-09-30 23:12:51 +01:00
< section class = "card panel" >
< div class = "panel-head" >
< span class = "step-chip" > 1</ span >
< h2 > Locate profile</ h2 >
< span class = "hint" v-if = "domainsLastCheckedLabel" > Permissions checked {{ domainsLastCheckedLabel }}</ span >
</ div >
< div class = "row-gap" style = "align-items:flex-end;" >
< div class = "flex-fill" style = "min-width:220px;" >
2026-10-01 02:03:07 +01:00
< label class = "cds--label" for = "domain" > Domain</ label >
< select id = "domain" class = "cds--select-input" v-model = "domain" >
2026-09-30 23:12:51 +01:00
< option v-for = "d in session.domains" v-bind:key = "d.code" v-bind:value = "d.code" > {{ d.name }} ({{ d.code }})</ option >
</ select >
</ div >
< div class = "flex-fill" style = "min-width:170px;" >
2026-10-01 02:03:07 +01:00
< label class = "cds--label" for = "reference" > Staff reference</ label >
< input id = "reference" class = "cds--text-input" v-model . trim = "reference" v-on:keyup . enter = "lookup" placeholder = "e.g. UC/0231" >
2026-09-30 23:12:51 +01:00
</ div >
2026-10-01 02:03:07 +01:00
< cds-button v-bind:disabled = "!canLookup" v-on:click = "lookup" >
2026-10-01 14:39:42 +01:00
< svg slot = "icon" width = "16" height = "16" viewBox = "0 0 32 32" fill = "currentColor" aria-hidden = "true" xmlns = "http://www.w3.org/2000/svg" >< path d = "M29,27.5859l-7.5521-7.5521a11.0177,11.0177,0,1,0-1.4141,1.4141L27.5859,29ZM4,13a9,9,0,1,1,9,9A9.01,9.01,0,0,1,4,13Z" /></ svg >
2026-09-30 23:12:51 +01:00
< span v-if = "!busy.lookup" > Get details</ span >
< span v-else > Checking… </ span >
2026-10-01 02:03:07 +01:00
</ cds-button >
< cds-button kind = "ghost" v-bind:disabled = "!refreshEnabled" v-on:click = "refreshDomains"
v-bind:title = "refreshEnabled ? 'Re-check which domains you may capture for' : 'Permissions were checked recently — refresh unlocks ' + refreshEtaLabel" >
2026-10-01 14:39:42 +01:00
< svg slot = "icon" width = "16" height = "16" viewBox = "0 0 32 32" fill = "currentColor" aria-hidden = "true" xmlns = "http://www.w3.org/2000/svg" >< path d = "M12 10H6.78A11 11 0 0127 16h2A13 13 0 006 7.68V4H4v8h8zM20 22h5.22A11 11 0 015 16H3a13 13 0 0023 8.32V28h2V20H20z" /></ svg >
2026-09-30 23:12:51 +01:00
< span v-if = "!refreshing" > Refresh domains</ span >
< span v-else > Refreshing… </ span >
2026-10-01 02:03:07 +01:00
</ cds-button >
2026-09-30 23:12:51 +01:00
</ div >
2026-10-01 02:03:07 +01:00
< cds-inline-notification v-if = "!session.domains.length" kind = "warning" title = "No permitted domains" hide-close-button class = "mt-1"
subtitle = "You are not permitted to capture fingerprints for any domain. Contact your domain administrator if you believe this is a mistake." >
</ cds-inline-notification >
2026-09-30 23:12:51 +01:00
</ section >
2026-10-01 02:03:07 +01:00
<!-- 2 · capture -->
2026-09-30 23:12:51 +01:00
< section class = "card panel" v-if = "staff" >
< div class = "panel-head" >
< span class = "step-chip" > 2</ span >
< h2 > Capture fingerprints</ h2 >
< span class = "hint" > Two fingers are required · place the finger on the scanner each scan</ span >
</ div >
2026-10-02 15:12:16 +01:00
< cds-inline-notification v-if = "scannerNotice" kind = "warning" hide-close-button class = "mt-1"
v-bind:title = "scannerNotice.title" v-bind:subtitle = "scannerNotice.subtitle" >
</ cds-inline-notification >
2026-09-30 23:12:51 +01:00
< dl class = "details" >
< div >< dt > Name</ dt >< dd > {{ staff.name }}</ dd ></ div >
< div >< dt > Reference</ dt >< dd > {{ staff.reference }}</ dd ></ div >
< div >< dt > Domain reference</ dt >< dd > {{ staff.domainReference }}</ dd ></ div >
< div >< dt > Rank</ dt >< dd > {{ staff.domainRankDescription }}</ dd ></ div >
< div >< dt > Prior enrollments</ dt >< dd > {{ staff.fingerPrintCaptureCount }}</ dd ></ div >
</ dl >
< div class = "finger-grid mt-2" >
< div class = "finger" v-for = "(label, finger) in fingerLabels" v-bind:key = "finger"
v-bind:class = "{ capturing: capturing === finger, done: fingers[finger].status === 'done' }" >
< div class = "finger-head" >
< h3 > {{ label }}</ h3 >
2026-10-01 02:03:07 +01:00
< cds-tag v-bind:type = "fingerTag(finger).type" > {{ fingerTag(finger).text }}</ cds-tag >
2026-09-30 23:12:51 +01:00
</ div >
2026-10-01 02:03:07 +01:00
< cds-progress-bar v-if = "fingers[finger].status === 'scanning'" v-bind:value = "Math.min(fingers[finger].stage, maxStage)"
v-bind:max = "maxStage" v-bind:label = "'Scan ' + Math.min(fingers[finger].stage, maxStage) + ' of ' + maxStage" >
</ cds-progress-bar >
< p class = "meta" v-if = "fingers[finger].status === 'scanning'" > Place the {{ label.toLowerCase() }} on the scanner.</ p >
2026-09-30 23:12:51 +01:00
< p class = "meta" v-if = "fingers[finger].status === 'done'" > Enrollment ID < strong > {{ fingers[finger].id }}</ strong ></ p >
< p class = "meta" v-if = "fingers[finger].status === 'failed'" > The last attempt failed. You can try again.</ p >
< div class = "row-gap mt-1" >
2026-10-02 15:12:16 +01:00
< cds-button v-if = "fingers[finger].status !== 'done'" v-bind:disabled = "capturing !== null || !captureReady" v-on:click = "capture(finger)" >
2026-10-01 14:39:42 +01:00
< svg slot = "icon" width = "16" height = "16" viewBox = "0 0 32 32" fill = "currentColor" aria-hidden = "true" xmlns = "http://www.w3.org/2000/svg" >< path d = "M7,5.21a.77.77,0,0,1-.46-1.38A15.46,15.46,0,0,1,16,1c2.66,0,6.48.45,9.5,2.62a.77.77,0,0,1,.18,1.07.78.78,0,0,1-1.08.17A15,15,0,0,0,16,2.53,14,14,0,0,0,7.5,5.05.74.74,0,0,1,7,5.21Z" />< path d = "M28.23,12.26a.78.78,0,0,1-.63-.33C25.87,9.49,22.78,6.24,16,6.24a14,14,0,0,0-11.63,5.7.77.77,0,0,1-1.07.17A.76.76,0,0,1,3.15,11,15.54,15.54,0,0,1,16,4.71c5.61,0,9.81,2.08,12.84,6.34a.77.77,0,0,1-.19,1.07A.79.79,0,0,1,28.23,12.26Z" />< path d = "M12.28,31a.78.78,0,0,1-.72-.49.75.75,0,0,1,.44-1c4.37-1.68,7-5.12,7-9.21a2.8,2.8,0,0,0-3-3c-1.86,0-2.76,1-3,3.35a4.27,4.27,0,0,1-4.52,3.83,4.27,4.27,0,0,1-4.32-4.59A11.71,11.71,0,0,1,16,8.39a12,12,0,0,1,12,11.93,18.66,18.66,0,0,1-1.39,6.5.78.78,0,0,1-1,.41.76.76,0,0,1-.41-1,17.25,17.25,0,0,0,1.27-5.91A10.45,10.45,0,0,0,16,9.92a10.18,10.18,0,0,0-10.38,10,2.77,2.77,0,0,0,2.79,3.06,2.74,2.74,0,0,0,3-2.48c.36-3.11,1.89-4.69,4.56-4.69a4.31,4.31,0,0,1,4.52,4.56c0,4.74-3,8.72-8,10.63A.92.92,0,0,1,12.28,31Z" />< path d = "M19.77,30.28a.81.81,0,0,1-.52-.2.76.76,0,0,1,0-1.08,12.63,12.63,0,0,0,3.54-8.68c0-1.56-.48-6.65-6.7-6.65a6.83,6.83,0,0,0-4.94,1.87A6.17,6.17,0,0,0,9.32,20a.77.77,0,0,1-.77.76h0A.76.76,0,0,1,7.78,20,7.73,7.73,0,0,1,10,14.46a8.34,8.34,0,0,1,6-2.32c6.08,0,8.24,4.4,8.24,8.18A14.09,14.09,0,0,1,20.34,30,.75.75,0,0,1,19.77,30.28Z" />< path d = "M8.66,27.74a14.14,14.14,0,0,1-1.56-.09.76.76,0,1,1,.17-1.52c2.49.28,4.45-.16,5.84-1.32a6.37,6.37,0,0,0,2.12-4.53.75.75,0,0,1,.82-.71.78.78,0,0,1,.72.81A7.89,7.89,0,0,1,14.09,26,8.2,8.2,0,0,1,8.66,27.74Z" /></ svg >
2026-09-30 23:12:51 +01:00
{{ fingers[finger].status === 'failed' ? 'Retry capture' : 'Capture fingerprint' }}
2026-10-01 02:03:07 +01:00
</ cds-button >
2026-10-02 15:12:16 +01:00
< cds-button kind = "secondary" v-if = "fingers[finger].status === 'done'" v-bind:disabled = "capturing !== null || !captureReady" v-on:click = "capture(finger)" >
2026-10-01 14:39:42 +01:00
< svg slot = "icon" width = "16" height = "16" viewBox = "0 0 32 32" fill = "currentColor" aria-hidden = "true" xmlns = "http://www.w3.org/2000/svg" >< path d = "M12 10H6.78A11 11 0 0127 16h2A13 13 0 006 7.68V4H4v8h8zM20 22h5.22A11 11 0 015 16H3a13 13 0 0023 8.32V28h2V20H20z" /></ svg >
2026-09-30 23:12:51 +01:00
Recapture
2026-10-01 02:03:07 +01:00
</ cds-button >
2026-10-01 14:39:42 +01:00
< cds-button kind = "danger" v-if = "capturing === finger" v-on:click = "cancelCapture" >
< svg slot = "icon" width = "16" height = "16" viewBox = "0 0 32 32" fill = "currentColor" aria-hidden = "true" xmlns = "http://www.w3.org/2000/svg" >< path d = "M17.4141 16L24 9.4141 22.5859 8 16 14.5859 9.4143 8 8 9.4141 14.5859 16 8 22.5859 9.4143 24 16 17.4141 22.5859 24 24 22.5859 17.4141 16z" /></ svg >
Cancel
</ cds-button >
2026-09-30 23:12:51 +01:00
</ div >
</ div >
</ div >
</ section >
2026-10-01 02:03:07 +01:00
<!-- 3 · save -->
2026-09-30 23:12:51 +01:00
< section class = "card panel" v-if = "bothCaptured" >
< div class = "panel-head" >
< span class = "step-chip" > 3</ span >
< h2 > Save enrollment</ h2 >
< span class = "hint" > Both fingerprints will be saved for {{ staff ? staff.name : '' }} ({{ reference }})</ span >
</ div >
< div class = "row-gap" style = "align-items:flex-end;" >
2026-10-01 02:03:07 +01:00
< cds-button v-bind:disabled = "!canSave" v-on:click = "save" >
2026-10-01 14:39:42 +01:00
< svg slot = "icon" width = "16" height = "16" viewBox = "0 0 32 32" fill = "currentColor" aria-hidden = "true" xmlns = "http://www.w3.org/2000/svg" >< path d = "M27.71,9.29l-5-5A1,1,0,0,0,22,4H6A2,2,0,0,0,4,6V26a2,2,0,0,0,2,2H26a2,2,0,0,0,2-2V10A1,1,0,0,0,27.71,9.29ZM12,6h8v4H12Zm8,20H12V18h8Zm2,0V18a2,2,0,0,0-2-2H12a2,2,0,0,0-2,2v8H6V6h4v4a2,2,0,0,0,2,2h8a2,2,0,0,0,2-2V6.41l4,4V26Z" /></ svg >
2026-10-01 02:03:07 +01:00
< span v-if = "!busy.save" > Save enrollment</ span >
2026-09-30 23:12:51 +01:00
< span v-else > Saving… </ span >
2026-10-01 02:03:07 +01:00
</ cds-button >
2026-09-30 23:12:51 +01:00
</ div >
</ section >
</ main >
< main class = "container" v-cloak v-if = "loading && !session" >
< div class = "narrow center-v" >
< div class = "card panel" style = "text-align:center;" > Loading your session… </ div >
</ div >
</ main >
< footer class = "foot" v-cloak v-if = "session" >
< div class = "container" >
< span > Capture agent < strong > {{ agent.captureAgentId || 'connecting…' }}</ strong ></ span >
< span > Signed in as {{ session.phone }}</ span >
</ div >
</ footer >
< script src = "https://cdn.jsdelivr.net/npm/vue@2" ></ script >
< script src = "https://unpkg.com/axios/dist/axios.min.js" ></ script >
< script src = "/assets/fp/app.js" ></ script >
</ div >
</ body >
</ html >