Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Videodebate users / viewers live presence count #76

Merged
merged 1 commit into from
Jan 30, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
6 changes: 6 additions & 0 deletions app/assets/assets/locales/en/videoDebate.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,5 +67,11 @@
"firstStatement": "Now <1>add your first statement</1> by clicking on the <3></3> icon next to the speaker's name",
"firstSpeaker": "Start by adding a speaker using left column",
"noContentUnauthenticated": "This video hasn't been verified yet. Login / Signup to contribute!"
},
"presence": {
"viewer": "{{count}} viewer",
"viewer_plural": "{{count}} viewers",
"user": "{{count}} fact-checker",
"user_plural": "{{count}} fact-checkers"
}
}
6 changes: 6 additions & 0 deletions app/assets/assets/locales/fr/videoDebate.json
Original file line number Diff line number Diff line change
Expand Up @@ -70,5 +70,11 @@
"firstStatement": "Maintenant <1>ajoutez votre première citation</1> en cliquant sur l'icone <3></3> à côté du nom de l'intervenant",
"firstSpeaker": "Commencez par ajouter un intervenant en utilisant la colonne de gauche",
"noContentUnauthenticated": "Cette vidéo n'a pas encore été vérifiée. Connectez-vous pour contribuer!"
},
"presence": {
"viewer": "{{count}} spectateur",
"viewer_plural": "{{count}} spectateurs",
"user": "{{count}} fact-checker",
"user_plural": "{{count}} fact-checkers"
}
}
10 changes: 9 additions & 1 deletion app/components/VideoDebate/ColumnVideo.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,23 @@ import React from "react"
import { connect } from "react-redux"
import classNames from "classnames"
import { translate } from 'react-i18next'
import { videoDebateOnlineUsersCount, videoDebateOnlineViewersCount } from '../../state/video_debate/presence/selectors'

import { AddSpeakerForm, SpeakerPreview } from "../Speakers"
import Tag from '../Utils/Tag'
import { VideoPlayer } from "../Videos"
import { LoadingFrame, Icon } from "../Utils"
import { Link } from 'react-router'
import { isAuthenticated } from "../../state/users/current_user/selectors"
import Presence from './Presence'


@connect(state => ({
video: state.VideoDebate.video.data,
isLoading: state.VideoDebate.video.isLoading,
authenticated: isAuthenticated(state),
nbUsers: videoDebateOnlineUsersCount(state),
nbViewers: videoDebateOnlineViewersCount(state),
}))
@translate('videoDebate')
export class ColumnVideo extends React.PureComponent {
Expand All @@ -26,7 +31,10 @@ export class ColumnVideo extends React.PureComponent {
return (
<div id="col-video" className="column is-5">
<VideoPlayer url={url}/>
<h2 className="title is-4">{title}</h2>
<div className="videoInfo">
<h2 className="title is-4">{title}</h2>
<Presence nbUsers={this.props.nbUsers} nbViewers={this.props.nbViewers}/>
</div>
<div className="tabs is-toggle is-fullwidth">
<ul>
<li className={classNames({'is-active': view === "debate"})}>
Expand Down
26 changes: 26 additions & 0 deletions app/components/VideoDebate/Presence.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { translate } from 'react-i18next'

import { Icon } from '../Utils'
import Tag from '../Utils/Tag'


const Presence = ({t, nbUsers, nbViewers}) =>
<div className="presence">
<Tag size="medium" type="danger">
<Icon size="small" name="group"/>
<span>{t('presence.user', {count: nbUsers})}</span>
</Tag>
<Tag size="medium" type="success">
<Icon size="small" name="eye"/>
<span>{t('presence.viewer', {count: nbViewers})}</span>
</Tag>
</div>

Presence.propTypes = {
nbUsers: PropTypes.number.isRequired,
nbViewers: PropTypes.number.isRequired,
}

export default translate('videoDebate')(Presence)
3 changes: 3 additions & 0 deletions app/state/video_debate/effects.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { SocketApi } from '../../API'
import { VIDEO_DEBATE_CHANNEL } from "../../constants"
import { presenceDiff, setPresence } from './presence/reducer'
import * as videoReducer from './video/reducer'
import { errorToFlash, errorMsgToFlash } from '../flashes/reducer'
import { createEffect, generateFSAError } from '../utils'
Expand All @@ -13,6 +14,8 @@ export const joinVideoDebateChannel = videoId => dispatch => {
"speaker_added": s => dispatch(videoReducer.addSpeaker(s)),
"speaker_removed": s => dispatch(videoReducer.removeSpeaker(s)),
"speaker_updated": s => dispatch(videoReducer.updateSpeaker(s)),
"presence_state": s => dispatch(setPresence(s)),
"presence_diff": s => dispatch(presenceDiff(s)),
}
)))
}
Expand Down
23 changes: 23 additions & 0 deletions app/state/video_debate/presence/reducer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { handleActions, createAction } from 'redux-actions'
import { Record } from 'immutable'


export const setPresence = createAction("PRESENCE/SET")
export const presenceDiff = createAction("PRESENCE/DIFF")


const INITIAL_STATE = new Record({
viewers: new Record({count: 0})(),
users: new Record({count: 0})(),
})
const PresenceReducer = handleActions({
[setPresence]: (state, {payload}) => state.merge(payload),
[presenceDiff]: (state, {payload: {leaves, joins}}) => {
return state.withMutations(record => record
.updateIn(['viewers', 'count'], x => x + joins.viewers.count - leaves.viewers.count)
.updateIn(['users', 'count'], x => x + joins.users.count - leaves.users.count)
)
}
}, INITIAL_STATE())

export default PresenceReducer
14 changes: 14 additions & 0 deletions app/state/video_debate/presence/selectors.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { createSelector } from 'reselect'


export const videoDebatePresence = state => state.VideoDebate.presence

export const videoDebateOnlineUsersCount = createSelector(
videoDebatePresence,
presence => presence.users.count
)

export const videoDebateOnlineViewersCount = createSelector(
videoDebatePresence,
presence => presence.viewers.count
)
2 changes: 2 additions & 0 deletions app/state/video_debate/reducer.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { combineReducers } from "redux"
import PresenceReducer from './presence/reducer'

import VideoReducer from './video/reducer'
import CommentsReducer from './comments/reducer'
import StatementsReducer from './statements/reducer'


const VideoDebateReducer = combineReducers({
presence: PresenceReducer,
video: VideoReducer,
statements: StatementsReducer,
comments: CommentsReducer
Expand Down
8 changes: 8 additions & 0 deletions app/styles/_components/VideoDebate/presence.sass
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.presence
.tag
margin: 0.125em
border-radius: 0.2em
font-size: 0.8em
float: right
.icon
margin-right: 0.25em
15 changes: 11 additions & 4 deletions app/styles/_components/VideoDebate/video_debate.sass
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,17 @@
+tablet
min-width: 370px

&> .title
padding: 18px 7px
border-bottom: 1px solid #f1f1f1
margin-bottom: 0
.videoInfo
display: flex
padding: 1em
align-items: center
.title
flex-grow: 10
flex-shrink: 1
margin: 0 0.5em 0 0
.presence
display: inline-block
flex-shrink: 10000

&> .tabs
margin-bottom: 0
Expand Down
2 changes: 1 addition & 1 deletion app/styles/_components/comments.sass
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ $max-comment-width: 600px
width: 50%
flex-direction: column
justify-content: flex-start
background: transparentize($primary-neutral, 0.96)
background: $white-bis
flex-basis: 400px
+mobile
flex-basis: 300px
Expand Down
1 change: 1 addition & 0 deletions app/styles/application.sass
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@
@import "_components/VideoDebate/action_bubble_menu"
@import "_components/VideoDebate/video_debate"
@import "_components/VideoDebate/history"
@import "_components/VideoDebate/presence"
@import "_components/VideoDebate/speaker_preview"
@import "_components/Speakers/speaker_page"
@import "_components/Speakers/speaker_preview"
Expand Down