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 all 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
1 change: 0 additions & 1 deletion circle.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ test:
- npm run lint
- npm run security:check
- npm run test:server
- npm run test:client -- --browsers PhantomJS
- export APP_HOST=`ifconfig eth0 | grep -oP 'inet addr:\K\S+'` && COMPOSE_FILE=docker-compose-test.yml docker-compose up -d
- npm run test:e2e

Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@
"security:check": "./node_modules/.bin/nsp check",
"start": "node build/server",
"test": "npm run test:server && npm run security:check",
"test-full": "npm run test:server && npm run test:client && npm run security:check && npm run lint && npm run test:e2e",
"test:client": "karma start spec/karma.config.js",
"test-full": "npm run test:server && npm run security:check && npm run lint && npm run test:e2e",
"test:e2e": "wdio spec/wdio.config.js",
"test:server": "mocha --compilers js:babel-core/register --require spec/mocha-helper.js --recursive --reporter spec $(find src -name *spec.js)"
},
Expand Down Expand Up @@ -76,6 +75,7 @@
"chai": "^3.5.0",
"css-loader": "^0.23.1",
"css-modules-require-hook": "^2.1.0",
"enzyme": "^2.4.1",
"eslint": "^2.12.0",
"eslint-config-airbnb": "^9.0.1",
"eslint-plugin-import": "^1.8.1",
Expand Down
9 changes: 8 additions & 1 deletion spec/fixtures/events.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,20 @@ export const defaultEvent = {
url: 'http://www.frontendlondon.co.uk/'
},
],
datetime: {
startDateTime: {
iso: '2016-06-25T11:00:00+0000',
date: '25',
month: '06',
monthSym: 'Jun',
year: '2016',
},
endDateTime: {
iso: '2016-06-28T11:00:00+0000',
date: '28',
month: '06',
monthSym: 'Jun',
year: '2016',
},
body: [
{
type: 'paragraph',
Expand Down
11 changes: 9 additions & 2 deletions src/server/api/controllers/events.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,14 @@ const allEventFields = `
title
url
}
datetime {
startDateTime {
iso
date
month
monthSym
year
}
endDateTime {
iso
date
month
Expand Down Expand Up @@ -77,7 +84,7 @@ export default class EventsController {
.then((response) => response.json())
.then((events) => {
res.send({ list: events.data.allEvents.sort((a, b) =>
Copy link
Contributor

Choose a reason for hiding this comment

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

Perhaps we could use our pathOr(['...]), that we have used in badger brain to access these nested object keys. Just thinking of a scenario where someone changes the query and doesn't actually query for the startDateTime but yet we try access the .iso key

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think that's a bit of premature optimization - this is a client and it knows what it just requested

Copy link
Contributor Author

Choose a reason for hiding this comment

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

oh you mean in case startDateTime is null? Maybe.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah. Basically whenever I see a.b.c.d.e these days I want to use pathOr

Copy link
Contributor

Choose a reason for hiding this comment

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

Totally should be built in :)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm putting this one on hold for now - at the moment if startDateTime is missing, the whole site will explode. We should handle this in a clever way, probably on BB level.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This should be addressed as part of a separate PR.

new Date(b.datetime.iso) - new Date(a.datetime.iso)
new Date(b.startDateTime.iso) - new Date(a.startDateTime.iso)
) });
})
.catch((err) => {
Expand Down
51 changes: 30 additions & 21 deletions src/shared/components/date-bubble/index.js
Original file line number Diff line number Diff line change
@@ -1,28 +1,37 @@
// Displays date bubble

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

export default class DateBubble extends Component {
static propTypes = {
date: React.PropTypes.string,
month: React.PropTypes.string,
year: React.PropTypes.string,
};

render() {
function displayDateContent(startDateTime, endDateTime) {
if (endDateTime) {
return (
<div className={styles.dateBubble}>
<div className={styles.date}>
{this.props.date}
</div>
<div className={styles.month}>
{this.props.month}
</div>
<div className={styles.year}>
{this.props.year}
</div>
</div>
);
`${startDateTime.date} ${startDateTime.monthSym} ${startDateTime.year} - `
+ `${endDateTime.date} ${endDateTime.monthSym} ${endDateTime.year}`);
}
return (
`${startDateTime.date} ${startDateTime.monthSym} ${startDateTime.year}`);
}

const DateBubble = ({
startDateTime,
endDateTime,
}) => (
<div className={styles.dateBubble}>
{displayDateContent(startDateTime, endDateTime)}
</div>
);


const dateShape = {
date: PropTypes.string.isRequired,
monthSym: PropTypes.string.isRequired,
year: PropTypes.string.isRequired,
};

DateBubble.propTypes = {
startDateTime: PropTypes.shape(dateShape).isRequired,
endDateTime: PropTypes.shape(dateShape),
Copy link
Contributor

Choose a reason for hiding this comment

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

These look required to me?

Copy link
Contributor

Choose a reason for hiding this comment

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

endDate not required too?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not anymore - if not provided DateBubble will use this as indication that date range should not be displayed at all

};

export default DateBubble;
33 changes: 8 additions & 25 deletions src/shared/components/date-bubble/style.css
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
@value mobile from "../variables/breakpoints.css";
@value red from "../variables/colors.css";

.dateBubble {
background: #be1414;
display: inline-block;
font-size: 0.8em;
color: #fff;
font-size: 0.9em;
font-weight: bold;
color: red;
text-align: center;
text-transform: uppercase;
min-width: 3em;
margin-bottom: 1em;
padding: 0.3em 0;
-moz-border-radius: 5px;
-webkit-border-radius: 5px;
border-radius: 5px;
Expand All @@ -18,27 +17,11 @@
}

.date {
font-size: 2em;
font-size: 0.9em;
line-height: 1.2em;
}

.month {
}

.year {
}

@media mobile {
.dateBubble {
padding: 0.3em;
}

.date, .month, .year {
display: inline-block;
margin: 0 2px;
}

.date {
font-size: 1em;
}
.date, .month, .year {
display: inline-block;
margin: 0 2px;
}
76 changes: 40 additions & 36 deletions src/shared/components/event-links-list/index.js
Original file line number Diff line number Diff line change
@@ -1,47 +1,51 @@
// Displays list of links related to the event

import React, { Component } from 'react';
import React, { PropTypes } from 'react';

import classNames from 'classnames';
import layout from '../utils/layout.css';
import icons from '../icons/style.css';
import styles from './style.css';

export default class EventLinksList extends Component {
static propTypes = {
linkList: React.PropTypes.arrayOf(React.PropTypes.object).isRequired,
listType: React.PropTypes.oneOf(['external', 'internal']).isRequired,
};
const EventLinksList = ({
linkList,
listType,
}) => {
if (linkList.length === 0) return (<noscript />);
return (
<div className={classNames({
[styles.eventLinkList]: true,
[layout.cf]: true,
})}>
{
linkList.map(eventLink => (
<a
className={styles.fullDetailsLink}
href={eventLink.url}
key={eventLink.url}
target={listType === 'external' ? '_blank' : null}
>
<span>{eventLink.title}</span>
<span className={classNames({
[icons.sketchExternalLink]: listType === 'external',
[icons.sketchArrowRight]: listType === 'internal',
[styles.externalLinkIcon]: true,
})}
/>
</a>
))
}
</div>
);
};

render() {
if (this.props.linkList.length === 0) return null;

const { listType } = this.props;
EventLinksList.propTypes = {
linkList: PropTypes.arrayOf(PropTypes.shape({
url: PropTypes.string,
title: PropTypes.string,
})).isRequired,
listType: React.PropTypes.oneOf(['external', 'internal']).isRequired,
};

return (
<div className={classNames({
[styles.eventLinkList]: true,
[layout.cf]: true,
})}>
{
this.props.linkList.map(eventLink => (
<a
className={styles.fullDetailsLink}
href={eventLink.url}
key={eventLink.url}
target={listType === 'external' ? '_blank' : null}
>
<span>{eventLink.title}</span>
<span className={classNames({
[icons.sketchExternalLink]: listType === 'external',
[icons.sketchArrowRight]: listType === 'internal',
[styles.externalLinkIcon]: true,
})}
/>
</a>
))
}
</div>
);
}
}
export default EventLinksList;
46 changes: 46 additions & 0 deletions src/shared/components/event-meta/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import React, { PropTypes } from 'react';
import styles from './style.css';

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

const EventMeta = ({
internalLinks,
externalLinks,
tags,
}) => {
if (internalLinks.length > 0 && externalLinks.length > 0) {
return (<div>
{
externalLinks || internalLinks ?
<div className={styles.eventLinks}>
<EventLinksList
linkList={externalLinks}
listType="external" />
<EventLinksList
linkList={internalLinks}
listType="internal" />
</div>
: <noscript />
}
{
tags
? <TagsList
tags={tags}
tagsLinkPath="about-us/events" />
: <noscript />
}
</div>
);
}

return (<noscript />);
};

EventMeta.propTypes = {
internalLinks: EventLinksList.propTypes.linkList,
externalLinks: EventLinksList.propTypes.linkList,
tags: PropTypes.arrayOf(PropTypes.string),
};

export default EventMeta;
16 changes: 16 additions & 0 deletions src/shared/components/event-meta/index.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import EventMeta from './index.js';
import React from 'react';
import { shallow } from 'enzyme';
import { expect } from 'chai';
import { defaultEvent } from '../../../../spec/fixtures/events.js';

describe('EventMeta component', () => {
it('renders successfully with default props', () => {
const wrapper = shallow(<EventMeta
internalLinks={defaultEvent.internalLinks}
externalLinks={defaultEvent.externalLinks}
tags={defaultEvent.tags}
/>);
expect(wrapper.find('div').length).to.equal(2);
});
});
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;
}
35 changes: 35 additions & 0 deletions src/shared/components/event-title/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import React, { PropTypes } from 'react';
Copy link
Contributor

Choose a reason for hiding this comment

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

Where is the test for this component? Check it renders at least.

import classNames from 'classnames';
import icons from '../icons/style.css';
import styles from './style.css';
import { h2 } from '../typography/style.css';

const EventTitle = ({
eventTitle,
eventHref,
}) => (
<a className={styles.eventTitleLink}
href={eventHref}>
<h2 className={classNames({
[styles.eventTitle]: true,
[h2]: true,
})}>
<span>
{eventTitle}
</span>
<span className={classNames(
{
[styles.arrow]: true,
[icons.sketchArrowRight]: true,
})}
/>
</h2>
</a>
);

EventTitle.propTypes = {
eventTitle: PropTypes.string.isRequired,
eventHref: PropTypes.string.isRequired,
};

export default EventTitle;
14 changes: 14 additions & 0 deletions src/shared/components/event-title/index.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import EventTitle from './index.js';
import React from 'react';
import { shallow } from 'enzyme';
import { expect } from 'chai';

describe('EventTitle component', () => {
it('renders successfully with default props', () => {
const wrapper = shallow(<EventTitle
eventTitle={'Event title'}
eventHref={'https://www.red-badger.com'}
/>);
expect(wrapper.find('h2').length).to.equal(1);
});
});
Loading