Files
cbsnexora/src/app/ctsclearing/inward-batch-detail/item-decision-dialog/item-decision-dialog.component.scss
T
Jaanu423andClaude Sonnet 5 a22f8e7e45
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(ctsclearing): validation comparison popup, decided-item read-only view, and dialog-close fixes
Adds a "Comparison Details" popup on the inward decision dialog showing
exactly what each automatic rule compared (amount figures vs words,
instrument date vs its valid-until window, balance vs amount, RBI
Positive Pay threshold, IQA sub-checks) instead of just the pass/fail
pill, mirroring InwardClearingValidationService.java's actual logic.
For an already-decided item, the stale/postdated "as of" date now shows
the decision date rather than today's live date.

Once a cheque is decided, the batch table's Validation column collapses
to a single outcome pill instead of permanently showing all 7 rule
badges, and the item-decision dialog itself switches to a read-only
decision summary (outcome, decisioned-on, note, settlement status)
instead of a re-openable Pass/Return form — the "Decide" action becomes
"View" for decided rows.

Also fixes two silently-broken directives: matTooltip and mat-dialog-close
were used throughout the decision dialogs without MatTooltipModule /
MatDialogClose being imported into the standalone components, so every
tooltip and every close button did nothing.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-22 18:29:18 +05:30

443 lines
7.8 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/.
*/
.info-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(130px, 1fr));
gap: 10px 16px;
margin-bottom: 16px;
> div {
display: flex;
flex-direction: column;
}
.k {
font-size: 0.72rem;
text-transform: uppercase;
letter-spacing: 0.04em;
color: rgb(0 0 0 / 50%);
margin-bottom: 2px;
}
.pill {
margin-left: 6px;
vertical-align: middle;
}
}
.mode-toggle {
display: flex;
gap: 8px;
margin: 16px 0 12px;
button.active {
background: rgb(25 118 210 / 12%);
}
}
.decided-summary {
padding: 14px 16px;
border-radius: 8px;
border-left: 4px solid rgb(0 0 0 / 30%);
background: rgb(0 0 0 / 4%);
&.ok {
border-left-color: #1a9c63;
background: #e8f8f0;
}
&.bad {
border-left-color: #d32f2f;
background: #fdeaea;
}
}
.decided-headline {
display: flex;
align-items: center;
gap: 8px;
margin-bottom: 10px;
}
.compare-row {
display: grid;
grid-template-columns: minmax(120px, 38%) 1fr;
gap: 6px 16px;
padding: 4px 0;
border-top: 1px solid rgb(255 255 255 / 60%);
&:first-of-type {
border-top: none;
}
}
.compare-label {
color: rgb(0 0 0 / 55%);
font-size: 0.72rem;
text-transform: uppercase;
letter-spacing: 0.04em;
}
.compare-value {
font-size: 0.85rem;
word-break: break-word;
}
mat-form-field {
width: 100%;
}
.section-title {
margin: 20px 0 8px;
font-size: 0.95rem;
}
.section-header {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
.section-title {
margin: 20px 0 8px;
}
}
.muted {
color: rgb(0 0 0 / 50%);
font-size: 0.82rem;
margin-bottom: 8px;
}
.image-row {
display: flex;
gap: 12px;
flex-wrap: wrap;
}
.cheque-image {
max-width: 260px;
max-height: 140px;
object-fit: contain;
border: 1px solid #ddd;
border-radius: 4px;
cursor: pointer;
background: #fafafa;
}
// the overlay boxes are positioned absolute relative to THIS wrapper, not the (possibly flex-centered)
// .cheque-stage — otherwise, once the stage centers the image via flexbox in fullscreen mode, the overlay's
// left/top coordinates (measured from the stage's own top-left corner) land nowhere near the actual image
.cheque-image-wrap {
position: relative;
display: inline-block;
line-height: 0;
transform-origin: center center;
}
.cheque-stage {
position: relative;
display: inline-block;
line-height: 0;
// fullscreen compare mode: the stage itself becomes a fixed, full-viewport backdrop so the cheque and
// every draggable signature overlay are shown as large as possible for a real side-by-side comparison
&.fullscreen-stage {
position: fixed;
inset: 0;
z-index: 2000;
display: flex;
align-items: center;
justify-content: center;
width: 100vw;
height: 100vh;
max-width: none;
overflow: auto;
background: rgb(0 0 0 / 92%);
.cheque-image {
width: auto;
max-width: 82vw;
max-height: 88vh;
cursor: zoom-in;
}
}
// matches the native fullscreen state directly (independent of Angular's class-binding timing), so the
// stage fills correctly the instant the browser promotes it to the top layer
&:fullscreen {
width: 100vw;
height: 100vh;
max-width: none;
display: flex;
align-items: center;
justify-content: center;
background: rgb(0 0 0 / 92%);
}
}
.fullscreen-close {
position: absolute;
top: 16px;
right: 16px;
z-index: 2010;
width: 36px;
height: 36px;
border-radius: 50%;
border: none;
background: rgb(255 255 255 / 15%);
color: #fff;
font-size: 16px;
cursor: pointer;
&:hover {
background: rgb(255 255 255 / 25%);
}
}
.fullscreen-zoom {
position: absolute;
top: 16px;
left: 50%;
transform: translateX(-50%);
z-index: 2010;
display: flex;
align-items: center;
gap: 6px;
padding: 4px 10px;
border-radius: 20px;
background: rgb(255 255 255 / 15%);
color: #fff;
font-size: 12px;
span {
min-width: 40px;
text-align: center;
font-variant-numeric: tabular-nums;
}
button {
width: 26px;
height: 26px;
border-radius: 50%;
border: none;
background: rgb(255 255 255 / 15%);
color: #fff;
font-size: 14px;
line-height: 1;
cursor: pointer;
&:hover {
background: rgb(255 255 255 / 25%);
}
}
}
.fullscreen-shelf {
position: absolute;
top: 16px;
left: 16px;
z-index: 2010;
display: flex;
flex-direction: column;
gap: 8px;
max-height: 88vh;
overflow-y: auto;
padding-right: 4px;
}
.shelf-item {
width: 150px;
padding: 4px;
border: 2px solid transparent;
border-radius: 4px;
background: #fff;
cursor: pointer;
text-align: center;
&.active {
border-color: #1976d2;
}
img {
display: block;
width: 100%;
height: 54px;
object-fit: contain;
}
span {
display: block;
margin-top: 2px;
color: #333;
font-size: 10px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
}
.sig-overlay {
position: absolute;
// must beat the fullscreen shelf/close-button (z-index: 2010) — they share the same stacking context
// (the fullscreen-stage), so a low z-index here meant the overlay silently rendered BEHIND the shelf
// wherever the two visually overlapped, e.g. when dragging it toward the top-left where the shelf sits
z-index: 2020;
box-sizing: border-box;
border: 1px dashed rgb(25 118 210 / 70%);
background: rgb(255 255 255 / 40%);
cursor: move;
user-select: none;
}
.sig-overlay-handle {
display: flex;
align-items: center;
justify-content: space-between;
gap: 4px;
padding: 1px 4px;
background: rgb(25 118 210 / 85%);
color: #fff;
font-size: 10px;
line-height: 1.6;
cursor: move;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.sig-overlay-close {
background: none;
border: none;
color: #fff;
cursor: pointer;
font-size: 11px;
line-height: 1;
padding: 0 2px;
}
.sig-overlay-img {
display: block;
width: 100%;
height: auto;
pointer-events: none;
}
.sig-overlay-resize {
position: absolute;
right: 0;
bottom: 0;
width: 12px;
height: 12px;
cursor: nwse-resize;
background: repeating-linear-gradient(135deg, rgb(25 118 210 / 80%) 0 2px, transparent 2px 4px);
}
.sig-overlay-opacity {
width: 44px;
height: 10px;
margin: 0 4px;
cursor: pointer;
}
.no-image {
padding: 12px;
border: 1px dashed #ccc;
border-radius: 4px;
color: rgb(0 0 0 / 40%);
font-size: 0.82rem;
&.small {
padding: 6px 10px;
width: 120px;
}
}
.check-badges {
display: flex;
gap: 6px;
flex-wrap: wrap;
margin-bottom: 6px;
}
.validation-detail {
margin-bottom: 8px;
}
.mode-label {
font-weight: 500;
}
.signer-row {
display: flex;
align-items: center;
gap: 14px;
padding: 8px 0;
border-bottom: 1px solid rgb(0 0 0 / 6%);
&:last-of-type {
border-bottom: none;
}
}
.signer-signature {
flex-shrink: 0;
}
.signature-image {
width: 140px;
height: 60px;
object-fit: contain;
border: 1px solid #ddd;
border-radius: 4px;
cursor: pointer;
background: #fafafa;
}
.signer-info {
flex: 1;
min-width: 0;
}
.signer-name {
font-weight: 500;
display: flex;
align-items: center;
gap: 8px;
}
.gate-warning {
color: #d32f2f;
font-size: 0.82rem;
margin-bottom: 8px;
}
.pill {
font-size: 11px;
padding: 2px 8px;
border-radius: 6px;
font-weight: 600;
white-space: nowrap;
&.ok {
background: #dff5e8;
color: #28c07a;
}
&.bad {
background: #fde3e3;
color: #d32f2f;
}
&.neutral {
background: #e0e0e0;
color: #757575;
}
}