Brings the DDS (Daily Deposit Scheme) UI from feature/dds onto the current dev-latest: - Agent settlement (Agent Tran), Close Party account, DDS reports, Party-Savings link field - Agent collection entry screen, per-agent GL account, maturity auto close - Approvals tab, vouchers, payout & close, Sundry GL search, closure tab and fixes - Menu: DDS Party Master, DDS Accounts, DDS Collection, DDS Reports and Locker links placed in the Deposits mega panel groups; Agent Master, Commission Slab and DDS Batch Processing under Organization; DDS Approvals tab in the checker inbox No content conflicts. Nothing from dev-latest is removed. Merge adjustments: - package-lock.json: kept dev-latest's lock file. feature/dds does not add or change any dependency in package.json; its lock file was only regenerated (about 18k lines removed and 12k added), which would have changed resolved versions for packages already on dev-latest. - Dropped src/app/deposits/party-master/CBS-Backend.code-workspace, a VS Code workspace file holding local folder paths, not app code. - angular.json: bundle budget raised to 18mb warning / 20mb error, as on feature/dds. Lint fixes required by the pre-commit hook (no behaviour change): - Prettier formatting on 12 DDS files. - create-party.component.scss: the dense data-entry section deliberately re-targets the base selectors to override them, so no-duplicate-selectors is disabled for that section instead of merging rules and changing the cascade. - notice-dialog / create-dds-account-type scss: stylelint-disable-line for the "ch" width unit. - commission-slab-master.component.scss: stylelint auto-fix. Verified with tsc -p src/tsconfig.app.json --noEmit, stylelint, prettier and eslint on all merged files. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
529 lines
11 KiB
SCSS
529 lines
11 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/.
|
|
*/
|
|
|
|
$primary: #0f766e;
|
|
|
|
.pm-container {
|
|
// Wider than the usual form page: the extra width is what keeps this many fields off a
|
|
// second screen.
|
|
max-width: 1280px;
|
|
margin: 0 auto;
|
|
padding: 12px 16px 20px;
|
|
}
|
|
|
|
.pm-header {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 14px;
|
|
margin-bottom: 10px;
|
|
|
|
&__title {
|
|
margin: 0;
|
|
font-size: 18px;
|
|
font-weight: 500;
|
|
}
|
|
}
|
|
|
|
.pm-back {
|
|
color: $primary;
|
|
}
|
|
|
|
.pm-card {
|
|
background: var(--md-sys-color-surface, #fff);
|
|
border-radius: 8px;
|
|
box-shadow: 0 2px 8px rgb(0 0 0 / 8%);
|
|
}
|
|
|
|
.pm-tabs {
|
|
::ng-deep .mat-mdc-tab-body-wrapper {
|
|
min-height: 300px;
|
|
}
|
|
}
|
|
|
|
.pm-tab-content {
|
|
padding: 20px 24px;
|
|
}
|
|
|
|
.pm-section {
|
|
padding: 16px 0;
|
|
border-bottom: 1px solid rgb(0 0 0 / 8%);
|
|
|
|
&:last-of-type {
|
|
border-bottom: none;
|
|
}
|
|
|
|
&__header {
|
|
display: flex;
|
|
align-items: center;
|
|
// The subtitle sits beside the title where there is room and drops below it where there is not.
|
|
flex-wrap: wrap;
|
|
gap: 2px 10px;
|
|
margin-bottom: 16px;
|
|
|
|
i {
|
|
color: $primary;
|
|
}
|
|
|
|
h3 {
|
|
margin: 0;
|
|
font-size: 16px;
|
|
font-weight: 600;
|
|
// Held at its natural width: letting it shrink breaks a two-word heading onto three lines.
|
|
flex: 0 0 auto;
|
|
white-space: nowrap;
|
|
}
|
|
}
|
|
}
|
|
|
|
.pm-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(4, 1fr);
|
|
gap: 2px 18px;
|
|
align-items: start;
|
|
}
|
|
|
|
/*
|
|
* Label to the left of its field, the way the screen this replaces laid them out. A stacked label
|
|
* costs a whole row of height per field, and with 60-odd fields that is the difference between an
|
|
* operator seeing the form at once and scrolling through three screens of it.
|
|
*/
|
|
.pm-f {
|
|
display: grid;
|
|
grid-template-columns: 104px minmax(0, 1fr);
|
|
align-items: start;
|
|
column-gap: 7px;
|
|
|
|
&--wide {
|
|
grid-column: span 2;
|
|
}
|
|
}
|
|
|
|
.pm-f-lbl {
|
|
font-size: 11.5px;
|
|
line-height: 1.25;
|
|
text-align: right;
|
|
color: rgb(0 0 0 / 68%);
|
|
padding-top: 7px;
|
|
|
|
// Required marker, in the same red the legacy screen used.
|
|
b {
|
|
color: #c1121f;
|
|
font-weight: 400;
|
|
margin-left: 2px;
|
|
}
|
|
}
|
|
|
|
.pm-field {
|
|
width: 100%;
|
|
}
|
|
|
|
.pm-checkbox-field {
|
|
display: flex;
|
|
align-items: center;
|
|
height: 56px;
|
|
}
|
|
|
|
.pm-radio-group {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 16px;
|
|
height: 56px;
|
|
}
|
|
|
|
.pm-add-nominee {
|
|
color: $primary;
|
|
height: fit-content;
|
|
align-self: center;
|
|
}
|
|
|
|
/*
|
|
* The running total of the shares entered, beside the button that adds another. Reads as ordinary
|
|
* text while the split still adds up and turns to the warning colour when it does not, so the clerk
|
|
* sees the state of the whole nomination without having to try to save it.
|
|
*/
|
|
.pm-share-total {
|
|
align-self: center;
|
|
margin-left: 12px;
|
|
font-size: 13px;
|
|
color: rgb(0 0 0 / 60%);
|
|
}
|
|
|
|
.pm-share-total-bad {
|
|
color: #b3261e;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.pm-empty {
|
|
color: rgb(0 0 0 / 50%);
|
|
font-size: 14px;
|
|
margin: 0 0 8px;
|
|
}
|
|
|
|
/*
|
|
* One nominee, laid out as fields that wrap rather than columns that must all fit.
|
|
*
|
|
* A fixed column per field only works while the count is fixed, and it is not - the Share % field
|
|
* appears and disappears with the split mode, and a tenth column pushed the remove button onto a
|
|
* line of its own. Each field instead states the width it needs to stay readable and the row breaks
|
|
* where it runs out of space, so nothing is squeezed and nothing is orphaned.
|
|
*/
|
|
.pm-nominee-row {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 4px 12px;
|
|
align-items: start;
|
|
padding: 12px 0;
|
|
border-top: 1px dashed rgb(0 0 0 / 10%);
|
|
|
|
&:first-of-type {
|
|
border-top: none;
|
|
}
|
|
|
|
/* Names and addresses need room; a date, Yes/No or a percentage does not. */
|
|
.pm-f {
|
|
flex: 1 1 170px;
|
|
min-width: 0;
|
|
}
|
|
|
|
.pm-f--date {
|
|
flex: 0 1 140px;
|
|
}
|
|
|
|
.pm-f--tight {
|
|
flex: 0 1 100px;
|
|
}
|
|
}
|
|
|
|
.pm-remove-nominee {
|
|
color: #b91c1c;
|
|
margin-top: 8px;
|
|
}
|
|
|
|
.pm-action-bar {
|
|
display: flex;
|
|
justify-content: flex-end;
|
|
gap: 12px;
|
|
padding: 16px 24px;
|
|
border-top: 1px solid rgb(0 0 0 / 8%);
|
|
}
|
|
|
|
.pm-callout {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 10px;
|
|
margin: 0 24px;
|
|
padding: 12px 16px;
|
|
background: rgb(185 28 28 / 8%);
|
|
border: 1px solid rgb(185 28 28 / 25%);
|
|
border-radius: 6px;
|
|
color: #b91c1c;
|
|
font-size: 0.9rem;
|
|
}
|
|
|
|
@media (width <= 1000px) {
|
|
.pm-grid {
|
|
grid-template-columns: repeat(2, 1fr);
|
|
}
|
|
}
|
|
|
|
/* Resolved name shown under a Client / Agent / Guardian id, as the legacy screen did in red. */
|
|
.pm-hint--found {
|
|
color: #15803d;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.pm-hint--missing {
|
|
color: #b91c1c;
|
|
font-weight: 500;
|
|
}
|
|
|
|
/* Explains why a block of fields is absent, so the screen does not just look unfinished. */
|
|
.pm-note {
|
|
margin: 4px 0 0;
|
|
font-size: 0.8rem;
|
|
color: rgb(0 0 0 / 55%);
|
|
font-style: italic;
|
|
}
|
|
|
|
.pm-closed-badge {
|
|
margin-left: 12px;
|
|
padding: 3px 11px;
|
|
border-radius: 11px;
|
|
font-size: 0.72rem;
|
|
font-weight: 500;
|
|
background: rgb(0 0 0 / 7%);
|
|
color: rgb(0 0 0 / 60%);
|
|
}
|
|
|
|
/* Says whose details a block of fields is for, so the screen explains itself. */
|
|
.pm-section__sub {
|
|
flex: 1 1 auto;
|
|
min-width: 0;
|
|
font-size: 0.78rem;
|
|
font-weight: 400;
|
|
line-height: 1.45;
|
|
color: rgb(0 0 0 / 55%);
|
|
}
|
|
|
|
.pm-search-ic {
|
|
color: rgb(0 0 0 / 38%);
|
|
font-size: 0.85rem;
|
|
}
|
|
|
|
/*
|
|
* Money reads right to left, so a column of figures only lines up when it is right-aligned; the
|
|
* tabular figures keep every digit the same width so the decimal points stack.
|
|
*/
|
|
input.pm-money {
|
|
text-align: right;
|
|
font-variant-numeric: tabular-nums;
|
|
}
|
|
|
|
/* One row of a Client / Sub Type search list: the id, the name, and where it belongs. */
|
|
.pm-opt {
|
|
display: flex;
|
|
align-items: baseline;
|
|
gap: 10px;
|
|
overflow: hidden;
|
|
}
|
|
|
|
/* The "there are more" footer row. Quieter than a real option, since it is not one. */
|
|
.pm-opt-more {
|
|
font-size: 0.75rem;
|
|
font-style: italic;
|
|
opacity: 0.75;
|
|
}
|
|
|
|
.pm-opt-id {
|
|
flex: 0 0 auto;
|
|
min-width: 52px;
|
|
font-family: ui-monospace, 'SF Mono', 'Cascadia Mono', monospace;
|
|
font-size: 0.78rem;
|
|
color: var(--pl-accent, #b45309);
|
|
}
|
|
|
|
/*
|
|
The name is the reason the row exists, so it gets whatever width is going and is the last thing
|
|
to be cut. Before this the branch was fixed-width and the name carried the ellipsis, so in the
|
|
narrow panel every customer read as a single letter.
|
|
*/
|
|
|
|
.pm-opt-main {
|
|
flex: 1 1 auto;
|
|
min-width: 8rem;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.pm-opt-sub {
|
|
flex: 0 1 auto;
|
|
min-width: 0;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
font-size: 0.75rem;
|
|
color: rgb(0 0 0 / 50%);
|
|
}
|
|
|
|
/* stylelint-disable no-duplicate-selectors -- the dense layout below deliberately re-targets the base selectors above to override them. */
|
|
|
|
/*
|
|
* Dense data-entry layout.
|
|
*
|
|
* The screen this replaces fitted the whole form on one page - an officer opening accounts all day
|
|
* reads it at a glance and never scrolls. Material's default field height and spacing turn the same
|
|
* 56 fields into three screens' worth, so the whole card is tightened: shorter fields, smaller type,
|
|
* and just enough room under each field for the hint that names the client or agent it resolved.
|
|
*/
|
|
|
|
/*
|
|
* With the label moved outside, the box only has to hold the value - so it loses the height Material
|
|
* reserves for a floating label, and the form fits a screen instead of three.
|
|
*/
|
|
.pm-card {
|
|
::ng-deep {
|
|
.mat-mdc-form-field {
|
|
font-size: 12.5px;
|
|
}
|
|
|
|
.mat-mdc-form-field-infix {
|
|
min-height: 26px;
|
|
padding-top: 3px !important;
|
|
padding-bottom: 3px !important;
|
|
border-top: 0;
|
|
}
|
|
|
|
.mat-mdc-text-field-wrapper {
|
|
padding-left: 8px;
|
|
padding-right: 8px;
|
|
}
|
|
|
|
.mat-mdc-input-element,
|
|
.mat-mdc-select-value-text {
|
|
font-size: 12.5px;
|
|
}
|
|
|
|
// Room for one line of hint - the resolved client/agent name that confirms the right record.
|
|
.mat-mdc-form-field-subscript-wrapper {
|
|
height: 14px;
|
|
min-height: 14px;
|
|
}
|
|
|
|
.mat-mdc-form-field-hint {
|
|
font-size: 10.5px;
|
|
line-height: 14px;
|
|
}
|
|
|
|
// Suffix icons and the datepicker toggle default to a 48px touch target, which reopens all the
|
|
// height just saved.
|
|
.mat-mdc-icon-button.mat-mdc-button-base {
|
|
width: 26px;
|
|
height: 26px;
|
|
padding: 3px;
|
|
}
|
|
|
|
.mat-mdc-form-field-icon-suffix {
|
|
padding-left: 2px;
|
|
|
|
.mat-datepicker-toggle svg {
|
|
width: 15px;
|
|
height: 15px;
|
|
}
|
|
}
|
|
|
|
.mat-mdc-tab-body-wrapper {
|
|
min-height: 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
.pm-tab-content {
|
|
padding: 8px 16px;
|
|
}
|
|
|
|
/*
|
|
* Blocks drawn the way the screen this replaces drew them: a hairline between groups of fields,
|
|
* with the group's name as a quiet caption above it rather than a heading bar of its own. An
|
|
* operator who has filled this form a hundred times navigates by field position; one filling their
|
|
* first still gets told which block is which.
|
|
*/
|
|
.pm-section {
|
|
padding: 8px 0 2px;
|
|
border-bottom: 1px solid rgb(0 0 0 / 11%);
|
|
|
|
&__header {
|
|
margin-bottom: 6px;
|
|
gap: 0 10px;
|
|
|
|
// Decoration the legacy screen did without, and the row is tighter for losing it.
|
|
i {
|
|
display: none;
|
|
}
|
|
|
|
h3 {
|
|
font-size: 11px;
|
|
font-weight: 700;
|
|
letter-spacing: 0.07em;
|
|
text-transform: uppercase;
|
|
color: $primary;
|
|
}
|
|
}
|
|
}
|
|
|
|
.pm-section__sub {
|
|
font-size: 0.72rem;
|
|
color: rgb(0 0 0 / 45%);
|
|
}
|
|
|
|
.pm-grid {
|
|
gap: 0 12px;
|
|
}
|
|
|
|
.pm-checkbox-field,
|
|
.pm-radio-group {
|
|
height: 28px;
|
|
|
|
::ng-deep label {
|
|
font-size: 12.5px;
|
|
}
|
|
}
|
|
|
|
// The nominee grid is its own row of fields, so its labels sit above rather than beside - there is
|
|
// no room for a label column eight fields across.
|
|
.pm-nominee-row {
|
|
gap: 0 10px;
|
|
padding: 3px 0;
|
|
|
|
.pm-f {
|
|
grid-template-columns: minmax(0, 1fr);
|
|
row-gap: 1px;
|
|
}
|
|
|
|
.pm-f-lbl {
|
|
text-align: left;
|
|
padding-top: 0;
|
|
font-size: 10.5px;
|
|
}
|
|
}
|
|
|
|
.pm-note {
|
|
margin: 0;
|
|
font-size: 0.74rem;
|
|
}
|
|
|
|
.pm-action-bar {
|
|
padding: 10px 18px;
|
|
}
|
|
|
|
/*
|
|
The customer's real deposit account. Not a form field - nothing here is typed, it is what the
|
|
bank's books say - so it reads as a fact rather than sitting in an input box pretending to be one.
|
|
*/
|
|
.pm-account {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 2px;
|
|
padding: 3px 0;
|
|
min-height: 26px;
|
|
justify-content: center;
|
|
}
|
|
|
|
.pm-account-no {
|
|
font-family: ui-monospace, 'SF Mono', 'Cascadia Mono', monospace;
|
|
font-size: 0.85rem;
|
|
letter-spacing: 0.02em;
|
|
}
|
|
|
|
.pm-account-meta {
|
|
font-size: 0.75rem;
|
|
color: rgb(0 0 0 / 55%);
|
|
}
|
|
|
|
.pm-account-live {
|
|
color: #15803d;
|
|
font-weight: 500;
|
|
}
|
|
|
|
/* Said plainly: this party has no account behind it, which is a real gap, not a blank field. */
|
|
.pm-account-missing {
|
|
font-size: 0.75rem;
|
|
font-style: italic;
|
|
color: #9b2c2c;
|
|
}
|
|
|
|
/*
|
|
Something the branch has to do, rather than something that has gone wrong - so it reads as an
|
|
instruction in the warning colour, not an error in red like the closed-account notice.
|
|
*/
|
|
.pm-callout--action {
|
|
background: rgb(180 83 9 / 8%);
|
|
border-color: rgb(180 83 9 / 25%);
|
|
color: #b45309;
|
|
}
|