diff --git a/packages/react-component-library/src/components/Timeline/Event.tsx b/packages/react-component-library/src/components/Timeline/Event.tsx index 30960bf384..b258dcf75c 100755 --- a/packages/react-component-library/src/components/Timeline/Event.tsx +++ b/packages/react-component-library/src/components/Timeline/Event.tsx @@ -6,17 +6,18 @@ import { DAY_WIDTH } from './constants' import { useTimelinePosition } from './hooks/useTimelinePosition' export interface EventProps extends ComponentWithClass { - startDate: Date + children?: string endDate: Date + startDate: Date status?: string - title?: string } export const Event: React.FC = ({ - startDate, + children, + className, endDate, + startDate, status = '', - title, }) => { const { offset, width, isBeforeStart, isAfterEnd } = useTimelinePosition( startDate, @@ -27,16 +28,17 @@ export const Event: React.FC = ({ const classes = classNames('timeline__event', { [`timeline__event--${status.toLowerCase()}`]: !!status, + className, }) return (
- {title || `Task ${format(new Date(startDate), 'dd/yyyy')}`} + {children || `Task ${format(new Date(startDate), 'dd/yyyy')}`}
+ | React.ReactElement[] +} + +export const Events: React.FC = (props) => { + return ( +
+ ) +} diff --git a/packages/react-component-library/src/components/Timeline/Row.tsx b/packages/react-component-library/src/components/Timeline/Row.tsx index 718a8ef547..f4cf231280 100755 --- a/packages/react-component-library/src/components/Timeline/Row.tsx +++ b/packages/react-component-library/src/components/Timeline/Row.tsx @@ -2,14 +2,14 @@ import React from 'react' import classNames from 'classnames' import { differenceInDays } from 'date-fns' +import { DAY_WIDTH } from './constants' +import { EventsProps } from '.' import { getKey, isOdd } from './helpers' import { TimelineContext } from './context' -import { TimelineEvent } from './context/types' -import { DAY_WIDTH } from './constants' -import { Event } from '.' export interface RowProps extends ComponentWithClass { - events: TimelineEvent[] + children: React.ReactElement | React.ReactElement[] + name: string } const RowWeeks: React.FC = () => { @@ -43,30 +43,12 @@ const RowWeeks: React.FC = () => { ) } -const RowEvents: React.FC = ({ events }) => { - return ( - <> - {events && - events.map(({ startDate, endDate, status, title }, index) => { - return ( - - ) - })} - - ) -} - -export const Row: React.FC = ({ events }) => { +export const Row: React.FC = ({ children, className }) => { + const classes = classNames('timeline__row', className) return ( -
+
- + {children}
) } diff --git a/packages/react-component-library/src/components/Timeline/Rows.tsx b/packages/react-component-library/src/components/Timeline/Rows.tsx new file mode 100644 index 0000000000..bd831b9d09 --- /dev/null +++ b/packages/react-component-library/src/components/Timeline/Rows.tsx @@ -0,0 +1,36 @@ +import React from 'react' +import classNames from 'classnames' + +import { RowProps } from '.' +import { getKey } from './helpers' +import { NO_DATA_MESSAGE } from './constants' + +export interface RowsProps extends ComponentWithClass { + children: React.ReactElement | React.ReactElement[] +} + +const noData = ( + + {NO_DATA_MESSAGE} + +) + +export const Rows: React.FC = ({ children, className }) => { + const classes = classNames('timeline__main', className) + const childrenWithKey = React.Children.map( + children, + (child: React.ReactElement, index: number) => + React.cloneElement(child, { + ...child.props, + key: getKey('timeline-row', index), + }) + ) + + return ( +
+ {childrenWithKey && childrenWithKey.length ? childrenWithKey : noData} +
+ ) +} + +Rows.displayName = 'Rows' diff --git a/packages/react-component-library/src/components/Timeline/Side.tsx b/packages/react-component-library/src/components/Timeline/Side.tsx index 8f924dfa87..d6c67d0729 100755 --- a/packages/react-component-library/src/components/Timeline/Side.tsx +++ b/packages/react-component-library/src/components/Timeline/Side.tsx @@ -5,12 +5,13 @@ import { Button } from '../Button' import { getKey } from './helpers' import { TimelineContext } from './context' import { TIMELINE_ACTIONS } from './context/types' +import { RowProps, RowsProps } from '.' export interface SideProps extends ComponentWithClass { - rowData?: any[] + children: React.ReactElement } -const SideList: React.FC = ({ rowData }) => { +const SideList: React.FC = ({ children }) => { return (
  1. @@ -19,23 +20,25 @@ const SideList: React.FC = ({ rowData }) => {
  2. Weeks
  3. - {rowData && - rowData.map(({ name }, index) => { + {React.Children.map( + children.props.children, + (child: React.ReactElement, index: number) => { return (
  4. - {name} + {child.props.name}
  5. ) - })} + } + )}
) } -export const Side: React.FC = ({ rowData }) => { +export const Side: React.FC = ({ children }) => { return ( {({ dispatch }) => { @@ -55,7 +58,7 @@ export const Side: React.FC = ({ rowData }) => { data-testid="side-button-right" />
- + {children} ) }} diff --git a/packages/react-component-library/src/components/Timeline/Timeline.stories.tsx b/packages/react-component-library/src/components/Timeline/Timeline.stories.tsx index 8882881494..0c61587294 100755 --- a/packages/react-component-library/src/components/Timeline/Timeline.stories.tsx +++ b/packages/react-component-library/src/components/Timeline/Timeline.stories.tsx @@ -1,29 +1,51 @@ import React from 'react' import { storiesOf } from '@storybook/react' -import { Timeline } from '.' +import { Timeline, Event, Events, Row, Rows } from '.' const stories = storiesOf('Timeline', module) -stories.add('No data', () => ) - -const rowData = [ - { - name: 'Example Row', - events: [ - { - title: 'Example Event', - startDate: new Date(2020, 3, 13), - endDate: new Date(2020, 3, 22), - }, - ], - }, -] +stories.add('No data', () => ( + + {} + +)) stories.add('With data', () => ( - + + + + + + Event 1 + + + Event 2 + + + + + + + Event 3 + + + Event 4 + + + + + )) diff --git a/packages/react-component-library/src/components/Timeline/Timeline.tsx b/packages/react-component-library/src/components/Timeline/Timeline.tsx index c65ea1c0fd..b3fe576f4f 100755 --- a/packages/react-component-library/src/components/Timeline/Timeline.tsx +++ b/packages/react-component-library/src/components/Timeline/Timeline.tsx @@ -1,28 +1,24 @@ import React from 'react' -import { getKey } from './helpers' import { TimelineProvider } from './context' - -import { NO_DATA_MESSAGE } from './constants' -import { Side, Row, TodayMarker, Months, Weeks } from '.' +import { Side, TodayMarker, Months, Weeks, RowProps } from '.' +import { RowsProps } from './Rows' export interface TimelineProps extends ComponentWithClass { - rowData: any[] + children: React.ReactElement startDate?: Date today?: Date } export const Timeline: React.FC = ({ - rowData, + children, startDate, today, }) => { - const isEmpty = !rowData || rowData.length === 0 - return (
- + {children}
@@ -30,18 +26,7 @@ export const Timeline: React.FC = ({
- {isEmpty && ( - - {NO_DATA_MESSAGE} - - )} - - {rowData && - rowData.map(({ events }, index) => { - return ( - - ) - })} + {children}
diff --git a/packages/react-component-library/src/components/Timeline/__tests__/Event.test.tsx b/packages/react-component-library/src/components/Timeline/__tests__/Event.test.tsx deleted file mode 100755 index ee7a930c5a..0000000000 --- a/packages/react-component-library/src/components/Timeline/__tests__/Event.test.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import React from 'react' -import '@testing-library/jest-dom/extend-expect' -import { render, RenderResult } from '@testing-library/react' - -import { TimelineProvider } from '../context' -import { Event } from '../Event' - -describe('Event', () => { - let wrapper: RenderResult - let status: string - let title: string - - describe('and the status and title props are provided', () => { - beforeEach(() => { - status = 'COMPLETED' - title = 'Example Title' - - wrapper = render( - - - - ) - }) - - it('applies the appropriate modifier class', () => { - expect(wrapper.getByTestId('event-wrapper').classList).toContain( - `timeline__event--${status.toLowerCase()}` - ) - }) - - it('renders the title element', () => { - expect(wrapper.queryByTestId('event-title')).toBeInTheDocument() - - expect(wrapper.getByTestId('event-title').innerHTML).toBe(title) - }) - }) -}) diff --git a/packages/react-component-library/src/components/Timeline/__tests__/Row.test.tsx b/packages/react-component-library/src/components/Timeline/__tests__/Row.test.tsx deleted file mode 100755 index 9186031b90..0000000000 --- a/packages/react-component-library/src/components/Timeline/__tests__/Row.test.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import React from 'react' -import '@testing-library/jest-dom/extend-expect' -import { render, RenderResult } from '@testing-library/react' - -import { TimelineProvider } from '../context' -import { Row } from '../Row' - -describe('Event', () => { - let wrapper: RenderResult - let events: any[] - - describe('provided with a collection of events', () => { - beforeEach(() => { - events = [ - { - // Within range (should render) - startDate: new Date(2020, 1, 1, 0, 0, 0), - endDate: new Date(2020, 1, 10, 0, 0, 0), - title: 'Example Event', - }, - { - // Outside range (should not render) - startDate: new Date(2020, 6, 1, 0, 0, 0), - endDate: new Date(2020, 6, 10, 0, 0, 0), - title: 'Example Event', - }, - ] - - wrapper = render( - - - - ) - }) - - it('renders the correct number of events', () => { - expect(wrapper.queryAllByTestId('event-wrapper').length).toEqual(1) - }) - }) -}) diff --git a/packages/react-component-library/src/components/Timeline/__tests__/Side.test.tsx b/packages/react-component-library/src/components/Timeline/__tests__/Side.test.tsx index 7509405390..754c479e1c 100755 --- a/packages/react-component-library/src/components/Timeline/__tests__/Side.test.tsx +++ b/packages/react-component-library/src/components/Timeline/__tests__/Side.test.tsx @@ -9,18 +9,20 @@ import { dispatchSpy } from '../context/__mocks__' import { TimelineProvider } from '../context' import { TIMELINE_ACTIONS } from '../context/types' +import { Event, Events, Row, Rows } from '..' jest.mock('../context') describe('Side', () => { let wrapper: RenderResult - let rowData: any[] describe('default props', () => { beforeEach(() => { wrapper = render( - + + {} + ) }) @@ -68,24 +70,44 @@ describe('Side', () => { describe('with rowData', () => { beforeEach(() => { - rowData = [ - { - name: 'Example Row', - events: [ - // - ], - }, - { - name: 'Example Row', - events: [ - // - ], - }, - ] - wrapper = render( - + + + + + + Event 1 + + + Event 2 + + + + + + + Event 3 + + + Event 4 + + + + + ) }) diff --git a/packages/react-component-library/src/components/Timeline/__tests__/Timeline.test.tsx b/packages/react-component-library/src/components/Timeline/__tests__/Timeline.test.tsx index 4227cc845c..07a1ecc098 100644 --- a/packages/react-component-library/src/components/Timeline/__tests__/Timeline.test.tsx +++ b/packages/react-component-library/src/components/Timeline/__tests__/Timeline.test.tsx @@ -2,49 +2,71 @@ import React from 'react' import '@testing-library/jest-dom/extend-expect' import { render, RenderResult } from '@testing-library/react' -import { TimelineProvider } from '../context' -import { Timeline } from '../Timeline' +import { Event, Events, Row, Rows, Timeline } from '..' + +const COMPLETED = 'COMPLETED' describe('Timeline', () => { let wrapper: RenderResult - let rowData: any[] - let startDate: Date describe('no data is provided', () => { beforeEach(() => { wrapper = render( - - - + + {} + ) }) - it('displays the no data message', () => { + it('should display the no data message', () => { expect(wrapper.queryByTestId('timeline-no-data')).toBeInTheDocument() }) + + it('should not display any rows', () => { + expect(wrapper.queryAllByTestId('row')).toHaveLength(0) + }) }) - describe('data is provided', () => { + describe('when data is provided', () => { beforeEach(() => { - startDate = new Date(2020, 3, 1) - - rowData = [ - { - name: 'Example Row', - events: [ - { - title: 'Example Event', - startDate: new Date(2020, 3, 10), - endDate: new Date(2020, 3, 16), - }, - ], - }, - ] - wrapper = render( - - - + + + + + + Event 1 + + + Event 2 + + + + + + + Event 3 + + + Event 4 + + + + + ) }) @@ -52,8 +74,68 @@ describe('Timeline', () => { expect(wrapper.queryByTestId('timeline-no-data')).not.toBeInTheDocument() }) - it('renders the event', () => { - expect(wrapper.queryByText('Example Event')).toBeInTheDocument() + it('should display 2 rows', () => { + expect(wrapper.queryAllByTestId('timeline-row')).toHaveLength(2) + expect(wrapper.getByText('Row 1')).toBeInTheDocument() + expect(wrapper.getByText('Row 2')).toBeInTheDocument() + }) + + it('should display 4 events', () => { + expect(wrapper.queryAllByTestId('timeline-event-wrapper')).toHaveLength(4) + expect(wrapper.getByText('Event 1')).toBeInTheDocument() + expect(wrapper.getByText('Event 2')).toBeInTheDocument() + expect(wrapper.getByText('Event 3')).toBeInTheDocument() + expect(wrapper.getByText('Event 4')).toBeInTheDocument() + }) + + it('should give the first event the correct modifier class based on status', () => { + expect( + wrapper.getAllByTestId('timeline-event-wrapper')[0].classList + ).toContain(`timeline__event--${COMPLETED.toLowerCase()}`) + }) + }) + + describe('when an event is outside the range', () => { + beforeEach(() => { + console.log('starting') + + const EventWithinRange: React.FC = () => ( + + Event 1 + + ) + + const EventOutsideRange: React.FC = () => ( + + Event 1 + + ) + + wrapper = render( + + + + + + + + + + + ) + + }) + + it('renders the correct number of events', () => { + expect(wrapper.queryAllByTestId('timeline-event-wrapper')).toHaveLength(1) }) }) }) diff --git a/packages/react-component-library/src/components/Timeline/index.ts b/packages/react-component-library/src/components/Timeline/index.ts index 3e50b61ab3..07ba724eb7 100755 --- a/packages/react-component-library/src/components/Timeline/index.ts +++ b/packages/react-component-library/src/components/Timeline/index.ts @@ -1,7 +1,9 @@ export * from './context' export * from './Event' +export * from './Events' export * from './Months' export * from './Row' +export * from './Rows' export * from './Side' export * from './Timeline' export * from './TodayMarker'