Files
cbsnexora/src/app/shares/reports/share-report.shared.scss
T
niteshandClaude Opus 5 3c363d0372 feat(shares): one-voucher-per-slot receipt dialogs, Apply Additional Shares as a popup
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>
2026-09-18 18:56:34 +05:30

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;
}
}