From 461c7086a172f3ba49804f9b2480c31092e5005e Mon Sep 17 00:00:00 2001 From: Kristian Ruiz Kyvik Date: Sat, 18 Jun 2016 19:53:55 +0200 Subject: [PATCH 1/8] moved archived field to the userRoom model and avoided using state to keep track of the archived status --- client/ChatterApp.jsx | 17 ++- client/components/MainSettings.jsx | 155 ++++++++++++--------- client/components/RoomList.jsx | 2 + client/template-helpers/router.jsx | 4 - client/template-helpers/settingsRouter.jsx | 3 - 5 files changed, 102 insertions(+), 79 deletions(-) diff --git a/client/ChatterApp.jsx b/client/ChatterApp.jsx index 122a504..22fe2f5 100644 --- a/client/ChatterApp.jsx +++ b/client/ChatterApp.jsx @@ -5,9 +5,9 @@ import getChatHTML from "./template-helpers/getChatHTML.jsx"; import router from "./template-helpers/router.jsx"; import Widget from "./components/Widget.jsx"; -const latestRooms = function (limit, withIds, archived) { +const latestRooms = function (limit, withIds) { return { - find: {"_id": {$in: withIds}, "archived": archived}, + find: {"_id": {$in: withIds}}, options: {sort: {lastActive: -1}, limit: limit} }; }; @@ -46,10 +46,15 @@ const ChatterApp = React.createClass({ const {activeRoomLimit, archivedRoomLimit} = this.state; if (userId) { - const userRooms = Chatter.UserRoom.find({userId}).fetch(); - const roomIds = _.pluck(userRooms, "roomId"); - const activeRoomQuery = latestRooms(activeRoomLimit, roomIds, false); - const archivedRoomQuery = latestRooms(archivedRoomLimit, roomIds, true); + const archivedUserRooms = Chatter.UserRoom.find({userId, archived: true}).fetch(); + const unarchivedUserRooms = Chatter.UserRoom.find({userId, archived: false}).fetch(); + + const archivedRoomIds = _.pluck(archivedUserRooms, "roomId"); + const unarchivedRoomIds = _.pluck(unarchivedUserRooms, "roomId"); + + const activeRoomQuery = latestRooms(activeRoomLimit, unarchivedRoomIds); + const archivedRoomQuery = latestRooms(archivedRoomLimit, archivedRoomIds); + activeRooms = Chatter.Room.find(activeRoomQuery.find, activeRoomQuery.options).fetch(); archivedRooms = Chatter.Room.find(archivedRoomQuery.find, archivedRoomQuery.options).fetch(); } diff --git a/client/components/MainSettings.jsx b/client/components/MainSettings.jsx index 4a2d2e4..1af6dc2 100644 --- a/client/components/MainSettings.jsx +++ b/client/components/MainSettings.jsx @@ -2,19 +2,34 @@ import React from 'react'; import Loader from "../components/Loader.jsx" const MainSettings = React.createClass({ + mixins: [ReactMeteorData], getInitialState: function() { return { - roomUsers: [], - archived: this.props.room.archived + roomUsers: [] }; }, + getMeteorData () { + const userId = Meteor.userId(); + const userRoomsHandle = Meteor.subscribe("chatterUserRooms"); + const subsReady = userRoomsHandle.ready(); + let room = this.props.room; + let user = null; + + if (subsReady) { + const ur = Chatter.UserRoom.findOne({roomId: this.props.room._id, userId}); + user = Meteor.user(); + room.archived = ur.archived; + } + + return { + subsReady, + room + } + }, + componentDidMount() { - $(".ui.toggle.checkbox").checkbox(); - if (this.state.archived) { - $(".ui.toggle.checkbox").checkbox('check'); - } Meteor.call("room.users", this.props.room._id, (error, result) => { this.setState({roomUsers: result}); }); @@ -22,16 +37,21 @@ const MainSettings = React.createClass({ toggleArchivedState() { const params = { - archived: !this.state.archived, - roomId: this.props.room._id + archived: !this.data.room.archived, + roomId: this.props.room._id, + userId: Meteor.userId() }; + Meteor.call("room.archive", params); - this.setState({archived: !this.state.archived}); }, render() { - const user = Meteor.user(); - + if (this.data.subsReady) { + $(".ui.toggle.checkbox").checkbox(); + if (this.data.room.archived) { + $(".ui.toggle.checkbox").checkbox('check'); + } + } const addUsersHTML = (
this.props.setView("addUsers")}> @@ -47,68 +67,71 @@ const MainSettings = React.createClass({ const roomUsersHTML = roomUsers.map(function(user) { const statusClass = user.profile.online ? "user-status online" : "user-status offline"; return ( -
-
- -
- - {user.profile.chatterNickname} - -
- Last logged in just now. +
+
+ +
+ + {user.profile.chatterNickname} + +
+ Last logged in just now. +
-
- ); - }); + ); + }); - - return ( -
-
- Channel description -
-

- {this.props.room.description} -

-

- This channel was created by {this.props.room.createdBy} on the {this.props.room.createdAt.toISOString()}. -

-
- - -
-

- Archived chats will store the conversation and stop notifications from bothering you in the future. -

-
-
- - - Channel members ({roomUsers.length}) - + if (roomUsers.length > 0) { + return ( +
+
+ Channel description +
+

+ {this.props.room.description} +

+

+ This channel was created by {this.props.room.createdBy} on the {this.props.room.createdAt.toISOString()}. +

+
+ +
-
-
- {user.profile.isChatterAdmin ? addUsersHTML : null} -
- {roomUsers.length > 0 ? roomUsersHTML : } +

+ Archived chats will store the conversation and stop notifications from bothering you in the future. +

+
+
+ + + Channel members ({roomUsers.length}) + +
+
+
+ {user.profile.isChatterAdmin ? addUsersHTML : null} +
+ {roomUsersHTML} +
-
- ); + ); + } else { + return + } } }); diff --git a/client/components/RoomList.jsx b/client/components/RoomList.jsx index 633f7fb..664cf1f 100644 --- a/client/components/RoomList.jsx +++ b/client/components/RoomList.jsx @@ -81,6 +81,7 @@ const RoomList = React.createClass({ const newRoomBtn = (user.profile.isChatterAdmin) ? newRoomBtnHTML : null; const activeRoomsHTML = activeRooms.map(room => { + room.archived = false; return { + room.archived = true; return @@ -35,8 +33,6 @@ const router = function(scope, view) { room: { view: "room", component: () => }, addUsers: { view: "addUsers", component: () => Date: Sat, 18 Jun 2016 20:21:27 +0200 Subject: [PATCH 2/8] reactive methods not cllend in render --- client/components/MainSettings.jsx | 62 +++++++++++++++--------------- client/components/Room.jsx | 4 +- client/components/RoomList.jsx | 2 +- 3 files changed, 34 insertions(+), 34 deletions(-) diff --git a/client/components/MainSettings.jsx b/client/components/MainSettings.jsx index 1af6dc2..0ea1b25 100644 --- a/client/components/MainSettings.jsx +++ b/client/components/MainSettings.jsx @@ -25,7 +25,8 @@ const MainSettings = React.createClass({ return { subsReady, - room + room, + user } }, @@ -47,45 +48,44 @@ const MainSettings = React.createClass({ render() { if (this.data.subsReady) { + const user = this.data.user; $(".ui.toggle.checkbox").checkbox(); if (this.data.room.archived) { $(".ui.toggle.checkbox").checkbox('check'); } - } - const addUsersHTML = ( -
this.props.setView("addUsers")}> - -
- - Add or remove users... - + const addUsersHTML = ( +
this.props.setView("addUsers")}> + +
-
- ); + ); - const roomUsers = this.state.roomUsers; - const roomUsersHTML = roomUsers.map(function(user) { - const statusClass = user.profile.online ? "user-status online" : "user-status offline"; - return ( -
-
- -
- - {user.profile.chatterNickname} - -
- Last logged in just now. + const roomUsers = this.state.roomUsers; + const roomUsersHTML = roomUsers.map(function(user) { + const statusClass = user.profile.online ? "user-status online" : "user-status offline"; + return ( +
+
+ +
+ + {user.profile.chatterNickname} + +
+ Last logged in just now. +
-
- ); - }); + ); + }); - if (roomUsers.length > 0) { return (
diff --git a/client/components/Room.jsx b/client/components/Room.jsx index 4dfba90..a7efffd 100644 --- a/client/components/Room.jsx +++ b/client/components/Room.jsx @@ -47,11 +47,11 @@ const Room = React.createClass({ componentDidMount() { this.scrollDown() - Meteor.call("room.counter.reset", this.props.roomId); + Meteor.call("room.unreadMsgCount.reset", this.props.roomId); }, componentWillUnmount() { - Meteor.call("room.counter.reset", this.props.roomId); + Meteor.call("room.unreadMsgCount.reset", this.props.roomId); }, componentWillUpdate() { diff --git a/client/components/RoomList.jsx b/client/components/RoomList.jsx index 664cf1f..7d9a8c5 100644 --- a/client/components/RoomList.jsx +++ b/client/components/RoomList.jsx @@ -23,7 +23,7 @@ const RoomList = React.createClass({ componentDidMount() { $('.ui.accordion').accordion(); - Meteor.call("get.room.counts", (error, response) => { + Meteor.call("get.room.unreadMsgCount", (error, response) => { this.setState(response); }); From 4d04af506beca1135a030c4ceb5a4ab6cc930c2a Mon Sep 17 00:00:00 2001 From: Kristian Ruiz Kyvik Date: Sat, 18 Jun 2016 20:39:22 +0200 Subject: [PATCH 3/8] added the configuration to ll sub manager instantiations --- client/ChatterApp.jsx | 6 +++++- client/components/Profile.jsx | 5 ++++- client/components/Room.jsx | 5 ++++- client/components/RoomListItem.jsx | 5 ++++- 4 files changed, 17 insertions(+), 4 deletions(-) diff --git a/client/ChatterApp.jsx b/client/ChatterApp.jsx index 22fe2f5..f159670 100644 --- a/client/ChatterApp.jsx +++ b/client/ChatterApp.jsx @@ -12,7 +12,11 @@ const latestRooms = function (limit, withIds) { }; }; -const chatterSubs = new SubsManager(); + +const chatterSubs = new SubsManager({ + cacheLimit: 10, + expireIn: 5 +}); const ChatterApp = React.createClass({ mixins: [ReactMeteorData], diff --git a/client/components/Profile.jsx b/client/components/Profile.jsx index 01ffc3d..1d509ed 100644 --- a/client/components/Profile.jsx +++ b/client/components/Profile.jsx @@ -2,7 +2,10 @@ import React from 'react'; import ReactDOM from 'react-dom'; import Loader from "../components/Loader.jsx" -const profileSubs = new SubsManager(); +const profileSubs = new SubsManager({ + cacheLimit: 15, + expireIn: 5 +}); const Profile = React.createClass({ mixins: [ReactMeteorData], diff --git a/client/components/Room.jsx b/client/components/Room.jsx index a7efffd..3b9c872 100644 --- a/client/components/Room.jsx +++ b/client/components/Room.jsx @@ -20,7 +20,10 @@ const timestampShouldBeDisplayed = function(currentMsg, nextMsg) { return veryRecentMessage && timeSinceLastMsgGreaterThan(2, currentMsg, nextMsg) || recentMessage && timeSinceLastMsgGreaterThan(60, currentMsg, nextMsg); } -const roomSubs = new SubsManager(); +const roomSubs = new SubsManager({ + cacheLimit: 50, + expireIn: 5 +}); const Room = React.createClass({ mixins: [ReactMeteorData], diff --git a/client/components/RoomListItem.jsx b/client/components/RoomListItem.jsx index 65dba1e..70e65d5 100644 --- a/client/components/RoomListItem.jsx +++ b/client/components/RoomListItem.jsx @@ -1,6 +1,9 @@ import React from 'react'; -const roomListItemSubs = new SubsManager(); +const roomListItemSubs = new SubsManager({ + cacheLimit: 50, + expireIn: 5 +}); const RoomListItem = React.createClass({ mixins: [ReactMeteorData], From 7532524ec27c7bd85dde04947dc3372d8f046857 Mon Sep 17 00:00:00 2001 From: Kristian Ruiz Kyvik Date: Sun, 19 Jun 2016 13:25:21 +0200 Subject: [PATCH 4/8] using the callback in ref attrib to focus and initializer the form which is easier and cleaner given that form is conditionally rendered --- client/components/Profile.jsx | 64 ++++++++++++++++++++--------------- 1 file changed, 36 insertions(+), 28 deletions(-) diff --git a/client/components/Profile.jsx b/client/components/Profile.jsx index 1d509ed..c4c0b20 100644 --- a/client/components/Profile.jsx +++ b/client/components/Profile.jsx @@ -7,6 +7,27 @@ const profileSubs = new SubsManager({ expireIn: 5 }); +const initializeInput = function(input) { + if (input) { + input.focus(); + $('.ui.form').form( + { + fields: { + nickname: { + identifier: 'nickname', + rules: [ + { + type : 'empty', + prompt : 'Please enter a valid nickname' + } + ] + } + } + } + ); + } +}; + const Profile = React.createClass({ mixins: [ReactMeteorData], @@ -18,14 +39,16 @@ const Profile = React.createClass({ getMeteorData () { const usersHandle = profileSubs.subscribe("users"); - let user = {}; + const subsReady = usersHandle.ready(); + let user = null; - if (usersHandle.ready()) { + if (subsReady) { user = Meteor.users.findOne(this.props.userProfile); } return { usersHandle, - user + user, + subsReady } }, @@ -40,33 +63,15 @@ const Profile = React.createClass({ }); }, - componentDidMount() { - if (this.data.usersHandle.ready() && this.props.userProfile == Meteor.userId()) { - ReactDOM.findDOMNode(this.refs.nickname).focus(); - $('.ui.form') - .form({ - fields: { - nickname: { - identifier: 'nickname', - rules: [ - { - type : 'empty', - prompt : 'Please enter a valid nickname' - } - ] - } - } - }); - } - }, - render() { - if (!this.data.usersHandle.ready()) { + if (!this.data.subsReady) { return ; } + const userId = this.data.user._id; const user = this.data.user.profile; const headerText = `${user.chatterNickname}'s Profile`; + const form = (
@@ -74,7 +79,12 @@ const Profile = React.createClass({ - +
); - - return (
@@ -101,7 +109,7 @@ const Profile = React.createClass({

{user.chatterNickname} is currently {user.online ? "online" : "offline"}.

- {this.props.userProfile == Meteor.userId() ? form : null} + {this.props.userProfile === userId ? form : null}
); } From cb020045bf875168ead3beaeb6ffde3ec452d926 Mon Sep 17 00:00:00 2001 From: Kristian Ruiz Kyvik Date: Sun, 19 Jun 2016 13:27:55 +0200 Subject: [PATCH 5/8] removed userHandle from data scope --- client/components/Profile.jsx | 1 - 1 file changed, 1 deletion(-) diff --git a/client/components/Profile.jsx b/client/components/Profile.jsx index c4c0b20..8a40e47 100644 --- a/client/components/Profile.jsx +++ b/client/components/Profile.jsx @@ -46,7 +46,6 @@ const Profile = React.createClass({ user = Meteor.users.findOne(this.props.userProfile); } return { - usersHandle, user, subsReady } From f93a9b099a74b27836809f71d511e8ef65a34b0c Mon Sep 17 00:00:00 2001 From: Kristian Ruiz Kyvik Date: Sun, 19 Jun 2016 15:17:30 +0200 Subject: [PATCH 6/8] created file with vonfig globals --- client/ChatterApp.jsx | 9 +++-- client/components/Profile.jsx | 56 +++++++++++++++++------------- client/components/Room.jsx | 28 +++++++++------ client/components/RoomListItem.jsx | 9 +++-- client/global-variables.js | 38 ++++++++++++++++++++ 5 files changed, 101 insertions(+), 39 deletions(-) create mode 100644 client/global-variables.js diff --git a/client/ChatterApp.jsx b/client/ChatterApp.jsx index f159670..73a88f1 100644 --- a/client/ChatterApp.jsx +++ b/client/ChatterApp.jsx @@ -5,6 +5,11 @@ import getChatHTML from "./template-helpers/getChatHTML.jsx"; import router from "./template-helpers/router.jsx"; import Widget from "./components/Widget.jsx"; +import { + CHATTER_CACHE_LIMIT, + CHATTER_EXPIRE_IN +} from "./global-variables.js"; + const latestRooms = function (limit, withIds) { return { find: {"_id": {$in: withIds}}, @@ -14,8 +19,8 @@ const latestRooms = function (limit, withIds) { const chatterSubs = new SubsManager({ - cacheLimit: 10, - expireIn: 5 + cacheLimit: CHATTER_CACHE_LIMIT, + expireIn: CHATTER_EXPIRE_IN }); const ChatterApp = React.createClass({ diff --git a/client/components/Profile.jsx b/client/components/Profile.jsx index 8a40e47..5e26bf6 100644 --- a/client/components/Profile.jsx +++ b/client/components/Profile.jsx @@ -2,32 +2,16 @@ import React from 'react'; import ReactDOM from 'react-dom'; import Loader from "../components/Loader.jsx" +import { + PROFILE_CACHE_LIMIT, + PROFILE_EXPIRE_IN +} from "../global-variables.js"; + const profileSubs = new SubsManager({ - cacheLimit: 15, - expireIn: 5 + cacheLimit: PROFILE_CACHE_LIMIT, + expireIn: PROFILE_EXPIRE_IN }); -const initializeInput = function(input) { - if (input) { - input.focus(); - $('.ui.form').form( - { - fields: { - nickname: { - identifier: 'nickname', - rules: [ - { - type : 'empty', - prompt : 'Please enter a valid nickname' - } - ] - } - } - } - ); - } -}; - const Profile = React.createClass({ mixins: [ReactMeteorData], @@ -51,9 +35,31 @@ const Profile = React.createClass({ } }, + initializeInput(input) { + if (input) { + this.nicknameInput = input; + input.focus(); + $('.ui.form').form( + { + fields: { + nickname: { + identifier: 'nickname', + rules: [ + { + type : 'empty', + prompt : 'Please enter a valid nickname' + } + ] + } + } + } + ); + } + }, + handleSubmit(e) { e.preventDefault(); - const nickname = ReactDOM.findDOMNode(this.refs.nickname).value.trim(); + const nickname = this.nicknameInput.value.trim(); if (nickname.length === 0) return; Meteor.call("user.changeNickname", nickname, (error, result) => { if (!error) { @@ -82,7 +88,7 @@ const Profile = React.createClass({ type="text" name="nickname" placeholder={user.chatterNickname} - ref={initializeInput} + ref={this.initializeInput} />