From bd743fed05c4b9651a39b6bdfbcac29e099962d8 Mon Sep 17 00:00:00 2001 From: LBSantos <118561969+lucasbuenoencora@users.noreply.github.com> Date: Wed, 1 Feb 2023 11:01:47 -0300 Subject: [PATCH] feat: existents seedlot (#35) * feat: create existing seedlot table * feat: added new components and unit tests * minor adjustments in layout --- .../components/ExistingSeedlot.test.tsx | 15 ++++ src/__test__/components/Participants.test.tsx | 44 ++++++++++++ src/__test__/components/SeedlotTable.test.tsx | 51 +++++++++++++ src/components/ExistingSeedlot/index.tsx | 53 ++++++++++++++ src/components/ExistingSeedlot/styles.scss | 51 +++++++++++++ src/components/Participants/index.tsx | 28 ++++++++ src/components/Participants/styles.css | 20 ++++++ src/components/SeedlotTable/index.tsx | 72 +++++++++++++++++++ src/components/SeedlotTable/styles.css | 10 +++ src/components/StatusItem/index.tsx | 3 + src/enums/ActivityStatus.ts | 3 +- src/mock-data/ExistingSeedlotItems.ts | 70 ++++++++++++++++++ src/theme/components-overrides.scss | 8 +++ src/types/Seedlot.ts | 13 ++++ src/views/SeedlotDashboard/index.tsx | 7 +- 15 files changed, 442 insertions(+), 6 deletions(-) create mode 100644 src/__test__/components/ExistingSeedlot.test.tsx create mode 100644 src/__test__/components/Participants.test.tsx create mode 100644 src/__test__/components/SeedlotTable.test.tsx create mode 100644 src/components/ExistingSeedlot/index.tsx create mode 100644 src/components/ExistingSeedlot/styles.scss create mode 100644 src/components/Participants/index.tsx create mode 100644 src/components/Participants/styles.css create mode 100644 src/components/SeedlotTable/index.tsx create mode 100644 src/components/SeedlotTable/styles.css create mode 100644 src/mock-data/ExistingSeedlotItems.ts create mode 100644 src/types/Seedlot.ts diff --git a/src/__test__/components/ExistingSeedlot.test.tsx b/src/__test__/components/ExistingSeedlot.test.tsx new file mode 100644 index 000000000..96cba78ac --- /dev/null +++ b/src/__test__/components/ExistingSeedlot.test.tsx @@ -0,0 +1,15 @@ +/* eslint-disable no-undef */ +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import ExistingSeedlot from '../../components/ExistingSeedlot'; +import '@testing-library/jest-dom'; + +//TODO test Empty Section +describe('Existing Seedlot component', () => { + it('should render title and subtitle correctly', () => { + render(); + + expect(screen.getByRole('heading', { level: 3 }).textContent).toEqual('Existing seedlot'); + expect(screen.getByText('Check a summary of your recent seedlots')).toBeInTheDocument(); + }); +}); diff --git a/src/__test__/components/Participants.test.tsx b/src/__test__/components/Participants.test.tsx new file mode 100644 index 000000000..247d01a8f --- /dev/null +++ b/src/__test__/components/Participants.test.tsx @@ -0,0 +1,44 @@ +/* eslint-disable no-undef */ +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import Participants from '../../components/Participants'; +import '@testing-library/jest-dom'; + +describe('Participants component', () => { + const number = 12456; + it('should render 3 participants correctly', () => { + const elements = ['Participant 1', 'Participant 2', 'Participant 3']; + render(); + + const images = screen.getAllByRole('img'); + expect(images).toHaveLength(3); + expect(images[0]).toBeInTheDocument(); + expect(images[0]).toHaveAttribute('alt', 'Participant 1'); + expect(images[1]).toBeInTheDocument(); + expect(images[1]).toHaveAttribute('alt', 'Participant 2'); + expect(images[2]).toBeInTheDocument(); + expect(images[2]).toHaveAttribute('alt', 'Participant 3'); + }); + + it('should render 2 participants correctly', () => { + const elements = ['Participant 1', 'Participant 2']; + render(); + + const images = screen.getAllByRole('img'); + expect(images).toHaveLength(2); + expect(images[0]).toBeInTheDocument(); + expect(images[0]).toHaveAttribute('alt', 'Participant 1'); + expect(images[1]).toBeInTheDocument(); + expect(images[1]).toHaveAttribute('alt', 'Participant 2'); + }); + + it('should render 1 participant correctly', () => { + const elements = ['Participant 1']; + render(); + + const images = screen.getAllByRole('img'); + expect(images).toHaveLength(1); + expect(images[0]).toBeInTheDocument(); + expect(images[0]).toHaveAttribute('alt', 'Participant 1'); + }); +}); diff --git a/src/__test__/components/SeedlotTable.test.tsx b/src/__test__/components/SeedlotTable.test.tsx new file mode 100644 index 000000000..3fdbb58df --- /dev/null +++ b/src/__test__/components/SeedlotTable.test.tsx @@ -0,0 +1,51 @@ +/* eslint-disable no-undef */ +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import SeedlotTable from '../../components/SeedlotTable'; +import ExistingSeedlotItems from '../../mock-data/ExistingSeedlotItems'; +import '@testing-library/jest-dom'; + +describe('Seedlot Table component', () => { + const listItems = ExistingSeedlotItems; + const tableHeaders: string[] = [ + 'Seedlot number', + 'Lot class', + 'Lot species', + 'Form step', + 'Status', + 'Participants', + 'Created at', + 'Last modified', + 'Approved at' + ]; + + beforeEach(() => { + render( + + ); + }); + + it('should render headers correctly', () => { + const headers = screen.getAllByRole('columnheader'); + expect(headers).toHaveLength(tableHeaders.length); + headers.forEach((th, idx) => { + expect(th.textContent).toEqual(tableHeaders[idx]); + }); + }); + + it('should render columns correctly', () => { + const cells = screen.getAllByRole('cell'); + expect(cells[0].textContent).toEqual('12456'); + expect(cells[1].textContent).toEqual('A class'); + expect(cells[2].textContent).toEqual('SX - Spruce hibrid'); + expect(cells[3].textContent).toEqual('Collection'); + expect(cells[4].textContent).toEqual('Incomplete'); + expect(cells[5]).toBeInTheDocument; + expect(cells[6].textContent).toEqual('October 10, 2021'); + expect(cells[7].textContent).toEqual('December 24, 2022'); + expect(cells[8].textContent).toEqual('--'); + }); +}); diff --git a/src/components/ExistingSeedlot/index.tsx b/src/components/ExistingSeedlot/index.tsx new file mode 100644 index 000000000..76149d392 --- /dev/null +++ b/src/components/ExistingSeedlot/index.tsx @@ -0,0 +1,53 @@ +import React from 'react'; + +import { Row, Column } from '@carbon/react'; + +import SeedlotTable from '../SeedlotTable'; +import EmptySection from '../EmptySection'; +import Subtitle from '../Subtitle'; + +import ExistingSeedlotItems from '../../mock-data/ExistingSeedlotItems'; + +import './styles.scss'; + +const ExistingSeedlot = () => { + const listItems = ExistingSeedlotItems; + + const tableHeaders: string[] = [ + 'Seedlot number', + 'Lot class', + 'Lot species', + 'Form step', + 'Status', + 'Participants', + 'Created at', + 'Last modified', + 'Approved at' + ]; + + return ( + + +

Existing seedlot

+ +
+ + + {(listItems.length === 0) && ( +
+ +
+ )} +
+
+ ); +}; + +export default ExistingSeedlot; diff --git a/src/components/ExistingSeedlot/styles.scss b/src/components/ExistingSeedlot/styles.scss new file mode 100644 index 000000000..5d2849a56 --- /dev/null +++ b/src/components/ExistingSeedlot/styles.scss @@ -0,0 +1,51 @@ +@use '../../theme/variables.scss' as vars; +@use '../../theme/colors.scss' as colors; + +h4.existing-seedlot-subtitle { + padding-bottom: 1rem; +} + +.existing-seedlot { + background-color: colors.$white !important; + margin-left: 2rem; + margin-right: 2rem; + border: 1px solid colors.$gray-20; + border-radius: 4px; +} + +.seedlot-table { + padding: 0 !important; +} + +table.#{vars.$bcgov-prefix}--data-table th, +table.#{vars.$bcgov-prefix}--data-table td { + padding-left: 2rem; +} + +.existing-seedlot-title { + padding-left: 2rem; +} + +.existing-seedlot-table { + padding: 0 !important; +} + +.empty-existing-seedlot { + margin: 3.44rem 0; +} + +@media only screen and (max-width: 1584px) { + .existing-seedlot-title { + padding-left: 3rem; + } +} + +@media only screen and (max-width: 672px) { + .existing-seedlot-title { + padding-left: 2rem; + } + + .existing-seedlot { + overflow-x: scroll; + } +} diff --git a/src/components/Participants/index.tsx b/src/components/Participants/index.tsx new file mode 100644 index 000000000..9938985aa --- /dev/null +++ b/src/components/Participants/index.tsx @@ -0,0 +1,28 @@ +import React from 'react'; + +import AvatarImage from '../AvatarImage'; + +import './styles.css'; + +interface ParticipantsProps { + elements: string[]; + number: number; +} + +const Participants = ({ elements, number }: ParticipantsProps) => ( +
+ {elements.map((participant, pidx) => ( +
+ +
+ ))} +
+); + +export default Participants; diff --git a/src/components/Participants/styles.css b/src/components/Participants/styles.css new file mode 100644 index 000000000..32cac9916 --- /dev/null +++ b/src/components/Participants/styles.css @@ -0,0 +1,20 @@ +.participants { + display: inline-flex; +} + +.img-participant1 { + position: relative; + z-index: 1; +} + +.img-participant2 { + position: relative; + z-index: 2; + right: 0.2rem; +} + +.img-participant3 { + position: relative; + z-index: 3; + right: 0.4rem; +} diff --git a/src/components/SeedlotTable/index.tsx b/src/components/SeedlotTable/index.tsx new file mode 100644 index 000000000..f80b3ff54 --- /dev/null +++ b/src/components/SeedlotTable/index.tsx @@ -0,0 +1,72 @@ +import React from 'react'; +import { hashObject } from 'react-hash-string'; + +import { + Table, + TableHead, + TableHeader, + TableRow, + TableBody, + TableCell +} from '@carbon/react'; + +import Participants from '../Participants'; +import StatusItem from '../StatusItem'; + +import Seedlot from '../../types/Seedlot'; + +import './styles.css'; + +interface TableProps { + elements: Seedlot[]; + headers: string[]; +} + +const SeedlotTable = ({ elements, headers }: TableProps) => { + const formatDate = (date: string) => { + if (typeof date !== 'undefined' && date) { + const options: Intl.DateTimeFormatOptions = { year: 'numeric', month: 'long', day: 'numeric' }; + return new Date(`${date}T00:00:00-08:00`).toLocaleDateString([], options); + } + return '--'; + }; + + return ( + + + + {headers.map((header, idx) => ( + + {header} + + ))} + + + + {elements.map((item, idx) => ( + + {item.number} + {`${item.class} class`} + {item.lot_species} + {item.form_step} + + + + + + + {formatDate(item.created_at)} + {formatDate(item.last_modified)} + {formatDate(item.approved_at)} + + ))} + +
+ ); +}; + +export default SeedlotTable; diff --git a/src/components/SeedlotTable/styles.css b/src/components/SeedlotTable/styles.css new file mode 100644 index 000000000..64731c9fa --- /dev/null +++ b/src/components/SeedlotTable/styles.css @@ -0,0 +1,10 @@ +a { + color: inherit; + text-decoration: inherit +} + +@media only screen and (max-width: 672px) { + .seedlot-table { + width: 56.25rem; + } +} diff --git a/src/components/StatusItem/index.tsx b/src/components/StatusItem/index.tsx index 338dbdfcd..4d74e1e4e 100644 --- a/src/components/StatusItem/index.tsx +++ b/src/components/StatusItem/index.tsx @@ -14,6 +14,9 @@ const statusClass = (param: number) => { case 3: // Canceled return 'magenta'; + case 4: + // Incomplete + return 'purple'; default: // Pending return 'gray'; diff --git a/src/enums/ActivityStatus.ts b/src/enums/ActivityStatus.ts index bbcd961e5..a1da71b9d 100644 --- a/src/enums/ActivityStatus.ts +++ b/src/enums/ActivityStatus.ts @@ -2,7 +2,8 @@ const ACTIVITY_STATUS = { PENDING: 'Pending', IN_PROGRESS: 'In progress', APPROVED: 'Approved', - CANCELED: 'Canceled' + CANCELED: 'Canceled', + INCOMPLETE: 'Incomplete' }; export default ACTIVITY_STATUS; diff --git a/src/mock-data/ExistingSeedlotItems.ts b/src/mock-data/ExistingSeedlotItems.ts new file mode 100644 index 000000000..9cfa0523e --- /dev/null +++ b/src/mock-data/ExistingSeedlotItems.ts @@ -0,0 +1,70 @@ +const ExistingSeedlotItems = [ + { + number: 12456, + class: 'A', + lot_species: 'SX - Spruce hibrid', + form_step: 'Collection', + status: 4, + participants: ['Participant 1', 'Participant 2', 'Participant 3'], + created_at: '2021-10-10', + last_modified: '2022-12-24', + approved_at: '' + }, + { + number: 12457, + class: 'A', + lot_species: 'SX - Spruce hibrid', + form_step: 'Collection', + status: 4, + participants: ['Participant 1', 'Participant 2', 'Participant 3'], + created_at: '2021-10-10', + last_modified: '2022-12-24', + approved_at: '' + }, + { + number: 12458, + class: 'A', + lot_species: 'SX - Spruce hibrid', + form_step: 'Collection', + status: 4, + participants: ['Participant 1', 'Participant 2', 'Participant 3'], + created_at: '2021-10-10', + last_modified: '2022-12-24', + approved_at: '' + }, + { + number: 12459, + class: 'A', + lot_species: 'SX - Spruce hibrid', + form_step: 'Collection', + status: 0, + participants: ['Participant 1', 'Participant 2', 'Participant 3'], + created_at: '2021-10-10', + last_modified: '2022-12-24', + approved_at: '' + }, + { + number: 12460, + class: 'A', + lot_species: 'SX - Spruce hibrid', + form_step: 'Collection', + status: 0, + participants: ['Participant 1', 'Participant 2', 'Participant 3'], + created_at: '2021-10-10', + last_modified: '2022-12-24', + approved_at: '' + }, + { + number: 12461, + class: 'A', + lot_species: 'SX - Spruce hibrid', + form_step: 'Collection', + status: 0, + participants: ['Participant 1', 'Participant 2', 'Participant 3'], + created_at: '2021-10-10', + last_modified: '2022-12-24', + approved_at: '2022-12-25' + } +]; + +export default ExistingSeedlotItems; diff --git a/src/theme/components-overrides.scss b/src/theme/components-overrides.scss index b2182a1ea..badd391a7 100644 --- a/src/theme/components-overrides.scss +++ b/src/theme/components-overrides.scss @@ -150,6 +150,14 @@ padding: 0 !important; } +.#{variables.$bcgov-prefix}--data-table tr th{ + background-color: var(--#{variables.$bcgov-prefix}-layer-01); +} + +.#{variables.$bcgov-prefix}--data-table tr td{ + background-color: var(--#{variables.$bcgov-prefix}-layer-02); +} + .#{variables.$bcgov-prefix}--table-header-label { font-weight: bold; } diff --git a/src/types/Seedlot.ts b/src/types/Seedlot.ts new file mode 100644 index 000000000..be27cb80a --- /dev/null +++ b/src/types/Seedlot.ts @@ -0,0 +1,13 @@ +type Seedlot = { + number: number; + class: string; + lot_species: string; + form_step: string; + status: number; + participants: string[]; + created_at: string; + last_modified: string; + approved_at: string; +} + +export default Seedlot; diff --git a/src/views/SeedlotDashboard/index.tsx b/src/views/SeedlotDashboard/index.tsx index 55d7815a3..7be23de1d 100644 --- a/src/views/SeedlotDashboard/index.tsx +++ b/src/views/SeedlotDashboard/index.tsx @@ -7,6 +7,7 @@ import { } from '@carbon/react'; import PageTitle from '../../components/PageTitle'; +import ExistingSeedlot from '../../components/ExistingSeedlot'; import './styles.css'; @@ -42,11 +43,7 @@ const SeedlotDashboard = () => ( - - - Exisisting Seedlot Placeholder - - + );