Upgrading to Angular 20:
Replaced checked in package-lock.json by regenerated one. Ran ng update @angular/core@20 @angular/cli@20 Ran npm install @angular-builders/jest@^20.0.0 @fortawesome/angular-fontawesome@^3.0.0 @swimlane/ngx-graph@^11 Ran npm install ngx-mat-select-search@^8.0.2. Ran ng update @angular/material@20. Updated all eslint and typescript to the latest versions. Removed @angular-devkit/schematics. Updated fontawesome. Updated rxjs and tslib. Moved required node version from 16 to 20. Updated jest-preset-angular. Set preserveWhitespaces to false. Corrected two type declarations in two typescript files to make ng serve run without errors. Removed unused angular-devkit/schematics from view-user.component.ts . Updated list of supported browsers. Upgraded prettier. Ran prettier . --write the first time. Ran prettier . --write the second time. Ran ng generate @angular/core:inject with defaults, excepted a handful of files. Fixed remaining eslint problems. Added dist directory to ignores in eslint.config.js. Let prettier fix formatting, almost everything is just line breaks. Made htmlhint ignore @if and @for Angular constructs. Updated node version in Github workflow to 22.12.0 (build.yml). Updated .env.ts. Updated Angular datetime format strings from YYYY-MM-DD to yyyy-MM-dd. Merged changes from dev into angular20 branch.
This commit is contained in:
@@ -1,12 +1,20 @@
|
||||
<span (mouseenter)="mouseEnter()" (mouseleave)="mouseLeave()">
|
||||
<span class="m-l-5" *ngIf="displayL && iconVisible" (click)="copyValue()"
|
||||
><b><fa-icon icon="copy" size="sm" title="{{ 'labels.text.Copy Account Number' | translate }}"></fa-icon></b
|
||||
></span>
|
||||
<span class="m-l-5" *ngIf="accountType">
|
||||
<a href="{{ getAccountLink() }}">{{ accountNo }}</a>
|
||||
</span>
|
||||
<span class="m-l-5" *ngIf="!accountType">{{ accountNo }}</span>
|
||||
<span class="m-l-3" *ngIf="displayR && iconVisible" (click)="copyValue()"
|
||||
><b><fa-icon icon="copy" size="sm" title="{{ 'labels.text.Copy Account Number' | translate }}"></fa-icon></b
|
||||
></span>
|
||||
@if (displayL && iconVisible) {
|
||||
<span class="m-l-5" (click)="copyValue()"
|
||||
><b><fa-icon icon="copy" size="sm" title="{{ 'labels.text.Copy Account Number' | translate }}"></fa-icon></b
|
||||
></span>
|
||||
}
|
||||
@if (accountType) {
|
||||
<span class="m-l-5">
|
||||
<a href="{{ getAccountLink() }}">{{ accountNo }}</a>
|
||||
</span>
|
||||
}
|
||||
@if (!accountType) {
|
||||
<span class="m-l-5">{{ accountNo }}</span>
|
||||
}
|
||||
@if (displayR && iconVisible) {
|
||||
<span class="m-l-3" (click)="copyValue()"
|
||||
><b><fa-icon icon="copy" size="sm" title="{{ 'labels.text.Copy Account Number' | translate }}"></fa-icon></b
|
||||
></span>
|
||||
}
|
||||
</span>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Component, Input, OnInit } from '@angular/core';
|
||||
import { Component, Input, OnInit, inject } from '@angular/core';
|
||||
import { Clipboard } from '@angular/cdk/clipboard';
|
||||
import { FaIconComponent } from '@fortawesome/angular-fontawesome';
|
||||
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
|
||||
@@ -13,6 +13,8 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
|
||||
]
|
||||
})
|
||||
export class AccountNumberComponent implements OnInit {
|
||||
private clipboard = inject(Clipboard);
|
||||
|
||||
@Input() accountNo: string;
|
||||
@Input() display = 'right';
|
||||
@Input() clientId: number | null = null;
|
||||
@@ -23,8 +25,6 @@ export class AccountNumberComponent implements OnInit {
|
||||
displayL = false;
|
||||
displayR = true;
|
||||
|
||||
constructor(private clipboard: Clipboard) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.displayL = this.display === 'left';
|
||||
this.displayR = this.display === 'right';
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
<span class="layout-row" *ngIf="accountTitle">
|
||||
<div [ngClass]="getWithClass(withTitle)" class="header">
|
||||
{{ 'labels.inputs.' + accountTitle | translate }}
|
||||
</div>
|
||||
@if (accountTitle) {
|
||||
<span class="layout-row">
|
||||
<div [ngClass]="getWithClass(withTitle)" class="header">
|
||||
{{ 'labels.inputs.' + accountTitle | translate }}
|
||||
</div>
|
||||
<div [ngClass]="getWithClass(withAccount)">
|
||||
{{ glAccountValue() }}
|
||||
</div>
|
||||
</span>
|
||||
}
|
||||
|
||||
<div [ngClass]="getWithClass(withAccount)">
|
||||
@if (!accountTitle) {
|
||||
<div class="flex-100">
|
||||
{{ glAccountValue() }}
|
||||
</div>
|
||||
</span>
|
||||
|
||||
<div class="flex-100" *ngIf="!accountTitle">
|
||||
{{ glAccountValue() }}
|
||||
</div>
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Component, Input } from '@angular/core';
|
||||
import { GLAccount } from 'app/shared/models/general.model';
|
||||
import { NgIf, NgClass } from '@angular/common';
|
||||
import { NgClass } from '@angular/common';
|
||||
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
|
||||
|
||||
@Component({
|
||||
|
||||
@@ -1,40 +1,48 @@
|
||||
<div class="layout-column m-r-10">
|
||||
<mat-form-field class="flex-100" *ngIf="required">
|
||||
<mat-label>{{ 'labels.inputs.' + inputLabel | translate }}</mat-label>
|
||||
@if (required) {
|
||||
<mat-form-field class="flex-100">
|
||||
<mat-label>{{ 'labels.inputs.' + inputLabel | translate }}</mat-label>
|
||||
<mat-select required [formControl]="inputFormControl">
|
||||
<mat-option>
|
||||
<ngx-mat-select-search
|
||||
placeholderLabel="{{ placeHolderLabel }}"
|
||||
noEntriesFoundLabel="{{ noEntriesFoundLabel }}"
|
||||
[formControl]="filterFormCtrl"
|
||||
></ngx-mat-select-search>
|
||||
</mat-option>
|
||||
@for (glAccount of glAccountData | async; track glAccount) {
|
||||
<mat-option [value]="glAccount.id">
|
||||
{{ '(' + glAccount.glCode + ') ' + glAccount.name }}
|
||||
</mat-option>
|
||||
}
|
||||
</mat-select>
|
||||
@if (inputFormControl.hasError('required')) {
|
||||
<mat-error>
|
||||
{{ 'labels.inputs.Account' | translate }} {{ 'labels.commons.is' | translate }}
|
||||
<strong>{{ 'labels.commons.required' | translate }}</strong>
|
||||
</mat-error>
|
||||
}
|
||||
</mat-form-field>
|
||||
}
|
||||
|
||||
<mat-select required [formControl]="inputFormControl">
|
||||
<mat-option>
|
||||
<ngx-mat-select-search
|
||||
placeholderLabel="{{ placeHolderLabel }}"
|
||||
noEntriesFoundLabel="{{ noEntriesFoundLabel }}"
|
||||
[formControl]="filterFormCtrl"
|
||||
></ngx-mat-select-search>
|
||||
</mat-option>
|
||||
<mat-option *ngFor="let glAccount of glAccountData | async" [value]="glAccount.id">
|
||||
{{ '(' + glAccount.glCode + ') ' + glAccount.name }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
<mat-error *ngIf="inputFormControl.hasError('required')">
|
||||
{{ 'labels.inputs.Account' | translate }} {{ 'labels.commons.is' | translate }}
|
||||
<strong>{{ 'labels.commons.required' | translate }}</strong>
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field class="flex-100" *ngIf="!required">
|
||||
<mat-label>{{ 'labels.inputs.' + inputLabel | translate }}</mat-label>
|
||||
|
||||
<mat-select [formControl]="inputFormControl">
|
||||
<mat-option>
|
||||
<ngx-mat-select-search
|
||||
[formControl]="filterFormCtrl"
|
||||
placeholderLabel="{{ placeHolderLabel }}"
|
||||
noEntriesFoundLabel="{{ noEntriesFoundLabel }}"
|
||||
>
|
||||
</ngx-mat-select-search>
|
||||
</mat-option>
|
||||
<mat-option *ngFor="let glAccount of glAccountData | async" [value]="glAccount.id">
|
||||
{{ '(' + glAccount.glCode + ') ' + glAccount.name }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
@if (!required) {
|
||||
<mat-form-field class="flex-100">
|
||||
<mat-label>{{ 'labels.inputs.' + inputLabel | translate }}</mat-label>
|
||||
<mat-select [formControl]="inputFormControl">
|
||||
<mat-option>
|
||||
<ngx-mat-select-search
|
||||
[formControl]="filterFormCtrl"
|
||||
placeholderLabel="{{ placeHolderLabel }}"
|
||||
noEntriesFoundLabel="{{ noEntriesFoundLabel }}"
|
||||
>
|
||||
</ngx-mat-select-search>
|
||||
</mat-option>
|
||||
@for (glAccount of glAccountData | async; track glAccount) {
|
||||
<mat-option [value]="glAccount.id">
|
||||
{{ '(' + glAccount.glCode + ') ' + glAccount.name }}
|
||||
</mat-option>
|
||||
}
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
}
|
||||
</div>
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { Component, Input, OnChanges, OnDestroy, OnInit, SimpleChanges } from '@angular/core';
|
||||
import { Component, Input, OnChanges, OnDestroy, OnInit, SimpleChanges, inject } from '@angular/core';
|
||||
import { UntypedFormControl, ReactiveFormsModule } from '@angular/forms';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { GLAccount } from 'app/shared/models/general.model';
|
||||
import { ReplaySubject, Subject } from 'rxjs';
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
import { NgIf, NgFor, AsyncPipe } from '@angular/common';
|
||||
import { AsyncPipe } from '@angular/common';
|
||||
import { NgxMatSelectSearchModule } from 'ngx-mat-select-search';
|
||||
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
|
||||
|
||||
@@ -19,6 +19,8 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
|
||||
]
|
||||
})
|
||||
export class GlAccountSelectorComponent implements OnInit, OnChanges, OnDestroy {
|
||||
private translateService = inject(TranslateService);
|
||||
|
||||
@Input() inputFormControl: UntypedFormControl;
|
||||
@Input() glAccountList: GLAccount[] = [];
|
||||
@Input() required = false;
|
||||
@@ -36,8 +38,6 @@ export class GlAccountSelectorComponent implements OnInit, OnChanges, OnDestroy
|
||||
placeHolderLabel = '';
|
||||
noEntriesFoundLabel = '';
|
||||
|
||||
constructor(private translateService: TranslateService) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
// listen for search field value changes
|
||||
this.filterFormCtrl.valueChanges.pipe(takeUntil(this._onDestroy)).subscribe(() => {
|
||||
|
||||
+150
-147
@@ -1,155 +1,158 @@
|
||||
<div *ngIf="isJournalEntryLoaded">
|
||||
<div *ngIf="dataSource?.data[0].manualEntry" class="layout-row layout-align-end container m-b-20">
|
||||
<button
|
||||
mat-raised-button
|
||||
color="primary"
|
||||
(click)="revertTransaction()"
|
||||
*mifosxHasPermission="'REVERSE_JOURNALENTRY'"
|
||||
[disabled]="dataSource?.data[0].reversed"
|
||||
>
|
||||
<span *ngIf="!dataSource.data[0].reversed">
|
||||
<fa-icon icon="undo" class="m-r-10"></fa-icon>{{ 'labels.buttons.Revert Transaction' | translate }}
|
||||
</span>
|
||||
<span *ngIf="dataSource.data[0].reversed">{{ 'labels.buttons.Transaction Reverted' | translate }}</span>
|
||||
</button>
|
||||
@if (isJournalEntryLoaded) {
|
||||
<div>
|
||||
@if (dataSource?.data[0].manualEntry) {
|
||||
<div class="layout-row layout-align-end container m-b-20">
|
||||
<button
|
||||
mat-raised-button
|
||||
color="primary"
|
||||
(click)="revertTransaction()"
|
||||
*mifosxHasPermission="'REVERSE_JOURNALENTRY'"
|
||||
[disabled]="dataSource?.data[0].reversed"
|
||||
>
|
||||
@if (!dataSource.data[0].reversed) {
|
||||
<span>
|
||||
<fa-icon icon="undo" class="m-r-10"></fa-icon>{{ 'labels.buttons.Revert Transaction' | translate }}
|
||||
</span>
|
||||
}
|
||||
@if (dataSource.data[0].reversed) {
|
||||
<span>{{ 'labels.buttons.Transaction Reverted' | translate }}</span>
|
||||
}
|
||||
</button>
|
||||
</div>
|
||||
}
|
||||
@if (isViewTransaction()) {
|
||||
<div class="container m-b-20">
|
||||
@if (dataSource) {
|
||||
<mat-card class="mat-elevation-z8" ngClass="{{ journalEntryColor() }}">
|
||||
<mat-card-content>
|
||||
<div class="layout-row-wrap">
|
||||
<div class="flex-25 header">
|
||||
{{ 'labels.inputs.Office' | translate }}
|
||||
</div>
|
||||
<div class="flex-25">
|
||||
{{ dataSource.data[0].officeName }}
|
||||
</div>
|
||||
<div class="flex-25 header">
|
||||
{{ 'labels.inputs.Transaction Date' | translate }}
|
||||
</div>
|
||||
<div class="flex-25">
|
||||
{{ dataSource.data[0].transactionDate | dateFormat }}
|
||||
</div>
|
||||
<div class="flex-25 header">
|
||||
{{ 'labels.inputs.Created By' | translate }}
|
||||
</div>
|
||||
<div class="flex-25">
|
||||
{{ dataSource.data[0].createdByUserName }}
|
||||
</div>
|
||||
<div class="flex-25 header">
|
||||
{{ 'labels.inputs.Submitted on' | translate }}
|
||||
</div>
|
||||
<div class="flex-25">
|
||||
{{ dataSource.data[0].submittedOnDate | datetimeFormat }}
|
||||
</div>
|
||||
<div class="flex-25 header">
|
||||
{{ 'labels.inputs.Manual Journal Entry' | translate }}
|
||||
</div>
|
||||
<div class="flex-25">
|
||||
{{ dataSource.data[0].manualEntry | yesNo }}
|
||||
</div>
|
||||
@if (dataSource.data[0].externalAssetOwner) {
|
||||
<div class="flex-25 header">
|
||||
{{ 'labels.inputs.External Asset Owner' | translate }}
|
||||
</div>
|
||||
}
|
||||
@if (dataSource.data[0].externalAssetOwner) {
|
||||
<div class="flex-25">
|
||||
{{ dataSource.data[0].externalAssetOwner }}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
<div class="mat-elevation-z8 container layout-align-center layout-row-wrap">
|
||||
<table mat-table [dataSource]="dataSource" matSort>
|
||||
<ng-container matColumnDef="id">
|
||||
<th mat-header-cell class="center" *matHeaderCellDef mat-sort-header>
|
||||
{{ 'labels.inputs.Entry ID' | translate }}
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let transaction">{{ transaction.id }}</td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="glAccountType">
|
||||
<th mat-header-cell class="center" *matHeaderCellDef mat-sort-header>
|
||||
{{ 'labels.inputs.Type' | translate }}
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let transaction">{{ transaction.glAccountType.value }}</td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="glAccountCode">
|
||||
<th mat-header-cell class="center" *matHeaderCellDef mat-sort-header>
|
||||
{{ 'labels.inputs.Account Code' | translate }}
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let transaction">{{ transaction.glAccountCode }}</td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="glAccountName">
|
||||
<th mat-header-cell class="center" *matHeaderCellDef mat-sort-header>
|
||||
{{ 'labels.inputs.Account Name' | translate }}
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let transaction">{{ transaction.glAccountName }}</td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="debit">
|
||||
<th mat-header-cell class="center" *matHeaderCellDef mat-sort-header>
|
||||
{{ 'labels.inputs.Debit' | translate }}
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let transaction">
|
||||
@if (transaction.entryType.value === 'DEBIT') {
|
||||
<span>
|
||||
{{ transaction.currency.displaySymbol || transaction.currency.code }}
|
||||
{{ transaction.amount | formatNumber }}
|
||||
</span>
|
||||
}
|
||||
</td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="credit">
|
||||
<th mat-header-cell class="center" *matHeaderCellDef mat-sort-header>
|
||||
{{ 'labels.inputs.Credit' | translate }}
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let transaction">
|
||||
@if (transaction.entryType.value === 'CREDIT') {
|
||||
<span>
|
||||
{{ transaction.currency.displaySymbol || transaction.currency.code }}
|
||||
{{ transaction.amount | formatNumber }}
|
||||
</span>
|
||||
}
|
||||
</td>
|
||||
</ng-container>
|
||||
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
||||
<tr
|
||||
mat-row
|
||||
*matRowDef="let row; columns: displayedColumns"
|
||||
(click)="viewJournalEntry(row)"
|
||||
class="select-row"
|
||||
></tr>
|
||||
</table>
|
||||
<div class="layout-row layout-align-center m-t-15 m-b-15 gap-5px layout-xs-column">
|
||||
<button type="button" color="primary" mat-raised-button (click)="goBack()">
|
||||
{{ 'labels.buttons.Back' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
<div class="container m-b-20" *ngIf="isViewTransaction()">
|
||||
<mat-card class="mat-elevation-z8" ngClass="{{ journalEntryColor() }}" *ngIf="dataSource">
|
||||
<mat-card-content>
|
||||
<div class="layout-row-wrap">
|
||||
<div class="flex-25 header">
|
||||
{{ 'labels.inputs.Office' | translate }}
|
||||
</div>
|
||||
|
||||
<div class="flex-25">
|
||||
{{ dataSource.data[0].officeName }}
|
||||
</div>
|
||||
|
||||
<div class="flex-25 header">
|
||||
{{ 'labels.inputs.Transaction Date' | translate }}
|
||||
</div>
|
||||
|
||||
<div class="flex-25">
|
||||
{{ dataSource.data[0].transactionDate | dateFormat }}
|
||||
</div>
|
||||
|
||||
<div class="flex-25 header">
|
||||
{{ 'labels.inputs.Created By' | translate }}
|
||||
</div>
|
||||
|
||||
<div class="flex-25">
|
||||
{{ dataSource.data[0].createdByUserName }}
|
||||
</div>
|
||||
|
||||
<div class="flex-25 header">
|
||||
{{ 'labels.inputs.Submitted on' | translate }}
|
||||
</div>
|
||||
|
||||
<div class="flex-25">
|
||||
{{ dataSource.data[0].submittedOnDate | datetimeFormat }}
|
||||
</div>
|
||||
|
||||
<div class="flex-25 header">
|
||||
{{ 'labels.inputs.Manual Journal Entry' | translate }}
|
||||
</div>
|
||||
|
||||
<div class="flex-25">
|
||||
{{ dataSource.data[0].manualEntry | yesNo }}
|
||||
</div>
|
||||
|
||||
<div class="flex-25 header" *ngIf="dataSource.data[0].externalAssetOwner">
|
||||
{{ 'labels.inputs.External Asset Owner' | translate }}
|
||||
</div>
|
||||
|
||||
<div class="flex-25" *ngIf="dataSource.data[0].externalAssetOwner">
|
||||
{{ dataSource.data[0].externalAssetOwner }}
|
||||
</div>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
</div>
|
||||
|
||||
<div class="mat-elevation-z8 container layout-align-center layout-row-wrap">
|
||||
<table mat-table [dataSource]="dataSource" matSort>
|
||||
<ng-container matColumnDef="id">
|
||||
<th mat-header-cell class="center" *matHeaderCellDef mat-sort-header>
|
||||
{{ 'labels.inputs.Entry ID' | translate }}
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let transaction">{{ transaction.id }}</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="glAccountType">
|
||||
<th mat-header-cell class="center" *matHeaderCellDef mat-sort-header>{{ 'labels.inputs.Type' | translate }}</th>
|
||||
<td mat-cell *matCellDef="let transaction">{{ transaction.glAccountType.value }}</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="glAccountCode">
|
||||
<th mat-header-cell class="center" *matHeaderCellDef mat-sort-header>
|
||||
{{ 'labels.inputs.Account Code' | translate }}
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let transaction">{{ transaction.glAccountCode }}</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="glAccountName">
|
||||
<th mat-header-cell class="center" *matHeaderCellDef mat-sort-header>
|
||||
{{ 'labels.inputs.Account Name' | translate }}
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let transaction">{{ transaction.glAccountName }}</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="debit">
|
||||
<th mat-header-cell class="center" *matHeaderCellDef mat-sort-header>
|
||||
{{ 'labels.inputs.Debit' | translate }}
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let transaction">
|
||||
<span *ngIf="transaction.entryType.value === 'DEBIT'">
|
||||
{{ transaction.currency.displaySymbol || transaction.currency.code }}
|
||||
{{ transaction.amount | formatNumber }}
|
||||
</span>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="credit">
|
||||
<th mat-header-cell class="center" *matHeaderCellDef mat-sort-header>
|
||||
{{ 'labels.inputs.Credit' | translate }}
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let transaction">
|
||||
<span *ngIf="transaction.entryType.value === 'CREDIT'">
|
||||
{{ transaction.currency.displaySymbol || transaction.currency.code }}
|
||||
{{ transaction.amount | formatNumber }}
|
||||
</span>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
||||
<tr
|
||||
mat-row
|
||||
*matRowDef="let row; columns: displayedColumns"
|
||||
(click)="viewJournalEntry(row)"
|
||||
class="select-row"
|
||||
></tr>
|
||||
</table>
|
||||
|
||||
@if (!isJournalEntryLoaded) {
|
||||
<div class="container m-b-20">
|
||||
<div class="alert">
|
||||
<div class="message">
|
||||
<i class="fa fa-exclamation-circle alert-check"></i>
|
||||
{{ 'labels.text.No data found' | translate }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="layout-row layout-align-center m-t-15 m-b-15 gap-5px layout-xs-column">
|
||||
<button type="button" color="primary" mat-raised-button (click)="goBack()">
|
||||
{{ 'labels.buttons.Back' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container m-b-20" *ngIf="!isJournalEntryLoaded">
|
||||
<div class="alert">
|
||||
<div class="message">
|
||||
<i class="fa fa-exclamation-circle alert-check"></i>
|
||||
{{ 'labels.text.No data found' | translate }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layout-row layout-align-center m-t-15 m-b-15 gap-5px layout-xs-column">
|
||||
<button type="button" color="primary" mat-raised-button (click)="goBack()">
|
||||
{{ 'labels.buttons.Back' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
+8
-16
@@ -1,4 +1,4 @@
|
||||
import { Component, OnInit, ViewChild } from '@angular/core';
|
||||
import { Component, OnInit, ViewChild, inject } from '@angular/core';
|
||||
import { ViewJournalEntryComponent } from '../view-journal-entry/view-journal-entry.component';
|
||||
import { RevertTransactionComponent } from 'app/accounting/revert-transaction/revert-transaction.component';
|
||||
import { AccountingService } from 'app/accounting/accounting.service';
|
||||
@@ -19,7 +19,7 @@ import {
|
||||
MatRowDef,
|
||||
MatRow
|
||||
} from '@angular/material/table';
|
||||
import { Location, NgIf } from '@angular/common';
|
||||
import { Location } from '@angular/common';
|
||||
import { FaIconComponent } from '@fortawesome/angular-fontawesome';
|
||||
import { DateFormatPipe } from '../../../pipes/date-format.pipe';
|
||||
import { DatetimeFormatPipe } from '../../../pipes/datetime-format.pipe';
|
||||
@@ -53,6 +53,12 @@ import { YesnoPipe } from '@pipes/yesno.pipe';
|
||||
]
|
||||
})
|
||||
export class ViewJournalEntryTransactionComponent implements OnInit {
|
||||
private accountingService = inject(AccountingService);
|
||||
private route = inject(ActivatedRoute);
|
||||
private router = inject(Router);
|
||||
dialog = inject(MatDialog);
|
||||
private location = inject(Location);
|
||||
|
||||
title: string;
|
||||
journalEntriesData: any[];
|
||||
/** Transaction data. */
|
||||
@@ -80,20 +86,6 @@ export class ViewJournalEntryTransactionComponent implements OnInit {
|
||||
|
||||
isManualJournalEntry = false;
|
||||
|
||||
/**
|
||||
* @param {AccountingService} accountingService Accounting Service.
|
||||
* @param {ActivatedRoute} route Activated Route.
|
||||
* @param {Router} router Router for navigation.
|
||||
* @param {MatDialog} dialog Dialog reference.
|
||||
*/
|
||||
constructor(
|
||||
private accountingService: AccountingService,
|
||||
private route: ActivatedRoute,
|
||||
private router: Router,
|
||||
public dialog: MatDialog,
|
||||
private location: Location
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Retrieves the transaction data from `resolve` and sets the transaction table.
|
||||
*/
|
||||
|
||||
@@ -39,8 +39,12 @@
|
||||
|
||||
<tr>
|
||||
<th>
|
||||
<span *ngIf="data.journalEntry.entryType.value === 'CREDIT'">{{ 'labels.inputs.Credit' | translate }}</span>
|
||||
<span *ngIf="data.journalEntry.entryType.value === 'DEBIT'">{{ 'labels.inputs.Debit' | translate }}</span>
|
||||
@if (data.journalEntry.entryType.value === 'CREDIT') {
|
||||
<span>{{ 'labels.inputs.Credit' | translate }}</span>
|
||||
}
|
||||
@if (data.journalEntry.entryType.value === 'DEBIT') {
|
||||
<span>{{ 'labels.inputs.Debit' | translate }}</span>
|
||||
}
|
||||
</th>
|
||||
<td>{{ data.journalEntry.currency.displaySymbol }} {{ data.journalEntry.amount | formatNumber }}</td>
|
||||
</tr>
|
||||
@@ -50,54 +54,74 @@
|
||||
<td>({{ data.journalEntry.currency.code }}) {{ data.journalEntry.currency.name }}</td>
|
||||
</tr>
|
||||
|
||||
<tr *ngIf="data.journalEntry.referenceNumber">
|
||||
<th>{{ 'labels.inputs.Reference Number' | translate }}</th>
|
||||
<td>{{ data.journalEntry.referenceNumber }}</td>
|
||||
</tr>
|
||||
@if (data.journalEntry.referenceNumber) {
|
||||
<tr>
|
||||
<th>{{ 'labels.inputs.Reference Number' | translate }}</th>
|
||||
<td>{{ data.journalEntry.referenceNumber }}</td>
|
||||
</tr>
|
||||
}
|
||||
|
||||
<tr *ngIf="data.journalEntry.comments">
|
||||
<th>{{ 'labels.inputs.Comments' | translate }}</th>
|
||||
<td>{{ data.journalEntry.comments }}</td>
|
||||
</tr>
|
||||
@if (data.journalEntry.comments) {
|
||||
<tr>
|
||||
<th>{{ 'labels.inputs.Comments' | translate }}</th>
|
||||
<td>{{ data.journalEntry.comments }}</td>
|
||||
</tr>
|
||||
}
|
||||
|
||||
<tr *ngIf="existsPaymentDetails">
|
||||
<th colspan="2" class="header">{{ 'labels.inputs.Payment Details' | translate }}</th>
|
||||
</tr>
|
||||
@if (existsPaymentDetails) {
|
||||
<tr>
|
||||
<th colspan="2" class="header">{{ 'labels.inputs.Payment Details' | translate }}</th>
|
||||
</tr>
|
||||
}
|
||||
|
||||
<tr *ngIf="existsPaymentDetails && data.journalEntry.transactionDetails.paymentDetails?.paymentType">
|
||||
<th>{{ 'labels.inputs.Payment Type' | translate }}</th>
|
||||
<td>{{ data.journalEntry.transactionDetails.paymentDetails.paymentType.name }}</td>
|
||||
</tr>
|
||||
@if (existsPaymentDetails && data.journalEntry.transactionDetails.paymentDetails?.paymentType) {
|
||||
<tr>
|
||||
<th>{{ 'labels.inputs.Payment Type' | translate }}</th>
|
||||
<td>{{ data.journalEntry.transactionDetails.paymentDetails.paymentType.name }}</td>
|
||||
</tr>
|
||||
}
|
||||
|
||||
<tr *ngIf="existsPaymentDetails && data.journalEntry.transactionDetails.paymentDetails?.accountNumber">
|
||||
<th>{{ 'labels.inputs.Account Number' | translate }}</th>
|
||||
<td>{{ data.journalEntry.transactionDetails.paymentDetails.accountNumber }}</td>
|
||||
</tr>
|
||||
@if (existsPaymentDetails && data.journalEntry.transactionDetails.paymentDetails?.accountNumber) {
|
||||
<tr>
|
||||
<th>{{ 'labels.inputs.Account Number' | translate }}</th>
|
||||
<td>{{ data.journalEntry.transactionDetails.paymentDetails.accountNumber }}</td>
|
||||
</tr>
|
||||
}
|
||||
|
||||
<tr *ngIf="existsPaymentDetails && data.journalEntry.transactionDetails.paymentDetails?.checkNumber">
|
||||
<th>{{ 'labels.inputs.Cheque Number' | translate }}</th>
|
||||
<td>{{ data.journalEntry.transactionDetails.paymentDetails.checkNumber }}</td>
|
||||
</tr>
|
||||
@if (existsPaymentDetails && data.journalEntry.transactionDetails.paymentDetails?.checkNumber) {
|
||||
<tr>
|
||||
<th>{{ 'labels.inputs.Cheque Number' | translate }}</th>
|
||||
<td>{{ data.journalEntry.transactionDetails.paymentDetails.checkNumber }}</td>
|
||||
</tr>
|
||||
}
|
||||
|
||||
<tr *ngIf="existsPaymentDetails && data.journalEntry.transactionDetails.paymentDetails?.routingCode">
|
||||
<th>{{ 'labels.inputs.Routing Code' | translate }}</th>
|
||||
<td>{{ data.journalEntry.transactionDetails.paymentDetails.routingCode }}</td>
|
||||
</tr>
|
||||
@if (existsPaymentDetails && data.journalEntry.transactionDetails.paymentDetails?.routingCode) {
|
||||
<tr>
|
||||
<th>{{ 'labels.inputs.Routing Code' | translate }}</th>
|
||||
<td>{{ data.journalEntry.transactionDetails.paymentDetails.routingCode }}</td>
|
||||
</tr>
|
||||
}
|
||||
|
||||
<tr *ngIf="existsPaymentDetails && data.journalEntry.transactionDetails.paymentDetails?.receiptNumber">
|
||||
<th>{{ 'labels.inputs.Receipt Number' | translate }}</th>
|
||||
<td>{{ data.journalEntry.transactionDetails.paymentDetails.receiptNumber }}</td>
|
||||
</tr>
|
||||
@if (existsPaymentDetails && data.journalEntry.transactionDetails.paymentDetails?.receiptNumber) {
|
||||
<tr>
|
||||
<th>{{ 'labels.inputs.Receipt Number' | translate }}</th>
|
||||
<td>{{ data.journalEntry.transactionDetails.paymentDetails.receiptNumber }}</td>
|
||||
</tr>
|
||||
}
|
||||
|
||||
<tr *ngIf="existsPaymentDetails && data.journalEntry.transactionDetails.paymentDetails?.bankNumber">
|
||||
<th>{{ 'labels.inputs.Bank Number' | translate }}</th>
|
||||
<td>{{ data.journalEntry.transactionDetails.paymentDetails.bankNumber }}</td>
|
||||
</tr>
|
||||
@if (existsPaymentDetails && data.journalEntry.transactionDetails.paymentDetails?.bankNumber) {
|
||||
<tr>
|
||||
<th>{{ 'labels.inputs.Bank Number' | translate }}</th>
|
||||
<td>{{ data.journalEntry.transactionDetails.paymentDetails.bankNumber }}</td>
|
||||
</tr>
|
||||
}
|
||||
|
||||
<tr *ngIf="existsPaymentDetails">
|
||||
<th>{{ 'labels.inputs.Created by' | translate }}</th>
|
||||
<td>{{ data.journalEntry.createdByUserName }}</td>
|
||||
</tr>
|
||||
@if (existsPaymentDetails) {
|
||||
<tr>
|
||||
<th>{{ 'labels.inputs.Created by' | translate }}</th>
|
||||
<td>{{ data.journalEntry.createdByUserName }}</td>
|
||||
</tr>
|
||||
}
|
||||
|
||||
<tr>
|
||||
<th>{{ 'labels.inputs.Submitted on' | translate }}</th>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/** Angular Imports */
|
||||
import { Component, Inject } from '@angular/core';
|
||||
import { Component, inject } from '@angular/core';
|
||||
import {
|
||||
MatDialogRef,
|
||||
MAT_DIALOG_DATA,
|
||||
@@ -34,15 +34,17 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
|
||||
]
|
||||
})
|
||||
export class ViewJournalEntryComponent {
|
||||
dialogRef = inject<MatDialogRef<ViewJournalEntryComponent>>(MatDialogRef);
|
||||
data = inject(MAT_DIALOG_DATA);
|
||||
|
||||
existsPaymentDetails = false;
|
||||
/**
|
||||
* @param {MatDialogRef} dialogRef Component reference to dialog.
|
||||
* @param {any} data Provides journal entry.
|
||||
*/
|
||||
constructor(
|
||||
public dialogRef: MatDialogRef<ViewJournalEntryComponent>,
|
||||
@Inject(MAT_DIALOG_DATA) public data: any
|
||||
) {
|
||||
constructor() {
|
||||
const data = this.data;
|
||||
|
||||
this.existsPaymentDetails =
|
||||
data.journalEntry.transactionDetails != null && data.journalEntry.transactionDetails.paymentDetails != null;
|
||||
}
|
||||
|
||||
+140
-131
@@ -1,150 +1,159 @@
|
||||
<div class="layout-row-wrap responsive-column">
|
||||
<div *ngIf="accountingRule" class="layout-row responsive-column flex-100">
|
||||
<span class="flex-40">{{ 'labels.inputs.Type' | translate }}:</span>
|
||||
<span class="flex-60">{{ 'labels.accounting.' + getAccountingRuleName(accountingRule.value) | translate }}</span>
|
||||
</div>
|
||||
@if (accountingRule) {
|
||||
<div class="layout-row responsive-column flex-100">
|
||||
<span class="flex-40">{{ 'labels.inputs.Type' | translate }}:</span>
|
||||
<span class="flex-60">{{ 'labels.accounting.' + getAccountingRuleName(accountingRule.value) | translate }}</span>
|
||||
</div>
|
||||
}
|
||||
|
||||
<div class="layout-row-wrap responsive-column flex-100">
|
||||
<div *ngIf="isCashOrAccrualAccounting()" class="layout-row-wrap responsive-column flex-100">
|
||||
<h4 class="mat-h4 flex-100">{{ 'labels.heading.Assets' | translate }}</h4>
|
||||
<div class="flex-100 layout-row-wrap responsive-column">
|
||||
<mifosx-gl-account-display
|
||||
class="flex-100"
|
||||
[accountTitle]="'Saving reference'"
|
||||
[glAccount]="accountingMappings.savingsReferenceAccount"
|
||||
[withTitle]="'40%'"
|
||||
>
|
||||
</mifosx-gl-account-display>
|
||||
</div>
|
||||
<div class="flex-100 layout-row-wrap responsive-column">
|
||||
<mifosx-gl-account-display
|
||||
class="flex-100"
|
||||
[accountTitle]="'Overdraft portfolio'"
|
||||
*ngIf="accountingMappings.overdraftPortfolioControl"
|
||||
[glAccount]="accountingMappings.overdraftPortfolioControl"
|
||||
[withTitle]="'40%'"
|
||||
>
|
||||
</mifosx-gl-account-display>
|
||||
</div>
|
||||
<div class="flex-100 layout-row-wrap responsive-column">
|
||||
<mifosx-gl-account-display
|
||||
class="flex-100"
|
||||
[accountTitle]="'Fees Receivable'"
|
||||
*ngIf="isAccrualAccounting()"
|
||||
[glAccount]="accountingMappings.feeReceivableAccount"
|
||||
[withTitle]="'40%'"
|
||||
>
|
||||
</mifosx-gl-account-display>
|
||||
</div>
|
||||
<div class="flex-100 layout-row-wrap responsive-column">
|
||||
<mifosx-gl-account-display
|
||||
class="flex-100"
|
||||
[accountTitle]="'Penalties Receivable'"
|
||||
*ngIf="isAccrualAccounting()"
|
||||
[glAccount]="accountingMappings.penaltyReceivableAccount"
|
||||
[withTitle]="'40%'"
|
||||
>
|
||||
</mifosx-gl-account-display>
|
||||
<mifosx-gl-account-display
|
||||
class="flex-100"
|
||||
[accountTitle]="'Interest Receivable'"
|
||||
*ngIf="isAccrualAccounting()"
|
||||
[glAccount]="accountingMappings.interestReceivableAccount"
|
||||
[withTitle]="'40%'"
|
||||
>
|
||||
</mifosx-gl-account-display>
|
||||
|
||||
<h4 class="mat-h4 flex-100">{{ 'labels.heading.Liabilities' | translate }}</h4>
|
||||
@if (isCashOrAccrualAccounting()) {
|
||||
<div class="layout-row-wrap responsive-column flex-100">
|
||||
<h4 class="mat-h4 flex-100">{{ 'labels.heading.Assets' | translate }}</h4>
|
||||
<div class="flex-100 layout-row-wrap responsive-column">
|
||||
<mifosx-gl-account-display
|
||||
class="flex-100"
|
||||
[accountTitle]="'Saving control'"
|
||||
[glAccount]="accountingMappings.savingsControlAccount"
|
||||
[accountTitle]="'Saving reference'"
|
||||
[glAccount]="accountingMappings.savingsReferenceAccount"
|
||||
[withTitle]="'40%'"
|
||||
>
|
||||
</mifosx-gl-account-display>
|
||||
</div>
|
||||
<div class="flex-100 layout-row-wrap responsive-column">
|
||||
<mifosx-gl-account-display
|
||||
class="flex-100"
|
||||
[accountTitle]="'Savings transfers in suspense'"
|
||||
[glAccount]="accountingMappings.transfersInSuspenseAccount"
|
||||
[withTitle]="'40%'"
|
||||
>
|
||||
</mifosx-gl-account-display>
|
||||
@if (accountingMappings.overdraftPortfolioControl) {
|
||||
<mifosx-gl-account-display
|
||||
class="flex-100"
|
||||
[accountTitle]="'Overdraft portfolio'"
|
||||
[glAccount]="accountingMappings.overdraftPortfolioControl"
|
||||
[withTitle]="'40%'"
|
||||
>
|
||||
</mifosx-gl-account-display>
|
||||
}
|
||||
</div>
|
||||
<div class="flex-100 layout-row-wrap responsive-column">
|
||||
<mifosx-gl-account-display
|
||||
class="flex-100"
|
||||
[accountTitle]="'Interest Payable'"
|
||||
*ngIf="isAccrualAccounting()"
|
||||
[glAccount]="accountingMappings.interestPayableAccount"
|
||||
[withTitle]="'40%'"
|
||||
>
|
||||
</mifosx-gl-account-display>
|
||||
@if (isAccrualAccounting()) {
|
||||
<mifosx-gl-account-display
|
||||
class="flex-100"
|
||||
[accountTitle]="'Fees Receivable'"
|
||||
[glAccount]="accountingMappings.feeReceivableAccount"
|
||||
[withTitle]="'40%'"
|
||||
>
|
||||
</mifosx-gl-account-display>
|
||||
}
|
||||
</div>
|
||||
<div class="flex-100 layout-row-wrap responsive-column">
|
||||
<mifosx-gl-account-display
|
||||
class="flex-100"
|
||||
[accountTitle]="'Escheat liability'"
|
||||
*ngIf="accountingMappings.escheatLiabilityAccount"
|
||||
[glAccount]="accountingMappings.escheatLiabilityAccount"
|
||||
[withTitle]="'40%'"
|
||||
>
|
||||
</mifosx-gl-account-display>
|
||||
</div>
|
||||
|
||||
<h4 class="mat-h4 flex-100">{{ 'labels.heading.Income' | translate }}</h4>
|
||||
<div class="flex-100 layout-row-wrap responsive-column">
|
||||
<mifosx-gl-account-display
|
||||
class="flex-100"
|
||||
[accountTitle]="'Income from fees'"
|
||||
[glAccount]="accountingMappings.incomeFromFeeAccount"
|
||||
[withTitle]="'40%'"
|
||||
>
|
||||
</mifosx-gl-account-display>
|
||||
</div>
|
||||
<div class="flex-100 layout-row-wrap responsive-column">
|
||||
<mifosx-gl-account-display
|
||||
class="flex-100"
|
||||
[accountTitle]="'Income from penalties'"
|
||||
[glAccount]="accountingMappings.incomeFromPenaltyAccount"
|
||||
[withTitle]="'40%'"
|
||||
>
|
||||
</mifosx-gl-account-display>
|
||||
</div>
|
||||
<div class="flex-100 layout-row-wrap responsive-column">
|
||||
<mifosx-gl-account-display
|
||||
class="flex-100"
|
||||
[accountTitle]="'Income from Interest'"
|
||||
*ngIf="accountingMappings.incomeFromInterest"
|
||||
[glAccount]="accountingMappings.incomeFromInterest"
|
||||
[withTitle]="'40%'"
|
||||
>
|
||||
</mifosx-gl-account-display>
|
||||
</div>
|
||||
|
||||
<h4 class="mat-h4 flex-100">{{ 'labels.heading.Expenses' | translate }}</h4>
|
||||
<div class="flex-100 layout-row-wrap responsive-column">
|
||||
<mifosx-gl-account-display
|
||||
class="flex-100"
|
||||
[accountTitle]="'Interest on savings'"
|
||||
[glAccount]="accountingMappings.interestOnSavingsAccount"
|
||||
[withTitle]="'40%'"
|
||||
>
|
||||
</mifosx-gl-account-display>
|
||||
</div>
|
||||
<div class="flex-100 layout-row-wrap responsive-column">
|
||||
<mifosx-gl-account-display
|
||||
class="flex-100"
|
||||
[accountTitle]="'Write-off'"
|
||||
*ngIf="accountingMappings.writeOffAccount"
|
||||
[glAccount]="accountingMappings.writeOffAccount"
|
||||
[withTitle]="'40%'"
|
||||
>
|
||||
</mifosx-gl-account-display>
|
||||
@if (isAccrualAccounting()) {
|
||||
<mifosx-gl-account-display
|
||||
class="flex-100"
|
||||
[accountTitle]="'Penalties Receivable'"
|
||||
[glAccount]="accountingMappings.penaltyReceivableAccount"
|
||||
[withTitle]="'40%'"
|
||||
>
|
||||
</mifosx-gl-account-display>
|
||||
}
|
||||
@if (isAccrualAccounting()) {
|
||||
<mifosx-gl-account-display
|
||||
class="flex-100"
|
||||
[accountTitle]="'Interest Receivable'"
|
||||
[glAccount]="accountingMappings.interestReceivableAccount"
|
||||
[withTitle]="'40%'"
|
||||
>
|
||||
</mifosx-gl-account-display>
|
||||
}
|
||||
<h4 class="mat-h4 flex-100">{{ 'labels.heading.Liabilities' | translate }}</h4>
|
||||
<div class="flex-100 layout-row-wrap responsive-column">
|
||||
<mifosx-gl-account-display
|
||||
class="flex-100"
|
||||
[accountTitle]="'Saving control'"
|
||||
[glAccount]="accountingMappings.savingsControlAccount"
|
||||
[withTitle]="'40%'"
|
||||
>
|
||||
</mifosx-gl-account-display>
|
||||
</div>
|
||||
<div class="flex-100 layout-row-wrap responsive-column">
|
||||
<mifosx-gl-account-display
|
||||
class="flex-100"
|
||||
[accountTitle]="'Savings transfers in suspense'"
|
||||
[glAccount]="accountingMappings.transfersInSuspenseAccount"
|
||||
[withTitle]="'40%'"
|
||||
>
|
||||
</mifosx-gl-account-display>
|
||||
</div>
|
||||
<div class="flex-100 layout-row-wrap responsive-column">
|
||||
@if (isAccrualAccounting()) {
|
||||
<mifosx-gl-account-display
|
||||
class="flex-100"
|
||||
[accountTitle]="'Interest Payable'"
|
||||
[glAccount]="accountingMappings.interestPayableAccount"
|
||||
[withTitle]="'40%'"
|
||||
>
|
||||
</mifosx-gl-account-display>
|
||||
}
|
||||
</div>
|
||||
<div class="flex-100 layout-row-wrap responsive-column">
|
||||
@if (accountingMappings.escheatLiabilityAccount) {
|
||||
<mifosx-gl-account-display
|
||||
class="flex-100"
|
||||
[accountTitle]="'Escheat liability'"
|
||||
[glAccount]="accountingMappings.escheatLiabilityAccount"
|
||||
[withTitle]="'40%'"
|
||||
>
|
||||
</mifosx-gl-account-display>
|
||||
}
|
||||
</div>
|
||||
<h4 class="mat-h4 flex-100">{{ 'labels.heading.Income' | translate }}</h4>
|
||||
<div class="flex-100 layout-row-wrap responsive-column">
|
||||
<mifosx-gl-account-display
|
||||
class="flex-100"
|
||||
[accountTitle]="'Income from fees'"
|
||||
[glAccount]="accountingMappings.incomeFromFeeAccount"
|
||||
[withTitle]="'40%'"
|
||||
>
|
||||
</mifosx-gl-account-display>
|
||||
</div>
|
||||
<div class="flex-100 layout-row-wrap responsive-column">
|
||||
<mifosx-gl-account-display
|
||||
class="flex-100"
|
||||
[accountTitle]="'Income from penalties'"
|
||||
[glAccount]="accountingMappings.incomeFromPenaltyAccount"
|
||||
[withTitle]="'40%'"
|
||||
>
|
||||
</mifosx-gl-account-display>
|
||||
</div>
|
||||
<div class="flex-100 layout-row-wrap responsive-column">
|
||||
@if (accountingMappings.incomeFromInterest) {
|
||||
<mifosx-gl-account-display
|
||||
class="flex-100"
|
||||
[accountTitle]="'Income from Interest'"
|
||||
[glAccount]="accountingMappings.incomeFromInterest"
|
||||
[withTitle]="'40%'"
|
||||
>
|
||||
</mifosx-gl-account-display>
|
||||
}
|
||||
</div>
|
||||
<h4 class="mat-h4 flex-100">{{ 'labels.heading.Expenses' | translate }}</h4>
|
||||
<div class="flex-100 layout-row-wrap responsive-column">
|
||||
<mifosx-gl-account-display
|
||||
class="flex-100"
|
||||
[accountTitle]="'Interest on savings'"
|
||||
[glAccount]="accountingMappings.interestOnSavingsAccount"
|
||||
[withTitle]="'40%'"
|
||||
>
|
||||
</mifosx-gl-account-display>
|
||||
</div>
|
||||
<div class="flex-100 layout-row-wrap responsive-column">
|
||||
@if (accountingMappings.writeOffAccount) {
|
||||
<mifosx-gl-account-display
|
||||
class="flex-100"
|
||||
[accountTitle]="'Write-off'"
|
||||
[glAccount]="accountingMappings.writeOffAccount"
|
||||
[withTitle]="'40%'"
|
||||
>
|
||||
</mifosx-gl-account-display>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+3
-3
@@ -1,4 +1,4 @@
|
||||
import { Component, Input } from '@angular/core';
|
||||
import { Component, Input, inject } from '@angular/core';
|
||||
import { Accounting } from 'app/core/utils/accounting';
|
||||
import { OptionData } from 'app/shared/models/option-data.model';
|
||||
import { GlAccountDisplayComponent } from '../gl-account-display/gl-account-display.component';
|
||||
@@ -14,11 +14,11 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
|
||||
]
|
||||
})
|
||||
export class ViewSavingsAccountingDetailsComponent {
|
||||
private accounting = inject(Accounting);
|
||||
|
||||
@Input() accountingRule: OptionData;
|
||||
@Input() accountingMappings: any[] = [];
|
||||
|
||||
constructor(private accounting: Accounting) {}
|
||||
|
||||
isCashOrAccrualAccounting(): boolean {
|
||||
if (this.accountingRule) {
|
||||
return this.accounting.isCashOrAccrualAccounting(this.accountingRule);
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<h1 mat-dialog-title>{{ 'labels.buttons.Cancel' | translate }}</h1>
|
||||
<div mat-dialog-content>
|
||||
<p *ngIf="!data.cancelContext">
|
||||
{{ 'labels.text.Are you sure you want to leave this page and lose all inputted data' | translate }}?
|
||||
</p>
|
||||
<p *ngIf="data.cancelContext">
|
||||
{{ 'labels.text.Are you sure you want to cancel' | translate }} {{ data.cancelContext }} ?
|
||||
</p>
|
||||
@if (!data.cancelContext) {
|
||||
<p>{{ 'labels.text.Are you sure you want to leave this page and lose all inputted data' | translate }}?</p>
|
||||
}
|
||||
@if (data.cancelContext) {
|
||||
<p>{{ 'labels.text.Are you sure you want to cancel' | translate }} {{ data.cancelContext }} ?</p>
|
||||
}
|
||||
</div>
|
||||
<mat-dialog-actions align="end">
|
||||
<button mat-raised-button mat-dialog-close>{{ 'labels.buttons.No' | translate }}</button>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/** Angular Imports */
|
||||
import { Component, Inject } from '@angular/core';
|
||||
import { Component, inject } from '@angular/core';
|
||||
import {
|
||||
MAT_DIALOG_DATA,
|
||||
MatDialogRef,
|
||||
@@ -28,11 +28,6 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
|
||||
]
|
||||
})
|
||||
export class CancelDialogComponent {
|
||||
/**
|
||||
* @param {MatDialogRef} dialogRef Component reference to dialog.
|
||||
*/
|
||||
constructor(
|
||||
public dialogRef: MatDialogRef<CancelDialogComponent>,
|
||||
@Inject(MAT_DIALOG_DATA) public data: any
|
||||
) {}
|
||||
dialogRef = inject<MatDialogRef<CancelDialogComponent>>(MatDialogRef);
|
||||
data = inject(MAT_DIALOG_DATA);
|
||||
}
|
||||
|
||||
@@ -9,17 +9,17 @@
|
||||
label="{{ 'Password' | translateKey: 'inputs' }}"
|
||||
></mifosx-input-password>
|
||||
<mat-error>
|
||||
<p
|
||||
*ngIf="
|
||||
changePasswordForm.get('password').errors?.['uppercase'] ||
|
||||
changePasswordForm.get('password').errors?.['number'] ||
|
||||
changePasswordForm.get('password').errors?.['repeated'] ||
|
||||
changePasswordForm.get('password').errors?.['specialChar'] ||
|
||||
changePasswordForm.get('password').errors?.['minlength']
|
||||
"
|
||||
>
|
||||
{{ 'labels.commons.Password validation' | translate: { minchar: minPasswordLength } }}
|
||||
</p>
|
||||
@if (
|
||||
changePasswordForm.get('password').errors?.['uppercase'] ||
|
||||
changePasswordForm.get('password').errors?.['number'] ||
|
||||
changePasswordForm.get('password').errors?.['repeated'] ||
|
||||
changePasswordForm.get('password').errors?.['specialChar'] ||
|
||||
changePasswordForm.get('password').errors?.['minlength']
|
||||
) {
|
||||
<p>
|
||||
{{ 'labels.commons.Password validation' | translate: { minchar: minPasswordLength } }}
|
||||
</p>
|
||||
}
|
||||
</mat-error>
|
||||
|
||||
<mifosx-input-password
|
||||
@@ -30,9 +30,11 @@
|
||||
</div>
|
||||
|
||||
<div class="error">
|
||||
<p *ngIf="changePasswordForm.get('repeatPassword').errors?.['notequal']">
|
||||
{{ 'Passwords do not match' | translateKey: 'inputs' }}
|
||||
</p>
|
||||
@if (changePasswordForm.get('repeatPassword').errors?.['notequal']) {
|
||||
<p>
|
||||
{{ 'Passwords do not match' | translateKey: 'inputs' }}
|
||||
</p>
|
||||
}
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/** Angular Imports */
|
||||
import { Component, OnInit, Inject } from '@angular/core';
|
||||
import { Component, OnInit, inject } from '@angular/core';
|
||||
import {
|
||||
MatDialogRef,
|
||||
MAT_DIALOG_DATA,
|
||||
@@ -41,6 +41,11 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
|
||||
]
|
||||
})
|
||||
export class ChangePasswordDialogComponent implements OnInit {
|
||||
dialogRef = inject<MatDialogRef<ChangePasswordDialogComponent>>(MatDialogRef);
|
||||
data = inject(MAT_DIALOG_DATA);
|
||||
private formBuilder = inject(UntypedFormBuilder);
|
||||
private passwordsUtility = inject(PasswordsUtility);
|
||||
|
||||
minPasswordLength: number = environment.minPasswordLength | 12;
|
||||
|
||||
/** Change Password Form */
|
||||
@@ -51,17 +56,6 @@ export class ChangePasswordDialogComponent implements OnInit {
|
||||
'password'
|
||||
];
|
||||
|
||||
/**
|
||||
* @param {MatDialogRef} dialogRef Component reference to dialog.
|
||||
* @param {any} data Provides any data.
|
||||
*/
|
||||
constructor(
|
||||
public dialogRef: MatDialogRef<ChangePasswordDialogComponent>,
|
||||
@Inject(MAT_DIALOG_DATA) public data: any,
|
||||
private formBuilder: UntypedFormBuilder,
|
||||
private passwordsUtility: PasswordsUtility
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.createChangePasswordForm();
|
||||
}
|
||||
@@ -78,7 +72,8 @@ export class ChangePasswordDialogComponent implements OnInit {
|
||||
'',
|
||||
[
|
||||
Validators.required,
|
||||
this.confirmPassword('password')]
|
||||
this.confirmPassword('password')
|
||||
]
|
||||
]
|
||||
},
|
||||
{ updateOn: 'blur' }
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/** Angular Imports */
|
||||
import { Component, OnInit, Inject } from '@angular/core';
|
||||
import { Component, OnInit, inject } from '@angular/core';
|
||||
import {
|
||||
MatDialogRef,
|
||||
MAT_DIALOG_DATA,
|
||||
@@ -30,16 +30,11 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
|
||||
]
|
||||
})
|
||||
export class ConfirmationDialogComponent implements OnInit {
|
||||
dialogRef = inject<MatDialogRef<ConfirmationDialogComponent>>(MatDialogRef);
|
||||
private dialogs = inject(Dialogs);
|
||||
data = inject<DialogData>(MAT_DIALOG_DATA);
|
||||
|
||||
color: string;
|
||||
/**
|
||||
* @param {MatDialogRef} dialogRef Component reference to dialog.
|
||||
* @param {any} data Provides a deleteContext.
|
||||
*/
|
||||
constructor(
|
||||
public dialogRef: MatDialogRef<ConfirmationDialogComponent>,
|
||||
private dialogs: Dialogs,
|
||||
@Inject(MAT_DIALOG_DATA) public data: DialogData
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.setColor();
|
||||
|
||||
@@ -2,7 +2,6 @@ import { Component, Input } from '@angular/core';
|
||||
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
|
||||
|
||||
/* eslint-disable @angular-eslint/component-selector */
|
||||
/* eslint-disable @angular-eslint/prefer-standalone */
|
||||
@Component({
|
||||
selector: 'ngx-mat-datetime-picker',
|
||||
template: `
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/** Angular Imports */
|
||||
import { Component, OnInit, Inject } from '@angular/core';
|
||||
import { Component, OnInit, inject } from '@angular/core';
|
||||
import {
|
||||
MatDialogRef,
|
||||
MAT_DIALOG_DATA,
|
||||
@@ -28,12 +28,6 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
|
||||
]
|
||||
})
|
||||
export class DeleteDialogComponent {
|
||||
/**
|
||||
* @param {MatDialogRef} dialogRef Component reference to dialog.
|
||||
* @param {any} data Provides a deleteContext.
|
||||
*/
|
||||
constructor(
|
||||
public dialogRef: MatDialogRef<DeleteDialogComponent>,
|
||||
@Inject(MAT_DIALOG_DATA) public data: any
|
||||
) {}
|
||||
dialogRef = inject<MatDialogRef<DeleteDialogComponent>>(MatDialogRef);
|
||||
data = inject(MAT_DIALOG_DATA);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/** Angular Imports */
|
||||
import { Component, Inject } from '@angular/core';
|
||||
import { Component, inject } from '@angular/core';
|
||||
import {
|
||||
MatDialogRef,
|
||||
MAT_DIALOG_DATA,
|
||||
@@ -28,12 +28,6 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
|
||||
]
|
||||
})
|
||||
export class DisableDialogComponent {
|
||||
/**
|
||||
* @param {MatDialogRef} dialogRef Component reference to dialog.
|
||||
* @param {any} data Provides a disableContext.
|
||||
*/
|
||||
constructor(
|
||||
public dialogRef: MatDialogRef<DisableDialogComponent>,
|
||||
@Inject(MAT_DIALOG_DATA) public data: any
|
||||
) {}
|
||||
dialogRef = inject<MatDialogRef<DisableDialogComponent>>(MatDialogRef);
|
||||
data = inject(MAT_DIALOG_DATA);
|
||||
}
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
<mat-form-field class="flex-28">
|
||||
<mat-label>{{ getLabelText() }}</mat-label>
|
||||
<mat-select placeholder="{{ getPlaceHolderText() }}" formControlName="controlSelect">
|
||||
<mat-option *ngFor="let option of selectOptions" [value]="option.id">
|
||||
{{ option.value | translateKey: 'catalogs' }}
|
||||
</mat-option>
|
||||
@for (option of selectOptions; track option) {
|
||||
<mat-option [value]="option.id">
|
||||
{{ option.value | translateKey: 'catalogs' }}
|
||||
</mat-option>
|
||||
}
|
||||
</mat-select>
|
||||
<button *ngIf="controlSelect" matSuffix mat-icon-button aria-label="Clear" (click)="clearProperty($event)">
|
||||
<mat-icon>{{ 'labels.buttons.Close' | translate }}</mat-icon>
|
||||
</button>
|
||||
@if (controlSelect) {
|
||||
<button matSuffix mat-icon-button aria-label="Clear" (click)="clearProperty($event)">
|
||||
<mat-icon>{{ 'labels.buttons.Close' | translate }}</mat-icon>
|
||||
</button>
|
||||
}
|
||||
</mat-form-field>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Component, Input } from '@angular/core';
|
||||
import { Component, Input, inject } from '@angular/core';
|
||||
import { UntypedFormControl, ReactiveFormsModule } from '@angular/forms';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { MatIconButton } from '@angular/material/button';
|
||||
@@ -16,14 +16,14 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
|
||||
]
|
||||
})
|
||||
export class DropdownComponent {
|
||||
private translateService = inject(TranslateService);
|
||||
|
||||
@Input() placeHolderText: string;
|
||||
@Input() labelText: string;
|
||||
@Input() selectOptions: any[] = [];
|
||||
@Input() controlSelect: UntypedFormControl;
|
||||
@Input() required: boolean;
|
||||
|
||||
constructor(private translateService: TranslateService) {}
|
||||
|
||||
getPlaceHolderText(): string {
|
||||
return this.placeHolderText ? this.translateService.instant('labels.inputs.' + this.placeHolderText) : '';
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/** Angular Imports */
|
||||
import { Component, Inject } from '@angular/core';
|
||||
import { Component, inject } from '@angular/core';
|
||||
import {
|
||||
MatDialogRef,
|
||||
MAT_DIALOG_DATA,
|
||||
@@ -28,12 +28,6 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
|
||||
]
|
||||
})
|
||||
export class EnableDialogComponent {
|
||||
/**
|
||||
* @param {MatDialogRef} dialogRef Component reference to dialog.
|
||||
* @param {any} data Provides a enableContext.
|
||||
*/
|
||||
constructor(
|
||||
public dialogRef: MatDialogRef<EnableDialogComponent>,
|
||||
@Inject(MAT_DIALOG_DATA) public data: any
|
||||
) {}
|
||||
dialogRef = inject<MatDialogRef<EnableDialogComponent>>(MatDialogRef);
|
||||
data = inject(MAT_DIALOG_DATA);
|
||||
}
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
<span (mouseenter)="mouseEnter()" (mouseleave)="mouseLeave()">
|
||||
<span class="m-l-5" *ngIf="displayL && iconVisible" (click)="copyValue()"
|
||||
><b><fa-icon icon="copy" size="sm" title="{{ 'labels.text.Copy Account Number' | translate }}"></fa-icon></b
|
||||
></span>
|
||||
@if (displayL && iconVisible) {
|
||||
<span class="m-l-5" (click)="copyValue()"
|
||||
><b><fa-icon icon="copy" size="sm" title="{{ 'labels.text.Copy Account Number' | translate }}"></fa-icon></b
|
||||
></span>
|
||||
}
|
||||
<span class="m-l-5"
|
||||
><b>{{ entityName }}</b></span
|
||||
>
|
||||
<span class="m-l-3" *ngIf="displayR && iconVisible" (click)="copyValue()"
|
||||
><b><fa-icon icon="copy" size="sm" title="{{ 'labels.text.Copy Account Number' | translate }}"></fa-icon></b
|
||||
></span>
|
||||
@if (displayR && iconVisible) {
|
||||
<span class="m-l-3" (click)="copyValue()"
|
||||
><b><fa-icon icon="copy" size="sm" title="{{ 'labels.text.Copy Account Number' | translate }}"></fa-icon></b
|
||||
></span>
|
||||
}
|
||||
</span>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Component, Input, OnInit } from '@angular/core';
|
||||
import { Component, Input, OnInit, inject } from '@angular/core';
|
||||
import { Clipboard } from '@angular/cdk/clipboard';
|
||||
import { FaIconComponent } from '@fortawesome/angular-fontawesome';
|
||||
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
|
||||
@@ -13,6 +13,8 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
|
||||
]
|
||||
})
|
||||
export class EntityNameComponent implements OnInit {
|
||||
private clipboard = inject(Clipboard);
|
||||
|
||||
@Input() entityName: string;
|
||||
@Input() display = 'right';
|
||||
|
||||
@@ -20,8 +22,6 @@ export class EntityNameComponent implements OnInit {
|
||||
displayL = false;
|
||||
displayR = true;
|
||||
|
||||
constructor(private clipboard: Clipboard) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.displayL = this.display === 'left';
|
||||
this.displayR = this.display === 'right';
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
<h1 mat-dialog-title>{{ 'Error Log' | translate }}</h1>
|
||||
|
||||
<div mat-dialog-content>
|
||||
<p *ngIf="!showAsCode">{{ displayData }}</p>
|
||||
<span *ngIf="showAsCode" [innerHTML]="sanitizedData"></span>
|
||||
@if (!showAsCode) {
|
||||
<p>{{ displayData }}</p>
|
||||
}
|
||||
@if (showAsCode) {
|
||||
<span [innerHTML]="sanitizedData"></span>
|
||||
}
|
||||
</div>
|
||||
|
||||
<mat-dialog-actions align="left">
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/** Angular Imports. */
|
||||
import { Component, OnInit, Inject, SecurityContext } from '@angular/core';
|
||||
import { Component, OnInit, SecurityContext, inject } from '@angular/core';
|
||||
import {
|
||||
MatDialogRef,
|
||||
MAT_DIALOG_DATA,
|
||||
@@ -26,17 +26,19 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
|
||||
]
|
||||
})
|
||||
export class ErrorDialogComponent {
|
||||
dialogRef = inject<MatDialogRef<ErrorDialogComponent>>(MatDialogRef);
|
||||
data = inject(MAT_DIALOG_DATA);
|
||||
private sanitizer = inject(DomSanitizer);
|
||||
|
||||
showAsCode = false;
|
||||
/**
|
||||
* @param {MatDialogRef} dialogRef Component reference to dialog.
|
||||
* @param {unknown} data Provides any data.
|
||||
* @param {DomSanitizer} sanitizer Service to sanitize HTML content.
|
||||
*/
|
||||
constructor(
|
||||
public dialogRef: MatDialogRef<ErrorDialogComponent>,
|
||||
@Inject(MAT_DIALOG_DATA) public data: unknown,
|
||||
private sanitizer: DomSanitizer
|
||||
) {
|
||||
constructor() {
|
||||
const data = this.data;
|
||||
|
||||
// Guard for non-string data to avoid runtime error
|
||||
this.showAsCode = typeof data === 'string' && data.startsWith('<pre><code>');
|
||||
}
|
||||
|
||||
@@ -1,16 +1,24 @@
|
||||
<span (mouseenter)="mouseEnter()" (mouseleave)="mouseLeave()" *ngIf="!emptyValue">
|
||||
<span (click)="copyValue()" *ngIf="displayL && iconVisible"
|
||||
><fa-icon icon="copy" size="sm" title="Copy External Id"></fa-icon
|
||||
></span>
|
||||
<span class="m-l-3" *ngIf="displayL && !completed && iconVisible && isLongValue()" (click)="showValue()"
|
||||
><fa-icon icon="eye" size="sm" [title]="externalId"></fa-icon
|
||||
></span>
|
||||
<span class="m-l-5" *ngIf="!completed" (click)="showValue()">{{ externalId | externalIdentifier }}</span>
|
||||
<span *ngIf="completed" (click)="showValue()">{{ externalId }}</span>
|
||||
<span class="m-l-5" *ngIf="displayR && !completed && iconVisible && isLongValue()" (click)="showValue()"
|
||||
><fa-icon icon="eye" size="sm" [title]="externalId"></fa-icon
|
||||
></span>
|
||||
<span class="m-l-3" (click)="copyValue()" *ngIf="displayR && iconVisible"
|
||||
><fa-icon icon="copy" size="sm" title="Copy External Id"></fa-icon
|
||||
></span>
|
||||
</span>
|
||||
@if (!emptyValue) {
|
||||
<span (mouseenter)="mouseEnter()" (mouseleave)="mouseLeave()">
|
||||
@if (displayL && iconVisible) {
|
||||
<span (click)="copyValue()"><fa-icon icon="copy" size="sm" title="Copy External Id"></fa-icon></span>
|
||||
}
|
||||
@if (displayL && !completed && iconVisible && isLongValue()) {
|
||||
<span class="m-l-3" (click)="showValue()"><fa-icon icon="eye" size="sm" [title]="externalId"></fa-icon></span>
|
||||
}
|
||||
@if (!completed) {
|
||||
<span class="m-l-5" (click)="showValue()">{{ externalId | externalIdentifier }}</span>
|
||||
}
|
||||
@if (completed) {
|
||||
<span (click)="showValue()">{{ externalId }}</span>
|
||||
}
|
||||
@if (displayR && !completed && iconVisible && isLongValue()) {
|
||||
<span class="m-l-5" (click)="showValue()"><fa-icon icon="eye" size="sm" [title]="externalId"></fa-icon></span>
|
||||
}
|
||||
@if (displayR && iconVisible) {
|
||||
<span class="m-l-3" (click)="copyValue()"
|
||||
><fa-icon icon="copy" size="sm" title="Copy External Id"></fa-icon
|
||||
></span>
|
||||
}
|
||||
</span>
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Component, Input, OnInit } from '@angular/core';
|
||||
import { Component, Input, OnInit, inject } from '@angular/core';
|
||||
import { Clipboard } from '@angular/cdk/clipboard';
|
||||
import { AlertService } from 'app/core/alert/alert.service';
|
||||
import { FaIconComponent } from '@fortawesome/angular-fontawesome';
|
||||
@@ -16,6 +16,9 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
|
||||
]
|
||||
})
|
||||
export class ExternalIdentifierComponent implements OnInit {
|
||||
private clipboard = inject(Clipboard);
|
||||
private alertService = inject(AlertService);
|
||||
|
||||
@Input() externalId: string;
|
||||
@Input() completed = false;
|
||||
@Input() display = 'right';
|
||||
@@ -25,11 +28,6 @@ export class ExternalIdentifierComponent implements OnInit {
|
||||
displayR = true;
|
||||
emptyValue = false;
|
||||
|
||||
constructor(
|
||||
private clipboard: Clipboard,
|
||||
private alertService: AlertService
|
||||
) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.emptyValue = !this.externalId || this.externalId === '';
|
||||
this.displayL = this.display === 'left';
|
||||
|
||||
@@ -1,35 +1,41 @@
|
||||
<div class="layout-column m-b-20 f12" ngClass="{{ styleClass }}" id="footer" *ngIf="displayBackEndInfo">
|
||||
<mat-divider class="divider align-center"></mat-divider>
|
||||
<div class="layout-column m-b-20 content-wrapper footer-center">
|
||||
<table class="versions">
|
||||
<tr>
|
||||
<td class="footer-content">Mifos</td>
|
||||
<td class="right footer-content">
|
||||
{{ versions.mifos }} - <b>{{ hash }}</b>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="footer-content">{{ 'labels.text.Fineract' | translate }}</td>
|
||||
<td class="right footer-content">
|
||||
{{ versions.fineract.version }} - <b>{{ versions.fineract.hash }}</b>
|
||||
</td>
|
||||
</tr>
|
||||
<tr *ngIf="displayBackEndInfo">
|
||||
<td class="footer-content">{{ 'labels.inputs.Server' | translate }}</td>
|
||||
<td class="right footer-content">
|
||||
{{ server }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr *ngIf="isBusinessDateDefined">
|
||||
<td class="footer-content">{{ 'labels.text.Current Business Date' | translate }}:</td>
|
||||
<td class="center footer-content business-date">
|
||||
<b>{{ businessDate | date: 'EEEE, MMMM dd, y' }}</b>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
@if (displayBackEndInfo) {
|
||||
<div class="layout-column m-b-20 f12" ngClass="{{ styleClass }}" id="footer">
|
||||
<mat-divider class="divider align-center"></mat-divider>
|
||||
<div class="layout-column m-b-20 content-wrapper footer-center">
|
||||
<table class="versions">
|
||||
<tr>
|
||||
<td class="footer-content">Mifos</td>
|
||||
<td class="right footer-content">
|
||||
{{ versions.mifos }} - <b>{{ hash }}</b>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="footer-content">{{ 'labels.text.Fineract' | translate }}</td>
|
||||
<td class="right footer-content">
|
||||
{{ versions.fineract.version }} - <b>{{ versions.fineract.hash }}</b>
|
||||
</td>
|
||||
</tr>
|
||||
@if (displayBackEndInfo) {
|
||||
<tr>
|
||||
<td class="footer-content">{{ 'labels.inputs.Server' | translate }}</td>
|
||||
<td class="right footer-content">
|
||||
{{ server }}
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
@if (isBusinessDateDefined) {
|
||||
<tr>
|
||||
<td class="footer-content">{{ 'labels.text.Current Business Date' | translate }}:</td>
|
||||
<td class="center footer-content business-date">
|
||||
<b>{{ businessDate | date: 'EEEE, MMMM dd, y' }}</b>
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
</table>
|
||||
</div>
|
||||
<mat-divider class="divider align-center"></mat-divider>
|
||||
</div>
|
||||
<mat-divider class="divider align-center"></mat-divider>
|
||||
</div>
|
||||
}
|
||||
<div class="layout-column m-b-20 copy-label">
|
||||
<p class="footer-content align-center">{{ 'APP_NAME' | translate }} {{ 'labels.text.by' | translate }} Mifos</p>
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/** Angular Imports */
|
||||
import { Component, Input, OnDestroy, OnInit } from '@angular/core';
|
||||
import { Component, Input, OnDestroy, OnInit, inject } from '@angular/core';
|
||||
import { Alert } from 'app/core/alert/alert.model';
|
||||
import { AlertService } from 'app/core/alert/alert.service';
|
||||
import { AuthenticationService } from 'app/core/authentication/authentication.service';
|
||||
@@ -11,7 +11,7 @@ import { VersionService } from 'app/system/version.service';
|
||||
/** Environment Configuration */
|
||||
import { environment } from '../../../environments/environment';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { NgIf, NgClass, DatePipe } from '@angular/common';
|
||||
import { NgClass, DatePipe } from '@angular/common';
|
||||
import { MatDivider } from '@angular/material/divider';
|
||||
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
|
||||
|
||||
@@ -30,6 +30,13 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
|
||||
]
|
||||
})
|
||||
export class FooterComponent implements OnInit, OnDestroy {
|
||||
private systemService = inject(SystemService);
|
||||
private settingsService = inject(SettingsService);
|
||||
private authenticationService = inject(AuthenticationService);
|
||||
private alertService = inject(AlertService);
|
||||
private dateUtils = inject(Dates);
|
||||
private versionService = inject(VersionService);
|
||||
|
||||
@Input() styleClass: string = '';
|
||||
|
||||
/** Mifos X version. */
|
||||
@@ -54,14 +61,7 @@ export class FooterComponent implements OnInit, OnDestroy {
|
||||
|
||||
displayBackEndInfo = true;
|
||||
|
||||
constructor(
|
||||
private systemService: SystemService,
|
||||
private settingsService: SettingsService,
|
||||
private authenticationService: AuthenticationService,
|
||||
private alertService: AlertService,
|
||||
private dateUtils: Dates,
|
||||
private versionService: VersionService
|
||||
) {
|
||||
constructor() {
|
||||
this.displayBackEndInfo = environment.displayBackEndInfo === 'true';
|
||||
}
|
||||
|
||||
|
||||
@@ -8,9 +8,11 @@
|
||||
'responsive-column'
|
||||
]"
|
||||
>
|
||||
<div *ngFor="let formfield of formfields" [ngClass]="'flex-' + layout.flex + ' responsive-flex-full'">
|
||||
<mifosx-formfield [formfield]="formfield" [form]="form" class="flex-fill"></mifosx-formfield>
|
||||
</div>
|
||||
@for (formfield of formfields; track formfield) {
|
||||
<div [ngClass]="'flex-' + layout.flex + ' responsive-flex-full'">
|
||||
<mifosx-formfield [formfield]="formfield" [form]="form" class="flex-fill"></mifosx-formfield>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
<mat-dialog-actions class="layout-row layout-xs-column layout-align-center gap-2percent" align="end">
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Component, OnInit, Inject } from '@angular/core';
|
||||
import { Component, OnInit, inject } from '@angular/core';
|
||||
import {
|
||||
MatDialogRef,
|
||||
MAT_DIALOG_DATA,
|
||||
@@ -13,7 +13,7 @@ import { FormfieldBase } from './formfield/model/formfield-base';
|
||||
|
||||
import { FormGroupService } from './form-group.service';
|
||||
import { CdkScrollable } from '@angular/cdk/scrolling';
|
||||
import { NgClass, NgFor } from '@angular/common';
|
||||
import { NgClass } from '@angular/common';
|
||||
import { FormfieldComponent } from './formfield/formfield.component';
|
||||
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
|
||||
|
||||
@@ -35,6 +35,10 @@ const layoutGap = 2;
|
||||
]
|
||||
})
|
||||
export class FormDialogComponent implements OnInit {
|
||||
dialogRef = inject<MatDialogRef<FormDialogComponent>>(MatDialogRef);
|
||||
data = inject(MAT_DIALOG_DATA);
|
||||
private formGroupService = inject(FormGroupService);
|
||||
|
||||
layout: {
|
||||
columns: number;
|
||||
columnWidth?: number;
|
||||
@@ -54,11 +58,9 @@ export class FormDialogComponent implements OnInit {
|
||||
formfields: FormfieldBase[];
|
||||
pristine: boolean;
|
||||
|
||||
constructor(
|
||||
public dialogRef: MatDialogRef<FormDialogComponent>,
|
||||
@Inject(MAT_DIALOG_DATA) public data: any,
|
||||
private formGroupService: FormGroupService
|
||||
) {
|
||||
constructor() {
|
||||
const data = this.data;
|
||||
|
||||
this.dialogRef.disableClose = data.disableClose !== undefined ? data.disableClose : true;
|
||||
this.formfields = data.formfields.sort(
|
||||
(formfieldA: FormfieldBase, formfieldB: FormfieldBase) => formfieldA.order - formfieldB.order
|
||||
|
||||
@@ -1,80 +1,95 @@
|
||||
<div [formGroup]="form" class="flex-fill">
|
||||
<div *ngIf="formfield.controlType === 'input' || formfield.controlType === 'select'" class="flex-fill">
|
||||
<mat-form-field class="flex-fill">
|
||||
<mat-label>{{ formfield.label }}</mat-label>
|
||||
@if (formfield.controlType === 'input' || formfield.controlType === 'select') {
|
||||
<div class="flex-fill">
|
||||
<mat-form-field class="flex-fill">
|
||||
<mat-label>{{ formfield.label }}</mat-label>
|
||||
@if (formfield.controlType === 'input') {
|
||||
<input
|
||||
[type]="formfield.type"
|
||||
matInput
|
||||
[formControlName]="formfield.controlName"
|
||||
[required]="formfield.required"
|
||||
/>
|
||||
}
|
||||
@if (form.controls[formfield.controlName].hasError('max')) {
|
||||
<mat-error>
|
||||
<strong>{{ 'labels.commons.Maximum Value must be' | translate }} {{ formfield.max }}</strong>
|
||||
</mat-error>
|
||||
}
|
||||
@if (form.controls[formfield.controlName].hasError('min')) {
|
||||
<mat-error>
|
||||
<strong>{{ 'labels.commons.Minimum Value must be' | translate }} {{ formfield.min }}</strong>
|
||||
</mat-error>
|
||||
}
|
||||
@if (formfield.controlType === 'select') {
|
||||
<mat-select [formControlName]="formfield.controlName" [required]="formfield.required">
|
||||
@for (option of formfield.options.data; track option) {
|
||||
<mat-option [value]="option[formfield.options.value]">
|
||||
{{ option[formfield.options.label] }}
|
||||
</mat-option>
|
||||
}
|
||||
</mat-select>
|
||||
}
|
||||
@if (form.controls[formfield.controlName].hasError('required')) {
|
||||
<mat-error>
|
||||
{{ formfield.label }} {{ 'labels.commons.is' | translate }}
|
||||
<strong>{{ 'labels.commons.required' | translate }}</strong>
|
||||
</mat-error>
|
||||
}
|
||||
</mat-form-field>
|
||||
</div>
|
||||
}
|
||||
|
||||
@if (formfield.controlType === 'datepicker') {
|
||||
<mat-form-field class="flex-fill" Fill (click)="datePicker.open()">
|
||||
<mat-label>{{ formfield.label }}</mat-label>
|
||||
<input
|
||||
*ngIf="formfield.controlType === 'input'"
|
||||
[type]="formfield.type"
|
||||
matInput
|
||||
[matDatepicker]="datePicker"
|
||||
[min]="formfield.minDate"
|
||||
[max]="formfield.maxDate"
|
||||
[formControlName]="formfield.controlName"
|
||||
[required]="formfield.required"
|
||||
/>
|
||||
<mat-error *ngIf="form.controls[formfield.controlName].hasError('max')">
|
||||
<strong>{{ 'labels.commons.Maximum Value must be' | translate }} {{ formfield.max }}</strong>
|
||||
</mat-error>
|
||||
<mat-error *ngIf="form.controls[formfield.controlName].hasError('min')">
|
||||
<strong>{{ 'labels.commons.Minimum Value must be' | translate }} {{ formfield.min }}</strong>
|
||||
</mat-error>
|
||||
<mat-datepicker-toggle matSuffix [for]="datePicker"></mat-datepicker-toggle>
|
||||
<mat-datepicker #datePicker></mat-datepicker>
|
||||
@if (form.controls[formfield.controlName].hasError('required')) {
|
||||
<mat-error>
|
||||
{{ formfield.label }} {{ 'labels.commons.is' | translate }}
|
||||
<strong>{{ 'labels.commons.required' | translate }}</strong>
|
||||
</mat-error>
|
||||
}
|
||||
</mat-form-field>
|
||||
}
|
||||
|
||||
<mat-select
|
||||
*ngIf="formfield.controlType === 'select'"
|
||||
@if (formfield.controlType === 'datetimepicker') {
|
||||
<mat-form-field class="flex-fill" Fill (click)="datePicker.open()">
|
||||
<mat-label>{{ formfield.label }}</mat-label>
|
||||
<input
|
||||
matInput
|
||||
type="datetime-local"
|
||||
[min]="formfield.minDate"
|
||||
[max]="formfield.maxDate"
|
||||
[formControlName]="formfield.controlName"
|
||||
[required]="formfield.required"
|
||||
>
|
||||
<mat-option *ngFor="let option of formfield.options.data" [value]="option[formfield.options.value]">
|
||||
{{ option[formfield.options.label] }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
|
||||
<mat-error *ngIf="form.controls[formfield.controlName].hasError('required')">
|
||||
{{ formfield.label }} {{ 'labels.commons.is' | translate }}
|
||||
<strong>{{ 'labels.commons.required' | translate }}</strong>
|
||||
</mat-error>
|
||||
/>
|
||||
@if (form.controls[formfield.controlName].hasError('required')) {
|
||||
<mat-error>
|
||||
{{ formfield.label }} {{ 'labels.commons.is' | translate }}
|
||||
<strong>{{ 'labels.commons.required' | translate }}</strong>
|
||||
</mat-error>
|
||||
}
|
||||
</mat-form-field>
|
||||
</div>
|
||||
}
|
||||
|
||||
<mat-form-field class="flex-fill" Fill *ngIf="formfield.controlType === 'datepicker'" (click)="datePicker.open()">
|
||||
<mat-label>{{ formfield.label }}</mat-label>
|
||||
<input
|
||||
matInput
|
||||
[matDatepicker]="datePicker"
|
||||
[min]="formfield.minDate"
|
||||
[max]="formfield.maxDate"
|
||||
@if (formfield.controlType === 'checkbox') {
|
||||
<mat-checkbox
|
||||
labelPosition="before"
|
||||
[checked]="formfield.value"
|
||||
[formControlName]="formfield.controlName"
|
||||
[required]="formfield.required"
|
||||
/>
|
||||
<mat-datepicker-toggle matSuffix [for]="datePicker"></mat-datepicker-toggle>
|
||||
<mat-datepicker #datePicker></mat-datepicker>
|
||||
<mat-error *ngIf="form.controls[formfield.controlName].hasError('required')">
|
||||
{{ formfield.label }} {{ 'labels.commons.is' | translate }}
|
||||
<strong>{{ 'labels.commons.required' | translate }}</strong>
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field class="flex-fill" Fill *ngIf="formfield.controlType === 'datetimepicker'" (click)="datePicker.open()">
|
||||
<mat-label>{{ formfield.label }}</mat-label>
|
||||
<input
|
||||
matInput
|
||||
type="datetime-local"
|
||||
[min]="formfield.minDate"
|
||||
[max]="formfield.maxDate"
|
||||
[formControlName]="formfield.controlName"
|
||||
[required]="formfield.required"
|
||||
/>
|
||||
<mat-error *ngIf="form.controls[formfield.controlName].hasError('required')">
|
||||
{{ formfield.label }} {{ 'labels.commons.is' | translate }}
|
||||
<strong>{{ 'labels.commons.required' | translate }}</strong>
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-checkbox
|
||||
*ngIf="formfield.controlType === 'checkbox'"
|
||||
labelPosition="before"
|
||||
[checked]="formfield.value"
|
||||
[formControlName]="formfield.controlName"
|
||||
[required]="formfield.required"
|
||||
>
|
||||
{{ formfield.label }}
|
||||
</mat-checkbox>
|
||||
>
|
||||
{{ formfield.label }}
|
||||
</mat-checkbox>
|
||||
}
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/** Angular Imports */
|
||||
import { NgModule } from '@angular/core';
|
||||
import { NgModule, inject } from '@angular/core';
|
||||
|
||||
/** Angular Font Awesome Imports */
|
||||
import { FontAwesomeModule, FaIconLibrary } from '@fortawesome/angular-fontawesome';
|
||||
@@ -125,7 +125,9 @@ import {
|
||||
exports: [FontAwesomeModule]
|
||||
})
|
||||
export class IconsModule {
|
||||
constructor(library: FaIconLibrary) {
|
||||
constructor() {
|
||||
const library = inject(FaIconLibrary);
|
||||
|
||||
library.addIcons(
|
||||
faAnchor,
|
||||
faArchive,
|
||||
|
||||
@@ -1,52 +1,72 @@
|
||||
<mat-form-field appearance="fill" class="flex-100 input-container" *ngIf="isRequired">
|
||||
<mat-label>{{ 'labels.inputs.' + inputLabel | translate }}</mat-label>
|
||||
<div class="input-group">
|
||||
<span>{{ currency.code }}</span>
|
||||
@if (isRequired) {
|
||||
<mat-form-field appearance="fill" class="flex-100 input-container">
|
||||
<mat-label>{{ 'labels.inputs.' + inputLabel | translate }}</mat-label>
|
||||
<div class="input-group">
|
||||
<span>{{ currency.code }}</span>
|
||||
<input
|
||||
mifosxFormatAmount="{{ currency.code }}:{{ currency.displaySymbol }}"
|
||||
class="right-input"
|
||||
[formControl]="inputFormControl"
|
||||
(keypress)="numberOnly($event)"
|
||||
required
|
||||
matInput
|
||||
(blur)="displayHint = false"
|
||||
(focus)="displayHint = true"
|
||||
/>
|
||||
</div>
|
||||
@if (inputFormControl.hasError('required')) {
|
||||
<mat-error>
|
||||
{{ 'labels.inputs.' + inputLabel | translate }} {{ 'labels.commons.is' | translate }}
|
||||
<strong>{{ 'labels.commons.required' | translate }}</strong>
|
||||
</mat-error>
|
||||
}
|
||||
@if (displayHint) {
|
||||
<mat-hint class="right-hint">{{
|
||||
inputFormControl.value | currency: currency.code : currency.displaySymbol : '1.2-2'
|
||||
}}</mat-hint>
|
||||
}
|
||||
@if (minVal && inputFormControl.hasError('min')) {
|
||||
<mat-error>
|
||||
{{ 'labels.inputs.Amount' | translate }} {{ 'labels.commons.Must be at least' | translate }} {{ minVal }}
|
||||
</mat-error>
|
||||
}
|
||||
@if (maxVal && inputFormControl.hasError('max')) {
|
||||
<mat-error>
|
||||
{{ 'labels.inputs.Amount' | translate }} {{ 'labels.commons.Must be less or equal to' | translate }}
|
||||
{{ maxVal }}
|
||||
</mat-error>
|
||||
}
|
||||
</mat-form-field>
|
||||
}
|
||||
@if (!isRequired) {
|
||||
<mat-form-field appearance="fill" class="flex-100">
|
||||
<mat-label>{{ 'labels.inputs.' + inputLabel | translate }}</mat-label>
|
||||
<span matTextSuffix class="m-l-10">{{ currency.code }}</span>
|
||||
<span class="flex-auto"></span>
|
||||
<input
|
||||
mifosxFormatAmount="{{ currency.code }}:{{ currency.displaySymbol }}"
|
||||
class="right-input"
|
||||
[formControl]="inputFormControl"
|
||||
(keypress)="numberOnly($event)"
|
||||
required
|
||||
matInput
|
||||
(blur)="displayHint = false"
|
||||
(focus)="displayHint = true"
|
||||
/>
|
||||
</div>
|
||||
<mat-error *ngIf="inputFormControl.hasError('required')">
|
||||
{{ 'labels.inputs.' + inputLabel | translate }} {{ 'labels.commons.is' | translate }}
|
||||
<strong>{{ 'labels.commons.required' | translate }}</strong>
|
||||
</mat-error>
|
||||
<mat-hint class="right-hint" *ngIf="displayHint">{{
|
||||
inputFormControl.value | currency: currency.code : currency.displaySymbol : '1.2-2'
|
||||
}}</mat-hint>
|
||||
<mat-error *ngIf="minVal && inputFormControl.hasError('min')">
|
||||
{{ 'labels.inputs.Amount' | translate }} {{ 'labels.commons.Must be at least' | translate }} {{ minVal }}
|
||||
</mat-error>
|
||||
<mat-error *ngIf="maxVal && inputFormControl.hasError('max')">
|
||||
{{ 'labels.inputs.Amount' | translate }} {{ 'labels.commons.Must be less or equal to' | translate }} {{ maxVal }}
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
<mat-form-field appearance="fill" class="flex-100" *ngIf="!isRequired">
|
||||
<mat-label>{{ 'labels.inputs.' + inputLabel | translate }}</mat-label>
|
||||
<span matTextSuffix class="m-l-10">{{ currency.code }}</span>
|
||||
<span class="flex-auto"></span>
|
||||
<input
|
||||
mifosxFormatAmount="{{ currency.code }}:{{ currency.displaySymbol }}"
|
||||
class="right-input"
|
||||
[formControl]="inputFormControl"
|
||||
(keypress)="numberOnly($event)"
|
||||
matInput
|
||||
(blur)="displayHint = false"
|
||||
(focus)="displayHint = true"
|
||||
/>
|
||||
<mat-hint class="right-hint" *ngIf="displayHint">{{
|
||||
inputFormControl.value | currency: currency.code : currency.displaySymbol : '1.2-2'
|
||||
}}</mat-hint>
|
||||
<mat-error *ngIf="minVal && inputFormControl.hasError('min')">
|
||||
{{ 'labels.inputs.Amount' | translate }} {{ 'labels.commons.Must be at least' | translate }} {{ minVal }}
|
||||
</mat-error>
|
||||
<mat-error *ngIf="maxVal && inputFormControl.hasError('max')">
|
||||
{{ 'labels.inputs.Amount' | translate }} {{ 'labels.commons.Must be less or equal to' | translate }} {{ maxVal }}
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
@if (displayHint) {
|
||||
<mat-hint class="right-hint">{{
|
||||
inputFormControl.value | currency: currency.code : currency.displaySymbol : '1.2-2'
|
||||
}}</mat-hint>
|
||||
}
|
||||
@if (minVal && inputFormControl.hasError('min')) {
|
||||
<mat-error>
|
||||
{{ 'labels.inputs.Amount' | translate }} {{ 'labels.commons.Must be at least' | translate }} {{ minVal }}
|
||||
</mat-error>
|
||||
}
|
||||
@if (maxVal && inputFormControl.hasError('max')) {
|
||||
<mat-error>
|
||||
{{ 'labels.inputs.Amount' | translate }} {{ 'labels.commons.Must be less or equal to' | translate }}
|
||||
{{ maxVal }}
|
||||
</mat-error>
|
||||
}
|
||||
</mat-form-field>
|
||||
}
|
||||
|
||||
@@ -11,6 +11,10 @@
|
||||
[value]="value"
|
||||
/>
|
||||
<mat-icon matSuffix (click)="onVisibilityClick($event)">{{ icon }}</mat-icon>
|
||||
<mat-error *ngIf="ngControl.hasError('required')">{{ label }} is a required field.</mat-error>
|
||||
<mat-error *ngIf="ngControl.hasError(customErrorName)">{{ customErrorMessage }}</mat-error>
|
||||
@if (ngControl.hasError('required')) {
|
||||
<mat-error>{{ label }} is a required field.</mat-error>
|
||||
}
|
||||
@if (ngControl.hasError(customErrorName)) {
|
||||
<mat-error>{{ customErrorMessage }}</mat-error>
|
||||
}
|
||||
</mat-form-field>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Component, Input, Optional, Self, ViewChild } from '@angular/core';
|
||||
import { Component, Input, ViewChild, inject } from '@angular/core';
|
||||
import {
|
||||
AbstractControl,
|
||||
ControlValueAccessor,
|
||||
@@ -22,6 +22,8 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
|
||||
]
|
||||
})
|
||||
export class InputPasswordComponent implements ControlValueAccessor, ErrorStateMatcher {
|
||||
ngControl = inject(NgControl, { optional: true, self: true });
|
||||
|
||||
disabled = false;
|
||||
|
||||
icon = 'visibility_off';
|
||||
@@ -61,7 +63,9 @@ export class InputPasswordComponent implements ControlValueAccessor, ErrorStateM
|
||||
|
||||
private _visible = false;
|
||||
|
||||
constructor(@Optional() @Self() public ngControl: NgControl) {
|
||||
constructor() {
|
||||
const ngControl = this.ngControl;
|
||||
|
||||
if (ngControl !== null) {
|
||||
ngControl.valueAccessor = this;
|
||||
}
|
||||
|
||||
@@ -2,25 +2,33 @@
|
||||
|
||||
<div mat-dialog-content>
|
||||
<div class="layout-column gap-2px">
|
||||
<ng-container *ngFor="let item of buttonConfig.buttonCombinations">
|
||||
@for (item of buttonConfig.buttonCombinations; track item) {
|
||||
<mat-divider [inset]="true"></mat-divider>
|
||||
<div class="flex-fill flex-50">
|
||||
<span class="flex-50">
|
||||
<span *ngIf="item.ctrlKey">
|
||||
<span class="modifier-key">{{ 'labels.inputs.Ctrl' | translate }}</span> +
|
||||
</span>
|
||||
<span *ngIf="item.shiftKey">
|
||||
<span class="modifier-key">{{ 'labels.inputs.Shift' | translate }}</span> +
|
||||
</span>
|
||||
<span *ngIf="item.altKey">
|
||||
<span class="modifier-key">{{ 'labels.inputs.Alt' | translate }}</span> +
|
||||
</span>
|
||||
<span *ngIf="item.key">
|
||||
<span class="modifier-key">{{ item.key }}</span></span
|
||||
>
|
||||
@if (item.ctrlKey) {
|
||||
<span>
|
||||
<span class="modifier-key">{{ 'labels.inputs.Ctrl' | translate }}</span> +
|
||||
</span>
|
||||
}
|
||||
@if (item.shiftKey) {
|
||||
<span>
|
||||
<span class="modifier-key">{{ 'labels.inputs.Shift' | translate }}</span> +
|
||||
</span>
|
||||
}
|
||||
@if (item.altKey) {
|
||||
<span>
|
||||
<span class="modifier-key">{{ 'labels.inputs.Alt' | translate }}</span> +
|
||||
</span>
|
||||
}
|
||||
@if (item.key) {
|
||||
<span>
|
||||
<span class="modifier-key">{{ item.key }}</span></span
|
||||
>
|
||||
}
|
||||
</span>
|
||||
<span class="flex-50">{{ item.title }}</span>
|
||||
</div>
|
||||
</ng-container>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/** Angular Imports */
|
||||
import { Component, OnInit, Inject } from '@angular/core';
|
||||
import { Component, OnInit, inject } from '@angular/core';
|
||||
import { MatDialogRef, MAT_DIALOG_DATA, MatDialogTitle, MatDialogContent } from '@angular/material/dialog';
|
||||
import { KeyboardShortcutsConfiguration } from '../../keyboards-shortcut-config';
|
||||
import { CdkScrollable } from '@angular/cdk/scrolling';
|
||||
@@ -21,13 +21,9 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
|
||||
]
|
||||
})
|
||||
export class KeyboardShortcutsDialogComponent implements OnInit {
|
||||
buttonConfig: KeyboardShortcutsConfiguration;
|
||||
dialogRef = inject<MatDialogRef<KeyboardShortcutsDialogComponent>>(MatDialogRef);
|
||||
|
||||
/**
|
||||
* @param {MatDialogRef} dialogRef Component reference to dialog.
|
||||
* @param {any} data Provides a deleteContext.
|
||||
*/
|
||||
constructor(public dialogRef: MatDialogRef<KeyboardShortcutsDialogComponent>) {}
|
||||
buttonConfig: KeyboardShortcutsConfiguration;
|
||||
|
||||
ngOnInit() {
|
||||
this.dialogRef.updateSize(`800px`);
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
<mat-form-field id="language-selector" class="m-l-10">
|
||||
<mat-label>{{ 'labels.inputs.Language' | translate }}</mat-label>
|
||||
<mat-select [formControl]="languageSelector" (selectionChange)="setLanguage()" class="languageselector">
|
||||
<mat-option *ngFor="let language of languages" [value]="language">
|
||||
{{ 'languages.' + language | translate }}
|
||||
</mat-option>
|
||||
@for (language of languages; track language) {
|
||||
<mat-option [value]="language">
|
||||
{{ 'languages.' + language | translate }}
|
||||
</mat-option>
|
||||
}
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/** Angular Imports */
|
||||
import { Component } from '@angular/core';
|
||||
import { Component, inject } from '@angular/core';
|
||||
import { UntypedFormControl, ReactiveFormsModule } from '@angular/forms';
|
||||
|
||||
/** Custom Services */
|
||||
@@ -22,6 +22,9 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
|
||||
]
|
||||
})
|
||||
export class LanguageSelectorComponent {
|
||||
private translateService = inject(TranslateService);
|
||||
private settingsService = inject(SettingsService);
|
||||
|
||||
/** Language selector form control. */
|
||||
languageSelector = new UntypedFormControl();
|
||||
|
||||
@@ -29,10 +32,7 @@ export class LanguageSelectorComponent {
|
||||
* Sets the language of the application in the selector on initial setup.
|
||||
* @param {TranslateService} translateService Translate Service.
|
||||
*/
|
||||
constructor(
|
||||
private translateService: TranslateService,
|
||||
private settingsService: SettingsService
|
||||
) {
|
||||
constructor() {
|
||||
this.languageSelector.setValue(this.currentLanguage);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,13 @@
|
||||
<span (mouseenter)="mouseEnter()" (mouseleave)="mouseLeave()" *ngIf="!emptyValue">
|
||||
<span class="m-l-3" *ngIf="isLongValue()" (click)="showValue()"
|
||||
><fa-icon icon="eye" size="sm" [title]="textValue"></fa-icon
|
||||
></span>
|
||||
<span class="m-l-5" *ngIf="isLongValue()" (click)="showValue()">{{ textValue | truncateText: printChars }}...</span>
|
||||
<span class="m-l-5" *ngIf="!isLongValue()" (click)="showValue()">{{ textValue }}</span>
|
||||
</span>
|
||||
@if (!emptyValue) {
|
||||
<span (mouseenter)="mouseEnter()" (mouseleave)="mouseLeave()">
|
||||
@if (isLongValue()) {
|
||||
<span class="m-l-3" (click)="showValue()"><fa-icon icon="eye" size="sm" [title]="textValue"></fa-icon></span>
|
||||
}
|
||||
@if (isLongValue()) {
|
||||
<span class="m-l-5" (click)="showValue()">{{ textValue | truncateText: printChars }}...</span>
|
||||
}
|
||||
@if (!isLongValue()) {
|
||||
<span class="m-l-5" (click)="showValue()">{{ textValue }}</span>
|
||||
}
|
||||
</span>
|
||||
}
|
||||
|
||||
@@ -13,29 +13,26 @@
|
||||
</button>
|
||||
|
||||
<mat-menu class="mifosx-notifications-menu" #notificationsMenu="matMenu" [overlapTrigger]="false">
|
||||
<div *ngIf="unreadNotifications.length === 0" class="layout-column align-center-center no-notifications">
|
||||
<mat-icon class="no-notifications-icon">
|
||||
<span class="material-icons">{{ 'labels.menus.Notifications' | translate }}</span>
|
||||
</mat-icon>
|
||||
<p>{{ 'labels.text.No notifications' | translate }}</p>
|
||||
</div>
|
||||
@if (unreadNotifications.length === 0) {
|
||||
<div class="layout-column align-center-center no-notifications">
|
||||
<mat-icon class="no-notifications-icon">
|
||||
<span class="material-icons">{{ 'labels.menus.Notifications' | translate }}</span>
|
||||
</mat-icon>
|
||||
<p>{{ 'labels.text.No notifications' | translate }}</p>
|
||||
</div>
|
||||
}
|
||||
|
||||
<button
|
||||
mat-menu-item
|
||||
class="unread"
|
||||
*ngFor="let notification of unreadNotifications"
|
||||
[routerLink]="[routeMap[notification.objectType], notification.objectId]"
|
||||
>
|
||||
{{ notification.content }}*<br />
|
||||
<span class="time">[{{ notification.createdAt }}]</span>
|
||||
</button>
|
||||
@for (notification of unreadNotifications; track notification) {
|
||||
<button mat-menu-item class="unread" [routerLink]="[routeMap[notification.objectType], notification.objectId]">
|
||||
{{ notification.content }}*<br />
|
||||
<span class="time">[{{ notification.createdAt }}]</span>
|
||||
</button>
|
||||
}
|
||||
|
||||
<button
|
||||
mat-menu-item
|
||||
*ngFor="let notification of displayedReadNotifications"
|
||||
[routerLink]="[routeMap[notification.objectType], notification.objectId]"
|
||||
>
|
||||
{{ notification.content }}<br />
|
||||
<span class="time">[{{ notification.createdAt }}]</span>
|
||||
</button>
|
||||
@for (notification of displayedReadNotifications; track notification) {
|
||||
<button mat-menu-item [routerLink]="[routeMap[notification.objectType], notification.objectId]">
|
||||
{{ notification.content }}<br />
|
||||
<span class="time">[{{ notification.createdAt }}]</span>
|
||||
</button>
|
||||
}
|
||||
</mat-menu>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/** Angular Imports */
|
||||
import { Component, OnInit, OnDestroy, ViewEncapsulation } from '@angular/core';
|
||||
import { Component, OnInit, OnDestroy, ViewEncapsulation, inject } from '@angular/core';
|
||||
|
||||
/** RxJS Imports */
|
||||
import { forkJoin } from 'rxjs';
|
||||
@@ -36,6 +36,8 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
|
||||
]
|
||||
})
|
||||
export class NotificationsTrayComponent implements OnInit, OnDestroy {
|
||||
notificationsService = inject(NotificationsService);
|
||||
|
||||
/** Wait time between API status calls 60 seg */
|
||||
waitTime = environment.waitTimeForNotifications || 60;
|
||||
/** Read Notifications */
|
||||
@@ -67,10 +69,11 @@ export class NotificationsTrayComponent implements OnInit, OnDestroy {
|
||||
/**
|
||||
* @param {NotificationsService} notificationsService Notifications Service
|
||||
*/
|
||||
constructor(public notificationsService: NotificationsService) {
|
||||
constructor() {
|
||||
forkJoin([
|
||||
this.notificationsService.getNotifications(true, 9),
|
||||
this.notificationsService.getNotifications(false, 9)]).subscribe((response: any[]) => {
|
||||
this.notificationsService.getNotifications(false, 9)
|
||||
]).subscribe((response: any[]) => {
|
||||
this.readNotifications = response[0].pageItems;
|
||||
this.unreadNotifications = response[1].pageItems;
|
||||
this.setNotifications();
|
||||
|
||||
@@ -1,19 +1,22 @@
|
||||
<div class="flex-100 layout-row">
|
||||
<div *ngIf="searchVisible" class="search-bar flex-90 layout-row hide-lt-sm" [@fadeInOut]>
|
||||
<mat-form-field class="search flex-45">
|
||||
<mat-label>{{ 'labels.text.Search' | translate }}</mat-label>
|
||||
<input matInput type="text" [formControl]="query" (keydown.enter)="search()" />
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field class="resource flex-50">
|
||||
<mat-label>{{ 'labels.inputs.Resource' | translate }}</mat-label>
|
||||
<mat-select [formControl]="resource">
|
||||
<mat-option *ngFor="let option of resourceOptions" [value]="option.value">
|
||||
{{ 'labels.text.' + option.name | translate }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
@if (searchVisible) {
|
||||
<div class="search-bar flex-90 layout-row hide-lt-sm" [@fadeInOut]>
|
||||
<mat-form-field class="search flex-45">
|
||||
<mat-label>{{ 'labels.text.Search' | translate }}</mat-label>
|
||||
<input matInput type="text" [formControl]="query" (keydown.enter)="search()" />
|
||||
</mat-form-field>
|
||||
<mat-form-field class="resource flex-50">
|
||||
<mat-label>{{ 'labels.inputs.Resource' | translate }}</mat-label>
|
||||
<mat-select [formControl]="resource">
|
||||
@for (option of resourceOptions; track option) {
|
||||
<mat-option [value]="option.value">
|
||||
{{ 'labels.text.' + option.name | translate }}
|
||||
</mat-option>
|
||||
}
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
}
|
||||
|
||||
<div class="search-icon flex-10">
|
||||
<button mat-icon-button (click)="toggleSearchVisibility()" class="hide-lt-sm">
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/** Angular Imports */
|
||||
import { Component } from '@angular/core';
|
||||
import { Component, inject } from '@angular/core';
|
||||
import { style, animate, transition, trigger } from '@angular/animations';
|
||||
import { Router } from '@angular/router';
|
||||
import { UntypedFormControl, ReactiveFormsModule } from '@angular/forms';
|
||||
@@ -19,12 +19,12 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
|
||||
trigger('fadeInOut', [
|
||||
transition(':enter', [
|
||||
style({ opacity: 0 }),
|
||||
animate(500, style({ opacity: 1 }))]),
|
||||
animate(500, style({ opacity: 1 }))
|
||||
]),
|
||||
transition(':leave', [
|
||||
animate(500, style({ opacity: 0 }))])
|
||||
|
||||
animate(500, style({ opacity: 0 }))
|
||||
])
|
||||
])
|
||||
|
||||
],
|
||||
imports: [
|
||||
...STANDALONE_SHARED_IMPORTS,
|
||||
@@ -34,6 +34,8 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
|
||||
]
|
||||
})
|
||||
export class SearchToolComponent {
|
||||
private router = inject(Router);
|
||||
|
||||
/** Query Form Control */
|
||||
query = new UntypedFormControl('');
|
||||
/** Resource Form Control */
|
||||
@@ -72,7 +74,7 @@ export class SearchToolComponent {
|
||||
/**
|
||||
* @param {Router} router Router
|
||||
*/
|
||||
constructor(private router: Router) {
|
||||
constructor() {
|
||||
this.resource.patchValue('clients,clientIdentifiers,groups,savings,shares,loans');
|
||||
}
|
||||
|
||||
|
||||
@@ -1,31 +1,36 @@
|
||||
<mat-form-field id="server-selector" *ngIf="existMoreThanOneServer">
|
||||
<mat-label>{{ 'labels.inputs.Server' | translate }}</mat-label>
|
||||
<mat-select
|
||||
[formControl]="serverSelector"
|
||||
(selectionChange)="setServer()"
|
||||
panelClass="server-panel"
|
||||
panelWidth="null"
|
||||
>
|
||||
<div class="sticky">
|
||||
<form [formGroup]="form" (ngSubmit)="addNewServer()">
|
||||
<div class="actions">
|
||||
<mat-form-field class="ml align-start">
|
||||
<span matPrefix><mat-icon>language</mat-icon></span>
|
||||
<mat-label>{{ 'labels.placeholders.Add new server' | translate }}</mat-label>
|
||||
<input matInput type="text" autocomplete="off" formControlName="url" />
|
||||
<mat-error *ngIf="form.controls.url.hasError('required')">
|
||||
{{ 'labels.inputs.Url' | translate }} <strong>{{ 'labels.commons.is required' | translate }}</strong>
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
<button type="submit" [disabled]="form.invalid" class="ml" mat-raised-button color="primary">
|
||||
{{ 'labels.buttons.Add' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<mat-option *ngFor="let server of servers" [value]="server">
|
||||
{{ server }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
@if (existMoreThanOneServer) {
|
||||
<mat-form-field id="server-selector">
|
||||
<mat-label>{{ 'labels.inputs.Server' | translate }}</mat-label>
|
||||
<mat-select
|
||||
[formControl]="serverSelector"
|
||||
(selectionChange)="setServer()"
|
||||
panelClass="server-panel"
|
||||
panelWidth="null"
|
||||
>
|
||||
<div class="sticky">
|
||||
<form [formGroup]="form" (ngSubmit)="addNewServer()">
|
||||
<div class="actions">
|
||||
<mat-form-field class="ml align-start">
|
||||
<span matPrefix><mat-icon>language</mat-icon></span>
|
||||
<mat-label>{{ 'labels.placeholders.Add new server' | translate }}</mat-label>
|
||||
<input matInput type="text" autocomplete="off" formControlName="url" />
|
||||
@if (form.controls.url.hasError('required')) {
|
||||
<mat-error>
|
||||
{{ 'labels.inputs.Url' | translate }} <strong>{{ 'labels.commons.is required' | translate }}</strong>
|
||||
</mat-error>
|
||||
}
|
||||
</mat-form-field>
|
||||
<button type="submit" [disabled]="form.invalid" class="ml" mat-raised-button color="primary">
|
||||
{{ 'labels.buttons.Add' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@for (server of servers; track server) {
|
||||
<mat-option [value]="server">
|
||||
{{ server }}
|
||||
</mat-option>
|
||||
}
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/** Angular Imports */
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { Component, OnInit, inject } from '@angular/core';
|
||||
import { UntypedFormControl, ReactiveFormsModule } from '@angular/forms';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { UntypedFormBuilder, Validators } from '@angular/forms';
|
||||
@@ -23,6 +23,10 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
|
||||
]
|
||||
})
|
||||
export class ServerSelectorComponent implements OnInit {
|
||||
private settingsService = inject(SettingsService);
|
||||
dialog = inject(MatDialog);
|
||||
private formBuilder = inject(UntypedFormBuilder);
|
||||
|
||||
/** Input server. */
|
||||
form: any;
|
||||
|
||||
@@ -35,15 +39,6 @@ export class ServerSelectorComponent implements OnInit {
|
||||
/** Server list to show */
|
||||
existMoreThanOneServer = false;
|
||||
|
||||
/**
|
||||
* @param {SettingsService} settingsService Settings Service
|
||||
*/
|
||||
constructor(
|
||||
private settingsService: SettingsService,
|
||||
public dialog: MatDialog,
|
||||
private formBuilder: UntypedFormBuilder
|
||||
) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.servers = this.settingsService.servers;
|
||||
this.existMoreThanOneServer = this.servers && this.servers.length > 1;
|
||||
|
||||
@@ -145,7 +145,6 @@ import { DatetimePickerStubComponent } from './datetime-picker-stub/datetime-pic
|
||||
DropdownComponent,
|
||||
InputAmountComponent,
|
||||
DatetimePickerStubComponent // Export stub for datetime picker
|
||||
|
||||
]
|
||||
})
|
||||
export class SharedModule {}
|
||||
|
||||
+37
-32
@@ -10,47 +10,52 @@
|
||||
</button>
|
||||
</span>
|
||||
<ng-container *mifosxHasPermission="'DELETE_' + datatableName">
|
||||
<span *ngIf="isSelected">
|
||||
<button class="delete-button" mat-raised-button color="warn" (click)="deleteSelected()">
|
||||
<fa-icon icon="trash" class="m-r-10"></fa-icon>
|
||||
{{ 'labels.buttons.Delete Selected' | translate }}
|
||||
</button>
|
||||
</span>
|
||||
@if (isSelected) {
|
||||
<span>
|
||||
<button class="delete-button" mat-raised-button color="warn" (click)="deleteSelected()">
|
||||
<fa-icon icon="trash" class="m-r-10"></fa-icon>
|
||||
{{ 'labels.buttons.Delete Selected' | translate }}
|
||||
</button>
|
||||
</span>
|
||||
}
|
||||
</ng-container>
|
||||
<ng-container *mifosxHasPermission="'DELETE_' + datatableName">
|
||||
<span *ngIf="datatableData.length > 0">
|
||||
<button class="delete-button" mat-raised-button color="warn" (click)="delete()">
|
||||
<fa-icon icon="trash" class="m-r-10"></fa-icon>
|
||||
{{ 'labels.buttons.Delete All' | translate }}
|
||||
</button>
|
||||
</span>
|
||||
@if (datatableData.length > 0) {
|
||||
<span>
|
||||
<button class="delete-button" mat-raised-button color="warn" (click)="delete()">
|
||||
<fa-icon icon="trash" class="m-r-10"></fa-icon>
|
||||
{{ 'labels.buttons.Delete All' | translate }}
|
||||
</button>
|
||||
</span>
|
||||
}
|
||||
</ng-container>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="m-t-10">
|
||||
<table #dataTable mat-table [dataSource]="datatableData" class="mat-elevation-z1 m-b-25">
|
||||
<ng-container *ngFor="let datatableColumn of datatableColumns; let i = index" [matColumnDef]="datatableColumn">
|
||||
<ng-container *ngIf="i === 0">
|
||||
<th mat-header-cell *matHeaderCellDef></th>
|
||||
<td mat-cell *matCellDef="let data">
|
||||
<mat-checkbox
|
||||
class="center"
|
||||
(click)="$event.stopPropagation()"
|
||||
(change)="$event ? itemToggle(data) : null"
|
||||
[checked]="selection.isSelected(data)"
|
||||
>
|
||||
</mat-checkbox>
|
||||
</td>
|
||||
@for (datatableColumn of datatableColumns; track datatableColumn; let i = $index) {
|
||||
<ng-container [matColumnDef]="datatableColumn">
|
||||
@if (i === 0) {
|
||||
<th mat-header-cell *matHeaderCellDef></th>
|
||||
<td mat-cell *matCellDef="let data">
|
||||
<mat-checkbox
|
||||
class="center"
|
||||
(click)="$event.stopPropagation()"
|
||||
(change)="$event ? itemToggle(data) : null"
|
||||
[checked]="selection.isSelected(data)"
|
||||
>
|
||||
</mat-checkbox>
|
||||
</td>
|
||||
}
|
||||
@if (i > 0) {
|
||||
<th mat-header-cell class="right" *matHeaderCellDef>{{ getInputName(datatableColumn) }}</th>
|
||||
<td mat-cell class="right" *matCellDef="let data" [ngClass]="isToDelete(data)">
|
||||
{{ formatValue(data, datatableColumn) }}
|
||||
</td>
|
||||
}
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="i > 0">
|
||||
<th mat-header-cell class="right" *matHeaderCellDef>{{ getInputName(datatableColumn) }}</th>
|
||||
<td mat-cell class="right" *matCellDef="let data" [ngClass]="isToDelete(data)">
|
||||
{{ formatValue(data, datatableColumn) }}
|
||||
</td>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
}
|
||||
|
||||
<tr mat-header-row *matHeaderRowDef="datatableColumns"></tr>
|
||||
<tr mat-row *matRowDef="let row; columns: datatableColumns"></tr>
|
||||
|
||||
+12
-23
@@ -1,6 +1,6 @@
|
||||
import { SelectionModel } from '@angular/cdk/collections';
|
||||
import { DecimalPipe, NgIf, NgFor, NgClass } from '@angular/common';
|
||||
import { Component, Input, OnChanges, OnDestroy, OnInit, SimpleChanges, ViewChild } from '@angular/core';
|
||||
import { DecimalPipe, NgClass } from '@angular/common';
|
||||
import { Component, Input, OnChanges, OnDestroy, OnInit, SimpleChanges, ViewChild, inject } from '@angular/core';
|
||||
import { MatCheckboxChange as MatCheckboxChange, MatCheckbox } from '@angular/material/checkbox';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import {
|
||||
@@ -51,6 +51,16 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
|
||||
]
|
||||
})
|
||||
export class DatatableMultiRowComponent implements OnInit, OnDestroy, OnChanges {
|
||||
private route = inject(ActivatedRoute);
|
||||
private dateUtils = inject(Dates);
|
||||
private systemService = inject(SystemService);
|
||||
private settingsService = inject(SettingsService);
|
||||
private dialog = inject(MatDialog);
|
||||
private datatables = inject(Datatables);
|
||||
private dateFormat = inject(DateFormatPipe);
|
||||
private dateTimeFormat = inject(DatetimeFormatPipe);
|
||||
private numberFormat = inject(DecimalPipe);
|
||||
|
||||
SELECT_NAME_FIELD = 'select';
|
||||
/** Data Object */
|
||||
@Input() dataObject: any;
|
||||
@@ -74,27 +84,6 @@ export class DatatableMultiRowComponent implements OnInit, OnDestroy, OnChanges
|
||||
/** Data Table Reference */
|
||||
@ViewChild('dataTable') dataTableRef: MatTable<Element>;
|
||||
|
||||
/**
|
||||
* Fetches center Id from parent route params.
|
||||
* @param {ActivatedRoute} route Activated Route.
|
||||
* @param {Dates} dateUtils Date Utils.
|
||||
* @param {SystemService} systemService system Service.
|
||||
* @param {SettingsService} settingsService Settings Service.
|
||||
* @param {MatDialog} dialog Mat Dialog.
|
||||
* @param {Datatables} datatables Datatable utils
|
||||
*/
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
private dateUtils: Dates,
|
||||
private systemService: SystemService,
|
||||
private settingsService: SettingsService,
|
||||
private dialog: MatDialog,
|
||||
private datatables: Datatables,
|
||||
private dateFormat: DateFormatPipe,
|
||||
private dateTimeFormat: DatetimeFormatPipe,
|
||||
private numberFormat: DecimalPipe
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Fetches data table name from route params.
|
||||
* subscription is required due to asynchronicity.
|
||||
|
||||
+83
-61
@@ -1,70 +1,92 @@
|
||||
<div class="tab-container mat-typography">
|
||||
<h3>{{ datatableName }}</h3>
|
||||
<div class="layout-row align-end m-b-20">
|
||||
<button mat-raised-button color="primary" (click)="add()" *ngIf="!dataObject.data[0]">
|
||||
<fa-icon icon="plus" class="m-r-10"></fa-icon>{{ 'labels.buttons.Add' | translate }}
|
||||
</button>
|
||||
<button mat-raised-button color="primary" (click)="edit()" *ngIf="dataObject.data[0]">
|
||||
<fa-icon icon="edit" class="m-r-10"></fa-icon>{{ 'labels.buttons.Edit' | translate }}
|
||||
</button>
|
||||
<button class="delete-button" mat-raised-button color="warn" (click)="delete()" *ngIf="dataObject.data[0]">
|
||||
<fa-icon icon="trash" class="m-r-10"></fa-icon>{{ 'labels.buttons.Delete' | translate }}
|
||||
</button>
|
||||
@if (!dataObject.data[0]) {
|
||||
<button mat-raised-button color="primary" (click)="add()">
|
||||
<fa-icon icon="plus" class="m-r-10"></fa-icon>{{ 'labels.buttons.Add' | translate }}
|
||||
</button>
|
||||
}
|
||||
@if (dataObject.data[0]) {
|
||||
<button mat-raised-button color="primary" (click)="edit()">
|
||||
<fa-icon icon="edit" class="m-r-10"></fa-icon>{{ 'labels.buttons.Edit' | translate }}
|
||||
</button>
|
||||
}
|
||||
@if (dataObject.data[0]) {
|
||||
<button class="delete-button" mat-raised-button color="warn" (click)="delete()">
|
||||
<fa-icon icon="trash" class="m-r-10"></fa-icon>{{ 'labels.buttons.Delete' | translate }}
|
||||
</button>
|
||||
}
|
||||
</div>
|
||||
|
||||
<mat-divider></mat-divider>
|
||||
|
||||
<div class="m-t-10" *ngIf="dataObject.data.length > 0">
|
||||
<div
|
||||
class="flex-fill"
|
||||
*ngFor="let columnHeader of dataObject.columnHeaders; let i = index"
|
||||
[ngClass]="setAttributeClass(columnHeader.columnName)"
|
||||
>
|
||||
<div class="mat-body-strong left flex-40">
|
||||
{{ columnHeader.columnDisplayName }}
|
||||
{{ getInputName(columnHeader.columnName) }}
|
||||
</div>
|
||||
|
||||
<div [ngSwitch]="getColumnType(columnHeader.columnDisplayType, columnHeader.columnType)" class="right flex-60">
|
||||
<span *ngSwitchCase="'DATE'">
|
||||
{{ dataObject.data[0].row[i] | dateFormat }}
|
||||
</span>
|
||||
<span *ngSwitchCase="'DATETIME'">
|
||||
{{ dataObject.data[0].row[i] | datetimeFormat }}
|
||||
</span>
|
||||
<span *ngSwitchCase="'INTEGER'">
|
||||
{{ dataObject.data[0].row[i] }}
|
||||
</span>
|
||||
<span *ngSwitchCase="'DECIMAL'">
|
||||
{{ dataObject.data[0].row[i] | formatNumber }}
|
||||
</span>
|
||||
<span *ngSwitchCase="'TEXT'" class="long-text">
|
||||
{{ dataObject.data[0].row[i] }}
|
||||
</span>
|
||||
<textarea
|
||||
*ngSwitchCase="'JSON'"
|
||||
cdkTextareaAutosize="true"
|
||||
cdkAutosizeMaxRows="20"
|
||||
cdkAutosizeMinRows="1"
|
||||
class="json-textarea"
|
||||
[innerHTML]="dataObject.data[0].row[i].value | prettyPrint"
|
||||
>
|
||||
</textarea>
|
||||
<span *ngSwitchDefault>
|
||||
<span class="m-r-5" *ngIf="isValidUrl(dataObject.data[0].row[i])">
|
||||
<button
|
||||
mat-icon-button
|
||||
matTooltip="{{ 'tooltips.View Link' | translate }}"
|
||||
(click)="openSite(dataObject.data[0].row[i])"
|
||||
matTooltipPosition="right"
|
||||
class="small-icon"
|
||||
>
|
||||
<fa-icon icon="eye" size="lg"></fa-icon>
|
||||
</button>
|
||||
</span>
|
||||
{{ dataObject.data[0].row[i] }}
|
||||
</span>
|
||||
</div>
|
||||
@if (dataObject.data.length > 0) {
|
||||
<div class="m-t-10">
|
||||
@for (columnHeader of dataObject.columnHeaders; track columnHeader; let i = $index) {
|
||||
<div class="flex-fill" [ngClass]="setAttributeClass(columnHeader.columnName)">
|
||||
<div class="mat-body-strong left flex-40">
|
||||
{{ columnHeader.columnDisplayName }}
|
||||
{{ getInputName(columnHeader.columnName) }}
|
||||
</div>
|
||||
<div class="right flex-60">
|
||||
@switch (getColumnType(columnHeader.columnDisplayType, columnHeader.columnType)) {
|
||||
@case ('DATE') {
|
||||
<span>
|
||||
{{ dataObject.data[0].row[i] | dateFormat }}
|
||||
</span>
|
||||
}
|
||||
@case ('DATETIME') {
|
||||
<span>
|
||||
{{ dataObject.data[0].row[i] | datetimeFormat }}
|
||||
</span>
|
||||
}
|
||||
@case ('INTEGER') {
|
||||
<span>
|
||||
{{ dataObject.data[0].row[i] }}
|
||||
</span>
|
||||
}
|
||||
@case ('DECIMAL') {
|
||||
<span>
|
||||
{{ dataObject.data[0].row[i] | formatNumber }}
|
||||
</span>
|
||||
}
|
||||
@case ('TEXT') {
|
||||
<span class="long-text">
|
||||
{{ dataObject.data[0].row[i] }}
|
||||
</span>
|
||||
}
|
||||
@case ('JSON') {
|
||||
<textarea
|
||||
cdkTextareaAutosize="true"
|
||||
cdkAutosizeMaxRows="20"
|
||||
cdkAutosizeMinRows="1"
|
||||
class="json-textarea"
|
||||
[innerHTML]="dataObject.data[0].row[i].value | prettyPrint"
|
||||
>
|
||||
</textarea>
|
||||
}
|
||||
@default {
|
||||
<span>
|
||||
@if (isValidUrl(dataObject.data[0].row[i])) {
|
||||
<span class="m-r-5">
|
||||
<button
|
||||
mat-icon-button
|
||||
matTooltip="{{ 'tooltips.View Link' | translate }}"
|
||||
(click)="openSite(dataObject.data[0].row[i])"
|
||||
matTooltipPosition="right"
|
||||
class="small-icon"
|
||||
>
|
||||
<fa-icon icon="eye" size="lg"></fa-icon>
|
||||
</button>
|
||||
</span>
|
||||
}
|
||||
{{ dataObject.data[0].row[i] }}
|
||||
</span>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
+9
-21
@@ -1,4 +1,4 @@
|
||||
import { Component, Input, OnInit } from '@angular/core';
|
||||
import { Component, Input, OnInit, inject } from '@angular/core';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { Datatables } from 'app/core/utils/datatables';
|
||||
@@ -8,7 +8,7 @@ import { DeleteDialogComponent } from 'app/shared/delete-dialog/delete-dialog.co
|
||||
import { FormDialogComponent } from 'app/shared/form-dialog/form-dialog.component';
|
||||
import { FormfieldBase } from 'app/shared/form-dialog/formfield/model/formfield-base';
|
||||
import { SystemService } from 'app/system/system.service';
|
||||
import { NgIf, NgFor, NgClass, NgSwitch, NgSwitchCase, NgSwitchDefault } from '@angular/common';
|
||||
import { NgClass } from '@angular/common';
|
||||
import { MatButton, MatIconButton } from '@angular/material/button';
|
||||
import { FaIconComponent } from '@fortawesome/angular-fontawesome';
|
||||
import { MatDivider } from '@angular/material/divider';
|
||||
@@ -29,10 +29,7 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
|
||||
FaIconComponent,
|
||||
MatDivider,
|
||||
NgClass,
|
||||
NgSwitch,
|
||||
NgSwitchCase,
|
||||
CdkTextareaAutosize,
|
||||
NgSwitchDefault,
|
||||
MatIconButton,
|
||||
MatTooltip,
|
||||
DateFormatPipe,
|
||||
@@ -42,27 +39,18 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
|
||||
]
|
||||
})
|
||||
export class DatatableSingleRowComponent implements OnInit {
|
||||
private route = inject(ActivatedRoute);
|
||||
private dateUtils = inject(Dates);
|
||||
private dialog = inject(MatDialog);
|
||||
private settingsService = inject(SettingsService);
|
||||
private datatables = inject(Datatables);
|
||||
private systemService = inject(SystemService);
|
||||
|
||||
@Input() dataObject: any;
|
||||
@Input() entityId: string;
|
||||
@Input() entityType: string;
|
||||
datatableName: string;
|
||||
|
||||
/**
|
||||
* @param {ActivatedRoute} route Activated Route.
|
||||
* @param {Dates} dateUtils Date Utils.
|
||||
* @param {SystemService} systemService System Service.
|
||||
* @param {SettingsService} settingsService Settings Service
|
||||
* @param {Datatables} datatables Datatable utils
|
||||
*/
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
private dateUtils: Dates,
|
||||
private dialog: MatDialog,
|
||||
private settingsService: SettingsService,
|
||||
private datatables: Datatables,
|
||||
private systemService: SystemService
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.route.params.subscribe((routeParams: any) => {
|
||||
this.datatableName = routeParams.datatableName;
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
<div>
|
||||
<mifosx-datatable-multi-row
|
||||
*ngIf="multiRowDatatableFlag"
|
||||
[entityType]="entityType"
|
||||
[entityId]="entityId"
|
||||
[dataObject]="entityDatatable"
|
||||
></mifosx-datatable-multi-row>
|
||||
<mifosx-datatable-single-row
|
||||
*ngIf="!multiRowDatatableFlag"
|
||||
[entityType]="entityType"
|
||||
[entityId]="entityId"
|
||||
[dataObject]="entityDatatable"
|
||||
></mifosx-datatable-single-row>
|
||||
@if (multiRowDatatableFlag) {
|
||||
<mifosx-datatable-multi-row
|
||||
[entityType]="entityType"
|
||||
[entityId]="entityId"
|
||||
[dataObject]="entityDatatable"
|
||||
></mifosx-datatable-multi-row>
|
||||
}
|
||||
@if (!multiRowDatatableFlag) {
|
||||
<mifosx-datatable-single-row
|
||||
[entityType]="entityType"
|
||||
[entityId]="entityId"
|
||||
[dataObject]="entityDatatable"
|
||||
></mifosx-datatable-single-row>
|
||||
}
|
||||
</div>
|
||||
|
||||
@@ -9,59 +9,71 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div *ngIf="entityDocuments?.length; else empty">
|
||||
<div class="document-grid">
|
||||
<div class="document-card" *ngFor="let document of entityDocuments; trackBy: trackByDocumentId">
|
||||
<div
|
||||
class="thumb"
|
||||
[class.clickable]="isPreviewable(document)"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
[attr.aria-label]="('labels.buttons.Preview' | translate) + ': ' + document.name"
|
||||
(keydown.enter)="isPreviewable(document) && openPreview(document)"
|
||||
(keydown.space)="isPreviewable(document) && openPreview(document)"
|
||||
(click)="isPreviewable(document) && openPreview(document)"
|
||||
>
|
||||
<ng-container *ngIf="previewThumbnails[document.id]; else placeholder">
|
||||
<img [src]="previewThumbnails[document.id]" [alt]="document.name" [title]="document.name" loading="lazy" />
|
||||
</ng-container>
|
||||
<ng-template #placeholder>
|
||||
<div class="placeholder">
|
||||
<fa-icon icon="file"></fa-icon>
|
||||
<span>{{ document.fileName || document.name }}</span>
|
||||
</div>
|
||||
</ng-template>
|
||||
<div class="preview-overlay" *ngIf="isPreviewable(document)">
|
||||
<fa-icon icon="eye"></fa-icon>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="title">{{ document.name }}</div>
|
||||
<div class="meta" *ngIf="document.fileName">{{ document.fileName }}</div>
|
||||
<div class="description" *ngIf="document.description">{{ document.description }}</div>
|
||||
<div class="actions">
|
||||
<button
|
||||
mat-icon-button
|
||||
color="warn"
|
||||
(click)="deleteDocument(document.id, document.name)"
|
||||
title="Delete"
|
||||
[attr.aria-label]="'labels.buttons.Delete' | translate"
|
||||
*mifosxHasPermission="'DELETE_DOCUMENT'"
|
||||
@if (entityDocuments?.length) {
|
||||
<div>
|
||||
<div class="document-grid">
|
||||
@for (document of entityDocuments; track trackByDocumentId($index, document)) {
|
||||
<div class="document-card">
|
||||
<div
|
||||
class="thumb"
|
||||
[class.clickable]="isPreviewable(document)"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
[attr.aria-label]="('labels.buttons.Preview' | translate) + ': ' + document.name"
|
||||
(keydown.enter)="isPreviewable(document) && openPreview(document)"
|
||||
(keydown.space)="isPreviewable(document) && openPreview(document)"
|
||||
(click)="isPreviewable(document) && openPreview(document)"
|
||||
>
|
||||
<fa-icon icon="times"></fa-icon>
|
||||
</button>
|
||||
@if (previewThumbnails[document.id]) {
|
||||
<img
|
||||
[src]="previewThumbnails[document.id]"
|
||||
[alt]="document.name"
|
||||
[title]="document.name"
|
||||
loading="lazy"
|
||||
/>
|
||||
} @else {
|
||||
<div class="placeholder">
|
||||
<fa-icon icon="file"></fa-icon>
|
||||
<span>{{ document.fileName || document.name }}</span>
|
||||
</div>
|
||||
}
|
||||
@if (isPreviewable(document)) {
|
||||
<div class="preview-overlay">
|
||||
<fa-icon icon="eye"></fa-icon>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="title">{{ document.name }}</div>
|
||||
@if (document.fileName) {
|
||||
<div class="meta">{{ document.fileName }}</div>
|
||||
}
|
||||
@if (document.description) {
|
||||
<div class="description">{{ document.description }}</div>
|
||||
}
|
||||
<div class="actions">
|
||||
<button
|
||||
mat-icon-button
|
||||
color="warn"
|
||||
(click)="deleteDocument(document.id, document.name)"
|
||||
title="Delete"
|
||||
[attr.aria-label]="'labels.buttons.Delete' | translate"
|
||||
*mifosxHasPermission="'DELETE_DOCUMENT'"
|
||||
>
|
||||
<fa-icon icon="times"></fa-icon>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ng-template #empty>
|
||||
} @else {
|
||||
<div class="empty-state">
|
||||
<p>{{ 'labels.text.NoDocuments' | translate }}</p>
|
||||
<p class="muted">{{ 'labels.text.UploadDocumentHint' | translate }}</p>
|
||||
</div>
|
||||
</ng-template>
|
||||
}
|
||||
</div>
|
||||
|
||||
<div #lightboxRoot class="document-lightbox-host"></div>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Component, ElementRef, Input, OnDestroy, OnInit, ViewChild } from '@angular/core';
|
||||
import { Component, ElementRef, Input, OnDestroy, OnInit, ViewChild, inject } from '@angular/core';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import lightGallery from 'lightgallery';
|
||||
import lgFullscreen from 'lightgallery/plugins/fullscreen';
|
||||
@@ -27,6 +27,12 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
|
||||
]
|
||||
})
|
||||
export class EntityDocumentsTabComponent implements OnInit, OnDestroy {
|
||||
dialog = inject(MatDialog);
|
||||
private savingsService = inject(SavingsService);
|
||||
private loansService = inject(LoansService);
|
||||
private clientsService = inject(ClientsService);
|
||||
private documentPreviewService = inject(DocumentPreviewService);
|
||||
|
||||
@ViewChild('lightboxRoot', { static: true }) lightboxRoot: ElementRef<HTMLElement>;
|
||||
|
||||
@Input() entityId: string;
|
||||
@@ -44,14 +50,6 @@ export class EntityDocumentsTabComponent implements OnInit, OnDestroy {
|
||||
lgFullscreen
|
||||
];
|
||||
|
||||
constructor(
|
||||
public dialog: MatDialog,
|
||||
private savingsService: SavingsService,
|
||||
private loansService: LoansService,
|
||||
private clientsService: ClientsService,
|
||||
private documentPreviewService: DocumentPreviewService
|
||||
) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.prefetchThumbnails();
|
||||
}
|
||||
|
||||
@@ -25,32 +25,32 @@
|
||||
</div>
|
||||
|
||||
<div class="notes-container">
|
||||
<div *ngIf="entityNotes && entityNotes.length > 0; else emptyState">
|
||||
<div class="note-card" *ngFor="let entityNote of entityNotes; let i = index">
|
||||
<div class="note-content">
|
||||
{{ entityNote.note }}
|
||||
</div>
|
||||
|
||||
<div class="note-footer">
|
||||
<div class="note-meta">
|
||||
<div class="created-by">Created by {{ entityNote.createdByUsername }}</div>
|
||||
<div class="created-date">
|
||||
{{ entityNote.createdOn | dateFormat }}
|
||||
@if (entityNotes && entityNotes.length > 0) {
|
||||
<div>
|
||||
@for (entityNote of entityNotes; track entityNote; let i = $index) {
|
||||
<div class="note-card">
|
||||
<div class="note-content">
|
||||
{{ entityNote.note }}
|
||||
</div>
|
||||
<div class="note-footer">
|
||||
<div class="note-meta">
|
||||
<div class="created-by">Created by {{ entityNote.createdByUsername }}</div>
|
||||
<div class="created-date">
|
||||
{{ entityNote.createdOn | dateFormat }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="note-actions">
|
||||
<button class="edit-btn" (click)="editNote(entityNote.id, entityNote.note, i)" title="Edit note">
|
||||
Edit
|
||||
</button>
|
||||
<button class="delete-btn" (click)="deleteNote(entityNote.id, i)" title="Delete note">Delete</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="note-actions">
|
||||
<button class="edit-btn" (click)="editNote(entityNote.id, entityNote.note, i)" title="Edit note">
|
||||
Edit
|
||||
</button>
|
||||
<button class="delete-btn" (click)="deleteNote(entityNote.id, i)" title="Delete note">Delete</button>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ng-template #emptyState>
|
||||
} @else {
|
||||
<div class="empty-state">No notes available</div>
|
||||
</ng-template>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Component, Input, OnInit, ViewChild } from '@angular/core';
|
||||
import { Component, Input, OnInit, ViewChild, inject } from '@angular/core';
|
||||
import { UntypedFormBuilder, UntypedFormGroup, Validators, ReactiveFormsModule } from '@angular/forms';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { ClientsService } from 'app/clients/clients.service';
|
||||
@@ -24,6 +24,13 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
|
||||
]
|
||||
})
|
||||
export class EntityNotesTabComponent implements OnInit {
|
||||
private formBuilder = inject(UntypedFormBuilder);
|
||||
private savingsService = inject(SavingsService);
|
||||
private loansService = inject(LoansService);
|
||||
private clientsService = inject(ClientsService);
|
||||
private groupsService = inject(GroupsService);
|
||||
private dialog = inject(MatDialog);
|
||||
|
||||
@ViewChild('formRef', { static: true }) formRef: any;
|
||||
|
||||
@Input() entityId: string;
|
||||
@@ -35,15 +42,6 @@ export class EntityNotesTabComponent implements OnInit {
|
||||
|
||||
noteForm: UntypedFormGroup;
|
||||
|
||||
constructor(
|
||||
private formBuilder: UntypedFormBuilder,
|
||||
private savingsService: SavingsService,
|
||||
private loansService: LoansService,
|
||||
private clientsService: ClientsService,
|
||||
private groupsService: GroupsService,
|
||||
private dialog: MatDialog
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.createNoteForm();
|
||||
}
|
||||
|
||||
@@ -4,8 +4,10 @@
|
||||
</span>
|
||||
<mat-label>{{ 'labels.inputs.Tenant' | translate }}</mat-label>
|
||||
<mat-select [formControl]="tenantSelector" (selectionChange)="setTenantIdentifier()" class="tenantselector">
|
||||
<mat-option *ngFor="let tenant of tenants" [value]="tenant">
|
||||
{{ tenant }}
|
||||
</mat-option>
|
||||
@for (tenant of tenants; track tenant) {
|
||||
<mat-option [value]="tenant">
|
||||
{{ tenant }}
|
||||
</mat-option>
|
||||
}
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { Component, OnInit, inject } from '@angular/core';
|
||||
import { UntypedFormControl, ReactiveFormsModule } from '@angular/forms';
|
||||
import { SettingsService } from 'app/settings/settings.service';
|
||||
import { MatFormField, MatPrefix, MatLabel } from '@angular/material/form-field';
|
||||
@@ -16,15 +16,11 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
|
||||
]
|
||||
})
|
||||
export class TenantSelectorComponent implements OnInit {
|
||||
private settingsService = inject(SettingsService);
|
||||
|
||||
/** Tenant selector form control. */
|
||||
tenantSelector = new UntypedFormControl();
|
||||
|
||||
/**
|
||||
* Sets the Tenant Identifier of the application in the selector on initial setup.
|
||||
* @param {SettingsService} settingsService Settings Service.
|
||||
*/
|
||||
constructor(private settingsService: SettingsService) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.tenantSelector.setValue(this.settingsService.tenantIdentifier);
|
||||
if (this.tenants.length > 1) {
|
||||
|
||||
@@ -4,19 +4,18 @@
|
||||
|
||||
<mat-menu class="mifosx-theme-picker-menu" #themeMenu="matMenu" x-position="before">
|
||||
<mat-grid-list cols="2">
|
||||
<mat-grid-tile *ngFor="let theme of themes">
|
||||
<div mat-menu-item (click)="installTheme(theme)">
|
||||
<div class="mifosx-theme-picker-swatch">
|
||||
<fa-icon
|
||||
class="mifosx-theme-chosen-icon"
|
||||
*ngIf="currentTheme.href === theme.href"
|
||||
icon="check-circle"
|
||||
size="lg"
|
||||
></fa-icon>
|
||||
<div class="mifosx-theme-picker-primary" [style.background]="theme.primary"></div>
|
||||
<div class="mifosx-theme-picker-accent" [style.background]="theme.accent"></div>
|
||||
@for (theme of themes; track theme) {
|
||||
<mat-grid-tile>
|
||||
<div mat-menu-item (click)="installTheme(theme)">
|
||||
<div class="mifosx-theme-picker-swatch">
|
||||
@if (currentTheme.href === theme.href) {
|
||||
<fa-icon class="mifosx-theme-chosen-icon" icon="check-circle" size="lg"></fa-icon>
|
||||
}
|
||||
<div class="mifosx-theme-picker-primary" [style.background]="theme.primary"></div>
|
||||
<div class="mifosx-theme-picker-accent" [style.background]="theme.accent"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</mat-grid-tile>
|
||||
</mat-grid-tile>
|
||||
}
|
||||
</mat-grid-list>
|
||||
</mat-menu>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/** Angular Imports */
|
||||
import { Component, OnInit, ViewEncapsulation } from '@angular/core';
|
||||
import { Component, OnInit, ViewEncapsulation, inject } from '@angular/core';
|
||||
|
||||
/** Custom Model */
|
||||
import { Theme } from './theme.model';
|
||||
@@ -36,6 +36,8 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
|
||||
]
|
||||
})
|
||||
export class ThemePickerComponent implements OnInit {
|
||||
themeStorageService = inject(ThemeStorageService);
|
||||
|
||||
/** Default theme for the application. */
|
||||
currentTheme: Theme = {
|
||||
href: 'denim-yellowgreen.css',
|
||||
@@ -79,11 +81,6 @@ export class ThemePickerComponent implements OnInit {
|
||||
}
|
||||
];
|
||||
|
||||
/**
|
||||
* @param {ThemeStorageService} themeStorageService Theme Storage Service.
|
||||
*/
|
||||
constructor(public themeStorageService: ThemeStorageService) {}
|
||||
|
||||
/**
|
||||
* Initializes the theme for the application.
|
||||
*/
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Injectable, EventEmitter } from '@angular/core';
|
||||
import { Injectable, EventEmitter, inject } from '@angular/core';
|
||||
import { Theme } from './theme.model';
|
||||
import { ThemeManagerService } from './theme-manager.service';
|
||||
|
||||
@@ -6,10 +6,12 @@ import { ThemeManagerService } from './theme-manager.service';
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class ThemeStorageService {
|
||||
themeManagerService = inject(ThemeManagerService);
|
||||
|
||||
private themeStorageKey = 'mifosXTheme';
|
||||
onThemeUpdate: EventEmitter<Theme>;
|
||||
|
||||
constructor(public themeManagerService: ThemeManagerService) {
|
||||
constructor() {
|
||||
this.onThemeUpdate = new EventEmitter<Theme>();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Component, OnChanges, OnInit, SimpleChanges } from '@angular/core';
|
||||
import { Component, OnChanges, OnInit, SimpleChanges, inject } from '@angular/core';
|
||||
import { ThemingService } from './theming.service';
|
||||
import { SettingsService } from 'app/settings/settings.service';
|
||||
import { MatIconButton } from '@angular/material/button';
|
||||
@@ -16,12 +16,10 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
|
||||
]
|
||||
})
|
||||
export class ThemeToggleComponent implements OnInit, OnChanges {
|
||||
darkModeOn: boolean;
|
||||
private themingService = inject(ThemingService);
|
||||
private settingsService = inject(SettingsService);
|
||||
|
||||
constructor(
|
||||
private themingService: ThemingService,
|
||||
private settingsService: SettingsService
|
||||
) {}
|
||||
darkModeOn: boolean;
|
||||
|
||||
ngOnInit(): void {
|
||||
this.darkModeOn = !!this.settingsService.themeDarkEnabled;
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import { ApplicationRef, Injectable } from '@angular/core';
|
||||
import { ApplicationRef, Injectable, inject } from '@angular/core';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class ThemingService {
|
||||
private ref = inject(ApplicationRef);
|
||||
|
||||
private darkModeOn = false;
|
||||
|
||||
themes = [
|
||||
@@ -13,7 +15,7 @@ export class ThemingService {
|
||||
]; // <- list all themes in this array
|
||||
theme = new BehaviorSubject('light-theme'); // <- initial theme
|
||||
|
||||
constructor(private ref: ApplicationRef) {
|
||||
constructor() {
|
||||
// Initially check if dark mode is enabled on system
|
||||
this.darkModeOn = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
|
||||
|
||||
|
||||
+39
-27
@@ -7,30 +7,42 @@
|
||||
{{ paymentDetailData.paymentType.name }}
|
||||
</div>
|
||||
</div>
|
||||
<table *ngIf="hasSomeValue()">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="mat-body-strong center" colspan="2">{{ 'labels.inputs.Payment Details' | translate }}</td>
|
||||
</tr>
|
||||
<tr *ngIf="isNotNullOrEmpty(paymentDetailData.accountNumber)">
|
||||
<td class="mat-body-strong">{{ 'labels.inputs.Account No' | translate }}</td>
|
||||
<td>{{ paymentDetailData.accountNumber }}</td>
|
||||
</tr>
|
||||
<tr *ngIf="isNotNullOrEmpty(paymentDetailData.checkNumber)">
|
||||
<td class="mat-body-strong">{{ 'labels.inputs.Cheque Number' | translate }}</td>
|
||||
<td>{{ paymentDetailData.checkNumber }}</td>
|
||||
</tr>
|
||||
<tr *ngIf="isNotNullOrEmpty(paymentDetailData.routingCode)">
|
||||
<td class="mat-body-strong">{{ 'labels.inputs.Routing Code' | translate }}</td>
|
||||
<td class="mat-body-strong">{{ paymentDetailData.routingCode }}</td>
|
||||
</tr>
|
||||
<tr *ngIf="isNotNullOrEmpty(paymentDetailData.receiptNumber)">
|
||||
<td class="mat-body-strong">{{ 'labels.inputs.Receipt No' | translate }}</td>
|
||||
<td>{{ paymentDetailData.receiptNumber }}</td>
|
||||
</tr>
|
||||
<tr *ngIf="isNotNullOrEmpty(paymentDetailData.bankNumber)">
|
||||
<td class="mat-body-strong">{{ 'labels.inputs.Bank No' | translate }}</td>
|
||||
<td>{{ paymentDetailData.bankNumber }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
@if (hasSomeValue()) {
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="mat-body-strong center" colspan="2">{{ 'labels.inputs.Payment Details' | translate }}</td>
|
||||
</tr>
|
||||
@if (isNotNullOrEmpty(paymentDetailData.accountNumber)) {
|
||||
<tr>
|
||||
<td class="mat-body-strong">{{ 'labels.inputs.Account No' | translate }}</td>
|
||||
<td>{{ paymentDetailData.accountNumber }}</td>
|
||||
</tr>
|
||||
}
|
||||
@if (isNotNullOrEmpty(paymentDetailData.checkNumber)) {
|
||||
<tr>
|
||||
<td class="mat-body-strong">{{ 'labels.inputs.Cheque Number' | translate }}</td>
|
||||
<td>{{ paymentDetailData.checkNumber }}</td>
|
||||
</tr>
|
||||
}
|
||||
@if (isNotNullOrEmpty(paymentDetailData.routingCode)) {
|
||||
<tr>
|
||||
<td class="mat-body-strong">{{ 'labels.inputs.Routing Code' | translate }}</td>
|
||||
<td class="mat-body-strong">{{ paymentDetailData.routingCode }}</td>
|
||||
</tr>
|
||||
}
|
||||
@if (isNotNullOrEmpty(paymentDetailData.receiptNumber)) {
|
||||
<tr>
|
||||
<td class="mat-body-strong">{{ 'labels.inputs.Receipt No' | translate }}</td>
|
||||
<td>{{ paymentDetailData.receiptNumber }}</td>
|
||||
</tr>
|
||||
}
|
||||
@if (isNotNullOrEmpty(paymentDetailData.bankNumber)) {
|
||||
<tr>
|
||||
<td class="mat-body-strong">{{ 'labels.inputs.Bank No' | translate }}</td>
|
||||
<td>{{ paymentDetailData.bankNumber }}</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user