Skip to content

Commit

Permalink
feat: existents seedlot (#35)
Browse files Browse the repository at this point in the history
* feat: create existing seedlot table

* feat: added new components and unit tests

* minor adjustments in layout
  • Loading branch information
lucasbuenoencora authored and DerekRoberts committed May 14, 2024
1 parent eba1ebf commit bd743fe
Show file tree
Hide file tree
Showing 15 changed files with 442 additions and 6 deletions.
15 changes: 15 additions & 0 deletions src/__test__/components/ExistingSeedlot.test.tsx
Original file line number Diff line number Diff line change
@@ -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(<ExistingSeedlot />);

expect(screen.getByRole('heading', { level: 3 }).textContent).toEqual('Existing seedlot');
expect(screen.getByText('Check a summary of your recent seedlots')).toBeInTheDocument();
});
});
44 changes: 44 additions & 0 deletions src/__test__/components/Participants.test.tsx
Original file line number Diff line number Diff line change
@@ -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(<Participants elements={elements} number={number} />);

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(<Participants elements={elements} number={number} />);

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(<Participants elements={elements} number={number} />);

const images = screen.getAllByRole('img');
expect(images).toHaveLength(1);
expect(images[0]).toBeInTheDocument();
expect(images[0]).toHaveAttribute('alt', 'Participant 1');
});
});
51 changes: 51 additions & 0 deletions src/__test__/components/SeedlotTable.test.tsx
Original file line number Diff line number Diff line change
@@ -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(
<SeedlotTable
elements={listItems}
headers={tableHeaders}
/>
);
});

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('--');
});
});
53 changes: 53 additions & 0 deletions src/components/ExistingSeedlot/index.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<Row className="existing-seedlot">
<Column sm={4} className="existing-seedlot-title">
<h3>Existing seedlot</h3>
<Subtitle text="Check a summary of your recent seedlots" className="existing-seedlot-subtitle" />
</Column>
<Column sm={4} className="existing-seedlot-table">
<SeedlotTable
elements={listItems}
headers={tableHeaders}
/>
{(listItems.length === 0) && (
<div className="empty-existing-seedlot">
<EmptySection
icon="Application"
title="There is no seedlot to show yet!"
description="Your recent seedlots will appear here once you generate one"
/>
</div>
)}
</Column>
</Row>
);
};

export default ExistingSeedlot;
51 changes: 51 additions & 0 deletions src/components/ExistingSeedlot/styles.scss
Original file line number Diff line number Diff line change
@@ -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;
}
}
28 changes: 28 additions & 0 deletions src/components/Participants/index.tsx
Original file line number Diff line number Diff line change
@@ -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) => (
<div className="participants">
{elements.map((participant, pidx) => (
<div
key={`${number} ${participant}`}
className={`img-participant${pidx + 1}`}
>
<AvatarImage
userName={participant}
size="small"
/>
</div>
))}
</div>
);

export default Participants;
20 changes: 20 additions & 0 deletions src/components/Participants/styles.css
Original file line number Diff line number Diff line change
@@ -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;
}
72 changes: 72 additions & 0 deletions src/components/SeedlotTable/index.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<Table size="lg" useZebraStyles={false} className="seedlot-table">
<TableHead>
<TableRow>
{headers.map((header, idx) => (
<TableHeader
key={header}
id={`header-${header}-${idx}`}
data-testid={`header-${header}-${idx}`}
>
{header}
</TableHeader>
))}
</TableRow>
</TableHead>
<TableBody>
{elements.map((item, idx) => (
<TableRow key={hashObject(item)} id={`row${idx}`}>
<TableCell>{item.number}</TableCell>
<TableCell>{`${item.class} class`}</TableCell>
<TableCell>{item.lot_species}</TableCell>
<TableCell>{item.form_step}</TableCell>
<TableCell>
<StatusItem status={item.status} />
</TableCell>
<TableCell>
<Participants elements={item.participants} number={item.number} />
</TableCell>
<TableCell>{formatDate(item.created_at)}</TableCell>
<TableCell>{formatDate(item.last_modified)}</TableCell>
<TableCell>{formatDate(item.approved_at)}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
);
};

export default SeedlotTable;
10 changes: 10 additions & 0 deletions src/components/SeedlotTable/styles.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
a {
color: inherit;
text-decoration: inherit
}

@media only screen and (max-width: 672px) {
.seedlot-table {
width: 56.25rem;
}
}
3 changes: 3 additions & 0 deletions src/components/StatusItem/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ const statusClass = (param: number) => {
case 3:
// Canceled
return 'magenta';
case 4:
// Incomplete
return 'purple';
default:
// Pending
return 'gray';
Expand Down
3 changes: 2 additions & 1 deletion src/enums/ActivityStatus.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Loading

0 comments on commit bd743fe

Please sign in to comment.