aboutsummaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorAkshit Kr Nagpal <akshitkrnagpal@gmail.com>2018-07-25 13:36:55 +0200
committerSaúl Ibarra Corretgé <s@saghul.net>2018-07-27 09:03:51 +0200
commit8156f6cd0786c9980da6546b3e38ad0c51e4cfbf (patch)
tree2ede6b65b02f769a8eaa77b46284a2bf87713b36 /app
parentd46c60e6884bd7346467184927a87df81a18ccb2 (diff)
Add recent-list
Diffstat (limited to 'app')
-rw-r--r--app/features/recent-list/components/RecentList.js122
-rw-r--r--app/features/recent-list/components/index.js1
-rw-r--r--app/features/recent-list/index.js4
-rw-r--r--app/features/recent-list/reducer.js89
-rw-r--r--app/features/recent-list/styled/ConferenceCard.js18
-rw-r--r--app/features/recent-list/styled/RecentListContainer.js9
-rw-r--r--app/features/recent-list/styled/TruncatedText.js8
-rw-r--r--app/features/recent-list/styled/index.js3
-rw-r--r--app/features/recent-list/types.js24
-rw-r--r--app/features/redux/reducers.js2
-rw-r--r--app/features/redux/store.js1
-rw-r--r--app/features/welcome/components/Welcome.js10
-rw-r--r--app/features/welcome/styled/Body.js12
-rw-r--r--app/features/welcome/styled/Header.js (renamed from app/features/welcome/styled/Content.js)2
-rw-r--r--app/features/welcome/styled/Wrapper.js (renamed from app/features/welcome/styled/WelcomeWrapper.js)3
-rw-r--r--app/features/welcome/styled/index.js5
16 files changed, 306 insertions, 7 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;
+};
diff --git a/app/features/redux/reducers.js b/app/features/redux/reducers.js
index 667b922..2f532e6 100644
--- a/app/features/redux/reducers.js
+++ b/app/features/redux/reducers.js
@@ -3,11 +3,13 @@
import { combineReducers } from 'redux';
import { reducer as navbarReducer } from '../navbar';
+import { reducer as recentListReducer } from '../recent-list';
import { reducer as routerReducer } from '../router';
import { reducer as settingsReducer } from '../settings';
export default combineReducers({
navbar: navbarReducer,
+ recentList: recentListReducer,
router: routerReducer,
settings: settingsReducer
});
diff --git a/app/features/redux/store.js b/app/features/redux/store.js
index 992e802..472cdbd 100644
--- a/app/features/redux/store.js
+++ b/app/features/redux/store.js
@@ -11,6 +11,7 @@ const persistConfig = {
key: 'root',
storage: createElectronStorage(),
whitelist: [
+ 'recentList',
'settings'
]
};
diff --git a/app/features/welcome/components/Welcome.js b/app/features/welcome/components/Welcome.js
index 648d0ef..519016d 100644
--- a/app/features/welcome/components/Welcome.js
+++ b/app/features/welcome/components/Welcome.js
@@ -11,9 +11,10 @@ import { connect } from 'react-redux';
import { push } from 'react-router-redux';
import { Navbar } from '../../navbar';
+import { RecentList } from '../../recent-list';
import { normalizeServerURL } from '../../utils';
-import { WelcomeWrapper as Wrapper, Content, Form } from '../styled';
+import { Body, Form, Header, Wrapper } from '../styled';
type Props = {
@@ -82,7 +83,7 @@ class Welcome extends Component<Props, State> {
<Page navigation = { <Navbar /> }>
<AtlasKitThemeProvider mode = 'light'>
<Wrapper>
- <Content>
+ <Header>
<Form onSubmit = { this._onFormSubmit }>
<FieldTextStateless
autoFocus = { true }
@@ -99,7 +100,10 @@ class Welcome extends Component<Props, State> {
type = 'button'>
GO
</Button>
- </Content>
+ </Header>
+ <Body>
+ <RecentList />
+ </Body>
</Wrapper>
</AtlasKitThemeProvider>
</Page>
diff --git a/app/features/welcome/styled/Body.js b/app/features/welcome/styled/Body.js
new file mode 100644
index 0000000..ad74e1c
--- /dev/null
+++ b/app/features/welcome/styled/Body.js
@@ -0,0 +1,12 @@
+// @flow
+
+import styled from 'styled-components';
+
+export default styled.div`
+ margin: 0 12.5%;
+ overflow: scroll;
+
+ ::-webkit-scrollbar {
+ display: none;
+ }
+`;
diff --git a/app/features/welcome/styled/Content.js b/app/features/welcome/styled/Header.js
index 33fcb67..e05f5d4 100644
--- a/app/features/welcome/styled/Content.js
+++ b/app/features/welcome/styled/Header.js
@@ -6,5 +6,5 @@ export default styled.div`
align-items: center;
display: flex;
margin: 0 auto;
- padding: 30px;
+ padding: 8em;
`;
diff --git a/app/features/welcome/styled/WelcomeWrapper.js b/app/features/welcome/styled/Wrapper.js
index 3fe50b7..5771c30 100644
--- a/app/features/welcome/styled/WelcomeWrapper.js
+++ b/app/features/welcome/styled/Wrapper.js
@@ -3,7 +3,8 @@
import styled from 'styled-components';
export default styled.div`
- background: linear-gradient(#165ecc,#44A5FF);
+ background: #1D69D4;
display: flex;
+ flex-direction: column;
height: 100vh;
`;
diff --git a/app/features/welcome/styled/index.js b/app/features/welcome/styled/index.js
index 6b132d9..191461c 100644
--- a/app/features/welcome/styled/index.js
+++ b/app/features/welcome/styled/index.js
@@ -1,3 +1,4 @@
-export { default as Content } from './Content';
+export { default as Body } from './Body';
export { default as Form } from './Form';
-export { default as WelcomeWrapper } from './WelcomeWrapper';
+export { default as Header } from './Header';
+export { default as Wrapper } from './Wrapper';