Files
cbsnexora/src/app/shares/reports/share-transfer/share-transfer.component.html
T
2026-09-23 15:51:10 +05:30

283 lines
11 KiB
HTML

<!--
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/.
-->
<div class="cert-root">
<div class="cert-head">
<div class="cert-head-l">
<fa-icon icon="exchange" class="cert-head-ic"></fa-icon>
<div>
<h2 class="cert-head-t">Share Transfer</h2>
<div class="cert-head-s">
Moving shares from one member to another, under board resolution — and the register of every transfer made.
</div>
</div>
</div>
<div class="cert-head-r">
<button class="cert-cta-btn" (click)="exportCsv()" [disabled]="loading || !filteredRows.length">
<fa-icon icon="file-alt"></fa-icon> Export CSV
</button>
<button class="cert-cta-btn" (click)="print()" [disabled]="loading || !filteredRows.length">
<fa-icon icon="print"></fa-icon> Print
</button>
</div>
</div>
@if (totals) {
<div class="cert-kpis">
<div class="cert-kpi cert-kpi--blue">
<fa-icon icon="exchange" class="cert-kpi-ic"></fa-icon>
<div>
<div class="cert-kpi-n">{{ totals.transferCount | number }}</div>
<div class="cert-kpi-l">Transfers</div>
</div>
</div>
<div class="cert-kpi" [ngClass]="totals.pendingCount ? 'cert-kpi--amber' : 'cert-kpi--blue'">
<fa-icon icon="sync" class="cert-kpi-ic"></fa-icon>
<div>
<div class="cert-kpi-n">{{ totals.pendingCount | number }}</div>
<div class="cert-kpi-l">Awaiting Approval</div>
</div>
</div>
<div class="cert-kpi cert-kpi--green">
<fa-icon icon="coins" class="cert-kpi-ic"></fa-icon>
<div>
<div class="cert-kpi-n">{{ totals.sharesTransferred | number }}</div>
<div class="cert-kpi-l">Shares Transferred</div>
</div>
</div>
<div class="cert-kpi cert-kpi--teal">
<fa-icon icon="balance-scale" class="cert-kpi-ic"></fa-icon>
<div>
<div class="cert-kpi-n">₹{{ totals.valueTransferred | number: '1.2-2' }}</div>
<div class="cert-kpi-l">Value Transferred</div>
</div>
</div>
</div>
}
<!-- Tabs -->
<div class="cert-filters srep-no-print">
<div class="cert-filter">
<label>&nbsp;</label>
<button class="cert-cta-btn" [class.srep-tab--active]="tab === 'register'" (click)="tab = 'register'">
Transfer register
</button>
</div>
<div class="cert-filter">
<label>&nbsp;</label>
<button class="cert-cta-btn" [class.srep-tab--active]="tab === 'new'" (click)="tab = 'new'">New transfer</button>
</div>
</div>
@if (tab === 'new') {
<!-- ── Raise a transfer ── -->
<div class="srep-stmt-head" style="display: block">
<div class="cert-filters" style="margin: 0">
<div class="cert-filter" style="flex: 2 1 300px; position: relative">
<label>Transfer FROM (member giving up shares)</label>
<div class="cert-input-ic">
<fa-icon icon="search"></fa-icon>
<input
type="text"
[ngModel]="fromSearch"
(ngModelChange)="onFromSearch($event)"
placeholder="Search member or share account number"
/>
</div>
@if (fromOptions.length && !fromAccount) {
<div class="srep-picker">
@for (opt of fromOptions; track opt.id) {
<button type="button" class="srep-picker-item" (click)="pickFrom(opt)">
<span class="srep-picker-name">{{ opt.clientName }}</span>
<span class="srep-picker-meta srep-mono">{{ opt.accountNo }}</span>
<span class="srep-picker-meta">
{{ opt.productName }} · holds {{ opt.totalApprovedShares | number }}
</span>
</button>
}
</div>
}
</div>
<div class="cert-filter" style="flex: 2 1 300px; position: relative">
<label>Transfer TO (member receiving shares)</label>
<div class="cert-input-ic">
<fa-icon icon="search"></fa-icon>
<input
type="text"
[ngModel]="toSearch"
(ngModelChange)="onToSearch($event)"
placeholder="Search member or share account number"
/>
</div>
@if (toOptions.length && !toAccount) {
<div class="srep-picker">
@for (opt of toOptions; track opt.id) {
<button type="button" class="srep-picker-item" (click)="pickTo(opt)">
<span class="srep-picker-name">{{ opt.clientName }}</span>
<span class="srep-picker-meta srep-mono">{{ opt.accountNo }}</span>
<span class="srep-picker-meta">
{{ opt.productName }} · holds {{ opt.totalApprovedShares | number }}
</span>
</button>
}
</div>
}
</div>
<div class="cert-filter">
<label>Shares to transfer</label>
<input type="number" min="1" [(ngModel)]="shares" placeholder="e.g. 20" />
</div>
<div class="cert-filter">
<label>Transfer date</label>
<input type="date" [(ngModel)]="transferDate" />
</div>
<div class="cert-filter">
<label>Board resolution no.</label>
<input type="text" [(ngModel)]="resolutionNumber" placeholder="e.g. BR-2026-41" />
</div>
<div class="cert-filter">
<label>Board meeting date</label>
<input type="date" [(ngModel)]="meetingDate" />
</div>
<div class="cert-filter" style="flex: 2 1 300px">
<label>Reason (optional)</label>
<input type="text" [(ngModel)]="reason" placeholder="e.g. transfer to legal heir" />
</div>
<div class="cert-filter">
<label>&nbsp;</label>
<button class="cert-cta-btn" (click)="submit()" [disabled]="!canSubmit">
{{ submitting ? 'Submitting…' : 'Submit for approval' }}
</button>
</div>
<div class="cert-filter">
<label>&nbsp;</label>
<button class="cert-cta-btn" (click)="resetForm()">Clear</button>
</div>
</div>
@if (fromAccount && toAccount && shares) {
<div class="srep-scope-note">
{{ shares | number }} shares of {{ fromAccount.productName }} move from
<b>{{ fromAccount.clientName }}</b> ({{ fromAccount.accountNo }}) to <b>{{ toAccount.clientName }}</b> ({{
toAccount.accountNo
}}). Share capital does not change — only the register does. Nothing moves until a checker approves it.
</div>
}
</div>
@if (submitError) {
<div class="srep-state srep-state--error"><fa-icon icon="exclamation-circle"></fa-icon> {{ submitError }}</div>
}
@if (submitSuccess) {
<div class="srep-state"><fa-icon icon="check-circle"></fa-icon> {{ submitSuccess }}</div>
}
}
<!-- ── Register ── -->
<div class="cert-filters" [class.srep-no-print]="tab === 'new'">
<div class="cert-filter">
<label>Member / Reference / Resolution</label>
<div class="cert-input-ic">
<fa-icon icon="search"></fa-icon>
<input type="text" [(ngModel)]="search" placeholder="e.g. member name or TRF-260917-0001" />
</div>
</div>
<div class="cert-filter">
<label>Status</label>
<select [(ngModel)]="statusFilter" (change)="loadRegister()">
<option value="ALL">All</option>
<option value="PENDING">Pending approval</option>
<option value="APPROVED">Approved</option>
<option value="REJECTED">Rejected</option>
</select>
</div>
</div>
@if (loading) {
<div class="srep-state">Loading the transfer register…</div>
} @else if (loadError) {
<div class="srep-state srep-state--error"><fa-icon icon="exclamation-circle"></fa-icon> {{ loadError }}</div>
} @else if (!rows.length) {
<div class="srep-state">No share transfer has been recorded yet.</div>
} @else if (!filteredRows.length) {
<div class="srep-state">No transfer matches the filters applied.</div>
} @else {
<div class="srep-table-wrap">
<table class="srep-table">
<thead>
<tr>
<th>Reference</th>
<th>Date</th>
<th>From</th>
<th>To</th>
<th>Product</th>
<th class="srep-num">Shares</th>
<th class="srep-num">Value</th>
<th>Board Resolution</th>
<th>Status</th>
<th class="srep-no-print">Action</th>
</tr>
</thead>
<tbody>
@for (row of filteredRows; track row.transferId) {
<tr>
<td class="srep-mono">{{ row.transferReference }}</td>
<td>{{ row.transferDate }}</td>
<td>
{{ row.fromClientName }}
<div class="srep-scope-note srep-mono" style="margin: 0">{{ row.fromAccountNo }}</div>
</td>
<td>
{{ row.toClientName }}
<div class="srep-scope-note srep-mono" style="margin: 0">{{ row.toAccountNo }}</div>
</td>
<td>{{ row.productName }}</td>
<td class="srep-num">{{ row.shares | number }}</td>
<td class="srep-num">₹{{ row.transferAmount | number: '1.2-2' }}</td>
<td class="srep-mono">
{{ row.resolutionNumber || '—' }}
@if (row.meetingDate) {
<div class="srep-scope-note" style="margin: 0">{{ row.meetingDate }}</div>
}
</td>
<td>
<span class="srep-pill" [ngClass]="statusClass(row.status)">{{ statusLabel(row.status) }}</span>
@if (row.status === 'REJECTED' && row.rejectionReason) {
<div class="srep-scope-note" style="margin: 0">{{ row.rejectionReason }}</div>
}
@if (row.status !== 'PENDING' && row.checkerName) {
<div class="srep-scope-note" style="margin: 0">by {{ row.checkerName }}</div>
}
</td>
<td class="srep-no-print">
@if (row.status === 'PENDING') {
<button class="cert-cta-btn" (click)="approve(row)" [disabled]="actioningId === row.transferId">
{{ actioningId === row.transferId ? '…' : 'Approve' }}
</button>
<button class="cert-cta-btn" (click)="reject(row)" [disabled]="actioningId === row.transferId">
Reject
</button>
} @else {
<span class="srep-scope-note">{{ row.actionedOn || '—' }}</span>
}
</td>
</tr>
}
</tbody>
</table>
</div>
}
</div>