Skip to content
This repository has been archived by the owner on Nov 8, 2018. It is now read-only.

Multiday events #197

Merged
merged 32 commits into from
Jul 25, 2016
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
9395e3c
New styles for date bubble
asavin Jul 13, 2016
5022309
Date bubble style update for single event page
asavin Jul 13, 2016
13f996d
Replacing events deprecated datetime with startDateTime
asavin Jul 13, 2016
7f2efc4
Date time component logic for displaying date ranges
asavin Jul 13, 2016
a7edbfb
Fixing tests for split events logic
asavin Jul 14, 2016
845a49b
Updating split events logic to accommodate multiday events. With tests.
asavin Jul 14, 2016
125733e
Events list now consumes updated split events logic and all is working
asavin Jul 14, 2016
c4c2dcd
Refactoring DateBubble component into an ES6 function
asavin Jul 15, 2016
6854a62
Refactoring EventsList component into ES6 function
asavin Jul 15, 2016
4921dd8
Refactoring events timeline title into a separate component
asavin Jul 15, 2016
79d780d
Refactoring event title into separate component, refactoring Date Bub…
asavin Jul 15, 2016
7351d54
Fixing karma test fail because of compose in css
asavin Jul 15, 2016
7fe089d
Refactoring DateBubble component so that date range is only displayed…
asavin Jul 19, 2016
69ef957
Refactoring event image path calculation, with tests
asavin Jul 19, 2016
fa49964
[fix] event image path resolving when filename is null
asavin Jul 19, 2016
c0b5025
Tests for EventsTimelineTitle component
asavin Jul 19, 2016
74a69ad
Fixing test for Karma on EventsTimelineTitle component
asavin Jul 19, 2016
8b2c1c3
Reverting proptype changes in events-list component in order to try a…
asavin Jul 19, 2016
27639a0
Disabling Karma tests for the whole project
asavin Jul 19, 2016
3f61db6
Revert "Reverting proptype changes in events-list component in order …
asavin Jul 19, 2016
3897ca8
Render test for EventsList component
asavin Jul 19, 2016
550b6b4
Tests for EventsTimelineTitle and EventsList components
asavin Jul 19, 2016
1e95e3e
Refactoring EventsList component WIP
asavin Jul 20, 2016
1183c19
Fix for error when start time is later than end time
asavin Jul 20, 2016
71d2841
Merge branch 'events-list-refactoring' into multiday-events
asavin Jul 20, 2016
3f863d2
Refactoring events-list component, fixing issues
asavin Jul 20, 2016
985e661
Refactoring date-bubble render logic into a function
asavin Jul 21, 2016
2ab654e
Refactoring event-meta and event-links-list components
asavin Jul 21, 2016
f543838
Fixing eslint no-else-return in components
asavin Jul 21, 2016
99702eb
Event container component now uses new event-meta component
asavin Jul 21, 2016
aa22624
Adding rendering tests for EventTitle, EventMeta and EventsList compo…
asavin Jul 25, 2016
a65d40b
Styles fix for event title component
asavin Jul 25, 2016
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions src/shared/components/event-meta/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import React, { PropTypes } from 'react';
import styles from './style.css';

import TagsList from '../tags-list';
import EventLinksList from '../event-links-list';

const EventMeta = ({
event,
}) => (
<div>
{
event.externalLinks || event.internalLinks ?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it make more sense to do this inside the child component?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah probably. There's also potential for refactoring in a way of only passing down elements of the event and not the whole event.

<div className={styles.eventLinks}>
{
event.externalLinks ?
<EventLinksList
linkList={event.externalLinks}
listType="external" />
: null
}
{
event.internalLinks ?
<EventLinksList
linkList={event.internalLinks}
listType="internal" />
: null
}
</div>
: null
}
{
event.tags
? <TagsList
tags={event.tags}
tagsLinkPath="about-us/events" />
: null
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that we need to update to React 15 in order to get that null returns working without warnings.

}
</div>
);

EventMeta.propTypes = {
event: PropTypes.object.isRequired,
};

export default EventMeta;
4 changes: 4 additions & 0 deletions src/shared/components/event-meta/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.eventLinks {
composes: cf from "../../components/utils/layout.css";
margin-bottom: 1em;
}
62 changes: 62 additions & 0 deletions src/shared/components/events-list-entry/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import React, { PropTypes } from 'react';
import styles from './style.css';
import EventImage from '../event-image';
import DateBubble from '../date-bubble';
import EventMeta from '../event-meta';
import EventTitle from '../event-title';
import HR from '../hr';
import { Grid, Cell } from '../grid';
import { setEndDate, eventImagePath } from '../../util/events';
import { eventHref } from '../../util/event';

const EventsListEntry = ({
event,
timeline,
}) => (
<li key={`event_${event.id}`} className={styles.eventItem}>
<Grid fit={false}>
<Cell size={12}>
<HR color="grey" customClassName=
{styles.mobileHorizontalLine} />
<DateBubble
startDateTime={event.startDateTime}
endDateTime={setEndDate(
timeline,
event.startDateTime,
event.endDateTime)}
/>
</Cell>
<Cell size={1} key="event_picture_mobile" hideOn="mobileSM">
<EventImage
imgPath={eventImagePath(event.featureImageFilename)}
href={eventHref(event)} />
</Cell>
<Cell size={12} breakOn="mobile">
<Grid fit={false}>
<Cell size={8} key='event_description'
breakOn="mobileS">
<EventTitle eventTitle={event.title}
eventHref={eventHref(event)} />
<div className={styles.eventDescription}>
{event.strapline}
</div>
<EventMeta event={event} />
</Cell>
<Cell size={4} key='event_picture' breakOn="mobileS"
hideOn="mobileS">
<EventImage
imgPath={eventImagePath(event.featureImageFilename)}
href={eventHref(event)} />
</Cell>
</Grid>
</Cell>
</Grid>
</li>
);

EventsListEntry.propTypes = {
event: PropTypes.object.isRequired,
timeline: PropTypes.oneOf(['past', 'future', 'today']).isRequired,
};

export default EventsListEntry;
15 changes: 15 additions & 0 deletions src/shared/components/events-list-entry/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
.eventItem {
position: relative;
list-style-type: none;
}

.mobileHorizontalLine {
display: block;
margin: 1.5em 0 0 0;
}

.eventDescription {
margin-top: 10px;
float: left;
}

85 changes: 8 additions & 77 deletions src/shared/components/events-list/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,9 @@

import React, { PropTypes } from 'react';
import styles from './style.css';

import EventImage from '../event-image';
import DateBubble from '../date-bubble';
import HR from '../hr';
import { Grid, Cell } from '../grid';

import TagsList from '../tags-list';
import EventLinksList from '../event-links-list';
import EventsTimelineTitle from '../events-timeline-title';
import EventTitle from '../event-title';
import { eventHref } from '../../util/event';
import { splitEvents, setEndDate, eventImagePath } from '../../util/events';
import EventsListEntry from '../events-list-entry';
import { splitEvents } from '../../util/events';

const EventsList = ({
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lots of new logic in this component, but no new tests. Do the existing ones cover the new paths?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Turned out this component has no tests at all. Adding tests.

events,
Expand All @@ -37,79 +28,19 @@ const EventsList = ({
<ul className={styles.eventsList}>
{
relevantEvents.map((event) => (
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is quite a complex component. Could simplify it further here to have a child '<RelevantEvent ... />' etc. I think more complex tests are needed to ensure that all the ? checks achieve the desired result - seems easy to break

<li key={`event_${event.id}`} className={styles.eventItem}>
<Grid fit={false}>
<Cell size={12}>
<HR color="grey" customClassName=
{styles.mobileHorizontalLine} />
<DateBubble
startDateTime={event.startDateTime}
endDateTime={setEndDate(
timeline,
event.startDateTime,
event.endDateTime)}
/>
</Cell>
<Cell size={1} key="event_picture_mobile" hideOn="mobileSM">
<EventImage
imgPath={eventImagePath(event.featureImageFilename)}
href={eventHref(event)} />
</Cell>
<Cell size={12} breakOn="mobile">
<Grid fit={false}>
<Cell size={8} key='event_description'
breakOn="mobileS">
<EventTitle eventTitle={event.title}
eventHref={eventHref(event)} />
<div className={styles.eventDescription}>
{event.strapline}
</div>
{
event.externalLinks || event.internalLinks ?
<div className={styles.eventLinks}>
{
event.externalLinks ?
<EventLinksList
linkList={event.externalLinks}
listType="external" />
: null
}
{
event.internalLinks ?
<EventLinksList
linkList={event.internalLinks}
listType="internal" />
: null
}
</div>
: null
}
{
event.tags
? <TagsList
tags={event.tags}
tagsLinkPath="about-us/events" />
: null
}
</Cell>
<Cell size={4} key='event_picture' breakOn="mobileS"
hideOn="mobileS">
<EventImage
imgPath={eventImagePath(event.featureImageFilename)}
href={eventHref(event)} />
</Cell>
</Grid>
</Cell>
</Grid>
</li>
<EventsListEntry
event={event}
timeline={timeline}
key={`key_${event.id}`}
/>
))
}
</ul>
</div>
);
}

return null;
return (<noscript />);
};

EventsList.propTypes = {
Expand Down
2 changes: 1 addition & 1 deletion src/shared/components/events-list/index.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,6 @@ describe('EventsList component', () => {
defaultEvent,
]}
/>);
expect(wrapper.find('li').length).to.equal(1);
expect(wrapper.find('ul').length).to.equal(1);
});
});
20 changes: 0 additions & 20 deletions src/shared/components/events-list/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -20,31 +20,11 @@
padding-left: 0;
}

.eventItem {
position: relative;
list-style-type: none;
}

.arrow {
color: red;
padding-left: 5px;
}

.eventDescription {
margin-top: 10px;
float: left;
}

.eventLinks {
composes: cf from "../../components/utils/layout.css";
margin-bottom: 1em;
}

.mobileHorizontalLine {
display: block;
margin: 1.5em 0 0 0;
}

@media mobile {
.eventsList {
padding: 0;
Expand Down
5 changes: 3 additions & 2 deletions src/shared/util/events.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@ export function splitEvents({
const endDateTime = dateFns.parse(event.endDateTime.iso);

// In a rare case of user error we omit this event from the output list
if (!dateFns.isSameDay(startDateTime, endDateTime) &&
!dateFns.isBefore(startDateTime, endDateTime)) {
if ((!dateFns.isSameDay(startDateTime, endDateTime) &&
!dateFns.isBefore(startDateTime, endDateTime)) ||
dateFns.differenceInMinutes(endDateTime, startDateTime) < 0) {
return false;
}

Expand Down
33 changes: 33 additions & 0 deletions src/shared/util/events.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ let testEventsSingleDay = [];
let testEventsMultiDay = [];
let testEventsMultiDayInProgress = [];
let testErrorMultiDay = [];
let testEventsSingleDayWrongStartEndTime = [];
let currentDate;

describe('Set end date', () => {
Expand Down Expand Up @@ -217,8 +218,29 @@ describe('SplitEvents', () => {
},
},
];

testEventsSingleDayWrongStartEndTime = [
{
id: 'earlier-event',
startDateTime: {
iso: earlierToday,
},
endDateTime: {
iso: laterToday,
},
},
{
id: 'later-today-event',
startDateTime: {
iso: laterToday,
},
endDateTime: {
iso: earlierToday,
},
}];
});


afterEach(() => {
MockDate.reset();
});
Expand Down Expand Up @@ -330,5 +352,16 @@ describe('SplitEvents', () => {
expect(returnedEvents[0].id).to.equal('future-event-2');
expect(returnedEvents[1].id).to.equal('future-event-1');
});

it('omits event from the result if end time is earlier than start time', () => {
const timeline = 'today';
const returnedEvents = splitEvents({
events: testEventsSingleDayWrongStartEndTime,
timeline,
todayDateTime: currentDate,
});
expect(returnedEvents.length).to.equal(1);
expect(returnedEvents[0].id).to.equal('earlier-event');
});
});
});