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>
443 lines
7.8 KiB
SCSS
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;
|
|
}
|
|
}
|