diff --git a/src/app/account-transfers/common-resolvers/standing-instructions-template.resolver.ts b/src/app/account-transfers/common-resolvers/standing-instructions-template.resolver.ts index b2971f442..be7518e89 100644 --- a/src/app/account-transfers/common-resolvers/standing-instructions-template.resolver.ts +++ b/src/app/account-transfers/common-resolvers/standing-instructions-template.resolver.ts @@ -41,6 +41,9 @@ export class StandingInstructionsTemplateResolver { case 'fromsavings': this.accountTypeId = '2'; break; + case 'fromcurrentaccount': + this.accountTypeId = '3'; + break; default: this.accountTypeId = '0'; } diff --git a/src/app/account-transfers/create-standing-instructions/create-standing-instructions.component.ts b/src/app/account-transfers/create-standing-instructions/create-standing-instructions.component.ts index b8b3c3c85..01f92e438 100644 --- a/src/app/account-transfers/create-standing-instructions/create-standing-instructions.component.ts +++ b/src/app/account-transfers/create-standing-instructions/create-standing-instructions.component.ts @@ -114,6 +114,9 @@ export class CreateStandingInstructionsComponent implements OnInit { case 'fromsavings': this.accountTypeId = '2'; break; + case 'fromcurrentaccount': + this.accountTypeId = '3'; + break; default: this.accountTypeId = '0'; } diff --git a/src/app/account-transfers/edit-standing-instructions/edit-standing-instructions.component.ts b/src/app/account-transfers/edit-standing-instructions/edit-standing-instructions.component.ts index f532a37fc..4c8b6bdf9 100644 --- a/src/app/account-transfers/edit-standing-instructions/edit-standing-instructions.component.ts +++ b/src/app/account-transfers/edit-standing-instructions/edit-standing-instructions.component.ts @@ -84,37 +84,76 @@ export class EditStandingInstructionsComponent implements OnInit { */ ngOnInit() { this.createEditStandingInstructionsForm(); - const presentDate = new Date(); - const n = presentDate.getFullYear(); - if (this.standingInstructionsData.recurrenceOnMonthDay) { - this.standingInstructionsData.recurrenceOnMonthDay.push(n); - } + const d = this.standingInstructionsData; this.editStandingInstructionsForm.patchValue({ - name: this.standingInstructionsData.name, - applicant: this.standingInstructionsData.fromClient.displayName, - type: this.standingInstructionsData.transferType.value, - priority: this.standingInstructionsData.priority.id, - status: this.standingInstructionsData.status.id, - fromAccountType: this.standingInstructionsData.fromAccountType.value, - fromAccount: this.standingInstructionsData.fromAccount.productName, + name: d.name, + applicant: d.fromClient?.displayName, + type: d.transferType?.value, + priority: d.priority?.id, + status: d.status?.id, + fromAccountType: d.fromAccountType?.value, + fromAccount: d.fromAccount?.productName + ? `${d.fromAccount.productName} - ${d.fromAccount.accountNo}` + : d.fromAccount?.accountNo, destination: this.allowclientedit ? 'Within Bank' : 'Own Account', - toOffice: this.standingInstructionsData.toOffice.name, - toClientId: this.standingInstructionsData.toClient.displayName, - toAccountType: this.standingInstructionsData.toAccountType.value, - toAccount: this.standingInstructionsData.toAccount.productName, - instructionType: this.standingInstructionsData.instructionType.id, - amount: this.standingInstructionsData.amount, - validFrom: this.standingInstructionsData.validFrom && new Date(this.standingInstructionsData.validFrom), - validTill: this.standingInstructionsData.validTill && new Date(this.standingInstructionsData.validTill), - recurrenceType: this.standingInstructionsData.recurrenceType.id, - recurrenceInterval: this.standingInstructionsData.recurrenceInterval, - recurrenceFrequency: this.standingInstructionsData.recurrenceFrequency.id, - recurrenceOnMonthDay: - this.standingInstructionsData.recurrenceOnMonthDay && - new Date(this.standingInstructionsData.recurrenceOnMonthDay) + toOffice: d.toOffice?.name, + toClientId: d.toClient?.displayName, + toAccountType: d.toAccountType?.value, + toAccount: d.toAccount?.productName + ? `${d.toAccount.productName} - ${d.toAccount.accountNo}` + : d.toAccount?.accountNo, + instructionType: d.instructionType?.id, + amount: d.amount, + validFrom: this.parseISODate(d.validFrom), + validTill: this.parseISODate(d.validTill), + recurrenceType: d.recurrenceType?.id, + recurrenceInterval: d.recurrenceInterval, + recurrenceFrequency: d.recurrenceFrequency?.id, + recurrenceOnMonthDay: this.parseMonthDay(d.recurrenceOnMonthDay) }); } + /** + * Parses an ISO date string "YYYY-MM-DD" or array [year, month, day] + * into a local-timezone Date (avoids UTC-offset off-by-one day issues). + */ + private parseISODate(value: any): Date | null { + if (!value) return null; + if (typeof value === 'string') { + const parts = value.split('-'); + if (parts.length === 3) { + return new Date(+parts[0], +parts[1] - 1, +parts[2]); + } + return new Date(value); + } + if (Array.isArray(value) && value.length >= 3) { + // Array format [year, month, day] — month is 1-indexed in Java + return new Date(value[0], value[1] - 1, value[2]); + } + return null; + } + + /** + * Parses a MonthDay value from the API into a Date for the current year. + * Handles ISO MonthDay string "--MM-DD" (Jackson default) and + * legacy array format [month, day]. + */ + private parseMonthDay(value: any): Date | null { + if (!value) return null; + const currentYear = new Date().getFullYear(); + if (typeof value === 'string') { + // ISO MonthDay: "--MM-DD" + const match = value.match(/^--(\d{2})-(\d{2})$/); + if (match) { + return new Date(currentYear, +match[1] - 1, +match[2]); + } + } else if (Array.isArray(value) && value.length >= 2) { + // Legacy array [month, day] — month is 1-indexed + return new Date(currentYear, value[0] - 1, value[1]); + } + return null; + } + /** * Creates the standing instructions form. */ diff --git a/src/app/account-transfers/list-standing-instructions/list-standing-instructions.component.html b/src/app/account-transfers/list-standing-instructions/list-standing-instructions.component.html index 49891fd9f..4c6fbaecd 100644 --- a/src/app/account-transfers/list-standing-instructions/list-standing-instructions.component.html +++ b/src/app/account-transfers/list-standing-instructions/list-standing-instructions.component.html @@ -46,7 +46,7 @@ {{ 'labels.inputs.Type' | translate }} - @for (transferTypeData of transferTypeDatas; track transferTypeData) { + @for (transferTypeData of transferTypeDatas; track transferTypeData.id) { {{ transferTypeData.value }} diff --git a/src/app/account-transfers/list-standing-instructions/list-standing-instructions.component.ts b/src/app/account-transfers/list-standing-instructions/list-standing-instructions.component.ts index 1662a3bfd..9fe316c02 100644 --- a/src/app/account-transfers/list-standing-instructions/list-standing-instructions.component.ts +++ b/src/app/account-transfers/list-standing-instructions/list-standing-instructions.component.ts @@ -118,12 +118,12 @@ export class ListStandingInstructionsComponent { constructor() { this.route.data.subscribe((data: { standingIntructionsTemplate: any }) => { this.standingIntructionsTemplateData = data.standingIntructionsTemplate; + this.setParams(); + this.transferTypeDatas = this.standingIntructionsTemplateData.transferTypeOptions; if (data.standingIntructionsTemplate.fromClient) { this.clientName = this.standingIntructionsTemplateData.fromClient.displayName; this.getStandingInstructions(); } - this.setParams(); - this.transferTypeDatas = this.standingIntructionsTemplateData.transferTypeOptions; }); } @@ -136,6 +136,9 @@ export class ListStandingInstructionsComponent { case 'fromsavings': this.accountTypeId = '2'; break; + case 'fromcurrentaccount': + this.accountTypeId = '3'; + break; default: this.accountTypeId = '0'; } diff --git a/src/app/account-transfers/view-standing-instructions/view-standing-instructions.component.html b/src/app/account-transfers/view-standing-instructions/view-standing-instructions.component.html index c52329a43..3a54526c2 100644 --- a/src/app/account-transfers/view-standing-instructions/view-standing-instructions.component.html +++ b/src/app/account-transfers/view-standing-instructions/view-standing-instructions.component.html @@ -6,134 +6,193 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/. --> -
- - -
-
+ +
+ + +
+ -
-

{{ standingInstructionsData.name }}

- - - -
- {{ 'labels.inputs.Applicant' | translate }}: - {{ standingInstructionsData.fromClient.displayName }} -
- -
- {{ 'labels.inputs.Type' | translate }}: - {{ standingInstructionsData.transferType.value }} -
- -
- {{ 'labels.inputs.Priority' | translate }}: - {{ standingInstructionsData.priority.value }} -
- -
- {{ 'labels.inputs.Status' | translate }}: - {{ standingInstructionsData.status.value }} -
- -
- {{ 'labels.inputs.From Account Type' | translate }}: - {{ standingInstructionsData.fromAccountType.value }} -
- -
- {{ 'labels.inputs.From Account' | translate }}: - {{ standingInstructionsData.fromAccount.productName }} - - {{ standingInstructionsData.fromAccount.accountNo }} -
- -
- {{ 'labels.inputs.Destination' | translate }}: - - @if (allowclientedit) { - {{ 'labels.inputs.Within Bank' | translate }} - } - @if (!allowclientedit) { - {{ 'labels.inputs.Own Account' | translate }} - } +
+ +
+

{{ standingInstructionsData?.name }}

+ + {{ standingInstructionsData?.status?.value }}
-
- {{ 'labels.inputs.To Office' | translate }}: - {{ standingInstructionsData.toOffice.name }} -
+ -
- {{ 'labels.inputs.Beneficiary' | translate }}: - {{ standingInstructionsData.toClient.displayName }} -
+ +
+

{{ 'labels.heading.General Information' | translate }}

+ -
- {{ 'labels.inputs.To Account Type' | translate }}: - {{ standingInstructionsData.toAccountType.value }} -
+
+
+ {{ 'labels.inputs.Applicant' | translate }}: + {{ standingInstructionsData?.fromClient?.displayName }} +
-
- {{ 'labels.inputs.To Account' | translate }}: - {{ standingInstructionsData.toAccount.productName }} - - {{ standingInstructionsData.toAccount.accountNo }} -
+
+ {{ 'labels.inputs.Type' | translate }}: + {{ standingInstructionsData?.transferType?.value }} +
-
- {{ 'labels.inputs.Standing Instruction Type' | translate }}: - {{ standingInstructionsData.instructionType.value }} -
+
+ {{ 'labels.inputs.Priority' | translate }}: + {{ standingInstructionsData?.priority?.value }} +
-
- {{ 'labels.inputs.Amount' | translate }}: - {{ standingInstructionsData.amount }} -
+
+ {{ 'labels.inputs.Standing Instruction Type' | translate }}: + {{ standingInstructionsData?.instructionType?.value }} +
+
+
-
- {{ 'labels.inputs.Validity' | translate }}: - {{ standingInstructionsData.validFrom | dateFormat }} - - {{ standingInstructionsData.validTill | dateFormat }} -
+ +
+

{{ 'labels.heading.From Account' | translate }}

+ -
- {{ 'labels.inputs.Recurrence Type' | translate }}: - {{ standingInstructionsData.recurrenceType.value }} -
+
+
+ {{ 'labels.inputs.Office' | translate }}: + {{ standingInstructionsData?.fromOffice?.name }} +
-
- {{ 'labels.inputs.Interval' | translate }}: - {{ standingInstructionsData.recurrenceInterval }} -
+
+ {{ 'labels.inputs.Client' | translate }}: + {{ standingInstructionsData?.fromClient?.displayName }} +
-
- {{ 'labels.inputs.Recurrence Frequency' | translate }}: - {{ standingInstructionsData.recurrenceFrequency.value }} -
+
+ {{ 'labels.inputs.Account Type' | translate }}: + {{ standingInstructionsData?.fromAccountType?.value }} +
-
- {{ 'labels.inputs.On Month Day' | translate }}: - {{ standingInstructionsData.recurrenceOnMonthDay | dateFormat }} -
+
+ {{ 'labels.inputs.Account' | translate }}: + + @if (standingInstructionsData?.fromAccount?.productName) { + {{ standingInstructionsData.fromAccount.productName }} — + } + {{ standingInstructionsData?.fromAccount?.accountNo }} + +
+
+
+ + +
+

{{ 'labels.heading.To Account' | translate }}

+ + +
+
+ {{ 'labels.inputs.Destination' | translate }}: + + @if (allowclientedit) { + {{ 'labels.inputs.Within Bank' | translate }} + } @else { + {{ 'labels.inputs.Own Account' | translate }} + } + +
+ +
+ {{ 'labels.inputs.Office' | translate }}: + {{ standingInstructionsData?.toOffice?.name }} +
+ +
+ {{ 'labels.inputs.Beneficiary' | translate }}: + {{ standingInstructionsData?.toClient?.displayName }} +
+ +
+ {{ 'labels.inputs.Account Type' | translate }}: + {{ standingInstructionsData?.toAccountType?.value }} +
+ +
+ {{ 'labels.inputs.Account' | translate }}: + + @if (standingInstructionsData?.toAccount?.productName) { + {{ standingInstructionsData.toAccount.productName }} — + } + {{ standingInstructionsData?.toAccount?.accountNo }} + +
+
+
+ + +
+

{{ 'labels.heading.Transfer Settings' | translate }}

+ + +
+
+ {{ 'labels.inputs.Amount' | translate }}: + {{ standingInstructionsData?.amount | number: '1.2-2' }} +
+ +
+ {{ 'labels.inputs.Valid From' | translate }}: + {{ standingInstructionsData?.validFrom | dateFormat }} +
+ +
+ {{ 'labels.inputs.Valid Till' | translate }}: + {{ standingInstructionsData?.validTill | dateFormat }} +
+
+
+ + +
+

{{ 'labels.heading.Recurrence Settings' | translate }}

+ + +
+
+ {{ 'labels.inputs.Recurrence Type' | translate }}: + {{ standingInstructionsData?.recurrenceType?.value }} +
+ +
+ {{ 'labels.inputs.Interval' | translate }}: + {{ standingInstructionsData?.recurrenceInterval }} +
+ +
+ {{ 'labels.inputs.Recurrence Frequency' | translate }}: + {{ standingInstructionsData?.recurrenceFrequency?.value }} +
+ + @if (standingInstructionsData?.recurrenceOnMonthDay) { +
+ {{ 'labels.inputs.On Month Day' | translate }}: + {{ standingInstructionsData?.recurrenceOnMonthDay | dateFormat }} +
+ } +
+
diff --git a/src/app/account-transfers/view-standing-instructions/view-standing-instructions.component.scss b/src/app/account-transfers/view-standing-instructions/view-standing-instructions.component.scss index ba91271cd..1f5d86bbd 100644 --- a/src/app/account-transfers/view-standing-instructions/view-standing-instructions.component.scss +++ b/src/app/account-transfers/view-standing-instructions/view-standing-instructions.component.scss @@ -6,25 +6,113 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -.mat-elevation-z1 { - margin: 1em 0 1.5em; +.action-buttons { + display: flex; + gap: 0.75rem; + justify-content: flex-end; + flex-wrap: wrap; } -h2, -h3, -h4 { +.si-container { + display: flex; + flex-direction: column; + gap: 1.5rem; +} + +.si-header { + display: flex; + align-items: center; + gap: 1rem; + flex-wrap: wrap; + + h2 { + margin: 0; + font-size: 1.4rem; + font-weight: 500; + flex: 1; + } +} + +.status-badge { + display: inline-block; + padding: 0.2rem 0.75rem; + border-radius: 12px; + font-size: 0.8rem; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.5px; + background-color: #e0e0e0; + color: #555; + + &.status-active { + background-color: #e8f5e9; + color: #2e7d32; + } + + &.status-disabled { + background-color: #fff3e0; + color: #e65100; + } + + &.status-deleted { + background-color: #f5f5f5; + color: #9e9e9e; + } +} + +.si-section { + display: flex; + flex-direction: column; + gap: 0.75rem; +} + +.section-title { margin: 0; - font-weight: 500; -} - -span { - margin: 0.5em 0; -} - -.margin-t { - margin-top: 1em; + font-size: 1rem; + font-weight: 600; + color: var(--mdc-theme-primary, #3f51b5); + text-transform: uppercase; + letter-spacing: 0.5px; } mat-divider { - margin: 0 0 1em; + margin-bottom: 0.25rem; +} + +.info-grid { + display: grid; + gap: 0.6rem; +} + +.info-row { + display: grid; + grid-template-columns: minmax(160px, 220px) 1fr; + gap: 1rem; + align-items: start; + + @media (width <= 768px) { + grid-template-columns: 1fr; + gap: 0.2rem; + } +} + +.info-label { + font-weight: 500; + color: rgb(0 0 0 / 60%); + + @media (width <= 768px) { + font-size: 0.8rem; + color: rgb(0 0 0 / 45%); + } +} + +.info-value { + word-break: break-word; + color: rgb(0 0 0 / 87%); + + &.amount-value { + font-size: 1.1rem; + font-weight: 600; + color: var(--mdc-theme-primary, #3f51b5); + } } diff --git a/src/app/current-accounts/current-account-view/standing-instructions-tab/standing-instructions-tab.component.html b/src/app/current-accounts/current-account-view/standing-instructions-tab/standing-instructions-tab.component.html index b517656ff..b7fce4f5c 100644 --- a/src/app/current-accounts/current-account-view/standing-instructions-tab/standing-instructions-tab.component.html +++ b/src/app/current-accounts/current-account-view/standing-instructions-tab/standing-instructions-tab.component.html @@ -16,32 +16,43 @@ {{ 'labels.inputs.Client' | translate }} - {{ instruction.fromClient.displayName }}-{{ instruction.fromClient.id }} + {{ instruction.fromClient?.displayName }}-{{ instruction.fromClient?.id }} {{ 'labels.inputs.From Account' | translate }} - {{ instruction.fromAccount.accountNo }} ({{ instruction.fromAccountType.value }}) + {{ instruction.fromAccount?.accountNo }} + @if (instruction.fromAccountType?.value) { + ({{ instruction.fromAccountType.value }}) + } {{ 'labels.inputs.Beneficiary' | translate }} - {{ instruction.toClient.displayName }} + {{ instruction.toClient?.displayName }} {{ 'labels.inputs.To Account' | translate }} - {{ instruction.toAccount.accountNo }} ({{ instruction.toAccountType.value }}) + {{ instruction.toAccount?.accountNo }} + @if (instruction.toAccountType?.value) { + ({{ instruction.toAccountType.value }}) + } {{ 'labels.inputs.Amount' | translate }} - {{ instruction.instructionType.value }}/{{ instruction.amount }} + + @if (instruction.instructionType?.value) { + {{ instruction.instructionType.value }}/ + } + {{ instruction.amount }} + @@ -55,7 +66,7 @@ {{ 'labels.inputs.Actions' | translate }} - @if (instruction.status.value !== 'Deleted') { + @if (instruction.status?.value !== 'Deleted') {