diff options
author | Akshit Kr Nagpal <akshitkrnagpal@gmail.com> | 2018-07-25 13:36:55 +0200 |
---|---|---|
committer | Saúl Ibarra Corretgé <s@saghul.net> | 2018-07-27 09:03:51 +0200 |
commit | 8156f6cd0786c9980da6546b3e38ad0c51e4cfbf (patch) | |
tree | 2ede6b65b02f769a8eaa77b46284a2bf87713b36 /app/features/recent-list | |
parent | d46c60e6884bd7346467184927a87df81a18ccb2 (diff) |
Add recent-list
Diffstat (limited to 'app/features/recent-list')
-rw-r--r-- | app/features/recent-list/components/RecentList.js | 122 | ||||
-rw-r--r-- | app/features/recent-list/components/index.js | 1 | ||||
-rw-r--r-- | app/features/recent-list/index.js | 4 | ||||
-rw-r--r-- | app/features/recent-list/reducer.js | 89 | ||||
-rw-r--r-- | app/features/recent-list/styled/ConferenceCard.js | 18 | ||||
-rw-r--r-- | app/features/recent-list/styled/RecentListContainer.js | 9 | ||||
-rw-r--r-- | app/features/recent-list/styled/TruncatedText.js | 8 | ||||
-rw-r--r-- | app/features/recent-list/styled/index.js | 3 | ||||
-rw-r--r-- | app/features/recent-list/types.js | 24 |
9 files changed, 278 insertions, 0 deletions
diff --git a/app/features/recent-list/components/RecentList.js b/app/features/recent-list/components/RecentList.js new file mode 100644 index 0000000..bc6819a --- /dev/null +++ b/app/features/recent-list/components/RecentList.js @@ -0,0 +1,122 @@ +// @flow + +import moment from 'moment'; +import React, { Component } from 'react'; +import { connect } from 'react-redux'; +import type { Dispatch } from 'redux'; +import { push } from 'react-router-redux'; + +import { ConferenceCard, RecentListContainer, TruncatedText } from '../styled'; +import type { RecentListItem } from '../types'; + +type Props = { + + /** + * Redux dispatch. + */ + dispatch: Dispatch<*>; + + /** + * Array of recent conferences. + */ + _recentList: Array<RecentListItem>; +}; + +/** + * Recent List Component. + */ +class RecentList extends Component<Props, *> { + /** + * Render function of component. + * + * @returns {ReactElement} + */ + render() { + return ( + <RecentListContainer> + { + this.props._recentList.map( + conference => this._renderRecentListEntry(conference) + ) + } + </RecentListContainer> + ); + } + + /** + * Creates a handler for navigatint to a conference. + * + * @param {RecentListItem} conference - Conference Details. + * @returns {void} + */ + _onNavigateToConference(conference: RecentListItem) { + return () => this.props.dispatch(push('/conference', conference)); + } + + /** + * Renders the conference card. + * + * @param {RecentListItem} conference - Conference Details. + * @returns {ReactElement} + */ + _renderRecentListEntry(conference: RecentListItem) { + return ( + <ConferenceCard + key = { conference.startTime } + onClick = { this._onNavigateToConference(conference) }> + <TruncatedText> + { conference.room } + </TruncatedText> + <TruncatedText> + { this._renderServerURL(conference.serverURL) } + </TruncatedText> + <TruncatedText> + { this._renderTimeAndDuration(conference) } + </TruncatedText> + </ConferenceCard> + ); + } + + /** + * Returns formatted Server URL. + * + * @param {string} serverURL - Server URL. + * @returns {string} - Formatted server URL. + */ + _renderServerURL(serverURL: string) { + // Strip protocol to make it cleaner. + return `${serverURL.replace('https://', '')}`; + + } + + /** + * Returns Date/Time and Duration of the conference in string format. + * + * @param {RecentListItem} conference - Conference Details. + * @returns {string} - Date/Time and Duration. + */ + _renderTimeAndDuration(conference: RecentListItem) { + const { startTime, endTime } = conference; + const start = moment(startTime); + const end = moment(endTime); + const duration = moment.duration(end.diff(start)).humanize(); + + return `${start.calendar()}, ${duration}`; + } +} + +/** + * Maps (parts of) the redux state to the React props. + * + * @param {Object} state - The redux state. + * @returns {{ + * _recentList: Array<RecentListItem> + * }} + */ +function _mapStateToProps(state: Object) { + return { + _recentList: state.recentList.recentList + }; +} + +export default connect(_mapStateToProps)(RecentList); diff --git a/app/features/recent-list/components/index.js b/app/features/recent-list/components/index.js new file mode 100644 index 0000000..03545a4 --- /dev/null +++ b/app/features/recent-list/components/index.js @@ -0,0 +1 @@ +export { default as RecentList } from './RecentList'; diff --git a/app/features/recent-list/index.js b/app/features/recent-list/index.js new file mode 100644 index 0000000..d04b4c3 --- /dev/null +++ b/app/features/recent-list/index.js @@ -0,0 +1,4 @@ +export * from './components'; +export * from './styled'; + +export { default as reducer } from './reducer'; diff --git a/app/features/recent-list/reducer.js b/app/features/recent-list/reducer.js new file mode 100644 index 0000000..13c15ac --- /dev/null +++ b/app/features/recent-list/reducer.js @@ -0,0 +1,89 @@ +// @flow + +import { CONFERENCE_ENDED, CONFERENCE_JOINED } from '../conference'; + +import type { RecentListItem } from './types'; + +type State = { + recentList: Array<RecentListItem>; +}; + +const DEFAULT_STATE = { + recentList: [] +}; + +/** + * Reduces redux actions for features/recent-list. + * + * @param {State} state - Current reduced redux state. + * @param {Object} action - Action which was dispatched. + * @returns {State} - Updated reduced redux state. + */ +export default (state: State = DEFAULT_STATE, action: Object) => { + switch (action.type) { + case CONFERENCE_ENDED: + return { + ...state, + recentList: + _updateEndtimeOfConference(state.recentList, action.conference) + }; + + case CONFERENCE_JOINED: + return { + ...state, + recentList: _insertConference(state.recentList, action.conference) + }; + + default: + return state; + } +}; + +/** + * Insert Conference details in the recent list array. + * + * @param {Array<RecentListItem>} recentList - Previous recent list array. + * @param {RecentListItem} newConference - Conference that has to be added + * to recent list. + * @returns {Array<RecentListItem>} - Updated recent list array. + */ +function _insertConference( + recentList: Array<RecentListItem>, + newConference: RecentListItem +) { + // Add start time to conference. + newConference.startTime = Date.now(); + + // Remove same conference. + const newRecentList = recentList.filter( + (conference: RecentListItem) => conference.room !== newConference.room + || conference.serverURL !== newConference.serverURL); + + // Add the conference at the beginning. + newRecentList.unshift(newConference); + + return newRecentList; +} + +/** + * Update the EndTime of the last conference. + * + * @param {Array<RecentListItem>} recentList - Previous recent list array. + * @param {RecentListItem} conference - Conference for which endtime has to + * be updated. + * @returns {Array<RecentListItem>} - Updated recent list array. + */ +function _updateEndtimeOfConference( + recentList: Array<RecentListItem>, + conference: RecentListItem +) { + for (const item of recentList) { + if (item.room === conference.room + && item.serverURL === conference.serverURL) { + item.endTime = Date.now(); + break; + } + } + + return recentList; +} diff --git a/app/features/recent-list/styled/ConferenceCard.js b/app/features/recent-list/styled/ConferenceCard.js new file mode 100644 index 0000000..fff3f75 --- /dev/null +++ b/app/features/recent-list/styled/ConferenceCard.js @@ -0,0 +1,18 @@ +// @flow + +import styled from 'styled-components'; + +export default styled.div` + background: #1754A9; + border-radius: 0.5em; + color: white; + display: flex; + flex-direction: column; + font-size: 0.9em; + margin: 0.5em; + padding: 1em; + + &:hover { + cursor: pointer; + } +`; diff --git a/app/features/recent-list/styled/RecentListContainer.js b/app/features/recent-list/styled/RecentListContainer.js new file mode 100644 index 0000000..b97ba86 --- /dev/null +++ b/app/features/recent-list/styled/RecentListContainer.js @@ -0,0 +1,9 @@ +// @flow + +import styled from 'styled-components'; + +export default styled.div` + display: grid; + grid-template-columns: repeat(3, 33.3%); + padding: 0.5em; +`; diff --git a/app/features/recent-list/styled/TruncatedText.js b/app/features/recent-list/styled/TruncatedText.js new file mode 100644 index 0000000..3a27ea7 --- /dev/null +++ b/app/features/recent-list/styled/TruncatedText.js @@ -0,0 +1,8 @@ +// @flow + +import styled from 'styled-components'; + +export default styled.span` + overflow: hidden; + text-overflow: ellipsis; +`; diff --git a/app/features/recent-list/styled/index.js b/app/features/recent-list/styled/index.js new file mode 100644 index 0000000..1affa12 --- /dev/null +++ b/app/features/recent-list/styled/index.js @@ -0,0 +1,3 @@ +export { default as ConferenceCard } from './ConferenceCard'; +export { default as RecentListContainer } from './RecentListContainer'; +export { default as TruncatedText } from './TruncatedText'; diff --git a/app/features/recent-list/types.js b/app/features/recent-list/types.js new file mode 100644 index 0000000..1fef7fd --- /dev/null +++ b/app/features/recent-list/types.js @@ -0,0 +1,24 @@ +// @flow + +export type RecentListItem = { + + /** + * Timestamp of ending time of conference. + */ + endTime: number; + + /** + * Conference Room Name. + */ + room: string; + + /** + * Conference Server URL. + */ + serverURL: string; + + /** + * Timestamp of starting time of conference. + */ + startTime: number; +}; |