Merge branch 'html5-new-userlist' into html-userlist

This commit is contained in:
gcampes 2016-05-31 08:37:14 -03:00
commit ce32ae5b20
17 changed files with 464 additions and 42 deletions

View File

@ -16,7 +16,7 @@ addLocaleData([...en, ...es, ...pt]);
// Safari sends us en-us instead of en-US
let locale = navigator.language.split('-');
locale = locale[1] ? `${locale[0]}-${locale[1].toUpperCase()}` : navigator.language;
// locale = 'pt-BR'; // Set a locale for testing
/* TODO: We should load the en first then merge with the en-US
(eg: load country translation then region) */
let messages = Locales[locale] || Locales['en'] || {};

View File

@ -116,3 +116,6 @@
.icon-bbb-audio-off:before {
content: "\e91c";
}
.rotate-quarter {
transform: rotate(-90deg);
}

View File

@ -28,7 +28,7 @@ eventEmitter.on('user_listening_only', function (arg) {
const handleVoiceEvent = function (arg) {
const meetingId = arg.payload.meeting_id;
const voiceUser = payload.user.voiceUser;
const voiceUser = arg.payload.user.voiceUser;
const voiceUserObj = {
web_userid: voiceUser.web_userid,
listen_only: arg.payload.listen_only,

View File

@ -141,8 +141,8 @@ eventEmitter.on('get_presentation_info_reply', function (arg) {
}
}
}
}
return arg.callback();
}
});

View File

@ -1,3 +1,7 @@
{
"app.home.greeting": "Welcome {name}! Your presentation will begin shortly..."
"app.home.greeting": "Welcome {name}! Your presentation will begin shortly...",
"app.userlist.participantsTitle": "Participants",
"app.userlist.messagesTitle": "Messages",
"app.userlist.presenter": "Presenter",
"app.userlist.you": "You"
}

View File

@ -1,3 +1,7 @@
{
"app.home.greeting": "Bem-vindo {name}! Sua aprensentação começará em breve..."
"app.home.greeting": "Bem-vindo {name}! Sua aprensentação começará em breve...",
"app.userlist.participantsTitle": "Participantes",
"app.userlist.messagesTitle": "Mensagens",
"app.userlist.presenter": "Apresentador",
"app.userlist.you": "Você"
}

View File

@ -4,10 +4,10 @@ import { Router, Route, Redirect, IndexRoute,
import { createHistory } from 'history';
// route components
import AppContainer from '../../ui/components/app/container';
import {setCredentials, subscribeForData} from '../../ui/components/app/service';
import UserListContainer from '../../ui/components/user-list/UserListContainer';
import ChatContainer from '../../ui/components/chat/ChatContainer';
import AppContainer from '../../ui/components/app/container.jsx';
import {setCredentials, subscribeForData} from '../../ui/components/app/service.js';
import UserListContainer from '../../ui/components/user-list/container.jsx';
import ChatContainer from '../../ui/components/chat/ChatContainer.jsx';
const browserHistory = useRouterHistory(createHistory)({
basename: '/html5client',

View File

@ -125,6 +125,7 @@ const handledMessageTypes = [
'presentation_shared_message',
'get_presentation_info_reply',
'presentation_page_changed_message',
'get_presentation_info_reply',
'presentation_removed_message',
'get_whiteboard_shapes_reply',
'send_whiteboard_shape_message',

View File

@ -96,6 +96,8 @@ $actionsbar-height: 50px; // TODO: Change to ActionsBar real height
.userList {
@extend %full-page;
z-index: 2;
background: green;
overflow: hidden;
@include mq($small-only) {
padding-top: $navbar-height;

View File

@ -1,24 +0,0 @@
import React, { Component } from 'react';
import styles from './styles.scss';
import { Link } from 'react-router';
export default class UserList extends Component {
render() {
return (
<div>
<ul>
<li><b>USER-LIST</b></li>
<li>
<Link to="/users/chat">Open Public chat</Link>
</li>
<li>
<Link to={`/users/chat/${'fred-dixon'}`}>Open Private Chat With Fred</Link>
</li>
<li>
<Link to={`/users/chat/${'tiago-jacobs'}`}>Open Private Chat With Tiago</Link>
</li>
</ul>
</div>
);
}
}

View File

@ -0,0 +1,23 @@
import React, { Component } from 'react';
import styles from '../styles.scss';
import { Link } from 'react-router';
import classNames from 'classnames';
export default class ChatListItem extends Component {
render() {
return (
<li tabIndex='0' className={styles.chatListItem}>
<div className={styles.chatThumbnail}>
<i className="icon-bbb-group-chat"></i>
</div>
<div className={styles.chatName}>
<h3 className={styles.chatNameMain}>Public Chat</h3>
</div>
<div className={styles.unreadMessages}>
<p className={styles.unreadMessagesText}>{Math.round(Math.random()*33)}</p>
</div>
</li>
);
}
}

View File

@ -0,0 +1,75 @@
import React, { Component } from 'react';
import styles from './styles.scss';
import { Link } from 'react-router';
import UserListItem from './user-list-item/component.jsx';
import ChatListItem from './chat-list-item/component.jsx';
import { FormattedMessage } from 'react-intl';
export default class UserList extends Component {
render() {
return (
<div className={styles.userList}>
{this.renderHeader()}
{this.renderContent()}
</div>
);
}
renderHeader() {
return (
<div className={styles.header}>
<h2 className={styles.headerTitle}>
<FormattedMessage
id="app.userlist.participantsTitle"
description="Title for the Header"
defaultMessage="Participants"
/>
</h2>
</div>
)
}
renderContent() {
return (
<div className={styles.content}>
{this.renderMessages()}
{this.renderParticipants()}
</div>
);
}
renderMessages() {
return (
<div className={styles.messages}>
<h3 className={styles.smallTitle}>
<FormattedMessage
id="app.userlist.messagesTitle"
description="Title of messages list"
defaultMessage="Messages"
/>
</h3>
<ul className={styles.chatsList} tabIndex="1">
<ChatListItem />
</ul>
</div>
)
}
renderParticipants() {
return (
<div className={styles.participants}>
<h3 className={styles.smallTitle}>
<FormattedMessage
id="app.userlist.participantsTitle"
description="Title for the Participants list"
defaultMessage="Participants"
/>
&nbsp;({this.props.users.length})
</h3>
<ul className={styles.participantsList} tabIndex="1">
{this.props.users.map(user => <UserListItem accessibilityLabel={'Status abc'} accessible={true} key={user.id} user={user}/>)}
</ul>
</div>
)
}
}

View File

@ -1,16 +1,15 @@
import React, { Component, PropTypes } from 'react';
import { createContainer } from 'meteor/react-meteor-data';
import Service from './service.js';
import UserList from './UserList';
import UserList from './component.jsx';
class UserListContainer extends Component {
constructor(props) {
super(props);
}
render() {
return (
<UserList {...this.props}>
<UserList
{...this.props}
users={this.props.users}>
{this.props.children}
</UserList>
);
@ -18,5 +17,6 @@ class UserListContainer extends Component {
}
export default createContainer(() => {
return {};
const data = Service.mapUsers();
return data;
}, UserListContainer);

View File

@ -0,0 +1,24 @@
import Users from '/imports/api/users';
import LocalStorage from '/imports/ui/services/storage';
let mapUsers = function() {
let currentUserID = LocalStorage.get('userID');
let users = Users.find().map(u => {
return {
id: u.user.userid,
name: u.user.name,
isPresenter: u.user.presenter,
isModerator: u.user.role === "MODERATOR",
isCurrent: u.user.userid === currentUserID,
isVoiceUser: u.user.voiceUser.joined,
isListenOnly: u.user.listenOnly,
isSharingWebcam: u.user.webcam_stream.length
};
});
return {
users: users
};
};
export default { mapUsers };

View File

@ -0,0 +1,201 @@
@import '../../stylesheets/variables/palette';
.flex-column {
display: flex;
flex-flow: column;
}
.zero-margin {
margin: 0;
}
.header {
@extend .flex-column;
justify-content: center;
min-height: 3rem;
flex-grow: 1;
}
.headerTitle {
font-size: 1rem;
margin-left: 30px;
}
.content {
@extend .flex-column;
flex-grow: 9;
}
.unreadMessages {
@extend .flex-column;
justify-content: center;
}
.unreadMessagesText {
@extend .flex-column;
@extend .zero-margin;
justify-content: center;
color: $color-white;
height: 1.3rem;
padding: 0 8px;
text-align: center;
border-radius: 0.5rem/50%;
font-size: 0.8rem;
background-color: $color-danger;
}
.userList {
@extend .flex-column;
justify-content: flex-start;
background-color: $color-white;
color: $color-gray-dark;
height: 100vh;
}
.lists {
@extend .flex-column;
@extend .zero-margin;
padding: 0;
}
.participantsList,
.chatsList {
@extend .lists;
}
.userListItem,
.chatListItem {
padding: 5px;
padding-left: 15px;
padding-right: 10px;
margin-left: 15px;
margin-top: 10px;
display: flex;
flex-flow: row;
cursor: pointer;
transition: all 0.3s;
border-top-left-radius: 5px;
border-bottom-left-radius: 5px;
&:hover,
&:focus {
background-color: darken($color-white, 7%);
}
&:first-child {
margin-top: 0px;
}
&:last-child {
margin-bottom: 20px;
}
}
.chatThumbnail {
@extend .flex-column;
justify-content: center;
flex-basis: 30px;
height: 30px;
font-size: 1.1rem;
}
.chatName {
@extend .flex-column;
flex-grow: 1;
justify-content: center;
}
.chatNameMain {
@extend .zero-margin;
font-size: 0.9rem;
}
.thumbnail {
@extend .flex-column;
flex-basis: 2rem;
height: 2rem;
justify-content: center;
font-size: 1.05rem;
text-align: center;
border-radius: 20px;
border: 2px solid $color-gray-light;
color: $color-gray-light;
}
.thumbnailContainer {
@extend .flex-column;
flex-basis: 2rem;
height: 2rem;
justify-content: center;
border-radius: 20px;
}
.voiceUser{
background-color: $color-success;
color: $color-white;
border: none;
}
.presenter {
border-radius: 2px;
}
.moderator {
border: none;
color: $color-white;
background-color: $color-primary;
}
.userName {
@extend .flex-column;
flex-grow: 1;
margin-left: 15px;
justify-content: center;
}
.userNameMain {
font-size: 0.9rem;
@extend .zero-margin;
}
.userNameSub {
@extend .zero-margin;
font-size: 0.8rem;
font-style: italic;
color: $color-gray-light;
}
.userIcons {
display: flex;
flex-flow: row;
justify-content: space-between;
text-align: right;
font-size: 1rem;
flex-basis: 4rem;
color: $color-gray-light;
}
.userIconsContainer {
@extend .flex-column;
text-align: center;
flex-basis: 1rem;
justify-content: center;
transition: 0.3s all;
&:hover,
&:focus {
color: $color-gray;
}
}
.smallTitle {
margin-bottom: 0;
color: $color-text;
font-size: 0.9rem;
text-transform: uppercase;
margin: 10px 30px;
margin-bottom: 10px;
}
.scrollable {
overflow: auto;
}

View File

@ -0,0 +1,94 @@
import React, { Component } from 'react';
import { FormattedMessage } from 'react-intl';
import styles from '../styles.scss';
import { Link } from 'react-router';
import classNames from 'classnames/bind';
let cx = classNames.bind(styles);
export default class ChatListItem extends Component {
render() {
return (
<li tabIndex='0' className={styles.userListItem}>
{this.renderThumbnail()}
{this.renderUserName()}
{this.renderUserIcons()}
</li>
);
}
renderThumbnail() {
let user = this.props.user;
let thumbnailClasses = {};
thumbnailClasses[styles.presenter] = user.isPresenter;
thumbnailClasses[styles.voiceUser] = user.isVoiceUser;
thumbnailClasses[styles.moderator] = user.isModerator;
thumbnailClasses[styles.image] = user.image;
return (
<div className={cx(thumbnailClasses, styles.thumbnail)}>
{user.name.slice(0, 1)}
</div>
)
}
renderUserName() {
let user = this.props.user;
let userNameSub = null;
if(user.isPresenter) {
userNameSub = (
<p className={styles.userNameSub}>
<FormattedMessage
id="app.userlist.presenter"
description="Title for the Header"
defaultMessage="Participants"
/>
</p>
);
} else if(user.isCurrent) {
userNameSub = (
<p className={styles.userNameSub}>
(<FormattedMessage
id="app.userlist.you"
description="Title for the Header"
defaultMessage="Participants"
/>)
</p>
);
}
return (
<div className={styles.userName}>
<h3 className={styles.userNameMain}>
{user.name}
</h3>
{userNameSub}
</div>
)
}
renderUserIcons() {
let user = this.props.user;
let audioChatIcons = null;
if (user.isVoiceUser || user.isListenOnly) {
audioChatIcons = user.isListenOnly ? <i className='icon-bbb-listen'></i> : <i className='icon-bbb-audio'></i>;
}
return (
<div className={styles.userIcons}>
<span className={styles.userIconsContainer}>
{user.isSharingWebcam ? <i className='icon-bbb-video'></i> : null}
</span>
<span className={styles.userIconsContainer}>
{audioChatIcons}
</span>
<span className={styles.userIconsContainer}>
<i className='icon-bbb-more rotate-quarter'></i>
</span>
</div>
)
}
}

View File

@ -0,0 +1,15 @@
const STORAGE = localStorage;
const PREFIX = 'bbb_';
function get(key) {
return STORAGE.getItem(key);
}
function set(key) {
STORAGE.setItem(key);
}
export default {
get,
set
}