diff --git a/src/app/accounting/accounting-rules/create-rule/create-rule.component.ts b/src/app/accounting/accounting-rules/create-rule/create-rule.component.ts index 7fa91fa9b..c047bb083 100644 --- a/src/app/accounting/accounting-rules/create-rule/create-rule.component.ts +++ b/src/app/accounting/accounting-rules/create-rule/create-rule.component.ts @@ -1,5 +1,7 @@ /** Angular Imports */ import { Component, OnInit, inject } from '@angular/core'; +import { TranslateService } from '@ngx-translate/core'; +import { MatSnackBar } from '@angular/material/snack-bar'; import { UntypedFormGroup, UntypedFormBuilder, Validators, ReactiveFormsModule } from '@angular/forms'; import { Router, ActivatedRoute, RouterLink } from '@angular/router'; @@ -33,6 +35,8 @@ export class CreateRuleComponent implements OnInit { private accountingService = inject(AccountingService); private route = inject(ActivatedRoute); private router = inject(Router); + private snackBar = inject(MatSnackBar); + private translateService = inject(TranslateService); /** Accounting rule form. */ accountingRuleForm: UntypedFormGroup; @@ -45,13 +49,6 @@ export class CreateRuleComponent implements OnInit { /** Credit tag data. */ creditTagData: any; - /** - * Retrieves the offices, gl accounts, debit tags and credit tags data from `resolve`. - * @param {FormBuilder} formBuilder Form Builder. - * @param {AccountingService} accountingService Accounting Service. - * @param {ActivatedRoute} route Activated Route. - * @param {Router} router Router for navigation. - */ constructor() { this.route.data.subscribe((data: { accountingRulesTemplate: any }) => { this.officeData = data.accountingRulesTemplate.allowedOffices; @@ -141,14 +138,42 @@ export class CreateRuleComponent implements OnInit { } delete accountingRule.debitRuleType; delete accountingRule.creditRuleType; - this.accountingService.createAccountingRule(accountingRule).subscribe((response: any) => { - this.router.navigate( - [ - '../view', - response.resourceId - ], - { relativeTo: this.route } - ); + this.accountingService.createAccountingRule(accountingRule).subscribe({ + next: (response: any) => { + this.router.navigate( + [ + '../view', + response.resourceId + ], + { relativeTo: this.route } + ); + }, + error: (err) => { + const duplicateMsg = this.translateService.instant('errors.accountingRule.duplicateName'); + if ( + err?.error?.defaultUserMessage?.includes('Duplicate entry') || + (typeof err?.error?.message === 'string' && err.error.message.includes('Duplicate entry')) || + (typeof err?.error === 'string' && err.error.includes('Duplicate entry')) + ) { + this.snackBar.open(duplicateMsg, 'Close', { + duration: 7000, + verticalPosition: 'top', + horizontalPosition: 'right', + panelClass: 'custom-snackbar-top-right' + }); + } else { + this.snackBar.open( + err?.error?.defaultUserMessage || err?.error?.message || 'An error occurred. Please try again.', + 'Close', + { + duration: 7000, + verticalPosition: 'top', + horizontalPosition: 'right', + panelClass: 'custom-snackbar-top-right' + } + ); + } + } }); } } diff --git a/src/assets/translations/cs-CS.json b/src/assets/translations/cs-CS.json index e7e0c9be4..6874b4c48 100644 --- a/src/assets/translations/cs-CS.json +++ b/src/assets/translations/cs-CS.json @@ -3,6 +3,9 @@ "Logged in as": "Přihlášen jako", "Remember me": "Zapamatuj si mě", "errors": { + "accountingRule": { + "duplicateName": "Omlouváme se, ale účetní pravidlo s tímto názvem již existuje." + }, "error.resource.notImplemented.type": "Nenaimplementovaná chyba", "error.resource.notImplemented.message": "Funkce není implementována!", "linkedSavingsAccountOwnership": "Propojený spořicí účet nepatří vybranému klientovi.", diff --git a/src/assets/translations/de-DE.json b/src/assets/translations/de-DE.json index e380385bf..e902f233d 100644 --- a/src/assets/translations/de-DE.json +++ b/src/assets/translations/de-DE.json @@ -3,6 +3,9 @@ "Logged in as": "Angemeldet als", "Remember me": "Erinnere dich an mich", "errors": { + "accountingRule": { + "duplicateName": "Entschuldigung, aber eine Buchungsregel mit diesem Namen existiert bereits." + }, "error.resource.notImplemented.type": "Nicht implementierter Fehler", "error.resource.notImplemented.message": "Nicht implementierte Funktion!", "linkedSavingsAccountOwnership": "Verknüpftes Sparkonto gehört nicht zum ausgewählten Kunden.", diff --git a/src/assets/translations/en-US.json b/src/assets/translations/en-US.json index 5254dfd28..b3e962680 100644 --- a/src/assets/translations/en-US.json +++ b/src/assets/translations/en-US.json @@ -5,6 +5,9 @@ "error.resource.notImplemented.type": "Not Implemented Error", "error.resource.notImplemented.message": "Not implemented functionality!", "errors": { + "accountingRule": { + "duplicateName": "Sorry, but an Accounting Rule with this Name exists already." + }, "linkedSavingsAccountOwnership": "Linked savings account does not belong to the selected client.", "clientNotInGSIM": "Client with ID {{id}} is not present in GSIM.", "Capitalized Income amount adjusted already adjusted": "Capitalized Income amount already adjusted", diff --git a/src/assets/translations/es-CL.json b/src/assets/translations/es-CL.json index ad610d76d..5338d75f5 100644 --- a/src/assets/translations/es-CL.json +++ b/src/assets/translations/es-CL.json @@ -3,6 +3,9 @@ "Logged in as": "Conectado como", "Remember me": "Recordar me", "errors": { + "accountingRule": { + "duplicateName": "Lo sentimos, pero ya existe una regla contable con este nombre." + }, "error.resource.notImplemented.type": "Error no implementado", "error.resource.notImplemented.message": "¡Funcionalidad no implementada!", "linkedSavingsAccountOwnership": "La cuenta de ahorro vinculada no pertenece al cliente seleccionado.", diff --git a/src/assets/translations/es-MX.json b/src/assets/translations/es-MX.json index bd5bfaaf3..1ac8818b1 100644 --- a/src/assets/translations/es-MX.json +++ b/src/assets/translations/es-MX.json @@ -3,6 +3,9 @@ "Logged in as": "Conectado como", "Remember me": "Recordar me", "errors": { + "accountingRule": { + "duplicateName": "Lo sentimos, pero ya existe una regla contable con este nombre." + }, "error.resource.notImplemented.type": "Error no implementado", "error.resource.notImplemented.message": "¡Funcionalidad no implementada!", "linkedSavingsAccountOwnership": "La cuenta de ahorro vinculada no pertenece al cliente seleccionado.", diff --git a/src/assets/translations/fr-FR.json b/src/assets/translations/fr-FR.json index 53463a72a..11ffa2962 100644 --- a/src/assets/translations/fr-FR.json +++ b/src/assets/translations/fr-FR.json @@ -3,6 +3,9 @@ "Logged in as": "connecté en tant que", "Remember me": "Souviens-toi de moi", "errors": { + "accountingRule": { + "duplicateName": "Désolé, mais une règle comptable portant ce nom existe déjà." + }, "error.resource.notImplemented.type": "Erreur non implémentée", "error.resource.notImplemented.message": "Fonctionnalité non implémentée !", "linkedSavingsAccountOwnership": "Le compte d'épargne lié n'appartient pas au client sélectionné.", diff --git a/src/assets/translations/it-IT.json b/src/assets/translations/it-IT.json index 0f62d7a69..0d17d6345 100644 --- a/src/assets/translations/it-IT.json +++ b/src/assets/translations/it-IT.json @@ -3,6 +3,9 @@ "Logged in as": "Collegato come", "Remember me": "Ricordati di me", "errors": { + "accountingRule": { + "duplicateName": "Spiacenti, ma esiste già una regola contabile con questo nome." + }, "error.resource.notImplemented.type": "Errore non implementato", "error.resource.notImplemented.message": "Funzionalità non implementata!", "linkedSavingsAccountOwnership": "Il conto di risparmio collegato non appartiene al cliente selezionato.", diff --git a/src/assets/translations/ko-KO.json b/src/assets/translations/ko-KO.json index b25348f6a..9295c7afe 100644 --- a/src/assets/translations/ko-KO.json +++ b/src/assets/translations/ko-KO.json @@ -3,6 +3,9 @@ "Logged in as": "다음 계정으로 로그인됨", "Remember me": "날 기억해", "errors": { + "accountingRule": { + "duplicateName": "죄송합니다. 이미 동일한 이름의 회계 규칙이 존재합니다." + }, "error.resource.notImplemented.type": "구현되지 않은 오류", "error.resource.notImplemented.message": "구현되지 않은 기능입니다!", "linkedSavingsAccountOwnership": "연결된 저축 계좌가 선택한 클라이언트에 속하지 않습니다.", diff --git a/src/assets/translations/lt-LT.json b/src/assets/translations/lt-LT.json index 07c462a93..b405a569e 100644 --- a/src/assets/translations/lt-LT.json +++ b/src/assets/translations/lt-LT.json @@ -3,6 +3,9 @@ "Logged in as": "prisijungęs kaip", "Remember me": "Prisimink mane", "errors": { + "accountingRule": { + "duplicateName": "Atsiprašome, bet apskaitos taisyklė su šiuo pavadinimu jau egzistuoja." + }, "error.resource.notImplemented.type": "Neįdiegta klaida", "error.resource.notImplemented.message": "Funkcionalumas neįdiegtas!", "linkedSavingsAccountOwnership": "Susieta taupomoji sąskaita nepriklauso pasirinktam klientui.", diff --git a/src/assets/translations/lv-LV.json b/src/assets/translations/lv-LV.json index f790ae8e6..1c6038a15 100644 --- a/src/assets/translations/lv-LV.json +++ b/src/assets/translations/lv-LV.json @@ -3,6 +3,9 @@ "Logged in as": "ielogojies Kā", "Remember me": "Atceries mani", "errors": { + "accountingRule": { + "duplicateName": "Atvainojiet, bet grāmatvedības noteikums ar šo nosaukumu jau pastāv." + }, "error.resource.notImplemented.type": "Neieviesta kļūda", "error.resource.notImplemented.message": "Funkcionalitāte nav ieviesta!", "linkedSavingsAccountOwnership": "Saistītais krājkonts nepieder izvēlētajam klientam.", diff --git a/src/assets/translations/ne-NE.json b/src/assets/translations/ne-NE.json index 662f52b2c..993005a71 100644 --- a/src/assets/translations/ne-NE.json +++ b/src/assets/translations/ne-NE.json @@ -3,6 +3,9 @@ "Logged in as": "को रूपमा लग इन गरियो", "Remember me": "मलाई सम्झनुहोस्", "errors": { + "accountingRule": { + "duplicateName": "माफ गर्नुहोस्, यो नामको लेखा नियम पहिले नै अवस्थित छ।" + }, "error.resource.notImplemented.type": "लागू नभएको त्रुटि", "error.resource.notImplemented.message": "कार्यक्षमता लागू गरिएको छैन!", "linkedSavingsAccountOwnership": "लिंक गरिएको बचत खाता चयनित ग्राहकको होइन।", diff --git a/src/assets/translations/pt-PT.json b/src/assets/translations/pt-PT.json index 78c33cbcb..c2754b6e9 100644 --- a/src/assets/translations/pt-PT.json +++ b/src/assets/translations/pt-PT.json @@ -3,6 +3,9 @@ "Logged in as": "logado como", "Remember me": "Lembre de mim", "errors": { + "accountingRule": { + "duplicateName": "Desculpe, mas já existe uma regra contabilística com este nome." + }, "error.resource.notImplemented.type": "Erro não implementado", "error.resource.notImplemented.message": "Funcionalidade não implementada!", "linkedSavingsAccountOwnership": "A conta poupança vinculada não pertence ao cliente selecionado.", diff --git a/src/assets/translations/sw-SW.json b/src/assets/translations/sw-SW.json index 790e29e90..6550a2592 100644 --- a/src/assets/translations/sw-SW.json +++ b/src/assets/translations/sw-SW.json @@ -3,6 +3,9 @@ "Logged in as": "Imeingia kama", "Remember me": "Nikumbuke", "errors": { + "accountingRule": { + "duplicateName": "Samahani, lakini Kanuni ya Uhasibu yenye jina hili tayari ipo." + }, "error.resource.notImplemented.type": "Hitilafu ya Kukamilika Haijatimizwa", "error.resource.notImplemented.message": "Utendakazi haujatekelezwa!", "linkedSavingsAccountOwnership": "Akaunti ya akiba iliyounganishwa haimilikiwi na mteja aliyechaguliwa.", diff --git a/src/main.scss b/src/main.scss index 90afcc0f8..f97bd9420 100644 --- a/src/main.scss +++ b/src/main.scss @@ -1,11 +1,3 @@ -// Version 1 - -/* - * Entry point of global application style. - * Component-specific style should not go here and be included directly as part of the components. - */ - -// Import Default Theme for MifosX @use 'theme/mifosx-theme'; @use 'theme/pictonblue-yellowgreen' as *; @use 'theme/indigo-pink' as *; @@ -17,13 +9,20 @@ @use 'lightgallery/scss/lg-thumbnail' as *; @use 'lightgallery/scss/lg-zoom' as *; @use 'lightgallery/scss/lg-fullscreen' as *; +@use 'app/core/error-handler/error-handler.component'; // Global Imports /* You can add global styles to this file, and also import other style files */ -// Error Handler Service Styles -@use 'app/core/error-handler/error-handler.component'; +.custom-snackbar-top-right { + top: 48px !important; + right: 24px !important; + left: auto !important; + transform: none !important; + position: fixed !important; + z-index: 9999; +} .scrollbar-styling { scrollbar-width: thin;