- Add Approval Center tab "Share Addition Requests": lists every pending additional-share tranche across all accounts (backed by the new /v1/shareadditionrequests endpoint), with a detail popup showing the board resolution and the route-specific proof of funding (voucher(s) for cash, or the linked savings account for savings). Approve/Reject call the same native approveadditionalshares/rejectadditionalshares commands the account-page buttons already used. - Remove "Debit from Savings" dialog/button and the "Share Savings Debit" Checker Inbox tab -- zero rows ever recorded on either tenant since it was built. - Remove "Approve Additional Shares"/"Reject Additional Shares" from the account-page menu now that every tranche is reviewed from the centralized queue instead. - Harden SharesButtonsConfiguration.removeButton(): a not-found name fed to splice(-1, 1) was quietly deleting the LAST button in the array instead of doing nothing -- removing the two menu entries above would otherwise have silently broken the rest of the Active-account button bar. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
150 lines
4.5 KiB
TypeScript
150 lines
4.5 KiB
TypeScript
/**
|
|
* 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/.
|
|
*/
|
|
|
|
/** Shares Account Buttons Configuration */
|
|
export class SharesButtonsConfiguration {
|
|
optionArray: {
|
|
name: string;
|
|
taskPermissionName: string;
|
|
}[];
|
|
|
|
buttonsArray: {
|
|
name: string;
|
|
icon: string;
|
|
taskPermissionName: string;
|
|
}[];
|
|
|
|
constructor(status: string) {
|
|
this.setOptions(status);
|
|
this.setButtons(status);
|
|
}
|
|
|
|
get singleButtons() {
|
|
return this.buttonsArray;
|
|
}
|
|
|
|
get options() {
|
|
return this.optionArray;
|
|
}
|
|
|
|
setButtons(status: string) {
|
|
switch (status) {
|
|
case 'Active':
|
|
this.buttonsArray = [
|
|
{
|
|
// Settles the member's Share Advance receipt: moves the money out of Share Sundry
|
|
// into share capital and reveals the purchase in the transactions/passbook.
|
|
name: 'Apply Collection',
|
|
icon: 'hand-holding-usd',
|
|
taskPermissionName: 'CREATE_JOURNALENTRY'
|
|
},
|
|
{
|
|
name: 'Apply Additional Shares',
|
|
icon: 'arrow-right',
|
|
taskPermissionName: 'APPLYADDITIONAL_SHAREACCOUNT'
|
|
}
|
|
// 'Approve Additional Shares' / 'Reject Additional Shares' are intentionally not offered
|
|
// here — every pending tranche across every account is reviewed and actioned from the
|
|
// Approval Center's Share Addition Requests queue instead, so a checker never has to know
|
|
// which account to open. 'Redeem Shares' is likewise not offered here — a share withdrawal
|
|
// must go through the Clerk Dashboard maker-checker flow (Clerk Dashboard > My Share
|
|
// Requests), never a direct one-step action from this view.
|
|
];
|
|
break;
|
|
case 'Submitted and pending approval':
|
|
this.buttonsArray = [
|
|
{
|
|
name: 'Modify Application',
|
|
icon: 'pencil',
|
|
taskPermissionName: 'UPDATE_SHAREACCOUNT'
|
|
},
|
|
{
|
|
name: 'Approve',
|
|
icon: 'check',
|
|
taskPermissionName: 'APPROVE_SHAREACCOUNT'
|
|
}
|
|
];
|
|
break;
|
|
case 'Approved':
|
|
this.buttonsArray = [
|
|
{
|
|
name: 'Undo Approval',
|
|
icon: 'undo',
|
|
taskPermissionName: 'APPROVALUNDO_SHAREACCOUNT'
|
|
},
|
|
{
|
|
name: 'Activate',
|
|
icon: 'check',
|
|
taskPermissionName: 'ACTIVATE_SHAREACCOUNT'
|
|
}
|
|
];
|
|
break;
|
|
default:
|
|
this.buttonsArray = [];
|
|
}
|
|
}
|
|
|
|
setOptions(status: string) {
|
|
switch (status) {
|
|
case 'Active':
|
|
this.optionArray = [
|
|
{
|
|
name: 'Edit Details',
|
|
taskPermissionName: 'SUBMITEDIT_SHAREACCOUNT'
|
|
},
|
|
{
|
|
name: 'Share Certificate',
|
|
taskPermissionName: 'READ_SHAREACCOUNTPURCHASE'
|
|
}
|
|
// 'Close' is intentionally not offered here — closing a share account must go through
|
|
// the Clerk Dashboard maker-checker flow (Clerk Dashboard > My Share Closures), never a
|
|
// direct one-step action from this view. The native close command also force-redeems any
|
|
// remaining shares, bypassing the governed Share Withdrawal approval flow entirely.
|
|
];
|
|
break;
|
|
case 'Submitted and pending approval':
|
|
this.optionArray = [
|
|
{
|
|
name: 'Reject',
|
|
taskPermissionName: 'REJECT_SHAREACCOUNT'
|
|
},
|
|
{
|
|
name: 'Delete',
|
|
taskPermissionName: 'DELETE_SHAREACCOUNT'
|
|
}
|
|
];
|
|
break;
|
|
case 'Approved':
|
|
default:
|
|
this.optionArray = [];
|
|
}
|
|
}
|
|
|
|
addOption(option: { name: string; taskPermissionName: string }) {
|
|
this.optionArray.push(option);
|
|
}
|
|
|
|
removeButton(name: string) {
|
|
const buttonNames = this.buttonsArray.map((entry) => entry.name);
|
|
const index = buttonNames.indexOf(name);
|
|
// -1 (not found) fed straight to splice would delete the LAST button instead of doing nothing —
|
|
// splice treats a negative index as "from the end", not "no match".
|
|
if (index > -1) {
|
|
this.buttonsArray.splice(index, 1);
|
|
}
|
|
}
|
|
|
|
removeOption(name: string) {
|
|
const optionNames = this.optionArray.map((entry) => entry.name);
|
|
const index = optionNames.indexOf(name);
|
|
if (index > -1) {
|
|
this.optionArray.splice(index, 1);
|
|
}
|
|
}
|
|
}
|