diff --git a/src/app/app.constants.ts b/src/app/app.constants.ts index 154ef236..5bbb1bde 100644 --- a/src/app/app.constants.ts +++ b/src/app/app.constants.ts @@ -109,3 +109,6 @@ export const LOADING = 'loading'; export const SESSION_IDLE_TIMEOUT = "sessionIdleTimeout"; export const SESSION_IDLE_TIMER = 'sessionIdleTimer'; export const SESSION_IDLE_PING = 'sessionIdlePing'; + +// +export const TERMS_AND_CONDTIONS_TEMPLATE = 'terms_and_conditions_template'; diff --git a/src/app/app.utils.ts b/src/app/app.utils.ts index 121d38de..e6fce580 100644 --- a/src/app/app.utils.ts +++ b/src/app/app.utils.ts @@ -900,4 +900,134 @@ export default class Utils { } } + static isConsentGiven(dataService: DataService, resourceBundleJson: any, dialog: MatDialog, version: string) { + return new Promise((resolve, reject) => { + dataService.isConsentGiven(version).subscribe( + (response: any) => { + if (response.errors && response.errors.length > 0) { + Utils.showConsentError(resourceBundleJson, response.errors, dialog); + reject(response.errors); + } else { + resolve(response['response']); + } + }, + (errors: any) => { + this.showConsentError(resourceBundleJson, errors, dialog); + reject(errors); + } + ) + }); + } + + static getTemplate(dataService: DataService, resourceBundleJson: any, dialog: MatDialog, langCode: string, templateName: string, version: string) { + return new Promise((resolve, reject) => { + dataService.getTemplate(langCode, templateName, version).subscribe( + (response: any) => { + if (response.errors && response.errors.length > 0) { + Utils.showConsentError(resourceBundleJson, response.errors, dialog); + reject(response.errors); + } else { + resolve(response['response']['template']); + } + }, + (errors: any) => { + Utils.showConsentError(resourceBundleJson, errors, dialog); + reject(errors); + } + ); + }); + } + + static getLatestTemplateVersion(dataService: DataService, resourceBundleJson: any, dialog: MatDialog, templateName: string) { + return new Promise((resolve, reject) => { + dataService.getLatestTemplateVersion(templateName).subscribe( + (response: any) => { + if (response.errors && response.errors.length > 0) { + Utils.showConsentError(resourceBundleJson, response.errors, dialog); + reject(response.errors); + } else { + resolve(response['response']); + } + }, + (errors: any) => { + Utils.showConsentError(resourceBundleJson, errors, dialog); + reject(errors); + } + ); + }); + } + + static showConsentError( + resourceBundle: any, + errorsList: any, + dialog: MatDialog, + customMsg?: string, + showErrCode?: boolean, + customErrorCode?: string + ) { + const titleOnError = resourceBundle.serviceErrors['error'] ? resourceBundle.serviceErrors['error'] : 'Error'; + let message = ''; + if (errorsList && errorsList.length > 0) { + let error = errorsList[0]; + const translatedMsg = resourceBundle.serviceErrors[error.errorCode]; + if (!showErrCode) { + if (translatedMsg) { + message = translatedMsg; + } else { + message = error.message; + } + } else { + if (translatedMsg) { + message = error.errorCode + ? error.errorCode + ' - ' + translatedMsg + : translatedMsg; + } else { + message = error.errorCode + ? error.errorCode + ' - ' + error.message + : error.message; + } + } + } + if (customMsg) { + message = customErrorCode ? resourceBundle.serviceErrors[customErrorCode] : customMsg; + } + if (message == '') { + message = 'Unexpected error occured.'; + } + const body = { + case: 'TERMS_AND_CONDITIONS_CONSENT_ERROR', + title: titleOnError, + message: message, + }; + const dialogRef = dialog.open(DialogComponent, { + width: '400px', + data: body, + }); + return dialogRef; + } + + static showConsentPrompt(resourceBundle: any, titleKey: string, messageKey: string, dialog: MatDialog, customMsg?: string) { + let title: any; + let message: any; + if (resourceBundle && resourceBundle[titleKey] && resourceBundle[messageKey]) { + title = resourceBundle[titleKey]; + message = resourceBundle[messageKey]; + } else { + title = titleKey; + message = messageKey; + } + if (customMsg) { + message = message + " " + customMsg; + } + const body = { + case: 'TERMS_AND_CONDITIONS_CONSENT_ERROR', + title: title, + message: message, + }; + const dialogRef = dialog.open(DialogComponent, { + width: '400px', + data: body, + }); + return dialogRef; + } } diff --git a/src/app/core/components/dialog/dialog.component.css b/src/app/core/components/dialog/dialog.component.css index f86471d6..2ea6f030 100644 --- a/src/app/core/components/dialog/dialog.component.css +++ b/src/app/core/components/dialog/dialog.component.css @@ -209,6 +209,21 @@ ul.reviewMessage li:before { margin-right: 5px; } +.checkbox-margin { + margin-bottom: 10px; + margin-left: 10px; +} + +.consent-checkbox { + margin-top: 10px; + margin-bottom: 5px; + margin-left: 10px; +} + +.consent-checkbox ::ng-deep .mat-checkbox-layout { + white-space: normal; +} + @media screen and (max-width: 750px) { .fieldContainer { margin-left: 60px; @@ -270,7 +285,7 @@ ul.reviewMessage li:before { margin-top: 15px; margin-bottom: 3px; } - ::ng-deep .mat-dialog-container{ + :not(.consent-box) ::ng-deep .mat-dialog-container{ display: flex; justify-content: center; } diff --git a/src/app/core/components/dialog/dialog.component.html b/src/app/core/components/dialog/dialog.component.html index c97125ea..5a1e4aaf 100644 --- a/src/app/core/components/dialog/dialog.component.html +++ b/src/app/core/components/dialog/dialog.component.html @@ -328,4 +328,34 @@

{{"dialogMessages.addProject"|tran + +
+

{{ input.title }}

+ +
+ clear {{ input.message }} +
+
+ + + +
diff --git a/src/app/core/components/dialog/dialog.component.ts b/src/app/core/components/dialog/dialog.component.ts index a1f7602c..98d086f1 100644 --- a/src/app/core/components/dialog/dialog.component.ts +++ b/src/app/core/components/dialog/dialog.component.ts @@ -54,6 +54,8 @@ export class DialogComponent implements OnInit { adminRejectComments: string = ''; rejectReport: boolean = false; isAndroidAppMode = environment.isAndroidAppMode == 'yes' ? true : false; + consentCheckbox: boolean; + consentTemplate: string; constructor( private router: Router, @@ -80,6 +82,9 @@ export class DialogComponent implements OnInit { this.resourceBundleJson = await Utils.getResourceBundle(this.userProfileService.getUserPreferredLanguage(), this.dataService); this.projectId = this.input.id; this.projectType = this.input.projectType; + if (this.input.case == 'TERMS_AND_CONDITIONS_CONSENT'){ + this.consentTemplate = this.input.consentTemplate; + } if(this.projectId) { if (this.projectType == appConstants.SBI) { this.initSbiProjectForm(); @@ -490,4 +495,38 @@ export class DialogComponent implements OnInit { this.dialogRef.close(); this.logoutservice.logout(); } + + setConsent() { + return new Promise((resolve, reject) => { + const subscription = this.dataService.setConsent().subscribe( + (response: any) => { + this.dialogRef.close(); + if (response.errors && response.errors.length > 0) { + Utils.showErrorMessage(this.resourceBundleJson, response.errors, this.dialog); + resolve(false); + } else { + const msg = 'addConsentDataSuccessMsg'; + const resourceBundle = this.resourceBundleJson.dialogMessages; + const successMsg = 'success'; + Utils.showSuccessMessage(resourceBundle, successMsg, msg, this.dialog); + resolve(true); + } + }, + (errors) => { + this.dialogRef.close(); + Utils.showErrorMessage(this.resourceBundleJson, errors, this.dialog); + resolve(false); + } + ); + this.subscriptions.push(subscription); + }); + } + + async closeConsentDialog() { + this.dialogRef.close(); + const msg = 'consentNotApproved'; + const resourceBundle = this.resourceBundleJson.dialogMessages; + const consentMsg = 'consent'; + Utils.showConsentPrompt(resourceBundle, consentMsg, msg, this.dialog); + } } diff --git a/src/app/core/services/data-service.ts b/src/app/core/services/data-service.ts index 2f3d5958..7a2ab225 100644 --- a/src/app/core/services/data-service.ts +++ b/src/app/core/services/data-service.ts @@ -248,6 +248,26 @@ export class DataService { return this.httpClient.get(url, { responseType: 'blob' }); } + getTemplate(langCode: string, templateName: string, version: string) { + const url = `${this.SERVICES_BASE_URL}getTemplate?langCode=${langCode}&templateName=${templateName}&version=${version}`; + return this.httpClient.get(url); + } + + getLatestTemplateVersion(templateName: string) { + const url = `${this.SERVICES_BASE_URL}getLatestTemplateVersion?templateName=${templateName}`; + return this.httpClient.get(url); + } + + setConsent() { + const url = `${this.SERVICES_BASE_URL}setConsent`; + return this.httpClient.post(url, {}); + } + + isConsentGiven(version: string) { + let url = `${this.SERVICES_BASE_URL}isConsentGiven?version=${version}`; + return this.httpClient.get(url); + } + getEncryptionKey() { let url = `${this.SERVICES_BASE_URL}getEncryptionKey`; return this.httpClient.get(url); diff --git a/src/app/features/dashboard/projects-dashboard/projects-dashboard.component.ts b/src/app/features/dashboard/projects-dashboard/projects-dashboard.component.ts index 1bb32ffa..630af394 100644 --- a/src/app/features/dashboard/projects-dashboard/projects-dashboard.component.ts +++ b/src/app/features/dashboard/projects-dashboard/projects-dashboard.component.ts @@ -84,10 +84,32 @@ export class ProjectsDashboardComponent implements OnInit { this.sort.sort(({ id: 'lastRunDt', start: 'desc'}) as MatSortable); } this.dataSource.sort = this.sort; + this.initConsent(); this.dataLoaded = true; this.sessionIdleTimeout(); } + async initConsent() { + let langCode = this.userProfileService.getUserPreferredLanguage(); + let templateName = appConstants.TERMS_AND_CONDTIONS_TEMPLATE; + try { + let latestTemplateVersion = await Utils.getLatestTemplateVersion(this.dataService, this.resourceBundleJson, this.dialog, templateName); + let isConsentGiven = await Utils.isConsentGiven(this.dataService, this.resourceBundleJson, this.dialog, latestTemplateVersion); + if (!isConsentGiven) { + let template = await Utils.getTemplate(this.dataService, this.resourceBundleJson, this.dialog, langCode, templateName, latestTemplateVersion); + const dialogRef = this.dialog.open(DialogComponent, { + width: '600px', + data: { + case: "TERMS_AND_CONDITIONS_CONSENT", + consentTemplate: template, + }, + }); + } + } catch (errors: any) { + console.error(errors[0].message); + } + } + sessionIdleTimeout() { const subs = this.sessionLogoutService.currentMessageAutoLogout.subscribe( (message) => (this.message = message) diff --git a/src/assets/i18n/ara.json b/src/assets/i18n/ara.json index da87b072..5c7a6396 100644 --- a/src/assets/i18n/ara.json +++ b/src/assets/i18n/ara.json @@ -41,7 +41,12 @@ "verifyMessage": "تحقق من قيم التجزئة وموقع الويب قبل المتابعة. إذا كانت القيم صحيحة، فاحفظ المشروع.", "saveBtn": "يحفظ", "sessionInactiveMessage": "سيتم مهلة لك بسبب عدم النشاط. الرجاء النقر في أي مكان لإعادة تنشيط جلستك", - "sessionInactivityLogoutMessage": "لقد تم تسجيل الخروج بسبب عدم النشاط." + "sessionInactivityLogoutMessage": "لقد تم تسجيل الخروج بسبب عدم النشاط.", + "consentNotApproved": "غير قادر على المتابعة دون موافقة الموافقة.", + "consentCheckbox": "أوافق على البنود والشروط", + "confirm": "يتأكد", + "consent": "موافقة", + "addConsentDataSuccessMsg": "لقد تم استلام موافقتك بنجاح." }, "breadcrumb": { "home": "بيت", @@ -2023,6 +2028,10 @@ "TOOLKIT_REQ_ERR_048": "اسم المشروع", "TOOLKIT_REQ_ERR_049": "رابط الموقع", "TOOLKIT_REQ_ERR_050": "عنوان URL لـ activeMQ", + "TOOLKIT_REQ_ERR_051": "لم يتم العثور على القالب. قم بتحميل القالب وحاول مرة أخرى!", + "TOOLKIT_REQ_ERR_052": "حدث خطأ أثناء جلب القالب", + "TOOLKIT_REQ_ERR_053": "تنسيق إصدار القالب غير صالح.", + "TOOLKIT_REQ_ERR_054": "حدث خطأ أثناء جلب نسخة القالب.", "TOOLKIT_REQ_ERR_500": "خطأ تقني", "TOOLKIT_DB_ERR_001": "لقد سبق لك إنشاء مشروع بالاسم", "TOOLKIT_DB_ERR_002": "لقد أضفت سابقًا بيانات اختبار القياسات الحيوية بالاسم", @@ -2061,6 +2070,8 @@ "TOOLKIT_REPORT_004": "حدث خطأ أثناء تغيير حالة التقرير", "TOOLKIT_REPORT_005": "حدث خطأ أثناء جلب قائمة التقارير.", "TOOLKIT_REPORT_006": "حدث خطأ أثناء جلب قائمة التقارير. حالة التقرير غير صالحة: ", + "TOOLKIT_CONSENT_ERR_001": "حدث خطأ أثناء جلب موافقة الشريك.", + "TOOLKIT_CONSENT_ERR_002": "حدث خطأ أثناء حفظ موافقة الشريك.", "error": "خطأ", "FILE_WITH_MULTIPLE_EXTENSIONS": "يجب ألا يحتوي اسم الملف على امتدادات متعددة" } diff --git a/src/assets/i18n/eng.json b/src/assets/i18n/eng.json index 30c000e5..aad550f6 100644 --- a/src/assets/i18n/eng.json +++ b/src/assets/i18n/eng.json @@ -41,7 +41,12 @@ "verifyMessage": "Verify the Hash and Website values before proceeding. If the values are correct, save the project.", "saveBtn": "Save", "sessionInactiveMessage": "You will be timed out due to inactivity. Please click anywhere to re-activate your session", - "sessionInactivityLogoutMessage": "You have been logged out due to inactivity." + "sessionInactivityLogoutMessage": "You have been logged out due to inactivity.", + "consentNotApproved": "Unable to proceed without consent approval.", + "consentCheckbox": "I agree to terms and conditions", + "confirm": "Confirm", + "consent": "Consent", + "addConsentDataSuccessMsg": "Your Consent has been successfully received." }, "breadcrumb": { "home": "Home", @@ -2023,6 +2028,10 @@ "TOOLKIT_REQ_ERR_048": "project name", "TOOLKIT_REQ_ERR_049": "website URL", "TOOLKIT_REQ_ERR_050": "active MQ URL", + "TOOLKIT_REQ_ERR_051": "Template not found. Upload template and try again!", + "TOOLKIT_REQ_ERR_052": "Error while fetching template", + "TOOLKIT_REQ_ERR_053": "Invalid template version format.", + "TOOLKIT_REQ_ERR_054": "Error while fetching template version.", "TOOLKIT_DB_ERR_001": "You have previously created a project with the same name", "TOOLKIT_DB_ERR_002": "You have previously added biometric test data with the same name", "TOOLKIT_DB_ERR_003": "You have previously created a collection with the same name", @@ -2061,6 +2070,8 @@ "TOOLKIT_REPORT_004": "Error while changing report status", "TOOLKIT_REPORT_005": "Error while fetching list of reports", "TOOLKIT_REPORT_006": "Error while fetching list of reports. Invalid report status: ", + "TOOLKIT_CONSENT_ERR_001": "Error while fetching partner consent.", + "TOOLKIT_CONSENT_ERR_002": "Error while saving partner consent.", "error": "Error", "FILE_WITH_MULTIPLE_EXTENSIONS": "File name should not contain multiple extensions" } diff --git a/src/assets/i18n/fra.json b/src/assets/i18n/fra.json index 789f0d3d..493705c9 100644 --- a/src/assets/i18n/fra.json +++ b/src/assets/i18n/fra.json @@ -41,7 +41,12 @@ "verifyMessage": "Vérifiez les valeurs de hachage et de site Web avant de continuer. Si les valeurs sont correctes, enregistrez le projet.", "saveBtn": "Sauvegarder", "sessionInactiveMessage": "Votre temps sera écoulé pour cause d'inactivité. Veuillez cliquer n'importe où pour réactiver votre session", - "sessionInactivityLogoutMessage": "Vous avez été déconnecté pour cause d'inactivité." + "sessionInactivityLogoutMessage": "Vous avez été déconnecté pour cause d'inactivité.", + "consentNotApproved": "Impossible de continuer sans l'approbation du consentement.", + "consentCheckbox": "J'accepte les termes et conditions", + "confirm": "Confirmer", + "consent": "Consentement", + "addConsentDataSuccessMsg": "Votre consentement a été reçu avec succès." }, "breadcrumb": { "home": "Maison", @@ -2023,6 +2028,10 @@ "TOOLKIT_REQ_ERR_048": "nom du projet", "TOOLKIT_REQ_ERR_049": "URL de site web", "TOOLKIT_REQ_ERR_050": "URL activeMQ", + "TOOLKIT_REQ_ERR_051": "Modèle introuvable. Téléchargez le modèle et réessayez !", + "TOOLKIT_REQ_ERR_052": "Erreur lors de la récupération du modèle", + "TOOLKIT_REQ_ERR_053": "Format de version de modèle non valide.", + "TOOLKIT_REQ_ERR_054": "Erreur lors de la récupération de la version du modèle.", "TOOLKIT_REQ_ERR_500": "Erreur technique", "TOOLKIT_DB_ERR_001": "Vous avez précédemment créé un projet avec le nom", "TOOLKIT_DB_ERR_002": "Vous avez précédemment ajouté des données de test biométrique avec le nom", @@ -2061,7 +2070,9 @@ "TOOLKIT_REPORT_004": "Erreur lors de la modification de l'état du rapport", "TOOLKIT_REPORT_005": "Erreur lors de la récupération de la liste des rapports.", "TOOLKIT_REPORT_006": "Erreur lors de la récupération de la liste des rapports. Statut du rapport invalide : ", - "error": "Errorerreur", + "TOOLKIT_CONSENT_ERR_001": "Erreur lors de la récupération du consentement du partenaire.", + "TOOLKIT_CONSENT_ERR_002": "Erreur lors de l'enregistrement du consentement du partenaire.", + "error": "Eerreur", "FILE_WITH_MULTIPLE_EXTENSIONS": "Le nom du fichier ne doit pas contenir plusieurs extensions" } } \ No newline at end of file