From c1a335efc0fcb69cc2d450a60bd1f06573b9aa67 Mon Sep 17 00:00:00 2001 From: Daniel Sanchez Munoz Date: Mon, 22 Jun 2020 16:35:14 +0200 Subject: [PATCH 01/19] config graphql client --- config/webpack/dev.js | 3 +++ dev.env | 2 +- prod.env | 2 +- src/core/api/graphql.client.ts | 4 ++++ src/core/api/index.ts | 1 + .../employee-list/api/employee-list.api.ts | 18 +++++++++++++++++- 6 files changed, 27 insertions(+), 3 deletions(-) create mode 100644 src/core/api/graphql.client.ts create mode 100644 src/core/api/index.ts 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/pods/employee-list/api/employee-list.api.ts b/src/pods/employee-list/api/employee-list.api.ts index 4cd5a38..6d2128d 100644 --- a/src/pods/employee-list/api/employee-list.api.ts +++ b/src/pods/employee-list/api/employee-list.api.ts @@ -1,10 +1,26 @@ +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 + } + } + `; + const { employees } = await graphQLClient.request( + query + ); + return employees; }; export const deleteEmployee = async (id: string): Promise => { From cee690ca4cae2718fa95dc9b5756d606049d3a8d Mon Sep 17 00:00:00 2001 From: Daniel Sanchez Munoz Date: Mon, 22 Jun 2020 16:58:24 +0200 Subject: [PATCH 02/19] implement delete method --- .../employee-list/api/employee-list.api.ts | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/pods/employee-list/api/employee-list.api.ts b/src/pods/employee-list/api/employee-list.api.ts index 6d2128d..5219a2e 100644 --- a/src/pods/employee-list/api/employee-list.api.ts +++ b/src/pods/employee-list/api/employee-list.api.ts @@ -1,8 +1,5 @@ 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[]; @@ -23,7 +20,18 @@ export const getEmployeeList = async (): Promise => { 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; }; From f281c07f4db1c6d552cdabd4ec3dd9a92ab3ceaf Mon Sep 17 00:00:00 2001 From: Daniel Sanchez Munoz Date: Mon, 22 Jun 2020 17:12:21 +0200 Subject: [PATCH 03/19] implement get employee by id --- .../api/employee-list.mock-data.ts | 1 + src/pods/employee/api/employee.api.ts | 19 +++++++++++++++++-- src/pods/employee/api/employee.mock-data.ts | 1 + 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/pods/employee-list/api/employee-list.mock-data.ts b/src/pods/employee-list/api/employee-list.mock-data.ts index b48dbfa..d16741d 100644 --- a/src/pods/employee-list/api/employee-list.mock-data.ts +++ b/src/pods/employee-list/api/employee-list.mock-data.ts @@ -1,5 +1,6 @@ import { Employee } from './employee-list.api-model'; +// TODO: Move to back export const mockEmployeeList: Employee[] = [ { id: '1', diff --git a/src/pods/employee/api/employee.api.ts b/src/pods/employee/api/employee.api.ts index 252d864..b51c83c 100644 --- a/src/pods/employee/api/employee.api.ts +++ b/src/pods/employee/api/employee.api.ts @@ -1,6 +1,21 @@ import { Employee } from './employee.api-model'; -import { mockEmployee } from './employee.mock-data'; +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 + } + } + `; + + const { employee } = await graphQLClient.request(query); + + return employee; }; diff --git a/src/pods/employee/api/employee.mock-data.ts b/src/pods/employee/api/employee.mock-data.ts index 6eaf7b5..d63aaa6 100644 --- a/src/pods/employee/api/employee.mock-data.ts +++ b/src/pods/employee/api/employee.mock-data.ts @@ -1,5 +1,6 @@ import { Employee, ProjectSummary } from './employee.api-model'; +// TODO: Move to back const mockProjectSummaryList: ProjectSummary[] = [ { id: '1', From c3b7c8060876a658ee0504547859fd7b26d5931c Mon Sep 17 00:00:00 2001 From: Daniel Sanchez Munoz Date: Mon, 22 Jun 2020 17:46:46 +0200 Subject: [PATCH 04/19] implement employee insert --- src/pods/employee/api/employee.api.ts | 23 +++++++++++++++++++++++ src/pods/employee/employee.container.tsx | 14 +++++++++++--- 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/src/pods/employee/api/employee.api.ts b/src/pods/employee/api/employee.api.ts index b51c83c..5fcc070 100644 --- a/src/pods/employee/api/employee.api.ts +++ b/src/pods/employee/api/employee.api.ts @@ -19,3 +19,26 @@ export const getEmployeeById = async (id: string): Promise => { return employee; }; + +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; +}; diff --git a/src/pods/employee/employee.container.tsx b/src/pods/employee/employee.container.tsx index 876923a..9ae7a7c 100644 --- a/src/pods/employee/employee.container.tsx +++ b/src/pods/employee/employee.container.tsx @@ -8,7 +8,7 @@ import { } from './employee.vm'; import { useSnackbarContext } from 'common/components'; import { trackPromise } from 'react-promise-tracker'; -import { getEmployeeById } from './api'; +import { getEmployeeById, saveEmployee } from './api'; import { mapEmployeeFromApiToVm } from './employee.mappers'; import { useParams } from 'react-router-dom'; import { isEditModeHelper } from 'common/helpers'; @@ -33,8 +33,16 @@ export const EmployeeContainer: React.FunctionComponent = () => { } }; - const handleSave = (employee: Employee) => { - console.log('Guardado'); + const handleSave = async (employee: Employee) => { + try { + // TODO: implement mapper + const apiEmployee: any = { id: employee.id, name: employee.name }; + const id = await saveEmployee(apiEmployee); + setEmployee({ ...employee, id }); + } catch (error) { + error && + showMessage('Ha ocurrido un error al guardar el empleado', 'error'); + } }; const handleCancel = () => { From 27d1b344a8ca9823aca81b89182275a4f9244c18 Mon Sep 17 00:00:00 2001 From: Antonio Contreras LEMONCODE Date: Mon, 22 Jun 2020 20:12:42 +0200 Subject: [PATCH 05/19] Fix employee api --- src/pods/employee-list/api/employee-list.api.ts | 3 +++ src/pods/employee/api/employee.api.ts | 3 +++ src/pods/employee/employee.container.tsx | 8 +++++--- src/pods/employee/employee.mappers.ts | 6 ++++++ 4 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/pods/employee-list/api/employee-list.api.ts b/src/pods/employee-list/api/employee-list.api.ts index 5219a2e..40672f3 100644 --- a/src/pods/employee-list/api/employee-list.api.ts +++ b/src/pods/employee-list/api/employee-list.api.ts @@ -11,6 +11,9 @@ export const getEmployeeList = async (): Promise => { employees { id name + isActive + email + lastDateIncurred } } `; diff --git a/src/pods/employee/api/employee.api.ts b/src/pods/employee/api/employee.api.ts index 5fcc070..6c15aa5 100644 --- a/src/pods/employee/api/employee.api.ts +++ b/src/pods/employee/api/employee.api.ts @@ -11,6 +11,9 @@ export const getEmployeeById = async (id: string): Promise => { employee(id: "${id}") { id name + isActive + email + lastDateIncurred } } `; diff --git a/src/pods/employee/employee.container.tsx b/src/pods/employee/employee.container.tsx index 9ae7a7c..95a1439 100644 --- a/src/pods/employee/employee.container.tsx +++ b/src/pods/employee/employee.container.tsx @@ -9,7 +9,10 @@ import { import { useSnackbarContext } from 'common/components'; import { trackPromise } from 'react-promise-tracker'; import { getEmployeeById, saveEmployee } from './api'; -import { mapEmployeeFromApiToVm } from './employee.mappers'; +import { + mapEmployeeFromApiToVm, + mapEmployeeFromVmToApi, +} from './employee.mappers'; import { useParams } from 'react-router-dom'; import { isEditModeHelper } from 'common/helpers'; @@ -35,8 +38,7 @@ export const EmployeeContainer: React.FunctionComponent = () => { const handleSave = async (employee: Employee) => { try { - // TODO: implement mapper - const apiEmployee: any = { id: employee.id, name: employee.name }; + const apiEmployee = mapEmployeeFromVmToApi(employee); const id = await saveEmployee(apiEmployee); setEmployee({ ...employee, id }); } catch (error) { diff --git a/src/pods/employee/employee.mappers.ts b/src/pods/employee/employee.mappers.ts index 3464896..01b26b7 100644 --- a/src/pods/employee/employee.mappers.ts +++ b/src/pods/employee/employee.mappers.ts @@ -23,3 +23,9 @@ export const mapEmployeeFromApiToVm = ( } : viewModel.createEmptyEmployee(); }; + +export const mapEmployeeFromVmToApi = ( + employee: viewModel.Employee +): apiModel.Employee => ({ + ...employee, +}); From 0b2c6ec65d846927e3d714b7b63af0e1465e86ca Mon Sep 17 00:00:00 2001 From: Antonio Contreras LEMONCODE Date: Tue, 23 Jun 2020 16:54:08 +0200 Subject: [PATCH 06/19] Refactor employee components and remove mock data --- .../api/employee-list.mock-data.ts | 61 ------------------- src/pods/employee/api/employee.api.ts | 5 ++ src/pods/employee/api/employee.mock-data.ts | 34 ----------- .../components/project-row.component.tsx | 18 +++++- .../employee/components/project.component.tsx | 25 +++++++- src/pods/employee/employee.component.tsx | 11 ++-- src/pods/employee/employee.container.tsx | 23 ++++++- 7 files changed, 69 insertions(+), 108 deletions(-) delete mode 100644 src/pods/employee-list/api/employee-list.mock-data.ts delete mode 100644 src/pods/employee/api/employee.mock-data.ts 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 d16741d..0000000 --- a/src/pods/employee-list/api/employee-list.mock-data.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { Employee } from './employee-list.api-model'; - -// TODO: Move to back -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.ts b/src/pods/employee/api/employee.api.ts index 6c15aa5..e6d02ad 100644 --- a/src/pods/employee/api/employee.api.ts +++ b/src/pods/employee/api/employee.api.ts @@ -14,6 +14,11 @@ export const getEmployeeById = async (id: string): Promise => { isActive email lastDateIncurred + projects { + id + isAssigned + projectName + } } } `; 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 d63aaa6..0000000 --- a/src/pods/employee/api/employee.mock-data.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { Employee, ProjectSummary } from './employee.api-model'; - -// TODO: Move to back -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..12df8d4 100644 --- a/src/pods/employee/components/project-row.component.tsx +++ b/src/pods/employee/components/project-row.component.tsx @@ -7,15 +7,27 @@ import { import Checkbox from '@material-ui/core/Checkbox'; import { ProjectSummary } from '../employee.vm'; -type Props = RowRendererProps; +interface RowProps extends RowRendererProps { + onChangeProject: (project: ProjectSummary) => void; +} -export const EmployeeRowComponent: React.FunctionComponent = ({ +export const EmployeeRowComponent: React.FunctionComponent = ({ row, + onChangeProject, }) => { return ( - + + onChangeProject({ + ...row, + isAssigned: checked, + }) + } + checked={row.isAssigned} + /> {row.projectName} diff --git a/src/pods/employee/components/project.component.tsx b/src/pods/employee/components/project.component.tsx index 00df731..e1e2abb 100644 --- a/src/pods/employee/components/project.component.tsx +++ b/src/pods/employee/components/project.component.tsx @@ -7,25 +7,44 @@ import { CommandFooterComponent } from 'common-app/command-footer'; interface Props { projectSummaryList: ProjectSummary[]; className?: string; + onSave: (project: ProjectSummary[]) => void; onCancel: () => void; } export const ProjectComponent: React.FunctionComponent = ({ projectSummaryList, className, + onSave, onCancel, }) => { + const [projectList, setProjectList] = React.useState( + projectSummaryList + ); + + React.useEffect(() => { + setProjectList(projectSummaryList); + }, [projectSummaryList]); + + const handleChangeProject = (id: string) => (project: ProjectSummary) => { + const updateProjectList = projectList.map(p => (p.id === id ? project : p)); + setProjectList(updateProjectList); + }; + + const handleSave = () => onSave(projectList); return ( <> ) => ( - + )} /> - + ); }; diff --git a/src/pods/employee/employee.component.tsx b/src/pods/employee/employee.component.tsx index 62591ea..647ad11 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, ProjectSummary } 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: ProjectSummary[]) => 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,7 +42,7 @@ export const EmployeeComponent: React.FunctionComponent = ({ @@ -49,6 +51,7 @@ export const EmployeeComponent: React.FunctionComponent = ({ diff --git a/src/pods/employee/employee.container.tsx b/src/pods/employee/employee.container.tsx index 95a1439..f482dd6 100644 --- a/src/pods/employee/employee.container.tsx +++ b/src/pods/employee/employee.container.tsx @@ -5,6 +5,7 @@ import { Report, createEmptyEmployee, createEmptyReport, + ProjectSummary, } from './employee.vm'; import { useSnackbarContext } from 'common/components'; import { trackPromise } from 'react-promise-tracker'; @@ -15,6 +16,8 @@ import { } from './employee.mappers'; import { useParams } from 'react-router-dom'; import { isEditModeHelper } from 'common/helpers'; +import { routes } from 'core/router'; +import { useHistory } from 'react-router'; export const EmployeeContainer: React.FunctionComponent = () => { const { id } = useParams(); @@ -24,6 +27,7 @@ export const EmployeeContainer: React.FunctionComponent = () => { const [isEditMode, setIsEditMode] = React.useState(false); const [report, setReport] = React.useState(createEmptyReport()); const { showMessage } = useSnackbarContext(); + const history = useHistory(); const onLoadEmployee = async () => { try { @@ -36,19 +40,31 @@ export const EmployeeContainer: React.FunctionComponent = () => { } }; - const handleSave = async (employee: Employee) => { + const handleSaveEmployee = async (employee: Employee) => { try { const apiEmployee = mapEmployeeFromVmToApi(employee); const id = await saveEmployee(apiEmployee); setEmployee({ ...employee, id }); + showMessage('Empleado guardado con éxito', 'success'); + history.push(routes.editEmployee(id)); } catch (error) { error && showMessage('Ha ocurrido un error al guardar el empleado', 'error'); } }; + const handleSaveProjectSelection = async ( + employeeProjects: ProjectSummary[] + ) => { + try { + console.log(employeeProjects); + } catch (error) { + error && showMessage('Ha ocurrido un error al guardar', 'error'); + } + }; + const handleCancel = () => { - history.back(); + history.goBack(); }; const handleGenerateExcel = (report: Report) => { @@ -69,7 +85,8 @@ export const EmployeeContainer: React.FunctionComponent = () => { employee={employee} isEditMode={isEditMode} report={report} - onSave={handleSave} + onSaveEmployee={handleSaveEmployee} + onSaveProjectSelection={handleSaveProjectSelection} onCancel={handleCancel} onGenerateExcel={handleGenerateExcel} /> From a5ad0303f16b7a35617a1310b19adf366350da15 Mon Sep 17 00:00:00 2001 From: Antonio Contreras LEMONCODE Date: Tue, 23 Jun 2020 19:05:55 +0200 Subject: [PATCH 07/19] Implement saveProjectSummaryList and mappers --- src/pods/employee/api/employee.api.ts | 18 +++++++++++++++++- src/pods/employee/employee.container.tsx | 23 +++++++++++++++++------ src/pods/employee/employee.mappers.ts | 13 +++++++++++++ 3 files changed, 47 insertions(+), 7 deletions(-) diff --git a/src/pods/employee/api/employee.api.ts b/src/pods/employee/api/employee.api.ts index e6d02ad..3fb93d9 100644 --- a/src/pods/employee/api/employee.api.ts +++ b/src/pods/employee/api/employee.api.ts @@ -1,4 +1,4 @@ -import { Employee } from './employee.api-model'; +import { Employee, ProjectSummary } from './employee.api-model'; import { graphQLClient } from 'core/api'; interface GetEmployeeResponse { @@ -50,3 +50,19 @@ export const saveEmployee = async (employee: Employee): Promise => { return saveEmployee.id; }; + +export const saveProjectSummary = async ( + id: string, + projectSummaryList: ProjectSummary[] +): Promise => { + const query = `mutation($projectSummaryList: [ProjectSummaryInput!]!) { + saveProjectSummaryList( + id: "${id}", + projectSummaryList: $projectSummaryList, + ) { + id + } + }`; + + await graphQLClient.request(query, { projectSummaryList }); +}; diff --git a/src/pods/employee/employee.container.tsx b/src/pods/employee/employee.container.tsx index f482dd6..860c088 100644 --- a/src/pods/employee/employee.container.tsx +++ b/src/pods/employee/employee.container.tsx @@ -9,10 +9,11 @@ import { } from './employee.vm'; import { useSnackbarContext } from 'common/components'; import { trackPromise } from 'react-promise-tracker'; -import { getEmployeeById, saveEmployee } from './api'; +import { getEmployeeById, saveEmployee, saveProjectSummary } from './api'; import { mapEmployeeFromApiToVm, mapEmployeeFromVmToApi, + mapProjectSummaryListFromVmToApi, } from './employee.mappers'; import { useParams } from 'react-router-dom'; import { isEditModeHelper } from 'common/helpers'; @@ -54,12 +55,22 @@ export const EmployeeContainer: React.FunctionComponent = () => { }; const handleSaveProjectSelection = async ( - employeeProjects: ProjectSummary[] + employeeSummary: ProjectSummary[] ) => { - try { - console.log(employeeProjects); - } catch (error) { - error && showMessage('Ha ocurrido un error al guardar', 'error'); + if (id) { + try { + const apiProjectSummary = mapProjectSummaryListFromVmToApi( + employeeSummary + ); + await saveProjectSummary(id, apiProjectSummary); + setEmployee({ + ...employee, + projects: employeeSummary, + }); + showMessage('Se actualizó con éxito', 'success'); + } catch (error) { + error && showMessage('Ha ocurrido un error al guardar', 'error'); + } } }; diff --git a/src/pods/employee/employee.mappers.ts b/src/pods/employee/employee.mappers.ts index 01b26b7..af69f3a 100644 --- a/src/pods/employee/employee.mappers.ts +++ b/src/pods/employee/employee.mappers.ts @@ -29,3 +29,16 @@ export const mapEmployeeFromVmToApi = ( ): apiModel.Employee => ({ ...employee, }); + +const mapProjectSummaryFromVmToApi = ( + projectSummary: viewModel.ProjectSummary +): apiModel.ProjectSummary => ({ + id: projectSummary.id, + isAssigned: projectSummary.isAssigned, + projectName: projectSummary.projectName, +}); + +export const mapProjectSummaryListFromVmToApi = ( + projectSummary: viewModel.ProjectSummary[] +): apiModel.ProjectSummary[] => + mapToCollection(projectSummary, mapProjectSummaryFromVmToApi); From 6aab1044aba549a8b30d4c70ee296fd09ed64150 Mon Sep 17 00:00:00 2001 From: Antonio Contreras LEMONCODE Date: Wed, 24 Jun 2020 10:50:39 +0200 Subject: [PATCH 08/19] Fix employee container logic --- src/core/router/index.ts | 1 + src/core/router/route-params.vm.ts | 3 +++ src/pods/employee/employee.container.tsx | 31 +++++++++++++++--------- 3 files changed, 23 insertions(+), 12 deletions(-) create mode 100644 src/core/router/route-params.vm.ts 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/employee.container.tsx b/src/pods/employee/employee.container.tsx index 860c088..3fe1f55 100644 --- a/src/pods/employee/employee.container.tsx +++ b/src/pods/employee/employee.container.tsx @@ -17,11 +17,11 @@ import { } from './employee.mappers'; import { useParams } from 'react-router-dom'; import { isEditModeHelper } from 'common/helpers'; -import { routes } from 'core/router'; +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() ); @@ -32,7 +32,7 @@ export const EmployeeContainer: React.FunctionComponent = () => { const onLoadEmployee = async () => { try { - const apiEmployee = await trackPromise(getEmployeeById(id)); + const apiEmployee = await trackPromise(getEmployeeById(params.id)); const viewModelEmployee = mapEmployeeFromApiToVm(apiEmployee); setEmployee(viewModelEmployee); } catch (error) { @@ -41,28 +41,35 @@ export const EmployeeContainer: React.FunctionComponent = () => { } }; + 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 saveEmployee(apiEmployee); - setEmployee({ ...employee, id }); - showMessage('Empleado guardado con éxito', 'success'); - history.push(routes.editEmployee(id)); + const id = await trackPromise(saveEmployee(apiEmployee)); + handleSuccessSaveEmployee(id, employee); } catch (error) { - error && - showMessage('Ha ocurrido un error al guardar el empleado', 'error'); + error && showMessage(error.message, 'error'); } }; const handleSaveProjectSelection = async ( employeeSummary: ProjectSummary[] ) => { - if (id) { + if (params.id) { try { const apiProjectSummary = mapProjectSummaryListFromVmToApi( employeeSummary ); - await saveProjectSummary(id, apiProjectSummary); + await trackPromise(saveProjectSummary(params.id, apiProjectSummary)); setEmployee({ ...employee, projects: employeeSummary, @@ -84,7 +91,7 @@ export const EmployeeContainer: React.FunctionComponent = () => { }; React.useEffect(() => { - const isEditMode = isEditModeHelper(id); + const isEditMode = isEditModeHelper(params.id); setIsEditMode(isEditMode); if (isEditMode) { onLoadEmployee(); From 7eb5db28531aab398c42b7ccee24f4a4a974e182 Mon Sep 17 00:00:00 2001 From: Antonio Contreras LEMONCODE Date: Wed, 24 Jun 2020 12:51:56 +0200 Subject: [PATCH 09/19] Fix view model and api model --- src/pods/employee/api/employee.api-model.ts | 10 +++++++--- src/pods/employee/api/employee.api.ts | 4 ++-- .../components/project-row.component.tsx | 8 ++++---- .../employee/components/project.component.tsx | 12 ++++++------ src/pods/employee/employee.component.tsx | 4 ++-- src/pods/employee/employee.container.tsx | 4 ++-- src/pods/employee/employee.mappers.ts | 17 ++++++++--------- src/pods/employee/employee.vm.ts | 11 ++++++++--- 8 files changed, 39 insertions(+), 31 deletions(-) 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 3fb93d9..ea91dec 100644 --- a/src/pods/employee/api/employee.api.ts +++ b/src/pods/employee/api/employee.api.ts @@ -1,4 +1,4 @@ -import { Employee, ProjectSummary } from './employee.api-model'; +import { Employee, EmployeeProject } from './employee.api-model'; import { graphQLClient } from 'core/api'; interface GetEmployeeResponse { @@ -53,7 +53,7 @@ export const saveEmployee = async (employee: Employee): Promise => { export const saveProjectSummary = async ( id: string, - projectSummaryList: ProjectSummary[] + projectSummaryList: EmployeeProject[] ): Promise => { const query = `mutation($projectSummaryList: [ProjectSummaryInput!]!) { saveProjectSummaryList( diff --git a/src/pods/employee/components/project-row.component.tsx b/src/pods/employee/components/project-row.component.tsx index 12df8d4..1dee59e 100644 --- a/src/pods/employee/components/project-row.component.tsx +++ b/src/pods/employee/components/project-row.component.tsx @@ -5,10 +5,10 @@ import { CellComponent, } from 'common/components'; import Checkbox from '@material-ui/core/Checkbox'; -import { ProjectSummary } from '../employee.vm'; +import { EmployeeProject } from '../employee.vm'; -interface RowProps extends RowRendererProps { - onChangeProject: (project: ProjectSummary) => void; +interface RowProps extends RowRendererProps { + onChangeProject: (project: EmployeeProject) => void; } export const EmployeeRowComponent: React.FunctionComponent = ({ @@ -29,7 +29,7 @@ export const EmployeeRowComponent: React.FunctionComponent = ({ checked={row.isAssigned} /> - {row.projectName} + {''} ); }; diff --git a/src/pods/employee/components/project.component.tsx b/src/pods/employee/components/project.component.tsx index e1e2abb..a1bf80b 100644 --- a/src/pods/employee/components/project.component.tsx +++ b/src/pods/employee/components/project.component.tsx @@ -1,13 +1,13 @@ 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[]; + projectSummaryList: EmployeeProject[]; className?: string; - onSave: (project: ProjectSummary[]) => void; + onSave: (project: EmployeeProject[]) => void; onCancel: () => void; } @@ -17,7 +17,7 @@ export const ProjectComponent: React.FunctionComponent = ({ onSave, onCancel, }) => { - const [projectList, setProjectList] = React.useState( + const [projectList, setProjectList] = React.useState( projectSummaryList ); @@ -25,7 +25,7 @@ export const ProjectComponent: React.FunctionComponent = ({ setProjectList(projectSummaryList); }, [projectSummaryList]); - const handleChangeProject = (id: string) => (project: ProjectSummary) => { + const handleChangeProject = (id: string) => (project: EmployeeProject) => { const updateProjectList = projectList.map(p => (p.id === id ? project : p)); setProjectList(updateProjectList); }; @@ -37,7 +37,7 @@ export const ProjectComponent: React.FunctionComponent = ({ columns={['Asignado', 'Nombre y Apellido']} rows={projectList} className={className} - rowRenderer={(rowProps: RowRendererProps) => ( + rowRenderer={(rowProps: RowRendererProps) => ( void; - onSaveProjectSelection: (project: ProjectSummary[]) => void; + onSaveProjectSelection: (project: EmployeeProject[]) => void; onCancel: () => void; onGenerateExcel: (report: Report) => void; } diff --git a/src/pods/employee/employee.container.tsx b/src/pods/employee/employee.container.tsx index 3fe1f55..4b6589e 100644 --- a/src/pods/employee/employee.container.tsx +++ b/src/pods/employee/employee.container.tsx @@ -5,7 +5,7 @@ import { Report, createEmptyEmployee, createEmptyReport, - ProjectSummary, + EmployeeProject, } from './employee.vm'; import { useSnackbarContext } from 'common/components'; import { trackPromise } from 'react-promise-tracker'; @@ -62,7 +62,7 @@ export const EmployeeContainer: React.FunctionComponent = () => { }; const handleSaveProjectSelection = async ( - employeeSummary: ProjectSummary[] + employeeSummary: EmployeeProject[] ) => { if (params.id) { try { diff --git a/src/pods/employee/employee.mappers.ts b/src/pods/employee/employee.mappers.ts index af69f3a..68daba8 100644 --- a/src/pods/employee/employee.mappers.ts +++ b/src/pods/employee/employee.mappers.ts @@ -3,14 +3,14 @@ import * as apiModel from './api/employee.api-model'; import * as viewModel from './employee.vm'; const mapProjectSummaryFromApiToVm = ( - projectSummary: apiModel.ProjectSummary -): viewModel.ProjectSummary => ({ + projectSummary: apiModel.EmployeeProject +): viewModel.EmployeeProject => ({ ...projectSummary, }); const mapProjectSummaryListFromApiToVm = ( - projectSummary: apiModel.ProjectSummary[] -): viewModel.ProjectSummary[] => + projectSummary: apiModel.EmployeeProject[] +): viewModel.EmployeeProject[] => mapToCollection(projectSummary, ps => mapProjectSummaryFromApiToVm(ps)); export const mapEmployeeFromApiToVm = ( @@ -31,14 +31,13 @@ export const mapEmployeeFromVmToApi = ( }); const mapProjectSummaryFromVmToApi = ( - projectSummary: viewModel.ProjectSummary -): apiModel.ProjectSummary => ({ + projectSummary: viewModel.EmployeeProject +): apiModel.EmployeeProject => ({ id: projectSummary.id, isAssigned: projectSummary.isAssigned, - projectName: projectSummary.projectName, }); export const mapProjectSummaryListFromVmToApi = ( - projectSummary: viewModel.ProjectSummary[] -): apiModel.ProjectSummary[] => + projectSummary: viewModel.EmployeeProject[] +): apiModel.EmployeeProject[] => mapToCollection(projectSummary, mapProjectSummaryFromVmToApi); diff --git a/src/pods/employee/employee.vm.ts b/src/pods/employee/employee.vm.ts index 5835537..a4de357 100644 --- a/src/pods/employee/employee.vm.ts +++ b/src/pods/employee/employee.vm.ts @@ -4,13 +4,18 @@ 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; + isAssigned?: boolean; + name: string; } export interface Report { From 796779d09c56cc621a5cd89a7de3ad66c372bf6f Mon Sep 17 00:00:00 2001 From: Antonio Contreras LEMONCODE Date: Wed, 24 Jun 2020 14:14:52 +0200 Subject: [PATCH 10/19] Work in progress --- src/pods/employee/api/employee.api.ts | 32 ++++++++++++++----- .../employee/components/project.component.tsx | 14 ++++---- src/pods/employee/employee.component.tsx | 2 +- src/pods/employee/employee.container.tsx | 19 ++++++++--- src/pods/employee/employee.mappers.spec.ts | 2 -- src/pods/employee/employee.mappers.ts | 15 ++++----- 6 files changed, 52 insertions(+), 32 deletions(-) diff --git a/src/pods/employee/api/employee.api.ts b/src/pods/employee/api/employee.api.ts index ea91dec..354c5f0 100644 --- a/src/pods/employee/api/employee.api.ts +++ b/src/pods/employee/api/employee.api.ts @@ -1,4 +1,4 @@ -import { Employee, EmployeeProject } from './employee.api-model'; +import { Employee, EmployeeProject, Project } from './employee.api-model'; import { graphQLClient } from 'core/api'; interface GetEmployeeResponse { @@ -17,7 +17,6 @@ export const getEmployeeById = async (id: string): Promise => { projects { id isAssigned - projectName } } } @@ -28,6 +27,23 @@ export const getEmployeeById = async (id: string): Promise => { return employee; }; +interface GetProjectListResponse { + projects: Project[]; +} + +export const getProjects = async (): Promise => { + const query = ` + projects { + id + name + } + `; + const { projects } = await graphQLClient.request( + query + ); + return projects; +}; + interface SaveEmployeeResponse { saveEmployee: Employee; } @@ -51,18 +67,18 @@ export const saveEmployee = async (employee: Employee): Promise => { return saveEmployee.id; }; -export const saveProjectSummary = async ( +export const saveEmployeeProjectList = async ( id: string, - projectSummaryList: EmployeeProject[] + employeeProjectList: EmployeeProject[] ): Promise => { - const query = `mutation($projectSummaryList: [ProjectSummaryInput!]!) { - saveProjectSummaryList( + const query = `mutation($employeeProjectList: [EmployeeProjectInput!]!) { + saveEmployeeProjectList( id: "${id}", - projectSummaryList: $projectSummaryList, + employeeProjectList: $employeeProjectList, ) { id } }`; - await graphQLClient.request(query, { projectSummaryList }); + await graphQLClient.request(query, { employeeProjectList }); }; diff --git a/src/pods/employee/components/project.component.tsx b/src/pods/employee/components/project.component.tsx index a1bf80b..d8a5846 100644 --- a/src/pods/employee/components/project.component.tsx +++ b/src/pods/employee/components/project.component.tsx @@ -5,25 +5,25 @@ import { EmployeeRowComponent } from './project-row.component'; import { CommandFooterComponent } from 'common-app/command-footer'; interface Props { - projectSummaryList: EmployeeProject[]; - 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( - projectSummaryList + employeeProjectList ); React.useEffect(() => { - setProjectList(projectSummaryList); - }, [projectSummaryList]); + setProjectList(employeeProjectList); + }, [employeeProjectList]); const handleChangeProject = (id: string) => (project: EmployeeProject) => { const updateProjectList = projectList.map(p => (p.id === id ? project : p)); diff --git a/src/pods/employee/employee.component.tsx b/src/pods/employee/employee.component.tsx index adbd500..6c54de4 100644 --- a/src/pods/employee/employee.component.tsx +++ b/src/pods/employee/employee.component.tsx @@ -49,7 +49,7 @@ export const EmployeeComponent: React.FunctionComponent = ({ { const onLoadEmployee = async () => { try { - const apiEmployee = await trackPromise(getEmployeeById(params.id)); + const [apiProjects, apiEmployee] = await trackPromise( + Promise.all([getProjects(), getEmployeeById(params.id)]) + ); const viewModelEmployee = mapEmployeeFromApiToVm(apiEmployee); setEmployee(viewModelEmployee); } catch (error) { @@ -66,10 +73,12 @@ export const EmployeeContainer: React.FunctionComponent = () => { ) => { if (params.id) { try { - const apiProjectSummary = mapProjectSummaryListFromVmToApi( + const apiProjectSummary = mapEmployeeProjectListFromVmToApi( employeeSummary ); - await trackPromise(saveProjectSummary(params.id, apiProjectSummary)); + await trackPromise( + saveEmployeeProjectList(params.id, apiProjectSummary) + ); setEmployee({ ...employee, projects: employeeSummary, diff --git a/src/pods/employee/employee.mappers.spec.ts b/src/pods/employee/employee.mappers.spec.ts index 8085341..18e0d39 100644 --- a/src/pods/employee/employee.mappers.spec.ts +++ b/src/pods/employee/employee.mappers.spec.ts @@ -90,7 +90,6 @@ describe('./pods/employee/employee.mappers', () => { projects: [ { id: 'test id', - projectName: 'test employee name', isAssigned: true, }, ], @@ -105,7 +104,6 @@ describe('./pods/employee/employee.mappers', () => { projects: [ { id: 'test id', - projectName: 'test employee name', isAssigned: true, }, ], diff --git a/src/pods/employee/employee.mappers.ts b/src/pods/employee/employee.mappers.ts index 68daba8..865f3c1 100644 --- a/src/pods/employee/employee.mappers.ts +++ b/src/pods/employee/employee.mappers.ts @@ -30,14 +30,11 @@ export const mapEmployeeFromVmToApi = ( ...employee, }); -const mapProjectSummaryFromVmToApi = ( - projectSummary: viewModel.EmployeeProject -): apiModel.EmployeeProject => ({ - id: projectSummary.id, - isAssigned: projectSummary.isAssigned, -}); +const mapEmployeeProjectFromVmToApi = ( + employeeProject: viewModel.EmployeeProject +): apiModel.EmployeeProject => ({ ...employeeProject }); -export const mapProjectSummaryListFromVmToApi = ( - projectSummary: viewModel.EmployeeProject[] +export const mapEmployeeProjectListFromVmToApi = ( + employeeProjectList: viewModel.EmployeeProject[] ): apiModel.EmployeeProject[] => - mapToCollection(projectSummary, mapProjectSummaryFromVmToApi); + mapToCollection(employeeProjectList, mapEmployeeProjectFromVmToApi); From 2a6caeea3b38f05c6669b422cbd07c551bc42b7f Mon Sep 17 00:00:00 2001 From: Antonio Contreras LEMONCODE Date: Wed, 24 Jun 2020 14:48:35 +0200 Subject: [PATCH 11/19] Fix query --- src/pods/employee/api/employee.api.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/pods/employee/api/employee.api.ts b/src/pods/employee/api/employee.api.ts index 354c5f0..3b521b3 100644 --- a/src/pods/employee/api/employee.api.ts +++ b/src/pods/employee/api/employee.api.ts @@ -33,10 +33,12 @@ interface GetProjectListResponse { export const getProjects = async (): Promise => { const query = ` + query { projects { id name } + } `; const { projects } = await graphQLClient.request( query From 32ed3de41f2302fb01818f8a730f987eb432efd4 Mon Sep 17 00:00:00 2001 From: Antonio Contreras LEMONCODE Date: Wed, 24 Jun 2020 16:44:09 +0200 Subject: [PATCH 12/19] Fix view model and mappers --- .../components/project-row.component.tsx | 2 +- src/pods/employee/employee.container.tsx | 5 +++- src/pods/employee/employee.mappers.ts | 27 ++++++++++++++----- src/pods/employee/employee.vm.ts | 1 + 4 files changed, 26 insertions(+), 9 deletions(-) diff --git a/src/pods/employee/components/project-row.component.tsx b/src/pods/employee/components/project-row.component.tsx index 1dee59e..f650ff0 100644 --- a/src/pods/employee/components/project-row.component.tsx +++ b/src/pods/employee/components/project-row.component.tsx @@ -29,7 +29,7 @@ export const EmployeeRowComponent: React.FunctionComponent = ({ checked={row.isAssigned} /> - {''} + {row.name} ); }; diff --git a/src/pods/employee/employee.container.tsx b/src/pods/employee/employee.container.tsx index 0bbe04e..c9e3342 100644 --- a/src/pods/employee/employee.container.tsx +++ b/src/pods/employee/employee.container.tsx @@ -40,7 +40,10 @@ export const EmployeeContainer: React.FunctionComponent = () => { const [apiProjects, apiEmployee] = await trackPromise( Promise.all([getProjects(), getEmployeeById(params.id)]) ); - const viewModelEmployee = mapEmployeeFromApiToVm(apiEmployee); + const viewModelEmployee = mapEmployeeFromApiToVm( + apiEmployee, + apiProjects + ); setEmployee(viewModelEmployee); } catch (error) { error && diff --git a/src/pods/employee/employee.mappers.ts b/src/pods/employee/employee.mappers.ts index 865f3c1..98790f6 100644 --- a/src/pods/employee/employee.mappers.ts +++ b/src/pods/employee/employee.mappers.ts @@ -3,23 +3,29 @@ import * as apiModel from './api/employee.api-model'; import * as viewModel from './employee.vm'; const mapProjectSummaryFromApiToVm = ( - projectSummary: apiModel.EmployeeProject + projectSummary: apiModel.EmployeeProject, + projects: apiModel.Project[] ): viewModel.EmployeeProject => ({ ...projectSummary, + name: projects.find(p => p.id === projectSummary.id).name, }); const mapProjectSummaryListFromApiToVm = ( - projectSummary: apiModel.EmployeeProject[] + projectSummary: apiModel.EmployeeProject[], + projects: apiModel.Project[] ): viewModel.EmployeeProject[] => - mapToCollection(projectSummary, ps => mapProjectSummaryFromApiToVm(ps)); + mapToCollection(projectSummary, ps => + mapProjectSummaryFromApiToVm(ps, projects) + ); export const mapEmployeeFromApiToVm = ( - employee: apiModel.Employee + employee: apiModel.Employee, + projects: apiModel.Project[] ): viewModel.Employee => { return Boolean(employee) ? { ...employee, - projects: mapProjectSummaryListFromApiToVm(employee.projects), + projects: mapProjectSummaryListFromApiToVm(employee.projects, projects), } : viewModel.createEmptyEmployee(); }; @@ -27,12 +33,19 @@ export const mapEmployeeFromApiToVm = ( export const mapEmployeeFromVmToApi = ( employee: viewModel.Employee ): apiModel.Employee => ({ - ...employee, + id: employee.id, + name: employee.name, + email: employee.email, + isActive: employee.isActive, + temporalPassword: employee.temporalPassword, }); const mapEmployeeProjectFromVmToApi = ( employeeProject: viewModel.EmployeeProject -): apiModel.EmployeeProject => ({ ...employeeProject }); +): apiModel.EmployeeProject => ({ + id: employeeProject.id, + isAssigned: employeeProject.isAssigned, +}); export const mapEmployeeProjectListFromVmToApi = ( employeeProjectList: viewModel.EmployeeProject[] diff --git a/src/pods/employee/employee.vm.ts b/src/pods/employee/employee.vm.ts index a4de357..1c6d6b4 100644 --- a/src/pods/employee/employee.vm.ts +++ b/src/pods/employee/employee.vm.ts @@ -10,6 +10,7 @@ export interface Employee { export interface EmployeeProject { id: string; isAssigned?: boolean; + name: string; } export interface Project { From eedf56a173a1c2c0605f65b2397952c10580be58 Mon Sep 17 00:00:00 2001 From: Antonio Contreras LEMONCODE Date: Wed, 24 Jun 2020 19:33:43 +0200 Subject: [PATCH 13/19] Add function to employee view model and fix mappers --- src/pods/employee/employee.mappers.ts | 27 ++++++++++++++++----------- src/pods/employee/employee.vm.ts | 6 ++++++ 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/src/pods/employee/employee.mappers.ts b/src/pods/employee/employee.mappers.ts index 98790f6..abc4c55 100644 --- a/src/pods/employee/employee.mappers.ts +++ b/src/pods/employee/employee.mappers.ts @@ -3,19 +3,24 @@ import * as apiModel from './api/employee.api-model'; import * as viewModel from './employee.vm'; const mapProjectSummaryFromApiToVm = ( - projectSummary: apiModel.EmployeeProject, - projects: apiModel.Project[] -): viewModel.EmployeeProject => ({ - ...projectSummary, - name: projects.find(p => p.id === projectSummary.id).name, -}); + 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.EmployeeProject[], - projects: apiModel.Project[] + project: apiModel.Project[], + employeeProject: apiModel.EmployeeProject[] ): viewModel.EmployeeProject[] => - mapToCollection(projectSummary, ps => - mapProjectSummaryFromApiToVm(ps, projects) + mapToCollection(project, p => + mapProjectSummaryFromApiToVm(p, employeeProject) ); export const mapEmployeeFromApiToVm = ( @@ -25,7 +30,7 @@ export const mapEmployeeFromApiToVm = ( return Boolean(employee) ? { ...employee, - projects: mapProjectSummaryListFromApiToVm(employee.projects, projects), + projects: mapProjectSummaryListFromApiToVm(projects, employee.projects), } : viewModel.createEmptyEmployee(); }; diff --git a/src/pods/employee/employee.vm.ts b/src/pods/employee/employee.vm.ts index 1c6d6b4..3fa7aac 100644 --- a/src/pods/employee/employee.vm.ts +++ b/src/pods/employee/employee.vm.ts @@ -37,3 +37,9 @@ export const createEmptyReport = (): Report => ({ month: '', year: '', }); + +export const createEmptyEmployeeProject = (): EmployeeProject => ({ + id: '', + name: '', + isAssigned: false, +}); From cd89bb5780d9e3c12cee082b8b7b439b0cfe10bd Mon Sep 17 00:00:00 2001 From: Antonio Contreras LEMONCODE Date: Wed, 24 Jun 2020 19:57:57 +0200 Subject: [PATCH 14/19] fix unit test --- src/pods/employee/employee.mappers.spec.ts | 85 +++++++++++++++++++--- 1 file changed, 76 insertions(+), 9 deletions(-) diff --git a/src/pods/employee/employee.mappers.spec.ts b/src/pods/employee/employee.mappers.spec.ts index 18e0d39..d67c497 100644 --- a/src/pods/employee/employee.mappers.spec.ts +++ b/src/pods/employee/employee.mappers.spec.ts @@ -6,9 +6,10 @@ describe('./pods/employee/employee.mappers', () => { it('should return empty employee when feeding null value', () => { // Arrange const employee = null; + const projects = null; // Act - const result = mapEmployeeFromApiToVm(employee); + const result = mapEmployeeFromApiToVm(employee, projects); // Assert expect(result).toEqual(viewModel.createEmptyEmployee()); @@ -17,9 +18,10 @@ describe('./pods/employee/employee.mappers', () => { it('should return empty employee when feeding undefined value', () => { // Arrange const employee = undefined; + const projects = undefined; // Act - const result = mapEmployeeFromApiToVm(employee); + const result = mapEmployeeFromApiToVm(employee, projects); // Assert expect(result).toEqual(viewModel.createEmptyEmployee()); @@ -36,17 +38,39 @@ describe('./pods/employee/employee.mappers', () => { 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: [], + projects: [ + { + id: '1', + name: 'project test 1', + isAssigned: false, + }, + { + id: '2', + name: 'project test 2', + isAssigned: false, + }, + ], }; // Act - const result = mapEmployeeFromApiToVm(employee); + const result = mapEmployeeFromApiToVm(employee, projects); // Assert expect(result).toEqual(expectedResult); @@ -69,11 +93,33 @@ describe('./pods/employee/employee.mappers', () => { email: 'test@email.com', isActive: true, temporalPassword: 'test password', - projects: [], + 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); + const result = mapEmployeeFromApiToVm(employee, projects); // Assert expect(result).toEqual(expectedResult); @@ -89,12 +135,27 @@ describe('./pods/employee/employee.mappers', () => { temporalPassword: 'test password', projects: [ { - id: 'test id', + 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', @@ -103,14 +164,20 @@ describe('./pods/employee/employee.mappers', () => { temporalPassword: 'test password', projects: [ { - id: 'test id', + id: '1', isAssigned: true, + name: 'project test 1', + }, + { + id: '2', + isAssigned: false, + name: 'project test 2', }, ], }; // Act - const result = mapEmployeeFromApiToVm(employee); + const result = mapEmployeeFromApiToVm(employee, projects); // Assert expect(result).toEqual(expectedResult); From 3e7044c12ddba0ea29c1521f63388d7412f7e40b Mon Sep 17 00:00:00 2001 From: Antonio Contreras LEMONCODE Date: Thu, 25 Jun 2020 09:35:38 +0200 Subject: [PATCH 15/19] Add others unit test --- src/pods/employee/employee.mappers.spec.ts | 423 ++++++++++++++------- src/pods/employee/employee.mappers.ts | 18 +- 2 files changed, 303 insertions(+), 138 deletions(-) diff --git a/src/pods/employee/employee.mappers.spec.ts b/src/pods/employee/employee.mappers.spec.ts index d67c497..01d3fcf 100644 --- a/src/pods/employee/employee.mappers.spec.ts +++ b/src/pods/employee/employee.mappers.spec.ts @@ -1,185 +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; - const projects = null; + describe('mapEmployeeFromApiToVm', () => { + it('should return empty employee when feeding null value', () => { + // Arrange + const employee = null; + const projects = null; - // Act - const result = mapEmployeeFromApiToVm(employee, projects); + // 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; - const projects = undefined; + it('should return empty employee when feeding undefined value', () => { + // Arrange + const employee = undefined; + const projects = undefined; - // Act - const result = mapEmployeeFromApiToVm(employee, projects); + // 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: [ + 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', - isAssigned: false, }, { id: '2', name: 'project test 2', - isAssigned: false, }, - ], - }; + ]; - // Act - const result = mapEmployeeFromApiToVm(employee, projects); + 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, + }, + ], + }; - // Assert - expect(result).toEqual(expectedResult); - }); + // Act + const result = mapEmployeeFromApiToVm(employee, projects); - 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: [ + // 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', - isAssigned: false, }, { id: '2', name: 'project test 2', - isAssigned: false, }, - ], - }; + ]; + + 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); + + // Assert + expect(result).toEqual(expectedResult); + }); + }); - const projects: apiModel.Project[] = [ - { + 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', - name: 'project test 1', - }, - { - id: '2', - name: 'project test 2', - }, - ]; - - // Act - const result = mapEmployeeFromApiToVm(employee, projects); - - // Assert - expect(result).toEqual(expectedResult); + 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: '1', + name: 'test name', isAssigned: true, }, { id: '2', + name: 'test name', 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: [ + const expectedResult: apiModel.EmployeeProject[] = [ { id: '1', isAssigned: true, - name: 'project test 1', }, { id: '2', isAssigned: false, - name: 'project test 2', }, - ], - }; + ]; - // Act - const result = mapEmployeeFromApiToVm(employee, projects); + // 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 abc4c55..2f7d128 100644 --- a/src/pods/employee/employee.mappers.ts +++ b/src/pods/employee/employee.mappers.ts @@ -37,13 +37,17 @@ export const mapEmployeeFromApiToVm = ( export const mapEmployeeFromVmToApi = ( employee: viewModel.Employee -): apiModel.Employee => ({ - id: employee.id, - name: employee.name, - email: employee.email, - isActive: employee.isActive, - temporalPassword: employee.temporalPassword, -}); +): 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 From 123e5b50cd693880595e94bfc5a8cb68642c14c7 Mon Sep 17 00:00:00 2001 From: Antonio Contreras LEMONCODE Date: Thu, 25 Jun 2020 13:02:56 +0200 Subject: [PATCH 16/19] Fix column name --- src/pods/employee/components/project.component.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pods/employee/components/project.component.tsx b/src/pods/employee/components/project.component.tsx index d8a5846..b9719d2 100644 --- a/src/pods/employee/components/project.component.tsx +++ b/src/pods/employee/components/project.component.tsx @@ -34,7 +34,7 @@ export const ProjectComponent: React.FunctionComponent = ({ return ( <> ) => ( From 22f6251a05cc8bfc6d2c29fc1f41c921d33cf309 Mon Sep 17 00:00:00 2001 From: Antonio Contreras LEMONCODE Date: Thu, 25 Jun 2020 13:08:59 +0200 Subject: [PATCH 17/19] Delete lastDateIncurred property from employee api --- src/pods/employee/api/employee.api.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pods/employee/api/employee.api.ts b/src/pods/employee/api/employee.api.ts index 3b521b3..91558b4 100644 --- a/src/pods/employee/api/employee.api.ts +++ b/src/pods/employee/api/employee.api.ts @@ -13,7 +13,6 @@ export const getEmployeeById = async (id: string): Promise => { name isActive email - lastDateIncurred projects { id isAssigned From a59b4defc905192d1afe4ae6817662406b1c3731 Mon Sep 17 00:00:00 2001 From: Antonio Contreras LEMONCODE Date: Thu, 25 Jun 2020 13:35:39 +0200 Subject: [PATCH 18/19] Remove Project view model interface --- src/pods/employee/employee.vm.ts | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/pods/employee/employee.vm.ts b/src/pods/employee/employee.vm.ts index 3fa7aac..f8229c6 100644 --- a/src/pods/employee/employee.vm.ts +++ b/src/pods/employee/employee.vm.ts @@ -13,12 +13,6 @@ export interface EmployeeProject { name: string; } -export interface Project { - id: string; - isAssigned?: boolean; - name: string; -} - export interface Report { month: string; year: string; From 5cf64f9c1e8c98ef4051545e34e0ef9e79af864c Mon Sep 17 00:00:00 2001 From: Antonio Contreras LEMONCODE Date: Mon, 29 Jun 2020 17:54:22 +0200 Subject: [PATCH 19/19] Fix project component --- src/pods/employee/components/project.component.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/pods/employee/components/project.component.tsx b/src/pods/employee/components/project.component.tsx index b9719d2..f9ac0bf 100644 --- a/src/pods/employee/components/project.component.tsx +++ b/src/pods/employee/components/project.component.tsx @@ -43,6 +43,8 @@ export const ProjectComponent: React.FunctionComponent = ({ onChangeProject={handleChangeProject(rowProps.row.id)} /> )} + enablePagination={true} + pageSize={5} />