From 1eaa8cc8cf99aa7fb0c042fb89406e89a9324b3c Mon Sep 17 00:00:00 2001 From: Nitesh Yadav Date: Thu, 24 Sep 2026 16:12:45 +0530 Subject: [PATCH] feat(fd): make the Payment dialog the FD Dashboard's Renew action too, redesign it The Payment dialog (Transfer to Savings / Reinvest Full / Reinvest Principal Only / Partial Reinvest, works whether an FD is Active or Matured) already had a complete, correct backend implementation for every closure type -- including one this session found and fixed a real gap in on the backend side (Reinvest Principal Only silently stranded its leftover interest). Rather than duplicating that logic in a second, narrower dialog, the FD Dashboard's Renew action now opens this same dialog in a `dashboardRenewal` mode: every closure type is still available, but the Closed On Date is computed from the product's grace window instead of picked freely (backdated to the original maturity date within grace, today once it's passed, picker hidden so it can't be moved off that value), and submit() calls the new gap-interest pre-step endpoint first when past grace, before the same generic `payment` command every other caller already used. Also: full visual redesign (bigger dialog, gradient header, per-option accent colors, refined spacing) applied to both entry points since they're the same component now; removes the native "Close" action from a Matured FD's Account Actions menu, since what happens at maturity now goes through the nightly job or this dialog, not a separate close command that bypassed both. Co-Authored-By: Claude Sonnet 5 --- .../payment-dialog.component.html | 97 ++-- .../payment-dialog.component.scss | 519 +++++++++++------- .../payment-dialog.component.ts | 78 ++- .../fixed-deposit-account-view.component.ts | 2 +- .../fixed-deposits-buttons.config.ts | 9 +- src/environments/.env.ts | 4 +- src/main.scss | 13 + 7 files changed, 480 insertions(+), 242 deletions(-) diff --git a/src/app/deposits/fixed-deposits/fixed-deposit-account-view/custom-dialogs/payment-dialog/payment-dialog.component.html b/src/app/deposits/fixed-deposits/fixed-deposit-account-view/custom-dialogs/payment-dialog/payment-dialog.component.html index 659f79528..34a510e7f 100644 --- a/src/app/deposits/fixed-deposits/fixed-deposit-account-view/custom-dialogs/payment-dialog/payment-dialog.component.html +++ b/src/app/deposits/fixed-deposits/fixed-deposit-account-view/custom-dialogs/payment-dialog/payment-dialog.component.html @@ -8,11 +8,24 @@
- -
-

{{ 'labels.heading.Payment' | translate }}

-

Process this Fixed Deposit now -- works whether it's Active or Matured.

+
+ +
+

+ {{ isDashboardRenewalMode ? 'Renew Fixed Deposit' : ('labels.heading.Payment' | translate) }} +

+

+ {{ + isDashboardRenewalMode + ? 'Renew ' + (dashboardRenewalRow?.accountNo ?? 'this matured FD') + '.' + : "Process this Fixed Deposit now -- works whether it's Active or Matured." + }} +

+
+
@@ -27,37 +40,46 @@
} @else {
+ @if (isDashboardRenewalMode) { +

+ + {{ dashboardRenewalTimingText }} +

+ } + @if (reinvestCap !== null && reinvestCap !== undefined) {
{{ - remainderIsApproximate - ? 'Amount available on the selected date' - : ('labels.inputs.Maturity Amount' | translate) + isDashboardRenewalMode || !remainderIsApproximate + ? ('labels.inputs.Maturity Amount' | translate) + : 'Amount available on the selected date' }} {{ reinvestCap | formatNumber }}
} - - {{ 'labels.inputs.Closed On Date' | translate }} - - - - @if (paymentForm.controls.closedOnDate.hasError('required')) { - - {{ 'labels.inputs.Closed On Date' | translate }} {{ 'labels.commons.is' | translate }} - {{ 'labels.commons.required' | translate }} - - } - + @if (!isDashboardRenewalMode) { + + {{ 'labels.inputs.Closed On Date' | translate }} + + + + @if (paymentForm.controls.closedOnDate.hasError('required')) { + + {{ 'labels.inputs.Closed On Date' | translate }} {{ 'labels.commons.is' | translate }} + {{ 'labels.commons.required' | translate }} + + } + + }
@@ -162,10 +184,12 @@ } - - {{ 'labels.inputs.Note' | translate }} - - + @if (!isDashboardRenewalMode) { + + {{ 'labels.inputs.Note' | translate }} + + + } @if (submitError) {
- +
diff --git a/src/app/deposits/fixed-deposits/fixed-deposit-account-view/custom-dialogs/payment-dialog/payment-dialog.component.scss b/src/app/deposits/fixed-deposits/fixed-deposit-account-view/custom-dialogs/payment-dialog/payment-dialog.component.scss index 48967437c..a95aa35aa 100644 --- a/src/app/deposits/fixed-deposits/fixed-deposit-account-view/custom-dialogs/payment-dialog/payment-dialog.component.scss +++ b/src/app/deposits/fixed-deposits/fixed-deposit-account-view/custom-dialogs/payment-dialog/payment-dialog.component.scss @@ -6,291 +6,404 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -$navy: #0d1b2a; -$slate: #475569; -$muted: #64748b; -$border: #e2e8f0; -$soft: #f8fafc; -$blue: #1e40af; -$blue-soft: #eff6ff; -$green: #166534; -$green-soft: #f0fdf4; +/** + * Payment / Renewal Dialog Styles + * CBSNexora Core Banking System + */ .pmt { display: flex; flex-direction: column; - min-height: 320px; - max-height: 85vh; + height: 100%; + max-height: 92vh; + box-sizing: border-box; + font-family: + 'DM Sans', + system-ui, + -apple-system, + sans-serif; + color: #0f172a; + border-radius: 16px; overflow: hidden; - margin: -24px; + box-shadow: 0 24px 48px -12px rgb(15 23 42 / 25%); } .pmt__header { - display: flex; - align-items: flex-start; - gap: 14px; - padding: 22px 28px 18px; - background: linear-gradient(135deg, #1e3a8a 0%, #1e40af 55%, #4338ca 100%); - color: #fff; - flex: 0 0 auto; -} - -.pmt__header-ico { - width: 40px; - height: 40px; - min-width: 40px; - border-radius: 10px; - background: rgb(255 255 255 / 15%); display: flex; align-items: center; - justify-content: center; - font-size: 18px; + justify-content: space-between; + gap: 16px; + padding: 26px 30px; + background: linear-gradient(135deg, #1e3a8a 0%, #1d4ed8 55%, #2563eb 100%); + color: #fff; + flex-shrink: 0; + position: relative; + overflow: hidden; + + &::after { + content: ''; + position: absolute; + inset: 0; + background: radial-gradient(circle at 88% -20%, rgb(255 255 255 / 22%), transparent 55%); + pointer-events: none; + } + + &-left { + display: flex; + align-items: center; + gap: 16px; + position: relative; + z-index: 1; + } + + &-ico { + width: 48px; + height: 48px; + border-radius: 14px; + background: rgb(255 255 255 / 16%); + border: 1px solid rgb(255 255 255 / 25%); + display: flex; + align-items: center; + justify-content: center; + font-size: 20px; + color: #fff; + flex-shrink: 0; + } + + &-text { + display: flex; + flex-direction: column; + } + + &-close { + position: relative; + z-index: 1; + background: rgb(255 255 255 / 14%); + border: none; + color: #fff; + width: 34px; + height: 34px; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + transition: all 0.2s ease; + flex-shrink: 0; + + &:hover:not(:disabled) { + background: rgb(255 255 255 / 28%); + transform: rotate(90deg); + } + + &:disabled { + opacity: 0.5; + cursor: not-allowed; + } + } } .pmt__title { margin: 0; - font-size: 19px; - font-weight: 700; + font-size: 20px; + font-weight: 800; + color: #fff; + line-height: 1.25; + letter-spacing: -0.01em; } .pmt__subtitle { - margin: 4px 0 0; - font-size: 12.5px; - color: rgb(255 255 255 / 82%); + margin: 5px 0 0; + font-size: 13px; + color: rgb(255 255 255 / 88%); line-height: 1.4; } .pmt__content { - padding: 22px 28px 8px !important; + padding: 26px 30px !important; overflow-y: auto; flex: 1 1 auto; + background: #fbfcfe; + + mat-form-field { + width: 100%; + } } .pmt__loading { display: flex; justify-content: center; align-items: center; - min-height: 260px; + min-height: 240px; } .pmt__stat { display: flex; flex-direction: column; - gap: 2px; - background: $blue-soft; - border: 1px solid #dbeafe; - border-radius: 10px; - padding: 12px 16px; + gap: 4px; + background: linear-gradient(135deg, #eff6ff 0%, #e0e9ff 100%); + border: 1px solid #bfdbfe; + border-radius: 14px; + padding: 18px 22px; margin-bottom: 18px; -} -.pmt__stat-label { - font-size: 11px; - font-weight: 700; - text-transform: uppercase; - letter-spacing: 0.05em; - color: $blue; -} + &-label { + font-size: 11.5px; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.07em; + color: #1d4ed8; + } -.pmt__stat-value { - font-size: 22px; - font-weight: 800; - color: $navy; - font-variant-numeric: tabular-nums; -} - -.pmt__date { - width: 100%; + &-value { + font-family: 'JetBrains Mono', 'DM Sans', monospace; + font-size: 28px; + font-weight: 800; + color: #0f172a; + letter-spacing: -0.01em; + } } .pmt__section-label { - font-size: 11.5px; + font-size: 12px; font-weight: 700; text-transform: uppercase; - letter-spacing: 0.05em; - color: $slate; - margin: 4px 0 10px; + letter-spacing: 0.06em; + color: #475569; + margin: 10px 0 12px; } +/* Action Options Grid - 2 Equal Columns, comfortably wide now that the dialog itself is wider */ .pmt__options { display: grid; - grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); - gap: 10px; - margin-bottom: 6px; + grid-template-columns: repeat(2, 1fr); + gap: 14px; + margin-bottom: 18px; + + @media (width <= 560px) { + grid-template-columns: 1fr; + } } .pmt__option { display: flex; align-items: flex-start; - gap: 10px; + gap: 14px; text-align: left; background: #fff; - border: 1.5px solid $border; - border-radius: 10px; - padding: 12px 14px; + border: 1.5px solid #e2e8f0; + border-radius: 14px; + padding: 16px; cursor: pointer; font: inherit; - transition: - border-color 0.15s, - background 0.15s, - box-shadow 0.15s; -} + transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1); + position: relative; -.pmt__option:hover { - border-color: #93c5fd; - background: $blue-soft; -} + &:hover { + border-color: #93c5fd; + background: #f8fafc; + box-shadow: 0 6px 16px rgb(15 23 42 / 6%); + transform: translateY(-1px); + } -.pmt__option--active { - border-color: $blue; - background: $blue-soft; - box-shadow: 0 0 0 1px $blue; -} + &--active { + border-color: #2563eb; + background: #eff6ff; + box-shadow: 0 0 0 1.5px #2563eb; -.pmt__option-ico { - width: 30px; - height: 30px; - min-width: 30px; - border-radius: 8px; - background: $soft; - color: $blue; - display: flex; - align-items: center; - justify-content: center; - font-size: 13px; -} + .pmt__option-ico { + background: #2563eb; + color: #fff; + border-color: #2563eb; + } + } -.pmt__option--active .pmt__option-ico { - background: $blue; - color: #fff; -} + &-ico { + width: 38px; + height: 38px; + min-width: 38px; + border-radius: 10px; + background: #f1f5f9; + border: 1px solid #e2e8f0; + color: #2563eb; + display: flex; + align-items: center; + justify-content: center; + font-size: 15px; + flex-shrink: 0; + transition: all 0.2s ease; + } -.pmt__option-text { - display: flex; - flex-direction: column; - gap: 2px; -} + // Distinct accent per option while unselected, purely presentational -- helps the four cards read + // apart at a glance. Selecting a card always fills its icon blue (see &--active above), matching the + // blue selection border/check regardless of which option it is, rather than mixing selection-blue + // with the option's own accent. + &:not(.pmt__option--active):nth-child(2) .pmt__option-ico { + color: #7c3aed; + } -.pmt__option-title { - font-size: 13px; - font-weight: 700; - color: $navy; -} + &:not(.pmt__option--active):nth-child(3) .pmt__option-ico { + color: #0d9488; + } -.pmt__option-desc { - font-size: 11px; - color: $muted; - line-height: 1.35; -} + &:not(.pmt__option--active):nth-child(4) .pmt__option-ico { + color: #d97706; + } -.pmt__option:focus-visible { - outline: 2px solid $blue; - outline-offset: 2px; -} + &-text { + display: flex; + flex-direction: column; + gap: 4px; + flex: 1; + } -.pmt__option-check { - margin-left: auto; - color: $blue; - font-size: 13px; + &-title { + font-size: 14px; + font-weight: 700; + color: #0f172a; + line-height: 1.3; + } + + &-desc { + font-size: 12px; + color: #64748b; + line-height: 1.4; + } + + &-check { + color: #2563eb; + font-size: 17px; + position: absolute; + top: 14px; + right: 14px; + } } .pmt__option-error { color: #b91c1c; font-size: 12px; - margin: 4px 0 14px; -} - -.pmt__error { - display: flex; - align-items: flex-start; - gap: 4px; - background: #fef2f2; - border: 1px solid #fecaca; - border-radius: 8px; - color: #b91c1c; - font-size: 12.5px; - line-height: 1.45; - padding: 10px 14px; - margin: 4px 0 8px; -} - -.pmt__hint { - display: flex; - align-items: flex-start; - gap: 4px; - background: $soft; - border: 1px solid $border; - border-radius: 8px; - color: $slate; - font-size: 12px; - line-height: 1.45; - padding: 9px 13px; - margin: 0 0 10px; -} - -.pmt__hint--warn { - background: #fffbeb; - border-color: #fde68a; - color: #92400e; + font-weight: 600; + margin: -10px 0 14px; } .pmt__split { display: flex; align-items: center; - gap: 12px; - background: $soft; + gap: 16px; + background: #f8fafc; border: 1px dashed #cbd5e1; - border-radius: 10px; - padding: 14px 16px 0; - margin: 4px 0 8px; + border-radius: 14px; + padding: 18px; + margin: 10px 0 18px; flex-wrap: wrap; + + &-input { + flex: 1 1 220px; + } + + &-arrow { + color: #94a3b8; + font-size: 17px; + } + + &-remainder { + display: flex; + flex-direction: column; + gap: 3px; + background: #f0fdf4; + border: 1px solid #bbf7d0; + border-radius: 10px; + padding: 12px 16px; + flex: 1 1 220px; + + &-label { + font-size: 11px; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.04em; + color: #166534; + } + + &-value { + font-family: 'JetBrains Mono', 'DM Sans', monospace; + font-size: 19px; + font-weight: 800; + color: #166534; + } + } } -.pmt__split-input { - flex: 1 1 180px; - min-width: 160px; -} - -.pmt__split-arrow { - color: $muted; - font-size: 14px; - margin-bottom: 20px; -} - -.pmt__split-remainder { +.pmt__hint { display: flex; - flex-direction: column; - gap: 2px; - background: $green-soft; - border: 1px solid #bbf7d0; - border-radius: 8px; - padding: 8px 14px; - margin-bottom: 14px; - flex: 1 1 180px; - min-width: 160px; + align-items: flex-start; + gap: 10px; + background: #f0f9ff; + border: 1px solid #bae6fd; + border-left: 4px solid #0284c7; + border-radius: 10px; + color: #0369a1; + font-size: 13px; + line-height: 1.5; + padding: 12px 16px; + margin: 0 0 18px; + + &--warn { + background: #fffbeb; + border-color: #fde68a; + border-left-color: #d97706; + color: #b45309; + } } -.pmt__split-remainder-label { - font-size: 10.5px; - font-weight: 700; - text-transform: uppercase; - letter-spacing: 0.04em; - color: $green; -} - -.pmt__split-remainder-value { - font-size: 16px; - font-weight: 800; - color: $green; - font-variant-numeric: tabular-nums; -} - -.pmt__content mat-form-field { - width: 100%; +.pmt__error { + display: flex; + align-items: flex-start; + gap: 10px; + background: #fef2f2; + border: 1px solid #fecaca; + border-left: 4px solid #ef4444; + border-radius: 10px; + color: #b91c1c; + font-size: 13px; + padding: 12px 16px; + margin: 10px 0; } .pmt__actions { - padding: 14px 28px 20px !important; - border-top: 1px solid $border; - flex: 0 0 auto; + padding: 18px 30px !important; + border-top: 1px solid #e2e8f0; + background: #fff; + display: flex; + align-items: center; + justify-content: flex-end; + gap: 14px; + flex-shrink: 0; + + .pmt__btn-cancel { + border-radius: 10px; + font-weight: 600; + color: #475569; + } + + .pmt__btn-submit { + border-radius: 10px; + font-weight: 700; + padding: 0 26px; + height: 42px; + background: linear-gradient(135deg, #1d4ed8 0%, #2563eb 100%); + color: #fff; + box-shadow: 0 8px 20px rgb(37 99 235 / 30%); + transition: all 0.2s ease; + + &:hover:not(:disabled) { + box-shadow: 0 10px 24px rgb(37 99 235 / 40%); + transform: translateY(-1px); + } + + &:disabled { + background: #cbd5e1; + box-shadow: none; + color: #64748b; + } + } } diff --git a/src/app/deposits/fixed-deposits/fixed-deposit-account-view/custom-dialogs/payment-dialog/payment-dialog.component.ts b/src/app/deposits/fixed-deposits/fixed-deposit-account-view/custom-dialogs/payment-dialog/payment-dialog.component.ts index cd433f83c..4e1cc8c39 100644 --- a/src/app/deposits/fixed-deposits/fixed-deposit-account-view/custom-dialogs/payment-dialog/payment-dialog.component.ts +++ b/src/app/deposits/fixed-deposits/fixed-deposit-account-view/custom-dialogs/payment-dialog/payment-dialog.component.ts @@ -27,12 +27,22 @@ import { SettingsService } from 'app/settings/settings.service'; import { Dates } from 'app/core/utils/dates'; import { FormatNumberPipe } from '../../../../../pipes/format-number.pipe'; import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module'; +import { FdMaturityRow } from 'app/fd-dashboard/fd-dashboard.compute'; /** * "Payment" dialog -- an always-available alternative to Premature Close (Active-only, no reinvest) and * Close (Matured-only, no partial option). Works on an FD in either state and offers a fourth choice, * Partial Reinvest, alongside the ones the backend's `DepositAccountOnClosureType` already had: the * entered amount renews on this same account, the rest transfers to a savings account picked here. + * + * Doubles as the FD Dashboard's Renew action when opened with `data.dashboardRenewal` set: same form, + * same full set of closure types (nothing removed -- Transfer to Savings and Partial Reinvest work from + * the Dashboard too, not just the two Reinvest options). The only two differences in that mode: the + * Closed On Date is computed from the FD's grace window instead of picked freely (backdated to the + * original maturity date within grace, today once it's passed -- the picker is hidden, not just + * defaulted, so it can't accidentally be moved off that date), and submit() first calls + * `creditGapInterestIfPastGrace` when past grace, crediting the gap-period interest (at the linked + * account's rate) onto the FD before the normal `payment` command runs and reads its balance. */ @Component({ selector: 'mifosx-payment-dialog', @@ -76,7 +86,13 @@ export class PaymentDialogComponent implements OnInit { }; dialogRef = inject>(MatDialogRef); - data: { accountId: number | string; accountBalance?: number; maturityDate?: any } = inject(MAT_DIALOG_DATA); + data: { + accountId: number | string; + accountBalance?: number; + maturityDate?: any; + /** Present only when opened from the FD Dashboard's Renew action. */ + dashboardRenewal?: { row: FdMaturityRow }; + } = inject(MAT_DIALOG_DATA); private formBuilder = inject(UntypedFormBuilder); private fixedDepositsService = inject(FixedDepositsService); private settingsService = inject(SettingsService); @@ -93,6 +109,10 @@ export class PaymentDialogComponent implements OnInit { submitError: string = null; maxDate: Date; + /** Whether gap-interest still needs crediting before this submits -- only ever true once, right + * after open; cleared as soon as `submit()` has credited it, so a retried submit doesn't double-post. */ + private gapInterestPending = false; + ngOnInit(): void { this.maxDate = this.settingsService.businessDate; this.paymentForm = this.formBuilder.group({ @@ -106,6 +126,18 @@ export class PaymentDialogComponent implements OnInit { ], note: [''] }); + + const dashboardRow = this.dashboardRenewalRow; + if (dashboardRow) { + // Computed from the grace window, never picked -- the date field stays in the form (the generic + // submit path and reinvestCap/processingOnOrAfterMaturity both key off it) but its picker is + // hidden in this mode (see the template), so it can't be moved off this value. + this.paymentForm + .get('closedOnDate') + .setValue(dashboardRow.withinGraceWindow ? new Date(dashboardRow.maturityDate) : this.maxDate); + this.gapInterestPending = !dashboardRow.withinGraceWindow; + } + this.paymentForm.get('onAccountClosureId').valueChanges.subscribe((id: number) => this.onClosureTypeChange(id)); // The cap depends on whether the chosen date is on or after maturity, so a date change can make an // already-entered amount valid or invalid. Without this the amount keeps its verdict from the old date. @@ -136,6 +168,25 @@ export class PaymentDialogComponent implements OnInit { }); } + get isDashboardRenewalMode(): boolean { + return !!this.data.dashboardRenewal; + } + + get dashboardRenewalRow(): FdMaturityRow | null { + return this.data.dashboardRenewal?.row ?? null; + } + + /** What clicking Confirm is actually about to do -- shown above the (hidden-picker) date in this + * mode, since the date itself is no longer visible to explain it. */ + get dashboardRenewalTimingText(): string { + const row = this.dashboardRenewalRow; + if (!row) return ''; + return row.withinGraceWindow + ? `Backdated to its original maturity date (${row.maturityDate}), at the currently active interest rate.` + : `This FD's grace period has passed -- gap-period interest (for the days since maturity) will be ` + + `credited at the linked account's rate first, then this renews from today.`; + } + /** * The amount being split, and the bound the entered partial amount is checked against. *

@@ -259,6 +310,31 @@ export class PaymentDialogComponent implements OnInit { } submit(): void { + if (this.gapInterestPending) { + this.submitting = true; + this.submitError = null; + this.fixedDepositsService.creditGapInterestIfPastGrace(this.data.accountId).subscribe({ + next: () => { + this.gapInterestPending = false; + this.submitGenericPayment(); + }, + error: (error: any) => { + this.submitting = false; + this.submitError = + error?.error?.defaultUserMessage ?? + error?.error?.errors?.[0]?.defaultUserMessage ?? + 'Could not credit gap-period interest. Please review the details and try again.'; + } + }); + return; + } + this.submitGenericPayment(); + } + + /** The same `command=payment` submission every non-Dashboard call to this dialog already used -- + * Dashboard-renewal mode reaches it too, once any gap-interest pre-step above has cleared, so every + * closure type behaves identically regardless of where the dialog was opened from. */ + private submitGenericPayment(): void { const formValue = { ...this.paymentForm.value }; const locale = this.settingsService.language.code; const dateFormat = this.settingsService.dateFormat; diff --git a/src/app/deposits/fixed-deposits/fixed-deposit-account-view/fixed-deposit-account-view.component.ts b/src/app/deposits/fixed-deposits/fixed-deposit-account-view/fixed-deposit-account-view.component.ts index fefdb323d..42f39f6c5 100644 --- a/src/app/deposits/fixed-deposits/fixed-deposit-account-view/fixed-deposit-account-view.component.ts +++ b/src/app/deposits/fixed-deposits/fixed-deposit-account-view/fixed-deposit-account-view.component.ts @@ -276,7 +276,7 @@ export class FixedDepositAccountViewComponent implements OnInit { */ private openPaymentDialog(): void { const paymentDialogRef = this.dialog.open(PaymentDialogComponent, { - width: '640px', + width: '720px', maxWidth: '95vw', data: { accountId: this.fixedDepositsAccountData.id, diff --git a/src/app/deposits/fixed-deposits/fixed-deposit-account-view/fixed-deposits-buttons.config.ts b/src/app/deposits/fixed-deposits/fixed-deposit-account-view/fixed-deposits-buttons.config.ts index 3146a730c..76abd062d 100644 --- a/src/app/deposits/fixed-deposits/fixed-deposit-account-view/fixed-deposits-buttons.config.ts +++ b/src/app/deposits/fixed-deposits/fixed-deposit-account-view/fixed-deposits-buttons.config.ts @@ -57,11 +57,12 @@ export class FixedDepositsButtonsConfiguration { ]; break; case 'Matured': + // 'Close' (the generic Fineract apply-maturity-instructions action) is deliberately left out + // here -- what happens to a matured FD is now handled either automatically by the nightly job + // (an account opened with an explicit instruction) or manually via the FD Dashboard's Renew + // action (an account left without one, backdated within grace / gap-interest after). Closing + // from here would go around both of those paths. this.buttonsArray = [ - { - name: 'Close', - icon: 'fa fa-arrow-right' - }, { name: 'Calculate Interest', icon: 'fa fa-table' diff --git a/src/environments/.env.ts b/src/environments/.env.ts index 0ec45a382..f08a6bab3 100644 --- a/src/environments/.env.ts +++ b/src/environments/.env.ts @@ -9,8 +9,8 @@ /* tslint:disable */ export default { 'mifos_x': { - 'version': '260921', - 'hash': '3c363d03' + 'version': '260923', + 'hash': '3f59cc6b' }, 'allow_switching_backend_instance': true }; diff --git a/src/main.scss b/src/main.scss index 16f91750d..c74b84479 100644 --- a/src/main.scss +++ b/src/main.scss @@ -55,6 +55,19 @@ box-shadow: none; } +// ===== Payment / Renewal Dialog Panel ===== +.pmt-dialog-panel .mat-mdc-dialog-container .mdc-dialog__surface { + padding: 0 !important; + border-radius: 16px !important; + overflow: hidden !important; + box-shadow: 0 20px 40px rgb(15 23 42 / 25%) !important; +} + +.pmt-dialog-panel .mat-mdc-dialog-content { + padding: 0 !important; + max-height: none !important; +} + .ipd-dialog .mdc-dialog__surface { border-radius: 20px !important; background: transparent !important;