Files
cbsnexora/src/app/clients/clients-view/custom-dialogs/capture-image-dialog/capture-image-dialog.component.scss
T
niteshandClaude Sonnet 5 733d9d22b2
build-run / Run Lint, Build and Deploy (push) Canceled after 0s
Publish Image in Docker Hub / build (push) Canceled after 0s
Playwright E2E Tests / Run Playwright Tests (push) Canceled after 0s
Tests / testRigor (push) Canceled after 0s
feat(clients): dual-OTP contact-change verification, webcam signature capture, and client history tab
Frontend counterpart to the backend dual-OTP contact-change feature:

- New ContactOtpBlockComponent (6-box segmented OTP input) used up to 4x in
  Edit Client (old/new mobile, old/new email — grouped under per-field
  sub-headers) and once each for mobile/email in Create Client, gating
  Save/Save & Next until every required box is verified.
- edit-client.component.ts: detects mobile/email/DOB changes against the
  loaded snapshot using local-date comparison (not `.toISOString()`, which
  false-triggers a day-shift in positive-UTC-offset timezones) and
  trimmed/case-insensitive email comparison (autofill whitespace or re-typed
  casing no longer reads as a change the masked preview can't explain).
- client-kyc-step.component.ts: new `invalidFieldLabels` getter names every
  currently-invalid required KYC field, surfaced via the Save & Next tooltip
  in both create-client and edit-client so a greyed-out button always
  explains what's still missing instead of a generic message.
- CaptureImageDialogComponent generalized for both profile photo and
  signature (photograph-a-paper-signature) capture:
  - Frame aspect now matches the requested getUserMedia resolution
    (4:3 profile / 16:9 signature) with object-fit: cover, eliminating the
    pillarboxing (black bars) a mismatched box previously caused.
  - Suppresses Chromium's auto-injected PiP/cast corner overlay icons.
  - Frame height capped in vh (not just px) so the dialog fits short
    viewports instead of pushing Cancel/Upload below the fold.
- upload-document-dialog.component.ts: generic Documents-tab upload now also
  offers "Capture from Webcam" alongside Browse, reusing the same capture
  dialog.
- New client History tab (reuses the existing Audit Trail data, scoped to
  this client) and dataUrlToFile/dataUrlToBlob util for routing webcam
  captures through the same upload pipelines as a picked file.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-26 14:51:04 +05:30

109 lines
3.0 KiB
SCSS

/**
* Copyright since 2025 Mifos Initiative
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
/* No explicit width/maxHeight is passed at every `dialog.open(CaptureImageDialogComponent)`
call site (there are several, across clients-view/create/edit flows) — capping height and
allowing internal scroll here, once, keeps the Cancel/Upload footer reachable on short
viewports instead of relying on every caller to remember a maxHeight config. */
:host {
display: block;
max-height: 90vh;
overflow-y: auto;
}
.capture-dialog {
padding: 4px 4px 8px;
}
.capture-title {
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
margin: 0;
fa-icon {
color: #1074b9;
font-size: 18px;
}
}
.capture-instructions {
margin: 4px 0 14px;
padding: 0 16px;
font-size: 13px;
color: rgb(0 0 0 / 60%);
}
.capture-frame {
width: 100%;
max-width: 640px;
/* Capped in vh, not just px, so the frame shrinks on short viewports (laptop screens with
browser chrome eating into the visible height) instead of pushing the Capture/Cancel/
Upload buttons below the fold — `object-fit: cover` on the video means shrinking this box
never reintroduces pillarboxing, it just changes how much of the live frame is visible. */
max-height: 42vh;
margin: 0 auto;
border-radius: 14px;
overflow: hidden;
background: #111;
box-shadow: 0 8px 24px -8px rgb(15 23 42 / 25%);
border: 1px solid rgb(255 255 255 / 8%);
/* Default (profile) frame follows the requested 4:3 capture stream. */
aspect-ratio: 4 / 3;
/* Signature capture uses a shorter, wider (16:9) frame — paper signatures are landscape-ish
and this matches the wider resolution requested from getUserMedia, so the live preview
fills the frame edge-to-edge instead of pillarboxing (black bars) inside a mismatched box. */
&--signature {
aspect-ratio: 16 / 9;
max-height: 36vh;
}
}
.capture-video {
width: 100%;
height: 100%;
object-fit: cover;
display: block;
/* Chromium auto-injects a Picture-in-Picture toggle (and sometimes a cast button) as small
square overlay icons in a bare <video>'s corners on hover — the `disablepictureinpicture`/
`disableremoteplayback` attributes stop the *feature*, but these pseudo-elements are the
belt-and-braces way to make sure the icons themselves never render. */
&::-webkit-media-controls,
&::-webkit-media-controls-panel,
&::-internal-media-controls-overlay-cast-button {
display: none !important;
}
}
.capture-actions-row {
display: flex;
justify-content: center;
margin: 16px 0 4px;
}
.capture-btn {
border-radius: 999px !important;
padding: 0 20px !important;
height: 42px;
font-weight: 600 !important;
}
.capture-dialog-footer {
padding: 8px 4px 0 !important;
.mat-mdc-raised-button {
border-radius: 999px !important;
font-weight: 600 !important;
}
}