mirror of
https://dev.azure.com/hugendubel/ISA/_git/ISA-Frontend
synced 2025-12-28 22:42:11 +01:00
Merged PR 1974: feat(crm): introduce PrimaryCustomerCardResource and format-name utility
feat(crm): introduce PrimaryCustomerCardResource and format-name utility Replace SelectedCustomerBonusCardsResource with a new PrimaryCustomerCardResource that automatically loads and exposes the primary customer card as a signal. This simplifies customer card access across the application by providing a centralized, root-level injectable resource with automatic tab synchronization. Create new @isa/utils/format-name library to consolidate customer name formatting logic previously duplicated across components. The utility formats names with configurable first name, last name, and organization name fields. Key changes: - Add PrimaryCustomerCardResource as providedIn root service with automatic customer selection tracking via effect - Remove SelectedCustomerBonusCardsResource and its manual provisioning - Extract formatName function to dedicated utility library with Vitest setup - Update all reward-related components to use new resource pattern - Migrate OMS components to use centralized format-name utility - Add comprehensive unit tests for formatName function BREAKING CHANGE: SelectedCustomerBonusCardsResource has been removed Ref: #5389
This commit is contained in:
committed by
Lorenz Hilpert
parent
f549c59bc8
commit
0b76552211
7
libs/utils/format-name/README.md
Normal file
7
libs/utils/format-name/README.md
Normal file
@@ -0,0 +1,7 @@
|
||||
# format-name
|
||||
|
||||
This library was generated with [Nx](https://nx.dev).
|
||||
|
||||
## Running unit tests
|
||||
|
||||
Run `nx test format-name` to execute the unit tests.
|
||||
34
libs/utils/format-name/eslint.config.cjs
Normal file
34
libs/utils/format-name/eslint.config.cjs
Normal file
@@ -0,0 +1,34 @@
|
||||
const nx = require('@nx/eslint-plugin');
|
||||
const baseConfig = require('../../../eslint.config.js');
|
||||
|
||||
module.exports = [
|
||||
...baseConfig,
|
||||
...nx.configs['flat/angular'],
|
||||
...nx.configs['flat/angular-template'],
|
||||
{
|
||||
files: ['**/*.ts'],
|
||||
rules: {
|
||||
'@angular-eslint/directive-selector': [
|
||||
'error',
|
||||
{
|
||||
type: 'attribute',
|
||||
prefix: 'lib',
|
||||
style: 'camelCase',
|
||||
},
|
||||
],
|
||||
'@angular-eslint/component-selector': [
|
||||
'error',
|
||||
{
|
||||
type: 'element',
|
||||
prefix: 'lib',
|
||||
style: 'kebab-case',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['**/*.html'],
|
||||
// Override or add rules here
|
||||
rules: {},
|
||||
},
|
||||
];
|
||||
20
libs/utils/format-name/project.json
Normal file
20
libs/utils/format-name/project.json
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"name": "format-name",
|
||||
"$schema": "../../../node_modules/nx/schemas/project-schema.json",
|
||||
"sourceRoot": "libs/utils/format-name/src",
|
||||
"prefix": "lib",
|
||||
"projectType": "library",
|
||||
"tags": [],
|
||||
"targets": {
|
||||
"test": {
|
||||
"executor": "@nx/vite:test",
|
||||
"outputs": ["{options.reportsDirectory}"],
|
||||
"options": {
|
||||
"reportsDirectory": "../../../coverage/libs/utils/format-name"
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"executor": "@nx/eslint:lint"
|
||||
}
|
||||
}
|
||||
}
|
||||
1
libs/utils/format-name/src/index.ts
Normal file
1
libs/utils/format-name/src/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from './lib/format-name/format-name.component';
|
||||
@@ -0,0 +1,125 @@
|
||||
import { formatName } from './format-name.component';
|
||||
|
||||
describe('formatName', () => {
|
||||
it('should format full name with first and last name', () => {
|
||||
// Arrange
|
||||
const input = {
|
||||
firstName: 'John',
|
||||
lastName: 'Doe',
|
||||
};
|
||||
|
||||
// Act
|
||||
const result = formatName(input);
|
||||
|
||||
// Assert
|
||||
expect(result).toBe('Doe John');
|
||||
});
|
||||
|
||||
it('should format name with organisation and full name', () => {
|
||||
// Arrange
|
||||
const input = {
|
||||
firstName: 'John',
|
||||
lastName: 'Doe',
|
||||
organisationName: 'Acme Corp',
|
||||
};
|
||||
|
||||
// Act
|
||||
const result = formatName(input);
|
||||
|
||||
// Assert
|
||||
expect(result).toBe('Acme Corp - Doe John');
|
||||
});
|
||||
|
||||
it('should format with only organisation name', () => {
|
||||
// Arrange
|
||||
const input = {
|
||||
organisationName: 'Acme Corp',
|
||||
};
|
||||
|
||||
// Act
|
||||
const result = formatName(input);
|
||||
|
||||
// Assert
|
||||
expect(result).toBe('Acme Corp');
|
||||
});
|
||||
|
||||
it('should format with only last name', () => {
|
||||
// Arrange
|
||||
const input = {
|
||||
lastName: 'Doe',
|
||||
};
|
||||
|
||||
// Act
|
||||
const result = formatName(input);
|
||||
|
||||
// Assert
|
||||
expect(result).toBe('Doe');
|
||||
});
|
||||
|
||||
it('should format with only first name', () => {
|
||||
// Arrange
|
||||
const input = {
|
||||
firstName: 'John',
|
||||
};
|
||||
|
||||
// Act
|
||||
const result = formatName(input);
|
||||
|
||||
// Assert
|
||||
expect(result).toBe('John');
|
||||
});
|
||||
|
||||
it('should return empty string when all inputs are undefined', () => {
|
||||
// Arrange
|
||||
const input = {};
|
||||
|
||||
// Act
|
||||
const result = formatName(input);
|
||||
|
||||
// Assert
|
||||
expect(result).toBe('');
|
||||
});
|
||||
|
||||
it('should return empty string when all inputs are empty strings', () => {
|
||||
// Arrange
|
||||
const input = {
|
||||
firstName: '',
|
||||
lastName: '',
|
||||
organisationName: '',
|
||||
};
|
||||
|
||||
// Act
|
||||
const result = formatName(input);
|
||||
|
||||
// Assert
|
||||
expect(result).toBe('');
|
||||
});
|
||||
|
||||
it('should format with organisation and only last name', () => {
|
||||
// Arrange
|
||||
const input = {
|
||||
lastName: 'Doe',
|
||||
organisationName: 'Acme Corp',
|
||||
};
|
||||
|
||||
// Act
|
||||
const result = formatName(input);
|
||||
|
||||
// Assert
|
||||
expect(result).toBe('Acme Corp - Doe');
|
||||
});
|
||||
|
||||
it('should format with organisation and only first name', () => {
|
||||
// Arrange
|
||||
const input = {
|
||||
firstName: 'John',
|
||||
organisationName: 'Acme Corp',
|
||||
};
|
||||
|
||||
// Act
|
||||
const result = formatName(input);
|
||||
|
||||
// Assert
|
||||
expect(result).toBe('Acme Corp - John');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* Formats a name by combining first name, last name, and organisation name.
|
||||
*
|
||||
* The function follows these formatting rules:
|
||||
* - Names are formatted as "LastName FirstName"
|
||||
* - Organisation name is separated from the personal name with " - "
|
||||
* - Empty or undefined values are filtered out
|
||||
* - If all values are empty/undefined, returns an empty string
|
||||
*
|
||||
* @param params - The name components to format
|
||||
* @param params.firstName - The person's first name (optional)
|
||||
* @param params.lastName - The person's last name (optional)
|
||||
* @param params.organisationName - The organisation name (optional)
|
||||
* @returns The formatted name string
|
||||
*
|
||||
* @example
|
||||
* formatName({ firstName: 'John', lastName: 'Doe' })
|
||||
* // Returns: "Doe John"
|
||||
*
|
||||
* @example
|
||||
* formatName({ firstName: 'John', lastName: 'Doe', organisationName: 'Acme Corp' })
|
||||
* // Returns: "Acme Corp - Doe John"
|
||||
*
|
||||
* @example
|
||||
* formatName({ organisationName: 'Acme Corp' })
|
||||
* // Returns: "Acme Corp"
|
||||
*/
|
||||
export const formatName = ({
|
||||
firstName,
|
||||
lastName,
|
||||
organisationName,
|
||||
}: {
|
||||
firstName?: string;
|
||||
lastName?: string;
|
||||
organisationName?: string;
|
||||
}): string => {
|
||||
const nameCombined = [lastName, firstName].filter((f) => !!f);
|
||||
const organisation = [organisationName].filter((f) => !!f);
|
||||
|
||||
return (
|
||||
[organisation.join(), nameCombined.join(' ')]
|
||||
.filter((f) => !!f)
|
||||
.join(' - ') ?? ''
|
||||
);
|
||||
};
|
||||
13
libs/utils/format-name/src/test-setup.ts
Normal file
13
libs/utils/format-name/src/test-setup.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import '@angular/compiler';
|
||||
import '@analogjs/vitest-angular/setup-zone';
|
||||
|
||||
import {
|
||||
BrowserTestingModule,
|
||||
platformBrowserTesting,
|
||||
} from '@angular/platform-browser/testing';
|
||||
import { getTestBed } from '@angular/core/testing';
|
||||
|
||||
getTestBed().initTestEnvironment(
|
||||
BrowserTestingModule,
|
||||
platformBrowserTesting(),
|
||||
);
|
||||
30
libs/utils/format-name/tsconfig.json
Normal file
30
libs/utils/format-name/tsconfig.json
Normal file
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"extends": "../../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"importHelpers": true,
|
||||
"moduleResolution": "bundler",
|
||||
"strict": true,
|
||||
"noImplicitOverride": true,
|
||||
"noPropertyAccessFromIndexSignature": true,
|
||||
"noImplicitReturns": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"module": "preserve"
|
||||
},
|
||||
"angularCompilerOptions": {
|
||||
"enableI18nLegacyMessageIdFormat": false,
|
||||
"strictInjectionParameters": true,
|
||||
"strictInputAccessModifiers": true,
|
||||
"typeCheckHostBindings": true,
|
||||
"strictTemplates": true
|
||||
},
|
||||
"files": [],
|
||||
"include": [],
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.lib.json"
|
||||
},
|
||||
{
|
||||
"path": "./tsconfig.spec.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
27
libs/utils/format-name/tsconfig.lib.json
Normal file
27
libs/utils/format-name/tsconfig.lib.json
Normal file
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../../dist/out-tsc",
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"inlineSources": true,
|
||||
"types": []
|
||||
},
|
||||
"exclude": [
|
||||
"src/**/*.spec.ts",
|
||||
"src/test-setup.ts",
|
||||
"jest.config.ts",
|
||||
"src/**/*.test.ts",
|
||||
"vite.config.ts",
|
||||
"vite.config.mts",
|
||||
"vitest.config.ts",
|
||||
"vitest.config.mts",
|
||||
"src/**/*.test.tsx",
|
||||
"src/**/*.spec.tsx",
|
||||
"src/**/*.test.js",
|
||||
"src/**/*.spec.js",
|
||||
"src/**/*.test.jsx",
|
||||
"src/**/*.spec.jsx"
|
||||
],
|
||||
"include": ["src/**/*.ts"]
|
||||
}
|
||||
29
libs/utils/format-name/tsconfig.spec.json
Normal file
29
libs/utils/format-name/tsconfig.spec.json
Normal file
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../../dist/out-tsc",
|
||||
"types": [
|
||||
"vitest/globals",
|
||||
"vitest/importMeta",
|
||||
"vite/client",
|
||||
"node",
|
||||
"vitest"
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
"vite.config.ts",
|
||||
"vite.config.mts",
|
||||
"vitest.config.ts",
|
||||
"vitest.config.mts",
|
||||
"src/**/*.test.ts",
|
||||
"src/**/*.spec.ts",
|
||||
"src/**/*.test.tsx",
|
||||
"src/**/*.spec.tsx",
|
||||
"src/**/*.test.js",
|
||||
"src/**/*.spec.js",
|
||||
"src/**/*.test.jsx",
|
||||
"src/**/*.spec.jsx",
|
||||
"src/**/*.d.ts"
|
||||
],
|
||||
"files": ["src/test-setup.ts"]
|
||||
}
|
||||
27
libs/utils/format-name/vite.config.mts
Normal file
27
libs/utils/format-name/vite.config.mts
Normal file
@@ -0,0 +1,27 @@
|
||||
/// <reference types='vitest' />
|
||||
import { defineConfig } from 'vite';
|
||||
import angular from '@analogjs/vite-plugin-angular';
|
||||
import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin';
|
||||
import { nxCopyAssetsPlugin } from '@nx/vite/plugins/nx-copy-assets.plugin';
|
||||
|
||||
export default defineConfig(() => ({
|
||||
root: __dirname,
|
||||
cacheDir: '../../../node_modules/.vite/libs/utils/format-name',
|
||||
plugins: [angular(), nxViteTsPaths(), nxCopyAssetsPlugin(['*.md'])],
|
||||
// Uncomment this if you are using workers.
|
||||
// worker: {
|
||||
// plugins: [ nxViteTsPaths() ],
|
||||
// },
|
||||
test: {
|
||||
watch: false,
|
||||
globals: true,
|
||||
environment: 'jsdom',
|
||||
include: ['{src,tests}/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
|
||||
setupFiles: ['src/test-setup.ts'],
|
||||
reporters: ['default'],
|
||||
coverage: {
|
||||
reportsDirectory: '../../../coverage/libs/utils/format-name',
|
||||
provider: 'v8' as const,
|
||||
},
|
||||
},
|
||||
}));
|
||||
Reference in New Issue
Block a user