From eadd4e3c81d2a98f7f2e6050659ceded99745fce Mon Sep 17 00:00:00 2001 From: shancheas Date: Thu, 27 Aug 2026 11:06:08 +0700 Subject: [PATCH] feat: enhance user entity and transformer with employeeId support - Added employeeId field to UserEntity and UserDto interfaces for better user management. - Updated UsersRemoteDataTransformer to handle employeeId mapping and transformation. - Enhanced unit tests to validate employeeId handling and added new test cases for audit actor UUIDs. - Modified user page index to display employeeId alongside employee details. These changes improve the user management module by providing additional employee identification capabilities, enhancing data handling and user experience. --- .../users/domain/entities/user.entity.ts | 6 +++-- .../user.remote.transformer.test.ts | 22 +++++++++++++++++++ .../transformers/user.remote.transformer.ts | 17 ++++++++++---- .../presentation/pages/user.page.index.tsx | 11 +++++++--- 4 files changed, 47 insertions(+), 9 deletions(-) diff --git a/apps/web/src/apps/main/modules/system/users/domain/entities/user.entity.ts b/apps/web/src/apps/main/modules/system/users/domain/entities/user.entity.ts index cb898b3..193b385 100644 --- a/apps/web/src/apps/main/modules/system/users/domain/entities/user.entity.ts +++ b/apps/web/src/apps/main/modules/system/users/domain/entities/user.entity.ts @@ -8,6 +8,7 @@ export interface UserEntity extends BaseEntity { isSuperadmin?: boolean; privilegeId?: string | null; privilege?: RelationRef | null; + employeeId?: string | null; employee?: RelationRef | null; status?: ConfigurationStatus; createdAt?: number; @@ -22,10 +23,11 @@ export interface UserDto { isSuperadmin?: boolean; privilegeId?: string | null; privilege?: RelationRef | null; + employeeId?: string | null; employee?: RelationRef | null; status?: ConfigurationStatus; createdAt?: number; updatedAt?: number; - createdBy?: string | { id: string; username: string }; - updatedBy?: string | { id: string; username: string }; + createdBy?: string | { id: string; username?: string }; + updatedBy?: string | { id: string; username?: string }; } diff --git a/apps/web/src/apps/main/modules/system/users/domain/transformers/user.remote.transformer.test.ts b/apps/web/src/apps/main/modules/system/users/domain/transformers/user.remote.transformer.test.ts index e8af1e1..0809ec0 100644 --- a/apps/web/src/apps/main/modules/system/users/domain/transformers/user.remote.transformer.test.ts +++ b/apps/web/src/apps/main/modules/system/users/domain/transformers/user.remote.transformer.test.ts @@ -27,11 +27,22 @@ describe('UsersRemoteDataTransformer', () => { privilegeId: 'priv-1', privilege: { id: 'priv-1', code: 'SALES_STAFF', name: 'Sales Staff' }, employee: { id: 'emp-1', code: 'EMP_01', name: 'Ada Lovelace' }, + employeeId: 'emp-1', createdBy: 'admin', updatedBy: 'bob', }); }); + it('keeps audit actor uuids and falls back to id when username is missing', () => { + const entity = transformer.transformToEntity({ + ...dto, + createdBy: '550e8400-e29b-41d4-a716-446655440000', + updatedBy: { id: 'u-99' }, + }); + expect(entity.createdBy).toBe('550e8400-e29b-41d4-a716-446655440000'); + expect(entity.updatedBy).toBe('u-99'); + }); + it('builds create payload with username, password, and privilegeId, without status', () => { const entity: UserEntity = { id: dto.id, @@ -120,4 +131,15 @@ describe('UsersRemoteDataTransformer', () => { privilegeId: 'priv-1', }); }); + + it('maps privilege string to privilegeId on filter payload', () => { + const payload = transformer.transformPayloadFilter({ + username: 'alice', + privilege: 'priv-1', + }); + expect(payload).toEqual({ + username: 'alice', + privilegeId: 'priv-1', + }); + }); }); diff --git a/apps/web/src/apps/main/modules/system/users/domain/transformers/user.remote.transformer.ts b/apps/web/src/apps/main/modules/system/users/domain/transformers/user.remote.transformer.ts index 44c137f..d8a2092 100644 --- a/apps/web/src/apps/main/modules/system/users/domain/transformers/user.remote.transformer.ts +++ b/apps/web/src/apps/main/modules/system/users/domain/transformers/user.remote.transformer.ts @@ -11,9 +11,12 @@ function resolvePrivilegeId(entity: Partial): string | null | undefi } function flattenActor(value: unknown): string | undefined { - if (typeof value === 'string') return value; - if (value && typeof value === 'object' && 'username' in value) { - return String((value as { username: unknown }).username); + if (typeof value === 'string') return value || undefined; + if (value && typeof value === 'object') { + const actor = value as { username?: unknown; name?: unknown; id?: unknown }; + const label = actor.username ?? actor.name ?? actor.id; + if (label === undefined || label === null || label === '') return undefined; + return String(label); } return undefined; } @@ -22,13 +25,16 @@ export class UsersRemoteDataTransformer extends BaseDataTransformer transformToEntity(dto: UserDto | UserEntity): UserEntity { const privilegeId = 'privilegeId' in dto ? dto.privilegeId : (dto as UserEntity).privilegeId; const privilege = (dto as UserEntity).privilege ?? null; + const employee = (dto as UserEntity).employee ?? null; + const employeeId = 'employeeId' in dto ? dto.employeeId : (dto as UserEntity).employeeId; return { id: dto.id, username: dto.username, isSuperadmin: dto.isSuperadmin, privilegeId: privilegeId ?? privilege?.id ?? null, privilege, - employee: (dto as UserEntity).employee ?? null, + employeeId: employeeId ?? employee?.id ?? null, + employee, status: dto.status, createdAt: dto.createdAt, updatedAt: dto.updatedAt, @@ -65,6 +71,9 @@ export class UsersRemoteDataTransformer extends BaseDataTransformer if (next.privilege && typeof next.privilege === 'object') { next.privilegeId = next.privilege.id; delete next.privilege; + } else if (typeof next.privilege === 'string') { + next.privilegeId = next.privilege; + delete next.privilege; } return omitEmptyFields(next); } diff --git a/apps/web/src/apps/main/modules/system/users/presentation/pages/user.page.index.tsx b/apps/web/src/apps/main/modules/system/users/presentation/pages/user.page.index.tsx index d17ba1a..18ffb32 100644 --- a/apps/web/src/apps/main/modules/system/users/presentation/pages/user.page.index.tsx +++ b/apps/web/src/apps/main/modules/system/users/presentation/pages/user.page.index.tsx @@ -21,25 +21,30 @@ export default function UserPageIndex() { field: 'privilege', headerName: t('common:fields.privilege'), minWidth: 180, - valueGetter: ({ data }) => relationLabel(data?.privilege), + valueGetter: ({ data }) => relationLabel(data?.privilege) || data?.privilegeId || '', }, { field: 'employee', headerName: t('common:fields.employee'), minWidth: 180, - valueGetter: ({ data }) => relationLabel(data?.employee), + valueGetter: ({ data }) => relationLabel(data?.employee) || data?.employeeId || '', }, { field: 'isSuperadmin', headerName: t('common:fields.isSuperadmin'), minWidth: 140, - valueFormatter: ({ value }) => t(value ? 'yes' : 'no'), + valueGetter: ({ data }) => t(data?.isSuperadmin ? 'yes' : 'no'), }, ]; }, [t]); const filterConfig = useMemo(() => { return { + defaultValues: { + username: '', + privilege: null, + status: '', + }, renderBody: (form: any) => { if (!form) return null; return ;