- @for (permission of permissions.permissions; track permission; let i = $index) {
+ @for (permission of displayedPermissions; track permission.code) {
-
+
{{ permissionName(permission.code) }}
+ @if (isSearchActive) {
+ ({{ formatName(permission.grouping || '') }})
+ }
}
diff --git a/src/app/system/configure-maker-checker-tasks/configure-maker-checker-tasks.component.scss b/src/app/system/configure-maker-checker-tasks/configure-maker-checker-tasks.component.scss
index 77ca1a6d4..d0941c2a8 100644
--- a/src/app/system/configure-maker-checker-tasks/configure-maker-checker-tasks.component.scss
+++ b/src/app/system/configure-maker-checker-tasks/configure-maker-checker-tasks.component.scss
@@ -46,3 +46,32 @@ mat-list-item {
.inactive:hover {
transform: scale(1.1);
}
+
+.mc-search-field {
+ width: 260px;
+ margin-right: 12px;
+}
+
+.mc-clear-search {
+ border: none;
+ background: transparent;
+ cursor: pointer;
+ color: inherit;
+ opacity: 0.6;
+}
+
+.mc-clear-search:hover {
+ opacity: 1;
+}
+
+.no-results {
+ padding-top: 15px;
+ font-style: italic;
+ opacity: 0.7;
+}
+
+.search-result-grouping {
+ padding-left: 6px;
+ font-size: 0.85rem;
+ opacity: 0.6;
+}
diff --git a/src/app/system/configure-maker-checker-tasks/configure-maker-checker-tasks.component.ts b/src/app/system/configure-maker-checker-tasks/configure-maker-checker-tasks.component.ts
index 51234802b..e61db0e91 100644
--- a/src/app/system/configure-maker-checker-tasks/configure-maker-checker-tasks.component.ts
+++ b/src/app/system/configure-maker-checker-tasks/configure-maker-checker-tasks.component.ts
@@ -27,6 +27,11 @@ interface Permission {
id: number;
selected: boolean;
grouping?: string;
+ /** Index of this permission's control within the `roster` FormArray (which is built from the
+ * full, globally-ordered permission list). Needed because the checkbox list on screen is
+ * rendered from a per-grouping filtered subset, whose own local index does not match the
+ * roster's global index. */
+ globalIndex?: number;
}
interface PermissionGroup {
@@ -70,6 +75,12 @@ export class ConfigureMakerCheckerTasksComponent implements OnInit, AfterViewIni
currentGrouping = '';
tempPermissionUIData: PermissionData = {};
permissions: PermissionGroup = { permissions: [] };
+ /** Flat list of every permission across all groupings, built once alongside
+ * tempPermissionUIData. Used only for global search - it is a read-only view over the same
+ * Permission objects (each still carrying its correct globalIndex), never a separate copy
+ * that could drift out of sync with the roster FormArray. */
+ allPermissions: Permission[] = [];
+ searchTerm = '';
formData = {};
isDisabled = true;
@@ -137,22 +148,30 @@ export class ConfigureMakerCheckerTasksComponent implements OnInit, AfterViewIni
setMakerCheckerTask(): void {
this.tempPermissionUIData = {};
+ this.allPermissions = [];
- for (const permission of this.permissionsData) {
+ this.permissionsData.forEach((permission: any, globalIndex: number) => {
if (permission.grouping !== this.currentGrouping) {
this.currentGrouping = permission.grouping || '';
this.groupings.push(this.currentGrouping);
this.tempPermissionUIData[this.currentGrouping] = { permissions: [] };
}
+ // globalIndex matches this permission's position in `this.formGroup.controls.roster`,
+ // since both this list and `roster` are built from the same `this.permissionsData` array
+ // in the same order (see createForm()). The checkbox must address the roster control by
+ // this global index, never by its local position within the current grouping's filtered view.
const temp: Permission = {
code: permission.code,
id: permission.id,
- selected: permission.selected
+ selected: permission.selected,
+ grouping: this.currentGrouping,
+ globalIndex
};
this.tempPermissionUIData[this.currentGrouping].permissions.push(temp);
- }
+ this.allPermissions.push(temp);
+ });
}
showPermissions(grouping: string): void {
@@ -164,6 +183,38 @@ export class ConfigureMakerCheckerTasksComponent implements OnInit, AfterViewIni
}
}
+ /**
+ * The permissions currently rendered as checkboxes. While a search term is active this is a
+ * global, cross-grouping match over `allPermissions`; otherwise it is the normal per-grouping
+ * view. Either way each item still carries its original globalIndex, so the checkbox template
+ * always resolves the same roster control regardless of which list produced it.
+ */
+ get displayedPermissions(): Permission[] {
+ if (!this.isSearchActive) {
+ return this.permissions.permissions;
+ }
+ const term = this.searchTerm.trim().toLowerCase();
+ return this.allPermissions.filter((permission) => this.matchesSearch(permission, term));
+ }
+
+ get isSearchActive(): boolean {
+ return this.searchTerm.trim().length > 0;
+ }
+
+ onSearchTermChange(value: string): void {
+ this.searchTerm = value;
+ }
+
+ clearSearch(): void {
+ this.searchTerm = '';
+ }
+
+ private matchesSearch(permission: Permission, term: string): boolean {
+ const readableName = permission.code.replace(/_/g, ' ').toLowerCase();
+ const haystack = `${permission.code.toLowerCase()} ${readableName}`;
+ return haystack.includes(term);
+ }
+
permissionName = function (name: any) {
name = name || '';
// replace '_' with ' '
diff --git a/src/app/tasks/checker-inbox-and-tasks-tabs/pending-account/pending-account.component.html b/src/app/tasks/checker-inbox-and-tasks-tabs/pending-account/pending-account.component.html
index a4ce2fedc..b74942d53 100644
--- a/src/app/tasks/checker-inbox-and-tasks-tabs/pending-account/pending-account.component.html
+++ b/src/app/tasks/checker-inbox-and-tasks-tabs/pending-account/pending-account.component.html
@@ -127,7 +127,106 @@
No pending accounts
-
There are no savings accounts awaiting approval at this time.
+
There are no accounts awaiting approval at this time.
+
+ }
+
+
+
Pending Share Accounts
+ @if (showShareData) {
+
+
+ search
+
+
+
+
+
+
+
+ | Account No. |
+ {{ account.accountNo }} |
+
+
+
+ Member |
+
+ {{ account.clientName }}
+ @if (account.officeName) {
+ {{ account.officeName }}
+ }
+ |
+
+
+
+ Product |
+ {{ account.productName }} |
+
+
+
+ Shares |
+ {{ account.requestedShares }} |
+
+
+
+ Amount |
+
+ {{ account.requestedAmount | number: '1.2-2' }}
+ |
+
+
+
+ Resolution |
+
+ {{ account.resolutionNumber || '—' }}
+ @if (account.resolutionDate) {
+ {{ formatShareDate(account.resolutionDate) }}
+ }
+ |
+
+
+
+ Submitted |
+
+ {{ formatShareDate(account.submittedDate) }}
+ @if (account.submittedByUsername) {
+ by {{ account.submittedByUsername }}
+ }
+ |
+
+
+
+ Actions |
+
+
+
+
+ |
+
+
+
+
+
+
+ }
+
+ @if (!showShareData) {
+
+
+
No pending share accounts
+
There are no share accounts awaiting approval at this time.
}
diff --git a/src/app/tasks/checker-inbox-and-tasks-tabs/pending-account/pending-account.component.scss b/src/app/tasks/checker-inbox-and-tasks-tabs/pending-account/pending-account.component.scss
index 25eff1326..2036b85b1 100644
--- a/src/app/tasks/checker-inbox-and-tasks-tabs/pending-account/pending-account.component.scss
+++ b/src/app/tasks/checker-inbox-and-tasks-tabs/pending-account/pending-account.component.scss
@@ -14,6 +14,16 @@ $text-muted: #64748b;
padding: 16px 0;
}
+/* Marks where the Share Account section begins below the normal-account table on this same screen. */
+.pa-section-heading {
+ margin: 28px 0 12px;
+ font-size: 15px;
+ font-weight: 700;
+ color: #0d1b2a;
+ padding-top: 16px;
+ border-top: 1px solid $border;
+}
+
.cv-action-bar {
display: flex;
align-items: center;
diff --git a/src/app/tasks/checker-inbox-and-tasks-tabs/pending-account/pending-account.component.ts b/src/app/tasks/checker-inbox-and-tasks-tabs/pending-account/pending-account.component.ts
index aea0233d3..1726073c2 100644
--- a/src/app/tasks/checker-inbox-and-tasks-tabs/pending-account/pending-account.component.ts
+++ b/src/app/tasks/checker-inbox-and-tasks-tabs/pending-account/pending-account.component.ts
@@ -29,17 +29,24 @@ import { MatCheckbox } from '@angular/material/checkbox';
import { FaIconComponent } from '@fortawesome/angular-fontawesome';
import { TasksService } from '../../tasks.service';
+import { SharesService } from 'app/shares/shares.service';
import { SettingsService } from 'app/settings/settings.service';
import { Dates } from 'app/core/utils/dates';
+import { DecimalPipe } from '@angular/common';
+import { ConfirmationDialogComponent } from 'app/shared/confirmation-dialog/confirmation-dialog.component';
import { FormDialogComponent } from 'app/shared/form-dialog/form-dialog.component';
import { FormfieldBase } from 'app/shared/form-dialog/formfield/model/formfield-base';
import { DatepickerBase } from 'app/shared/form-dialog/formfield/model/datepicker-base';
+import { InputBase } from 'app/shared/form-dialog/formfield/model/input-base';
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
@Component({
selector: 'mifosx-pending-account',
templateUrl: './pending-account.component.html',
- styleUrls: ['./pending-account.component.scss'],
+ styleUrls: [
+ './pending-account.component.scss',
+ '../pending-share-accounts/pending-share-accounts.component.scss'
+ ],
imports: [
...STANDALONE_SHARED_IMPORTS,
FaIconComponent,
@@ -54,7 +61,8 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
MatHeaderRow,
MatRowDef,
MatRow,
- MatIcon
+ MatIcon,
+ DecimalPipe
]
})
export class PendingAccountComponent {
@@ -64,6 +72,7 @@ export class PendingAccountComponent {
private dateUtils = inject(Dates);
private settingsService = inject(SettingsService);
private tasksService = inject(TasksService);
+ private sharesService = inject(SharesService);
dataSource: MatTableDataSource