diff --git a/bigbluebutton-html5/imports/api/common/server/helpers.js b/bigbluebutton-html5/imports/api/common/server/helpers.js index 2cbf139a3e..22897e07d6 100755 --- a/bigbluebutton-html5/imports/api/common/server/helpers.js +++ b/bigbluebutton-html5/imports/api/common/server/helpers.js @@ -4,7 +4,7 @@ import { clearShapesCollection } from '/imports/api/shapes/server/modifiers/clea import { clearSlidesCollection } from '/imports/api/slides/server/modifiers/clearSlidesCollection'; import { clearPresentationsCollection } from '/imports/api/presentations/server/modifiers/clearPresentationsCollection'; -import { clearMeetingsCollection} +import { clearMeetingsCollection } from '/imports/api/meetings/server/modifiers/clearMeetingsCollection'; import { clearPollCollection } from '/imports/api/polls/server/modifiers/clearPollCollection'; import { clearCursorCollection } from '/imports/api/cursor/server/modifiers/clearCursorCollection'; @@ -23,6 +23,16 @@ export function appendMessageHeader(eventName, messageObj) { export function clearCollections() { console.log('in function clearCollections'); + + /* + This is to prevent collection clearing in development environment when the server + refreshes. Related to: https://github.com/meteor/meteor/issues/6576 + */ + + if (process.env.NODE_ENV === "development") { + return; + } + clearUsersCollection(); clearChatCollection(); clearMeetingsCollection(); diff --git a/bigbluebutton-html5/imports/startup/client/routes.js b/bigbluebutton-html5/imports/startup/client/routes.js index bd685f9ad9..db74455a07 100755 --- a/bigbluebutton-html5/imports/startup/client/routes.js +++ b/bigbluebutton-html5/imports/startup/client/routes.js @@ -1,14 +1,14 @@ import React from 'react'; -import { Router, Route, Redirect, IndexRoute, - IndexRedirect, useRouterHistory } from 'react-router'; +import { Router, Route, Redirect, IndexRoute, useRouterHistory } from 'react-router'; import { createHistory } from 'history'; // route components -import AppContainer from '../../ui/components/app/container'; -import {setCredentials, subscribeForData} from '../../ui/components/app/service'; +import AppContainer from '/imports/ui/components/app/container'; +import { subscribeToCollections, setCredentials } from '/imports/ui/components/app/service'; -import ChatContainer from '../../ui/components/chat/container'; -import UserListContainer from '../../ui/components/user-list/container'; +import ChatContainer from '/imports/ui/components/chat/container'; +import UserListContainer from '/imports/ui/components/user-list/container'; +import Loader from '/imports/ui/components/loader/component'; const browserHistory = useRouterHistory(createHistory)({ basename: '/html5client', @@ -16,22 +16,30 @@ const browserHistory = useRouterHistory(createHistory)({ export const renderRoutes = () => ( - - - - + + { + subscribeToCollections() + }} + getComponent={(nextState, cb) => { + subscribeToCollections(() => cb(null, AppContainer)); + }}> + - { + subscribeToCollections(() => cb(null, { userList: UserListContainer, - }} /> + })); + }} /> - { + subscribeToCollections(() => cb(null, { userList: UserListContainer, chat: ChatContainer, - }} /> - - - + })); + }} /> + + + ); diff --git a/bigbluebutton-html5/imports/ui/components/actions-bar/component.jsx b/bigbluebutton-html5/imports/ui/components/actions-bar/component.jsx index 623306db37..fe7146a0c5 100644 --- a/bigbluebutton-html5/imports/ui/components/actions-bar/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/actions-bar/component.jsx @@ -1,5 +1,8 @@ import React, { Component, PropTypes } from 'react'; import styles from './styles.scss'; +import Chats from '/imports/api/chat'; + +import ChatsService from '/imports/ui/components/chat/service'; import Button from '../button/component'; @@ -9,7 +12,20 @@ export default class ActionsBar extends Component { } handleClick() { - console.log('dummy handler'); + const SYSTEM_CHAT_TYPE = 'SYSTEM_MESSAGE'; + const PUBLIC_CHAT_TYPE = 'PUBLIC_CHAT'; + const PRIVATE_CHAT_TYPE = 'PRIVATE_CHAT'; + + console.log(Chats.find({ + 'message.chat_type': { $in: [PUBLIC_CHAT_TYPE, SYSTEM_CHAT_TYPE] }, + }, { + sort: ['message.from_time'], + }) + .fetch()); + } + + handleClick2() { + console.log(ChatsService.getPublicMessages()); } render() { @@ -35,7 +51,7 @@ export default class ActionsBar extends Component { circle={true} /> +
+
)} ); diff --git a/bigbluebutton-html5/imports/ui/components/user-list/chat-list-item/component.jsx b/bigbluebutton-html5/imports/ui/components/user-list/chat-list-item/component.jsx index 5934300358..76369a8f08 100755 --- a/bigbluebutton-html5/imports/ui/components/user-list/chat-list-item/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/user-list/chat-list-item/component.jsx @@ -12,6 +12,7 @@ const propTypes = { chat: React.PropTypes.shape({ id: React.PropTypes.string.isRequired, name: React.PropTypes.string.isRequired, + unreadCounter: React.PropTypes.number.isRequired, }).isRequired, }; @@ -26,10 +27,10 @@ class ChatListItem extends Component { } = this.props; const linkPath = [PRIVATE_CHAT_PATH, chat.id].join(''); - let fakeUnreadCount = Math.round(Math.random() * 33); let linkClasses = {}; linkClasses[styles.active] = chat.id === openChat; + return (
  • @@ -37,9 +38,11 @@ class ChatListItem extends Component {

    {chat.name}

    -
    -

    {fakeUnreadCount}

    -
    + {(chat.unreadCounter > 0) ? +
    +

    {chat.unreadCounter}

    +
    + : null}
  • ); diff --git a/bigbluebutton-html5/imports/ui/components/user-list/service.js b/bigbluebutton-html5/imports/ui/components/user-list/service.js index 059af8222e..21eef391c4 100644 --- a/bigbluebutton-html5/imports/ui/components/user-list/service.js +++ b/bigbluebutton-html5/imports/ui/components/user-list/service.js @@ -1,6 +1,7 @@ import Users from '/imports/api/users'; import Chat from '/imports/api/chat'; import Auth from '/imports/ui/services/auth'; +import UnreadMessages from '/imports/ui/services/unread-messages'; import { callServer } from '/imports/ui/services/api'; @@ -182,12 +183,17 @@ const getOpenChats = chatID => { openChats = Users .find({ 'user.userid': { $in: openChats } }) .map(u => u.user) - .map(mapUser); + .map(mapUser) + .map(op => { + op.unreadCounter = UnreadMessages.count(op.id); + return op; + }); openChats.push({ id: 'public', name: 'Public Chat', icon: 'group-chat', + unreadCounter: UnreadMessages.count('public_chat_userid'), }); return openChats diff --git a/bigbluebutton-html5/imports/ui/components/whiteboard/component.jsx b/bigbluebutton-html5/imports/ui/components/whiteboard/component.jsx index b0190362bd..b01dc3d0ae 100755 --- a/bigbluebutton-html5/imports/ui/components/whiteboard/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/whiteboard/component.jsx @@ -4,6 +4,7 @@ import { createContainer } from 'meteor/react-meteor-data'; import Slide from './slide/component.jsx'; import styles from './styles.scss'; import ReactCSSTransitionGroup from 'react-addons-css-transition-group'; +import PollingContainer from '/imports/ui/components/polling/container'; export default class Whiteboard extends React.Component { constructor(props) { @@ -36,7 +37,10 @@ export default class Whiteboard extends React.Component { @@ -69,8 +73,13 @@ export default class Whiteboard extends React.Component { render() { return ( -
    - {this.renderWhiteboard()} +
    +
    +
    + {this.renderWhiteboard()} +
    +
    +
    ); } diff --git a/bigbluebutton-html5/imports/ui/components/whiteboard/shapes/poll/component.jsx b/bigbluebutton-html5/imports/ui/components/whiteboard/shapes/poll/component.jsx index 025a3cbb1e..d5490c1e6d 100755 --- a/bigbluebutton-html5/imports/ui/components/whiteboard/shapes/poll/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/whiteboard/shapes/poll/component.jsx @@ -77,13 +77,13 @@ export default class PollDrawComponent extends React.Component { //counting the total number of votes, finding the biggest number of votes this.props.shape.result.reduce(function (previousValue, currentValue, currentIndex, array) { - votesTotal += currentValue.num_votes; + votesTotal = previousValue + currentValue.num_votes; if (maxNumVotes < currentValue.num_votes) { maxNumVotes = currentValue.num_votes; } return votesTotal; - }); + }, 0); //filling the textArray with data to display //adding value of the iterator to each line needed to create unique diff --git a/bigbluebutton-html5/imports/ui/components/whiteboard/slide/component.jsx b/bigbluebutton-html5/imports/ui/components/whiteboard/slide/component.jsx index 7fdf4f51a6..7df77561ce 100755 --- a/bigbluebutton-html5/imports/ui/components/whiteboard/slide/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/whiteboard/slide/component.jsx @@ -12,9 +12,9 @@ export default class Slide extends React.Component { + strokeWidth="0.8" + > : null } diff --git a/bigbluebutton-html5/imports/ui/components/whiteboard/styles.scss b/bigbluebutton-html5/imports/ui/components/whiteboard/styles.scss index f8306530f0..b720efc78b 100755 --- a/bigbluebutton-html5/imports/ui/components/whiteboard/styles.scss +++ b/bigbluebutton-html5/imports/ui/components/whiteboard/styles.scss @@ -32,3 +32,18 @@ max-width: 100%; max-height: 100%; } + +.whiteboardContainer { + display: flex; + flex-direction: column; + height: 100%; + width: 100%; +} + +.whiteboardWrapper { + order: 1; + width: 100%; + height: 100%; + display: block; + position: relative; +} diff --git a/bigbluebutton-html5/imports/ui/services/unread-messages/index.js b/bigbluebutton-html5/imports/ui/services/unread-messages/index.js index af5393eac2..65461aefb1 100644 --- a/bigbluebutton-html5/imports/ui/services/unread-messages/index.js +++ b/bigbluebutton-html5/imports/ui/services/unread-messages/index.js @@ -2,6 +2,7 @@ import Storage from '/imports/ui/services/storage/session'; import Auth from '/imports/ui/services/auth'; import Chats from '/imports/api/chat'; +const PUBLIC_CHAT_USERID = 'public_chat_userid'; const STORAGE_KEY = 'UNREAD_CHATS'; const get = (chatID) => { @@ -20,18 +21,27 @@ const update = (chatID, timestamp = 0) => { return unreadChats[chatID]; }; -const count = (chatID) => Chats.find({ +const count = (chatID) => { + let filter = { 'message.from_time': { $gt: get(chatID), }, 'message.from_userid': { $ne: Auth.getUser() }, - $or: [ - { 'message.to_userid': chatID }, - { 'message.from_userid': chatID }, - ], - }).count(); + }; + + // Minimongo does not support $eq. See https://github.com/meteor/meteor/issues/4142 + if (chatID === PUBLIC_CHAT_USERID) { + filter['message.to_userid'] = { $not: { $ne: chatID } }; + } else { + filter['message.to_userid'] = { $not: { $ne: Auth.getUser() } }; + filter['message.from_userid'].$not = { $ne: chatID }; + } + + return Chats.find(filter).count(); +}; export default { + get, count, update, }; diff --git a/bigbluebutton-html5/package.json b/bigbluebutton-html5/package.json index f1c956f5ed..edebb57565 100755 --- a/bigbluebutton-html5/package.json +++ b/bigbluebutton-html5/package.json @@ -12,16 +12,17 @@ "classnames": "^2.2.3", "history": "^2.1.1", "meteor-node-stubs": "^0.2.3", - "react": "^15.0.1", - "react-addons-pure-render-mixin": "^15.0.1", - "react-dom": "^15.0.1", + "react": "~15.2.0", + "react-addons-pure-render-mixin": "~15.2.0", + "react-dom": "~15.2.0", "image-size": "~0.5.0", - "react-intl": "^2.1.2", - "react-modal": "^1.2.1", - "react-router": "^2.4.0", - "react-addons-css-transition-group": "^15.1.0", + "react-intl": "~2.1.3", + "react-modal": "~1.4.0", + "react-router": "~2.5.2", + "react-addons-css-transition-group": "~15.2.0", "underscore": "~1.8.3", - "react-autosize-textarea": "~0.3.1" + "react-autosize-textarea": "~0.3.1", + "grunt-cli": "~1.2.0" }, "devDependencies": { "autoprefixer": "^6.3.6", @@ -34,11 +35,23 @@ "grunt-shell": "~1.2.1", "jscs": "~2.11.0", "load-grunt-tasks": "~3.4.1", - "grunt-newer": "~1.2.0" + "grunt-newer": "~1.2.0", + "postcss-modules-extract-imports": "1.0.0", + "postcss-modules-local-by-default": "1.0.0", + "postcss-modules-scope": "1.0.0", + "postcss-modules-values": "1.1.1", + "postcss-nested": "1.0.0" }, "cssModules": { "extensions": [ "scss" - ] + ], + "postcssPlugins": { + "postcss-nested": {}, + "postcss-modules-local-by-default": {}, + "postcss-modules-extract-imports": {}, + "postcss-modules-scope": {}, + "autoprefixer": {} + } } }