diff --git a/package-lock.json b/package-lock.json
index 0c262dd4..15d4a0f6 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "eudistack-wallet-ui",
- "version": "2.0.13",
+ "version": "2.0.14",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "eudistack-wallet-ui",
- "version": "2.0.13",
+ "version": "2.0.14",
"dependencies": {
"@angular/common": "^18.2.2",
"@angular/core": "^18.2.2",
diff --git a/package.json b/package.json
index 4a410e49..710d654d 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "eudistack-wallet-ui",
- "version": "2.0.13",
+ "version": "2.0.14",
"author": "Ionic Framework",
"homepage": "https://ionicframework.com/",
"scripts": {
diff --git a/src/app/interfaces/websocket-data.ts b/src/app/interfaces/websocket-data.ts
index f7b8e93d..4c203778 100644
--- a/src/app/interfaces/websocket-data.ts
+++ b/src/app/interfaces/websocket-data.ts
@@ -3,14 +3,22 @@ interface PinRequestData {
timeout?: number;
}
-interface NotificationData {
+export interface Power {
+ function: string;
+ action: string[];
+}
+
+export interface CredentialPreview {
+ power: Power[];
+ subjectName: string;
+ organization: string;
+ expirationDate: string;
+}
+
+
+export interface NotificationData {
decision: boolean;
- credentialPreview?: {
- subjectName?: string;
- organization?: string;
- issuer?: string;
- expirationDate?: string;
- };
+ credentialPreview?: CredentialPreview;
timeout?: number;
expiresAt?: number;
}
diff --git a/src/app/services/websocket.service.spec.ts b/src/app/services/websocket.service.spec.ts
index 610695f9..72ab1f6b 100644
--- a/src/app/services/websocket.service.spec.ts
+++ b/src/app/services/websocket.service.spec.ts
@@ -7,6 +7,7 @@ import { environment } from 'src/environments/environment';
import { TranslateModule, TranslateService } from '@ngx-translate/core';
import { WEBSOCKET_PIN_PATH } from '../constants/api.constants';
import { LoaderService } from './loader.service';
+import { Power } from '../interfaces/verifiable-credential';
//todo mock broadcast channel
@@ -415,8 +416,8 @@ describe('WebsocketService', () => {
timeout: 60,
credentialPreview: {
subjectName: 'John Doe',
+ power: [{ function: 'Administrar', action: ['create', 'update'] }],
organization: 'Test Org',
- issuer: 'Test Issuer',
expirationDate: '2025-12-31',
},
}),
@@ -670,4 +671,78 @@ describe('WebsocketService', () => {
clearIntervalSpy.mockRestore();
}));
+ it('should map powers to human readable format with single power', () => {
+ const powers = [
+ { function: 'Administrar', action: ['create', 'update'] }
+ ];
+
+ const result = service['mapPowersToHumanReadable'](powers);
+
+ expect(translateMock.instant).toHaveBeenCalledWith('vc-fields.power.administrar');
+ expect(translateMock.instant).toHaveBeenCalledWith('vc-fields.power.create');
+ expect(translateMock.instant).toHaveBeenCalledWith('vc-fields.power.update');
+ expect(result).toContain(':');
+ });
+
+ it('should map powers to human readable format with multiple powers', () => {
+ const powers = [
+ { function: 'Administrar', action: ['crear'] },
+ { function: 'Gestionar', action: ['borrar', 'modificar'] }
+ ];
+
+ const result = service['mapPowersToHumanReadable'](powers);
+
+ expect(result).toContain('
');
+ expect(translateMock.instant).toHaveBeenCalledWith('vc-fields.power.administrar');
+ expect(translateMock.instant).toHaveBeenCalledWith('vc-fields.power.gestionar');
+ });
+
+ it('should return empty string for empty powers array', () => {
+ expect(service['mapPowersToHumanReadable']([])).toBe('');
+ });
+
+ it('should normalize key by removing special characters and converting to lowercase', () => {
+ expect(service['normalizeKey']('Administrar')).toBe('administrar');
+ expect(service['normalizeKey']('Test Key-123')).toBe('testkey123');
+ expect(service['normalizeKey']('Special@#$Chars')).toBe('specialchars');
+ expect(service['normalizeKey'](' spaces ')).toBe('spaces');
+ });
+
+ it('should normalize key with null or undefined', () => {
+ expect(service['normalizeKey'](null)).toBe('');
+ expect(service['normalizeKey'](undefined)).toBe('');
+ });
+
+ it('should normalize key with numbers', () => {
+ expect(service['normalizeKey'](123)).toBe('123');
+ expect(service['normalizeKey'](0)).toBe('0');
+ });
+
+ it('should normalize action keys from array', () => {
+ const actions = ['Crear', 'Editar', 'Borrar'];
+ const result = service['normalizeActionKeys'](actions);
+
+ expect(result).toEqual(['crear', 'editar', 'borrar']);
+ });
+
+ it('should normalize action keys with special characters', () => {
+ const actions = ['Test-Action', 'Special@Char', '123Number'];
+ const result = service['normalizeActionKeys'](actions);
+
+ expect(result).toEqual(['testaction', 'specialchar', '123number']);
+ });
+
+ it('should return empty array for non-array action keys', () => {
+ expect(service['normalizeActionKeys'](null)).toEqual([]);
+ expect(service['normalizeActionKeys'](undefined)).toEqual([]);
+ expect(service['normalizeActionKeys']('not-array')).toEqual([]);
+ });
+
+ it('should filter out empty strings from normalized action keys', () => {
+ const actions = ['valid', '', ' ', 'another'];
+ const result = service['normalizeActionKeys'](actions);
+
+ expect(result).toEqual(['valid', 'another']);
+ });
+
});
diff --git a/src/app/services/websocket.service.ts b/src/app/services/websocket.service.ts
index 71fa5f65..f015bbda 100644
--- a/src/app/services/websocket.service.ts
+++ b/src/app/services/websocket.service.ts
@@ -6,7 +6,7 @@ import { TranslateService } from '@ngx-translate/core';
import { WEBSOCKET_NOTIFICATION_PATH, WEBSOCKET_PIN_PATH } from '../constants/api.constants';
import { LoaderService } from './loader.service';
import { ToastServiceHandler } from './toast.service';
-import { isPinRequest, isNotificationRequest } from '../interfaces/websocket-data';
+import { isPinRequest, isNotificationRequest, Power, CredentialPreview } from '../interfaces/websocket-data';
@Injectable({
providedIn: 'root',
@@ -200,9 +200,10 @@ export class WebsocketService {
const counter = data.timeout || 80;
- const preview = data.credentialPreview;
+ const preview = data.credentialPreview as CredentialPreview;
const subjectLabel = this.translate.instant('confirmation.holder');
const organizationLabel = this.translate.instant('confirmation.organization');
+ const powersLabel = this.translate.instant('confirmation.powers');
const expirationLabel = this.translate.instant('confirmation.expiration');
@@ -219,9 +220,13 @@ export class WebsocketService {
${organizationLabel}${this.escapeHtml(preview.organization)}
-