Apply Collection and Apply Additional Shares settle the same Share Collection receipts for the same member, so they are now deliberately the same screen. Apply Collection takes exactly two receipts and no more: one for the share value, one for the entry fee, in two separate slots. They are different things -- the share receipt is money moving into share capital, while the fee receipt only proves the fee was already collected and is never posted a second time -- and picking both out of one ticked list made that distinction invisible. Apply Additional Shares moves from its own route to a dialog. It was a full page a clerk had to leave the account for and come back from, to fill in a short form with the member standing at the counter. Its old route, resolver case and action- host branch are removed rather than left behind as dead paths. Both screens now draw their receipts from a single pool, whether a receipt already names the member or is a voucher paid straight into a GL account; an unattributed one is attached at the moment it is picked, so what used to be an Attach in one table and a tick in another is one deliberate click. The by-voucher search and the GL-entry detail both sit behind buttons, as exceptions rather than permanent furniture. Dialog chrome and the receipt shape are shared (share-dialog.shared.scss, share-receipt-option.ts) so the two cannot drift apart again. Also fixes content being clipped at the dialog edges: the wrapper cancelled a 24px surface padding that the panel class had already zeroed, pushing every edge outside the surface where overflow:hidden cut it off, and the height cap sat on the scrolling body rather than the wrapper, letting the footer stack past the bottom of the viewport. Adds the product-wise share summary report (authorised, issued, available and unpaid shares, distinctive range and account count per product). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
512 lines
9.8 KiB
SCSS
512 lines
9.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/.
|
|
*/
|
|
|
|
/**
|
|
* Shared table, pill and print styling for the share reports.
|
|
*
|
|
* Layered on top of certificates.shared.scss, which already supplies the page frame
|
|
* (.cert-root / .cert-head / .cert-kpis / .cert-filters). Only what those do not cover lives here.
|
|
*/
|
|
|
|
$srep-border: #e2e8f0;
|
|
$srep-border-soft: #f1f5f9;
|
|
$srep-head-bg: #f8fafc;
|
|
$srep-text: #0f172a;
|
|
$srep-muted: #64748b;
|
|
|
|
.srep-table-wrap {
|
|
overflow-x: auto;
|
|
border: 1px solid $srep-border;
|
|
border-radius: 10px;
|
|
background: #fff;
|
|
}
|
|
|
|
.srep-table {
|
|
width: 100%;
|
|
border-collapse: collapse;
|
|
font-size: 0.82rem;
|
|
|
|
th {
|
|
position: sticky;
|
|
top: 0;
|
|
z-index: 1;
|
|
background: $srep-head-bg;
|
|
color: $srep-muted;
|
|
font-size: 0.68rem;
|
|
font-weight: 700;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.04em;
|
|
text-align: left;
|
|
padding: 0.55rem 0.7rem;
|
|
border-bottom: 1px solid $srep-border;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
td {
|
|
padding: 0.5rem 0.7rem;
|
|
border-bottom: 1px solid $srep-border-soft;
|
|
color: $srep-text;
|
|
vertical-align: middle;
|
|
}
|
|
|
|
tbody tr:last-child td {
|
|
border-bottom: none;
|
|
}
|
|
|
|
tbody tr.srep-row--click {
|
|
cursor: pointer;
|
|
|
|
&:hover {
|
|
background: #f4f7fb;
|
|
}
|
|
}
|
|
|
|
// A row that is over — closed, rejected, never activated — still belongs on the register, but it
|
|
// must not read like a live holding. Dimmed and marked at the edge rather than hidden, because a
|
|
// closed account that silently disappears is its own kind of confusion at a counter.
|
|
tbody tr.srep-row--muted {
|
|
background: #fafbfc;
|
|
color: $srep-muted;
|
|
|
|
td {
|
|
color: $srep-muted;
|
|
}
|
|
|
|
td:first-child {
|
|
box-shadow: inset 3px 0 0 #cbd5e1;
|
|
}
|
|
}
|
|
|
|
// Allotted but never collected. Flagged, not dimmed: this one is live and wants chasing.
|
|
tbody tr.srep-row--flag {
|
|
background: #fffdf5;
|
|
|
|
td:first-child {
|
|
box-shadow: inset 3px 0 0 #f59e0b;
|
|
}
|
|
}
|
|
|
|
.srep-num {
|
|
text-align: right;
|
|
font-variant-numeric: tabular-nums;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.srep-mono {
|
|
font-family: 'Courier New', monospace;
|
|
}
|
|
|
|
// A second line under a figure, for the qualifier the figure alone cannot carry — "50 unpaid"
|
|
// beneath a held count of nothing.
|
|
.srep-sub {
|
|
margin-top: 1px;
|
|
font-size: 0.68rem;
|
|
font-weight: 600;
|
|
color: #b45309;
|
|
}
|
|
|
|
tfoot td {
|
|
background: $srep-head-bg;
|
|
font-weight: 700;
|
|
border-top: 2px solid $srep-border;
|
|
border-bottom: none;
|
|
}
|
|
}
|
|
|
|
.srep-pill {
|
|
display: inline-block;
|
|
padding: 1px 9px;
|
|
border-radius: 999px;
|
|
font-size: 0.68rem;
|
|
font-weight: 700;
|
|
white-space: nowrap;
|
|
|
|
&.srep-pill--green {
|
|
background: #ecfdf5;
|
|
color: #059669;
|
|
border: 1px solid #a7f3d0;
|
|
}
|
|
|
|
&.srep-pill--amber {
|
|
background: #fffbeb;
|
|
color: #d97706;
|
|
border: 1px solid #fde68a;
|
|
}
|
|
|
|
&.srep-pill--red {
|
|
background: #fef2f2;
|
|
color: #dc2626;
|
|
border: 1px solid #fecaca;
|
|
}
|
|
|
|
&.srep-pill--blue {
|
|
background: #eff6ff;
|
|
color: #2563eb;
|
|
border: 1px solid #bfdbfe;
|
|
}
|
|
|
|
&.srep-pill--grey {
|
|
background: #f1f5f9;
|
|
color: #475569;
|
|
border: 1px solid #cbd5e1;
|
|
}
|
|
}
|
|
|
|
.srep-state {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
gap: 0.5rem;
|
|
padding: 2rem 1rem;
|
|
color: $srep-muted;
|
|
font-size: 0.85rem;
|
|
text-align: center;
|
|
}
|
|
|
|
.srep-state--error {
|
|
color: #dc2626;
|
|
}
|
|
|
|
/* A narrowed view says so, right where the numbers are, so it is never read as the whole society. */
|
|
.srep-scope-note {
|
|
margin-top: 0.5rem;
|
|
font-size: 0.75rem;
|
|
color: $srep-muted;
|
|
}
|
|
|
|
/* Account picker — results drop under the search box rather than into a dialog, so choosing an
|
|
account is one click from typing rather than a modal that has to be dismissed. */
|
|
.srep-picker {
|
|
position: absolute;
|
|
top: 100%;
|
|
left: 0;
|
|
right: 0;
|
|
z-index: 20;
|
|
margin-top: 2px;
|
|
max-height: 260px;
|
|
overflow-y: auto;
|
|
background: #fff;
|
|
border: 1px solid $srep-border;
|
|
border-radius: 8px;
|
|
box-shadow: 0 10px 24px -8px rgb(15 23 42 / 18%);
|
|
}
|
|
|
|
.srep-picker-item {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 1px;
|
|
width: 100%;
|
|
padding: 0.45rem 0.7rem;
|
|
background: none;
|
|
border: none;
|
|
border-bottom: 1px solid $srep-border-soft;
|
|
text-align: left;
|
|
cursor: pointer;
|
|
|
|
&:last-child {
|
|
border-bottom: none;
|
|
}
|
|
|
|
&:hover {
|
|
background: #f4f7fb;
|
|
}
|
|
}
|
|
|
|
.srep-picker-name {
|
|
font-size: 0.82rem;
|
|
font-weight: 600;
|
|
color: $srep-text;
|
|
}
|
|
|
|
.srep-picker-meta {
|
|
font-size: 0.72rem;
|
|
color: $srep-muted;
|
|
}
|
|
|
|
/* Inline distribution bar — the shareholding pattern reads as a shape before it reads as numbers,
|
|
and a chart library for one bar per row would be a dependency for nothing. */
|
|
.srep-bar {
|
|
width: 100%;
|
|
height: 8px;
|
|
background: $srep-border-soft;
|
|
border-radius: 999px;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.srep-bar-fill {
|
|
height: 100%;
|
|
background: linear-gradient(90deg, #2563eb, #60a5fa);
|
|
border-radius: 999px;
|
|
}
|
|
|
|
/* Statement header — the identity block a printed statement has to carry. */
|
|
.srep-stmt-head {
|
|
display: flex;
|
|
align-items: flex-start;
|
|
justify-content: space-between;
|
|
gap: 1rem;
|
|
padding: 0.85rem 1rem;
|
|
margin-bottom: 0.85rem;
|
|
background: #f8fafc;
|
|
border: 1px solid $srep-border;
|
|
border-radius: 10px;
|
|
}
|
|
|
|
.srep-stmt-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
|
|
gap: 0.6rem 1.2rem;
|
|
flex: 1;
|
|
}
|
|
|
|
.srep-stmt-l {
|
|
font-size: 0.66rem;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.04em;
|
|
color: $srep-muted;
|
|
font-weight: 700;
|
|
}
|
|
|
|
.srep-stmt-v {
|
|
font-size: 0.84rem;
|
|
color: $srep-text;
|
|
font-weight: 500;
|
|
}
|
|
|
|
/* A share class's own authorised-vs-issued fraction, read at a glance rather than only in the two
|
|
numbers beside it. */
|
|
.product-utilisation-bar {
|
|
width: 100%;
|
|
min-width: 90px;
|
|
height: 6px;
|
|
border-radius: 999px;
|
|
background: $srep-border-soft;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.product-utilisation-fill {
|
|
height: 100%;
|
|
border-radius: 999px;
|
|
background: linear-gradient(90deg, #2563eb, #059669);
|
|
}
|
|
|
|
/* Something the reader has to know before trusting the number above it — an exclusion, a gap, a
|
|
figure that will not reconcile until someone acts. Loud enough to be read, not an error. */
|
|
.srep-warn {
|
|
display: flex;
|
|
align-items: flex-start;
|
|
gap: 0.6rem;
|
|
margin: 0.6rem 0;
|
|
padding: 0.65rem 0.85rem;
|
|
background: #fffbeb;
|
|
border: 1px solid #fde68a;
|
|
border-left: 4px solid #d97706;
|
|
border-radius: 8px;
|
|
font-size: 0.82rem;
|
|
line-height: 1.55;
|
|
color: #92400e;
|
|
}
|
|
|
|
/* The selected tab, in a screen that has two halves rather than two pages. */
|
|
.srep-tab--active {
|
|
background: #eff6ff !important;
|
|
border-color: #2563eb !important;
|
|
color: #1e40af !important;
|
|
font-weight: 700;
|
|
}
|
|
|
|
/* Printed certificate — a document, not a screen: it carries the society's letterhead, a body in
|
|
sentences and a signature block, because that is what a member is handed and files. */
|
|
.spc-doc {
|
|
border: 1px solid $srep-border;
|
|
border-radius: 10px;
|
|
padding: 1.5rem 1.75rem;
|
|
background: #fff;
|
|
}
|
|
|
|
.spc-letterhead {
|
|
text-align: center;
|
|
border-bottom: 2px solid $srep-text;
|
|
padding-bottom: 0.75rem;
|
|
margin-bottom: 1.1rem;
|
|
}
|
|
|
|
.spc-org {
|
|
font-size: 1.15rem;
|
|
font-weight: 700;
|
|
color: $srep-text;
|
|
letter-spacing: 0.02em;
|
|
}
|
|
|
|
.spc-org-sub {
|
|
font-size: 0.78rem;
|
|
color: $srep-muted;
|
|
margin-top: 2px;
|
|
}
|
|
|
|
.spc-title {
|
|
margin-top: 0.7rem;
|
|
font-size: 0.95rem;
|
|
font-weight: 700;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.08em;
|
|
color: $srep-text;
|
|
}
|
|
|
|
.spc-body {
|
|
font-size: 0.88rem;
|
|
line-height: 1.7;
|
|
color: $srep-text;
|
|
margin-bottom: 1rem;
|
|
}
|
|
|
|
.spc-words {
|
|
margin-top: 0.75rem;
|
|
font-size: 0.85rem;
|
|
color: $srep-text;
|
|
}
|
|
|
|
.spc-foot {
|
|
display: flex;
|
|
align-items: flex-end;
|
|
justify-content: space-between;
|
|
gap: 2rem;
|
|
margin-top: 2.5rem;
|
|
font-size: 0.82rem;
|
|
}
|
|
|
|
.spc-sign {
|
|
text-align: center;
|
|
font-size: 0.8rem;
|
|
color: $srep-text;
|
|
}
|
|
|
|
.spc-sign-line {
|
|
width: 170px;
|
|
border-top: 1px solid $srep-text;
|
|
margin-bottom: 4px;
|
|
}
|
|
|
|
/* Label sheet — a grid sized to the label stationery a branch buys, printed straight from here. */
|
|
.slab-sheet {
|
|
display: grid;
|
|
gap: 0.5rem;
|
|
margin-top: 0.6rem;
|
|
}
|
|
|
|
.slab {
|
|
border: 1px dashed $srep-border;
|
|
border-radius: 6px;
|
|
padding: 0.65rem 0.8rem;
|
|
min-height: 92px;
|
|
font-size: 0.82rem;
|
|
line-height: 1.45;
|
|
color: $srep-text;
|
|
break-inside: avoid;
|
|
}
|
|
|
|
.slab-name {
|
|
font-weight: 700;
|
|
}
|
|
|
|
.slab-line {
|
|
color: $srep-text;
|
|
}
|
|
|
|
.slab-meta {
|
|
margin-top: 3px;
|
|
font-size: 0.7rem;
|
|
color: $srep-muted;
|
|
}
|
|
|
|
/* One letter, one page. */
|
|
.slet-page {
|
|
border: 1px solid $srep-border;
|
|
border-radius: 10px;
|
|
padding: 1.5rem 1.75rem;
|
|
margin-top: 0.85rem;
|
|
background: #fff;
|
|
break-after: page;
|
|
}
|
|
|
|
.slet-meta {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
gap: 1.5rem;
|
|
font-size: 0.84rem;
|
|
line-height: 1.5;
|
|
margin-bottom: 1.1rem;
|
|
}
|
|
|
|
.slet-date {
|
|
white-space: nowrap;
|
|
color: $srep-muted;
|
|
}
|
|
|
|
.slet-subject {
|
|
font-weight: 700;
|
|
font-size: 0.86rem;
|
|
margin-bottom: 0.9rem;
|
|
}
|
|
|
|
.slet-salutation {
|
|
font-size: 0.86rem;
|
|
margin-bottom: 0.6rem;
|
|
}
|
|
|
|
.slet-body {
|
|
font-size: 0.86rem;
|
|
line-height: 1.75;
|
|
white-space: pre-wrap;
|
|
color: $srep-text;
|
|
}
|
|
|
|
.slet-body-input {
|
|
width: 100%;
|
|
padding: 0.55rem 0.7rem;
|
|
border: 1px solid $srep-border;
|
|
border-radius: 8px;
|
|
font-family: inherit;
|
|
font-size: 0.84rem;
|
|
line-height: 1.6;
|
|
color: $srep-text;
|
|
resize: vertical;
|
|
}
|
|
|
|
@media print {
|
|
.cert-head-r,
|
|
.cert-filters,
|
|
.srep-no-print {
|
|
display: none !important;
|
|
}
|
|
|
|
.slab {
|
|
border: 1px solid #999;
|
|
}
|
|
|
|
.slet-page {
|
|
border: none;
|
|
padding: 0;
|
|
margin: 0;
|
|
}
|
|
|
|
.spc-doc {
|
|
border: none;
|
|
padding: 0;
|
|
}
|
|
|
|
.srep-table-wrap {
|
|
overflow: visible;
|
|
border: none;
|
|
}
|
|
|
|
.srep-table th {
|
|
position: static;
|
|
}
|
|
}
|