diff --git a/config/webpack/dev.js b/config/webpack/dev.js index a6514f8..0bd9544 100644 --- a/config/webpack/dev.js +++ b/config/webpack/dev.js @@ -28,6 +28,9 @@ module.exports = merge.strategy({ port: 8080, stats: 'minimal', hot: true, + proxy: { + '/graphql': 'http://localhost:8081', + }, }, plugins: [ new Dotenv({ diff --git a/dev.env b/dev.env index 0033ebb..636dd1a 100644 --- a/dev.env +++ b/dev.env @@ -1,2 +1,2 @@ NODE_ENV=development -GRAPHQL_URL=http://localhost:8081/graphql/employee +GRAPHQL_URL=/graphql/admin diff --git a/prod.env b/prod.env index 624e793..479c7bd 100644 --- a/prod.env +++ b/prod.env @@ -1,2 +1,2 @@ NODE_ENV=production -GRAPHQL_URL=/graphql/employee +GRAPHQL_URL=/graphql/admin diff --git a/src/core/api/graphql.client.ts b/src/core/api/graphql.client.ts new file mode 100644 index 0000000..61505b9 --- /dev/null +++ b/src/core/api/graphql.client.ts @@ -0,0 +1,4 @@ +import { GraphQLClient } from 'graphql-request'; + +const url = process.env.GRAPHQL_URL; +export const graphQLClient = new GraphQLClient(url); diff --git a/src/core/api/index.ts b/src/core/api/index.ts new file mode 100644 index 0000000..38f62bb --- /dev/null +++ b/src/core/api/index.ts @@ -0,0 +1 @@ +export * from './graphql.client'; diff --git a/src/core/router/index.ts b/src/core/router/index.ts index 0e1ad7f..8b4a4d1 100644 --- a/src/core/router/index.ts +++ b/src/core/router/index.ts @@ -1,2 +1,3 @@ export * from './router.component'; export * from './routes'; +export * from './route-params.vm'; diff --git a/src/core/router/route-params.vm.ts b/src/core/router/route-params.vm.ts new file mode 100644 index 0000000..66c2e6d --- /dev/null +++ b/src/core/router/route-params.vm.ts @@ -0,0 +1,3 @@ +export interface EditParams { + id: string; +} diff --git a/src/pods/employee-list/api/employee-list.api.ts b/src/pods/employee-list/api/employee-list.api.ts index 4cd5a38..40672f3 100644 --- a/src/pods/employee-list/api/employee-list.api.ts +++ b/src/pods/employee-list/api/employee-list.api.ts @@ -1,13 +1,40 @@ +import { graphQLClient } from 'core/api'; import { Employee } from './employee-list.api-model'; -import { mockEmployeeList } from './employee-list.mock-data'; -let employeeList = [...mockEmployeeList]; +interface GetEmployeeListResponse { + employees: Employee[]; +} export const getEmployeeList = async (): Promise => { - return employeeList; + const query = ` + query { + employees { + id + name + isActive + email + lastDateIncurred + } + } + `; + const { employees } = await graphQLClient.request( + query + ); + return employees; }; +interface DeleteEmployeeResponse { + deleteEmployee: boolean; +} + export const deleteEmployee = async (id: string): Promise => { - employeeList = employeeList.filter(e => e.id !== id); - return true; + const query = ` + mutation { + deleteEmployee(id: "${id}") + } + `; + const { deleteEmployee } = await graphQLClient.request< + DeleteEmployeeResponse + >(query); + return deleteEmployee; }; diff --git a/src/pods/employee-list/api/employee-list.mock-data.ts b/src/pods/employee-list/api/employee-list.mock-data.ts deleted file mode 100644 index b48dbfa..0000000 --- a/src/pods/employee-list/api/employee-list.mock-data.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { Employee } from './employee-list.api-model'; - -export const mockEmployeeList: Employee[] = [ - { - id: '1', - isActive: true, - name: 'Daniel Perez', - email: 'daniel.perez@empresa.com', - lastDateIncurred: '02/02/2020', - }, - { - id: '2', - isActive: true, - name: 'Jose Gomez', - email: 'jose.gomez@empresa.com', - lastDateIncurred: '05/02/2020', - }, - { - id: '3', - isActive: false, - name: 'Manuel Ruiz', - email: 'manuel.ruiz@empresa.com', - lastDateIncurred: '06/02/2020', - }, - { - id: '4', - isActive: true, - name: 'Ramón Gomez', - email: 'ramon.gomez@empresa.com', - lastDateIncurred: '02/05/2020', - }, - { - id: '5', - isActive: false, - name: 'María Lopez', - email: 'maria.lopez@empresa.com', - lastDateIncurred: '05/08/2020', - }, - { - id: '6', - isActive: true, - name: 'Manuel Ortiz', - email: 'manuel.ortiz@empresa.com', - lastDateIncurred: '06/06/2020', - }, - { - id: '7', - isActive: false, - name: 'David Martos', - email: 'david.martos@empresa.com', - lastDateIncurred: '14/08/2020', - }, - { - id: '8', - isActive: true, - name: 'Luz Roca', - email: 'luz.roca@empresa.com', - lastDateIncurred: '20/06/2020', - }, -]; diff --git a/src/pods/employee/api/employee.api-model.ts b/src/pods/employee/api/employee.api-model.ts index 87202d4..ea4a1ff 100644 --- a/src/pods/employee/api/employee.api-model.ts +++ b/src/pods/employee/api/employee.api-model.ts @@ -4,11 +4,15 @@ export interface Employee { email: string; isActive: boolean; temporalPassword?: string; - projects?: ProjectSummary[]; + projects?: EmployeeProject[]; } -export interface ProjectSummary { +export interface EmployeeProject { id: string; isAssigned?: boolean; - projectName: string; +} + +export interface Project { + id: string; + name: string; } diff --git a/src/pods/employee/api/employee.api.ts b/src/pods/employee/api/employee.api.ts index 252d864..91558b4 100644 --- a/src/pods/employee/api/employee.api.ts +++ b/src/pods/employee/api/employee.api.ts @@ -1,6 +1,85 @@ -import { Employee } from './employee.api-model'; -import { mockEmployee } from './employee.mock-data'; +import { Employee, EmployeeProject, Project } from './employee.api-model'; +import { graphQLClient } from 'core/api'; + +interface GetEmployeeResponse { + employee: Employee; +} export const getEmployeeById = async (id: string): Promise => { - return mockEmployee; + const query = ` + query { + employee(id: "${id}") { + id + name + isActive + email + projects { + id + isAssigned + } + } + } + `; + + const { employee } = await graphQLClient.request(query); + + return employee; +}; + +interface GetProjectListResponse { + projects: Project[]; +} + +export const getProjects = async (): Promise => { + const query = ` + query { + projects { + id + name + } + } + `; + const { projects } = await graphQLClient.request( + query + ); + return projects; +}; + +interface SaveEmployeeResponse { + saveEmployee: Employee; +} + +export const saveEmployee = async (employee: Employee): Promise => { + const query = ` + mutation($employee: EmployeeInput!) { + saveEmployee(employee: $employee) { + id + } + } + `; + + const { saveEmployee } = await graphQLClient.request( + query, + { + employee, + } + ); + + return saveEmployee.id; +}; + +export const saveEmployeeProjectList = async ( + id: string, + employeeProjectList: EmployeeProject[] +): Promise => { + const query = `mutation($employeeProjectList: [EmployeeProjectInput!]!) { + saveEmployeeProjectList( + id: "${id}", + employeeProjectList: $employeeProjectList, + ) { + id + } + }`; + + await graphQLClient.request(query, { employeeProjectList }); }; diff --git a/src/pods/employee/api/employee.mock-data.ts b/src/pods/employee/api/employee.mock-data.ts deleted file mode 100644 index 6eaf7b5..0000000 --- a/src/pods/employee/api/employee.mock-data.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { Employee, ProjectSummary } from './employee.api-model'; - -const mockProjectSummaryList: ProjectSummary[] = [ - { - id: '1', - isAssigned: true, - projectName: 'Mapfre', - }, - { - id: '2', - isAssigned: false, - projectName: 'Bankia', - }, - { - id: '3', - isAssigned: false, - projectName: 'Vacaciones', - }, - { - id: '4', - isAssigned: true, - projectName: 'Baja', - }, -]; - -export const mockEmployee: Employee = { - id: '1', - name: 'Prueba Nombre', - email: 'prueba@email.com', - isActive: true, - temporalPassword: 'admin', - projects: mockProjectSummaryList, -}; diff --git a/src/pods/employee/components/project-row.component.tsx b/src/pods/employee/components/project-row.component.tsx index af5c32f..f650ff0 100644 --- a/src/pods/employee/components/project-row.component.tsx +++ b/src/pods/employee/components/project-row.component.tsx @@ -5,19 +5,31 @@ import { CellComponent, } from 'common/components'; import Checkbox from '@material-ui/core/Checkbox'; -import { ProjectSummary } from '../employee.vm'; +import { EmployeeProject } from '../employee.vm'; -type Props = RowRendererProps; +interface RowProps extends RowRendererProps { + onChangeProject: (project: EmployeeProject) => void; +} -export const EmployeeRowComponent: React.FunctionComponent = ({ +export const EmployeeRowComponent: React.FunctionComponent = ({ row, + onChangeProject, }) => { return ( - + + onChangeProject({ + ...row, + isAssigned: checked, + }) + } + checked={row.isAssigned} + /> - {row.projectName} + {row.name} ); }; diff --git a/src/pods/employee/components/project.component.tsx b/src/pods/employee/components/project.component.tsx index 00df731..f9ac0bf 100644 --- a/src/pods/employee/components/project.component.tsx +++ b/src/pods/employee/components/project.component.tsx @@ -1,31 +1,52 @@ import React from 'react'; import { TableContainer, RowRendererProps } from 'common/components'; -import { ProjectSummary } from '../employee.vm'; +import { EmployeeProject } from '../employee.vm'; import { EmployeeRowComponent } from './project-row.component'; import { CommandFooterComponent } from 'common-app/command-footer'; interface Props { - projectSummaryList: ProjectSummary[]; - className?: string; + employeeProjectList: EmployeeProject[]; + onSave: (project: EmployeeProject[]) => void; onCancel: () => void; + className?: string; } export const ProjectComponent: React.FunctionComponent = ({ - projectSummaryList, - className, + employeeProjectList, + onSave, onCancel, + className, }) => { + const [projectList, setProjectList] = React.useState( + employeeProjectList + ); + + React.useEffect(() => { + setProjectList(employeeProjectList); + }, [employeeProjectList]); + + const handleChangeProject = (id: string) => (project: EmployeeProject) => { + const updateProjectList = projectList.map(p => (p.id === id ? project : p)); + setProjectList(updateProjectList); + }; + + const handleSave = () => onSave(projectList); return ( <> ) => ( - + rowRenderer={(rowProps: RowRendererProps) => ( + )} + enablePagination={true} + pageSize={5} /> - + ); }; diff --git a/src/pods/employee/employee.component.tsx b/src/pods/employee/employee.component.tsx index 62591ea..6c54de4 100644 --- a/src/pods/employee/employee.component.tsx +++ b/src/pods/employee/employee.component.tsx @@ -6,14 +6,15 @@ import { } from 'common/components'; import AppBar from '@material-ui/core/AppBar'; import { DataComponent, ProjectComponent, ReportComponent } from './components'; -import { Employee, Report } from './employee.vm'; +import { Employee, Report, EmployeeProject } from './employee.vm'; import * as classes from './employee.styles'; interface Props { employee: Employee; isEditMode: boolean; report: Report; - onSave: (employee: Employee) => void; + onSaveEmployee: (employee: Employee) => void; + onSaveProjectSelection: (project: EmployeeProject[]) => void; onCancel: () => void; onGenerateExcel: (report: Report) => void; } @@ -22,7 +23,8 @@ export const EmployeeComponent: React.FunctionComponent = ({ employee, isEditMode, report, - onSave, + onSaveEmployee, + onSaveProjectSelection, onCancel, onGenerateExcel, }) => { @@ -40,15 +42,16 @@ export const EmployeeComponent: React.FunctionComponent = ({ diff --git a/src/pods/employee/employee.container.tsx b/src/pods/employee/employee.container.tsx index 876923a..c9e3342 100644 --- a/src/pods/employee/employee.container.tsx +++ b/src/pods/employee/employee.container.tsx @@ -5,27 +5,45 @@ import { Report, createEmptyEmployee, createEmptyReport, + EmployeeProject, } from './employee.vm'; import { useSnackbarContext } from 'common/components'; import { trackPromise } from 'react-promise-tracker'; -import { getEmployeeById } from './api'; -import { mapEmployeeFromApiToVm } from './employee.mappers'; +import { + getEmployeeById, + saveEmployee, + saveEmployeeProjectList, + getProjects, +} from './api'; +import { + mapEmployeeFromApiToVm, + mapEmployeeFromVmToApi, + mapEmployeeProjectListFromVmToApi, +} from './employee.mappers'; import { useParams } from 'react-router-dom'; import { isEditModeHelper } from 'common/helpers'; +import { routes, EditParams } from 'core/router'; +import { useHistory } from 'react-router'; export const EmployeeContainer: React.FunctionComponent = () => { - const { id } = useParams(); + const params = useParams(); const [employee, setEmployee] = React.useState( createEmptyEmployee() ); const [isEditMode, setIsEditMode] = React.useState(false); const [report, setReport] = React.useState(createEmptyReport()); const { showMessage } = useSnackbarContext(); + const history = useHistory(); const onLoadEmployee = async () => { try { - const apiEmployee = await trackPromise(getEmployeeById(id)); - const viewModelEmployee = mapEmployeeFromApiToVm(apiEmployee); + const [apiProjects, apiEmployee] = await trackPromise( + Promise.all([getProjects(), getEmployeeById(params.id)]) + ); + const viewModelEmployee = mapEmployeeFromApiToVm( + apiEmployee, + apiProjects + ); setEmployee(viewModelEmployee); } catch (error) { error && @@ -33,12 +51,50 @@ export const EmployeeContainer: React.FunctionComponent = () => { } }; - const handleSave = (employee: Employee) => { - console.log('Guardado'); + const handleSuccessSaveEmployee = (id: string, newEmployee: Employee) => { + if (id) { + showMessage('Empleado guardado con éxito', 'success'); + setEmployee(newEmployee); + history.push(routes.editEmployee(id)); + } else { + showMessage('Ha ocurrido un error al guardar el empleado', 'error'); + } + }; + + const handleSaveEmployee = async (employee: Employee) => { + try { + const apiEmployee = mapEmployeeFromVmToApi(employee); + const id = await trackPromise(saveEmployee(apiEmployee)); + handleSuccessSaveEmployee(id, employee); + } catch (error) { + error && showMessage(error.message, 'error'); + } + }; + + const handleSaveProjectSelection = async ( + employeeSummary: EmployeeProject[] + ) => { + if (params.id) { + try { + const apiProjectSummary = mapEmployeeProjectListFromVmToApi( + employeeSummary + ); + await trackPromise( + saveEmployeeProjectList(params.id, apiProjectSummary) + ); + setEmployee({ + ...employee, + projects: employeeSummary, + }); + showMessage('Se actualizó con éxito', 'success'); + } catch (error) { + error && showMessage('Ha ocurrido un error al guardar', 'error'); + } + } }; const handleCancel = () => { - history.back(); + history.goBack(); }; const handleGenerateExcel = (report: Report) => { @@ -47,7 +103,7 @@ export const EmployeeContainer: React.FunctionComponent = () => { }; React.useEffect(() => { - const isEditMode = isEditModeHelper(id); + const isEditMode = isEditModeHelper(params.id); setIsEditMode(isEditMode); if (isEditMode) { onLoadEmployee(); @@ -59,7 +115,8 @@ export const EmployeeContainer: React.FunctionComponent = () => { employee={employee} isEditMode={isEditMode} report={report} - onSave={handleSave} + onSaveEmployee={handleSaveEmployee} + onSaveProjectSelection={handleSaveProjectSelection} onCancel={handleCancel} onGenerateExcel={handleGenerateExcel} /> diff --git a/src/pods/employee/employee.mappers.spec.ts b/src/pods/employee/employee.mappers.spec.ts index 8085341..01d3fcf 100644 --- a/src/pods/employee/employee.mappers.spec.ts +++ b/src/pods/employee/employee.mappers.spec.ts @@ -1,120 +1,346 @@ -import { mapEmployeeFromApiToVm } from './employee.mappers'; +import { + mapEmployeeFromApiToVm, + mapEmployeeFromVmToApi, + mapEmployeeProjectListFromVmToApi, +} from './employee.mappers'; import * as apiModel from './api/employee.api-model'; import * as viewModel from './employee.vm'; describe('./pods/employee/employee.mappers', () => { - it('should return empty employee when feeding null value', () => { - // Arrange - const employee = null; + describe('mapEmployeeFromApiToVm', () => { + it('should return empty employee when feeding null value', () => { + // Arrange + const employee = null; + const projects = null; - // Act - const result = mapEmployeeFromApiToVm(employee); + // Act + const result = mapEmployeeFromApiToVm(employee, projects); - // Assert - expect(result).toEqual(viewModel.createEmptyEmployee()); - }); + // Assert + expect(result).toEqual(viewModel.createEmptyEmployee()); + }); - it('should return empty employee when feeding undefined value', () => { - // Arrange - const employee = undefined; + it('should return empty employee when feeding undefined value', () => { + // Arrange + const employee = undefined; + const projects = undefined; - // Act - const result = mapEmployeeFromApiToVm(employee); + // Act + const result = mapEmployeeFromApiToVm(employee, projects); - // Assert - expect(result).toEqual(viewModel.createEmptyEmployee()); - }); + // Assert + expect(result).toEqual(viewModel.createEmptyEmployee()); + }); + + it('should return expected result but feeding null project list', () => { + // Arrange + const employee: apiModel.Employee = { + id: 'test id', + name: 'test name', + email: 'test@email.com', + isActive: true, + temporalPassword: 'test password', + projects: null, + }; + + const projects: apiModel.Project[] = [ + { + id: '1', + name: 'project test 1', + }, + { + id: '2', + name: 'project test 2', + }, + ]; + + const expectedResult: viewModel.Employee = { + id: 'test id', + name: 'test name', + email: 'test@email.com', + isActive: true, + temporalPassword: 'test password', + projects: [ + { + id: '1', + name: 'project test 1', + isAssigned: false, + }, + { + id: '2', + name: 'project test 2', + isAssigned: false, + }, + ], + }; + + // Act + const result = mapEmployeeFromApiToVm(employee, projects); + + // Assert + expect(result).toEqual(expectedResult); + }); + + it('should return expected result but feeding undefined project list', () => { + // Arrange + const employee: apiModel.Employee = { + id: 'test id', + name: 'test name', + email: 'test@email.com', + isActive: true, + temporalPassword: 'test password', + projects: undefined, + }; + + const expectedResult: viewModel.Employee = { + id: 'test id', + name: 'test name', + email: 'test@email.com', + isActive: true, + temporalPassword: 'test password', + projects: [ + { + id: '1', + name: 'project test 1', + isAssigned: false, + }, + { + id: '2', + name: 'project test 2', + isAssigned: false, + }, + ], + }; + + const projects: apiModel.Project[] = [ + { + id: '1', + name: 'project test 1', + }, + { + id: '2', + name: 'project test 2', + }, + ]; + + // Act + const result = mapEmployeeFromApiToVm(employee, projects); + + // Assert + expect(result).toEqual(expectedResult); + }); + + it('should return expected result feeding correct values', () => { + // Arrange + const employee: apiModel.Employee = { + id: 'test id', + name: 'test name', + email: 'test@email.com', + isActive: true, + temporalPassword: 'test password', + projects: [ + { + id: '1', + isAssigned: true, + }, + { + id: '2', + isAssigned: false, + }, + ], + }; + + const projects: apiModel.Project[] = [ + { + id: '1', + name: 'project test 1', + }, + { + id: '2', + name: 'project test 2', + }, + ]; + + const expectedResult: viewModel.Employee = { + id: 'test id', + name: 'test name', + email: 'test@email.com', + isActive: true, + temporalPassword: 'test password', + projects: [ + { + id: '1', + isAssigned: true, + name: 'project test 1', + }, + { + id: '2', + isAssigned: false, + name: 'project test 2', + }, + ], + }; + + // Act + const result = mapEmployeeFromApiToVm(employee, projects); - it('should return expected result but feeding null project list', () => { - // Arrange - const employee: apiModel.Employee = { - id: 'test id', - name: 'test name', - email: 'test@email.com', - isActive: true, - temporalPassword: 'test password', - projects: null, - }; - - const expectedResult: viewModel.Employee = { - id: 'test id', - name: 'test name', - email: 'test@email.com', - isActive: true, - temporalPassword: 'test password', - projects: [], - }; - - // Act - const result = mapEmployeeFromApiToVm(employee); - - // Assert - expect(result).toEqual(expectedResult); + // Assert + expect(result).toEqual(expectedResult); + }); }); - it('should return expected result but feeding undefined project list', () => { - // Arrange - const employee: apiModel.Employee = { - id: 'test id', - name: 'test name', - email: 'test@email.com', - isActive: true, - temporalPassword: 'test password', - projects: undefined, - }; - - const expectedResult: viewModel.Employee = { - id: 'test id', - name: 'test name', - email: 'test@email.com', - isActive: true, - temporalPassword: 'test password', - projects: [], - }; - - // Act - const result = mapEmployeeFromApiToVm(employee); - - // Assert - expect(result).toEqual(expectedResult); + describe('mapEmployeeFromVmToApi', () => { + it('should return empty employee when feeding null', () => { + // Arrange + const employee = null; + + // Act + const result = mapEmployeeFromVmToApi(employee); + + //Assert + expect(result).toEqual(viewModel.createEmptyEmployee()); + }); + + it('should return empty employee when feeding undefined', () => { + // Arrange + const employee = undefined; + + // Act + const result = mapEmployeeFromVmToApi(employee); + + //Assert + expect(result).toEqual(viewModel.createEmptyEmployee()); + }); + + it('should return expected value when feeding employee, and empty project list', () => { + // Arrange + const employee: viewModel.Employee = { + id: '1', + isActive: true, + name: 'test name', + email: 'test@email.com', + temporalPassword: 'test', + projects: [], + }; + + const expectedValue: apiModel.Employee = { + id: '1', + isActive: true, + name: 'test name', + email: 'test@email.com', + temporalPassword: 'test', + }; + + // Act + const result = mapEmployeeFromVmToApi(employee); + + //Assert + expect(result).toEqual(expectedValue); + }); + + it('should return expected value when feeding employee, and project list', () => { + // Arrange + const employee: viewModel.Employee = { + id: '1', + isActive: true, + name: 'test name', + email: 'test@email.com', + temporalPassword: 'test', + projects: [ + { + id: '1', + isAssigned: true, + name: 'test name', + }, + { + id: '2', + isAssigned: false, + name: 'test name', + }, + ], + }; + + const expectedValue: apiModel.Employee = { + id: '1', + isActive: true, + name: 'test name', + email: 'test@email.com', + temporalPassword: 'test', + }; + + // Act + const result = mapEmployeeFromVmToApi(employee); + + //Assert + expect(result).toEqual(expectedValue); + }); }); - it('should return expected result feeding correct values', () => { - // Arrange - const employee: apiModel.Employee = { - id: 'test id', - name: 'test name', - email: 'test@email.com', - isActive: true, - temporalPassword: 'test password', - projects: [ + describe('mapEmployeeProjectListFromVmToApi', () => { + it('should return emtpy array when feeding employee project null', () => { + // Arrange + const employeeProjectList = null; + + // Act + const result = mapEmployeeProjectListFromVmToApi(employeeProjectList); + + // Assert + expect(result).toEqual([]); + }); + + it('should return emtpy array when feeding employee project undefined', () => { + // Arrange + const employeeProjectList = undefined; + + // Act + const result = mapEmployeeProjectListFromVmToApi(employeeProjectList); + + // Assert + expect(result).toEqual([]); + }); + + it('should return emtpy array when feeding employee project empty array', () => { + // Arrange + const employeeProjectList = []; + + // Act + const result = mapEmployeeProjectListFromVmToApi(employeeProjectList); + + // Assert + expect(result).toEqual([]); + }); + + it('should return expected result when feeding employee project list', () => { + // Arrange + const employeeProjectList: viewModel.EmployeeProject[] = [ { - id: 'test id', - projectName: 'test employee name', + id: '1', + name: 'test name', isAssigned: true, }, - ], - }; - - const expectedResult: viewModel.Employee = { - id: 'test id', - name: 'test name', - email: 'test@email.com', - isActive: true, - temporalPassword: 'test password', - projects: [ { - id: 'test id', - projectName: 'test employee name', + id: '2', + name: 'test name', + isAssigned: false, + }, + ]; + + const expectedResult: apiModel.EmployeeProject[] = [ + { + id: '1', isAssigned: true, }, - ], - }; + { + id: '2', + isAssigned: false, + }, + ]; - // Act - const result = mapEmployeeFromApiToVm(employee); + // Act + const result = mapEmployeeProjectListFromVmToApi(employeeProjectList); - // Assert - expect(result).toEqual(expectedResult); + // Assert + expect(result).toEqual(expectedResult); + }); }); }); diff --git a/src/pods/employee/employee.mappers.ts b/src/pods/employee/employee.mappers.ts index 3464896..2f7d128 100644 --- a/src/pods/employee/employee.mappers.ts +++ b/src/pods/employee/employee.mappers.ts @@ -3,23 +3,60 @@ import * as apiModel from './api/employee.api-model'; import * as viewModel from './employee.vm'; const mapProjectSummaryFromApiToVm = ( - projectSummary: apiModel.ProjectSummary -): viewModel.ProjectSummary => ({ - ...projectSummary, -}); + project: apiModel.Project, + employeeProjectList: apiModel.EmployeeProject[] +): viewModel.EmployeeProject => { + const employeeProject = employeeProjectList + ? employeeProjectList.find(ep => ep.id === project.id) + : viewModel.createEmptyEmployeeProject(); + return { + ...project, + isAssigned: employeeProject?.isAssigned, + }; +}; const mapProjectSummaryListFromApiToVm = ( - projectSummary: apiModel.ProjectSummary[] -): viewModel.ProjectSummary[] => - mapToCollection(projectSummary, ps => mapProjectSummaryFromApiToVm(ps)); + project: apiModel.Project[], + employeeProject: apiModel.EmployeeProject[] +): viewModel.EmployeeProject[] => + mapToCollection(project, p => + mapProjectSummaryFromApiToVm(p, employeeProject) + ); export const mapEmployeeFromApiToVm = ( - employee: apiModel.Employee + employee: apiModel.Employee, + projects: apiModel.Project[] ): viewModel.Employee => { return Boolean(employee) ? { ...employee, - projects: mapProjectSummaryListFromApiToVm(employee.projects), + projects: mapProjectSummaryListFromApiToVm(projects, employee.projects), } : viewModel.createEmptyEmployee(); }; + +export const mapEmployeeFromVmToApi = ( + employee: viewModel.Employee +): apiModel.Employee => { + return Boolean(employee) + ? { + id: employee.id, + name: employee.name, + email: employee.email, + isActive: employee.isActive, + temporalPassword: employee.temporalPassword, + } + : viewModel.createEmptyEmployee(); +}; + +const mapEmployeeProjectFromVmToApi = ( + employeeProject: viewModel.EmployeeProject +): apiModel.EmployeeProject => ({ + id: employeeProject.id, + isAssigned: employeeProject.isAssigned, +}); + +export const mapEmployeeProjectListFromVmToApi = ( + employeeProjectList: viewModel.EmployeeProject[] +): apiModel.EmployeeProject[] => + mapToCollection(employeeProjectList, mapEmployeeProjectFromVmToApi); diff --git a/src/pods/employee/employee.vm.ts b/src/pods/employee/employee.vm.ts index 5835537..f8229c6 100644 --- a/src/pods/employee/employee.vm.ts +++ b/src/pods/employee/employee.vm.ts @@ -4,13 +4,13 @@ export interface Employee { email: string; isActive: boolean; temporalPassword?: string; - projects: ProjectSummary[]; + projects: EmployeeProject[]; } -export interface ProjectSummary { +export interface EmployeeProject { id: string; isAssigned?: boolean; - projectName: string; + name: string; } export interface Report { @@ -31,3 +31,9 @@ export const createEmptyReport = (): Report => ({ month: '', year: '', }); + +export const createEmptyEmployeeProject = (): EmployeeProject => ({ + id: '', + name: '', + isAssigned: false, +});