diff --git a/api/channel.go b/api/channel.go index 3e4398e72e..97b604699a 100644 --- a/api/channel.go +++ b/api/channel.go @@ -846,14 +846,21 @@ func setLastViewedAt(c *Context, w http.ResponseWriter, r *http.Request) { Srv.Store.Channel().SetLastViewedAt(id, c.Session.UserId, newLastViewedAt) - preference := model.Preference{ + chanPref := model.Preference{ UserId: c.Session.UserId, - Category: model.PREFERENCE_CATEGORY_LAST, + Category: c.TeamId, Name: model.PREFERENCE_NAME_LAST_CHANNEL, Value: id, } - Srv.Store.Preference().Save(&model.Preferences{preference}) + teamPref := model.Preference{ + UserId: c.Session.UserId, + Category: model.PREFERENCE_CATEGORY_LAST, + Name: model.PREFERENCE_NAME_LAST_TEAM, + Value: c.TeamId, + } + + Srv.Store.Preference().Save(&model.Preferences{teamPref, chanPref}) message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_CHANNEL_VIEWED, c.TeamId, "", c.Session.UserId, nil) message.Add("channel_id", id) @@ -901,14 +908,21 @@ func updateLastViewedAt(c *Context, w http.ResponseWriter, r *http.Request) { go clearPushNotification(c.Session.UserId, id) } - preference := model.Preference{ + chanPref := model.Preference{ UserId: c.Session.UserId, - Category: model.PREFERENCE_CATEGORY_LAST, + Category: c.TeamId, Name: model.PREFERENCE_NAME_LAST_CHANNEL, Value: id, } - Srv.Store.Preference().Save(&model.Preferences{preference}) + teamPref := model.Preference{ + UserId: c.Session.UserId, + Category: model.PREFERENCE_CATEGORY_LAST, + Name: model.PREFERENCE_NAME_LAST_TEAM, + Value: c.TeamId, + } + + Srv.Store.Preference().Save(&model.Preferences{teamPref, chanPref}) message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_CHANNEL_VIEWED, c.TeamId, "", c.Session.UserId, nil) message.Add("channel_id", id) diff --git a/api/post.go b/api/post.go index a4a493060a..7603c7955f 100644 --- a/api/post.go +++ b/api/post.go @@ -824,6 +824,7 @@ func sendNotifications(c *Context, post *model.Post, team *model.Team, channel * message.Add("post", post.ToJson()) message.Add("channel_type", channel.Type) message.Add("channel_display_name", channel.DisplayName) + message.Add("channel_name", channel.Name) message.Add("sender_name", senderUsername) message.Add("team_id", team.Id) diff --git a/api/team.go b/api/team.go index 1d4de6b9e1..f7fe9b8306 100644 --- a/api/team.go +++ b/api/team.go @@ -32,6 +32,8 @@ func InitTeam() { BaseRoutes.Teams.Handle("/get_invite_info", ApiAppHandler(getInviteInfo)).Methods("POST") BaseRoutes.Teams.Handle("/find_team_by_name", ApiAppHandler(findTeamByName)).Methods("POST") BaseRoutes.Teams.Handle("/name/{team_name:[A-Za-z0-9\\-]+}", ApiAppHandler(getTeamByName)).Methods("GET") + BaseRoutes.Teams.Handle("/members", ApiUserRequired(getMyTeamMembers)).Methods("GET") + BaseRoutes.Teams.Handle("/unread", ApiUserRequired(getMyTeamsUnread)).Methods("GET") BaseRoutes.NeedTeam.Handle("/me", ApiUserRequired(getMyTeam)).Methods("GET") BaseRoutes.NeedTeam.Handle("/stats", ApiUserRequired(getTeamStats)).Methods("GET") @@ -358,6 +360,11 @@ func LeaveTeam(team *model.Team, user *model.User) *model.AppError { return uua.Err } + // delete the preferences that set the last channel used in the team and other team specific preferences + if result := <-Srv.Store.Preference().DeleteCategory(user.Id, team.Id); result.Err != nil { + return result.Err + } + RemoveAllSessionsForUserId(user.Id) InvalidateCacheForUser(user.Id) @@ -723,6 +730,32 @@ func getTeamByName(c *Context, w http.ResponseWriter, r *http.Request) { } } +func getMyTeamMembers(c *Context, w http.ResponseWriter, r *http.Request) { + if len(c.Session.TeamMembers) > 0 { + w.Write([]byte(model.TeamMembersToJson(c.Session.TeamMembers))) + } else { + if result := <-Srv.Store.Team().GetTeamsForUser(c.Session.UserId); result.Err != nil { + c.Err = result.Err + return + } else { + data := result.Data.([]*model.TeamMember) + w.Write([]byte(model.TeamMembersToJson(data))) + } + } +} + +func getMyTeamsUnread(c *Context, w http.ResponseWriter, r *http.Request) { + teamId := r.URL.Query().Get("id") + + if result := <-Srv.Store.Team().GetTeamsUnreadForUser(teamId, c.Session.UserId); result.Err != nil { + c.Err = result.Err + return + } else { + data := result.Data.([]*model.TeamUnread) + w.Write([]byte(model.TeamsUnreadToJson(data))) + } +} + func InviteMembers(team *model.Team, senderName string, invites []string) { for _, invite := range invites { if len(invite) > 0 { @@ -801,6 +834,10 @@ func updateTeam(c *Context, w http.ResponseWriter, r *http.Request) { oldTeam.Sanitize() + message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_UPDATE_TEAM, "", "", "", nil) + message.Add("team", oldTeam.ToJson()) + go Publish(message) + w.Write([]byte(oldTeam.ToJson())) } diff --git a/api/team_test.go b/api/team_test.go index 2af46f4dc8..c4bcb1868a 100644 --- a/api/team_test.go +++ b/api/team_test.go @@ -576,6 +576,41 @@ func TestGetTeamMembers(t *testing.T) { } } +func TestGetMyTeamMembers(t *testing.T) { + th := Setup().InitBasic() + + if result, err := th.BasicClient.GetMyTeamMembers(); err != nil { + t.Fatal(err) + } else { + members := result.Data.([]*model.TeamMember) + if len(members) == 0 { + t.Fatal("should have results") + } + } +} + +func TestGetMyTeamsUnread(t *testing.T) { + th := Setup().InitBasic() + + if result, err := th.BasicClient.GetMyTeamsUnread(""); err != nil { + t.Fatal(err) + } else { + members := result.Data.([]*model.TeamUnread) + if len(members) == 0 { + t.Fatal("should have results") + } + } + + if result, err := th.BasicClient.GetMyTeamsUnread(th.BasicTeam.Id); err != nil { + t.Fatal(err) + } else { + members := result.Data.([]*model.TeamUnread) + if len(members) != 0 { + t.Fatal("should not have results") + } + } +} + func TestGetTeamMember(t *testing.T) { th := Setup().InitBasic() diff --git a/i18n/en.json b/i18n/en.json index fb68f741e3..d4d026d64a 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -4863,6 +4863,10 @@ "id": "store.sql_team.get_teams_for_email.app_error", "translation": "We encountered a problem when looking up teams" }, + { + "id": "store.sql_team.get_unread.app_error", + "translation": "We couldn't get the teams unread messages" + }, { "id": "store.sql_team.permanent_delete.app_error", "translation": "We couldn't delete the existing team" diff --git a/model/client.go b/model/client.go index b8bd9fc448..431c4fa8a9 100644 --- a/model/client.go +++ b/model/client.go @@ -1752,6 +1752,36 @@ func (c *Client) GetTeamMembers(teamId string, offset int, limit int) (*Result, } } +// GetMyTeamMembers will return an array with team member objects that the current user +// is a member of. Must be authenticated. +func (c *Client) GetMyTeamMembers() (*Result, *AppError) { + if r, err := c.DoApiGet("/teams/members", "", ""); err != nil { + return nil, err + } else { + defer closeBody(r) + return &Result{r.Header.Get(HEADER_REQUEST_ID), + r.Header.Get(HEADER_ETAG_SERVER), TeamMembersFromJson(r.Body)}, nil + } +} + +// GetMyTeamsUnread will return an array with TeamUnread objects that contain the amount of +// unread messages and mentions the current user has for the teams it belongs to. +// An optional team ID can be set to exclude that team from the results. Must be authenticated. +func (c *Client) GetMyTeamsUnread(teamId string) (*Result, *AppError) { + endpoint := "/teams/unread" + + if teamId != "" { + endpoint += fmt.Sprintf("?id=%s", url.QueryEscape(teamId)) + } + if r, err := c.DoApiGet(endpoint, "", ""); err != nil { + return nil, err + } else { + defer closeBody(r) + return &Result{r.Header.Get(HEADER_REQUEST_ID), + r.Header.Get(HEADER_ETAG_SERVER), TeamsUnreadFromJson(r.Body)}, nil + } +} + // GetTeamMember will return a team member object based on the team id and user id provided. // Must be authenticated. func (c *Client) GetTeamMember(teamId string, userId string) (*Result, *AppError) { diff --git a/model/preference.go b/model/preference.go index cc35768cbc..94807d2c97 100644 --- a/model/preference.go +++ b/model/preference.go @@ -33,6 +33,7 @@ const ( PREFERENCE_CATEGORY_LAST = "last" PREFERENCE_NAME_LAST_CHANNEL = "channel" + PREFERENCE_NAME_LAST_TEAM = "team" PREFERENCE_CATEGORY_NOTIFICATIONS = "notifications" PREFERENCE_NAME_EMAIL_INTERVAL = "email_interval" diff --git a/model/team_member.go b/model/team_member.go index a040e916be..36a567a458 100644 --- a/model/team_member.go +++ b/model/team_member.go @@ -16,6 +16,12 @@ type TeamMember struct { DeleteAt int64 `json:"delete_at"` } +type TeamUnread struct { + TeamId string `json:"team_id"` + MsgCount int64 `json:"msg_count"` + MentionCount int64 `json:"mention_count"` +} + func (o *TeamMember) ToJson() string { b, err := json.Marshal(o) if err != nil { @@ -55,6 +61,25 @@ func TeamMembersFromJson(data io.Reader) []*TeamMember { } } +func TeamsUnreadToJson(o []*TeamUnread) string { + if b, err := json.Marshal(o); err != nil { + return "[]" + } else { + return string(b) + } +} + +func TeamsUnreadFromJson(data io.Reader) []*TeamUnread { + decoder := json.NewDecoder(data) + var o []*TeamUnread + err := decoder.Decode(&o) + if err == nil { + return o + } else { + return nil + } +} + func (o *TeamMember) IsValid() *AppError { if len(o.TeamId) != 26 { diff --git a/model/websocket_message.go b/model/websocket_message.go index c3530c0380..5c956d5763 100644 --- a/model/websocket_message.go +++ b/model/websocket_message.go @@ -18,6 +18,7 @@ const ( WEBSOCKET_EVENT_DIRECT_ADDED = "direct_added" WEBSOCKET_EVENT_NEW_USER = "new_user" WEBSOCKET_EVENT_LEAVE_TEAM = "leave_team" + WEBSOCKET_EVENT_UPDATE_TEAM = "update_team" WEBSOCKET_EVENT_USER_ADDED = "user_added" WEBSOCKET_EVENT_USER_UPDATED = "user_updated" WEBSOCKET_EVENT_USER_REMOVED = "user_removed" diff --git a/store/sql_preference_store.go b/store/sql_preference_store.go index e20226ce67..5c46d1328b 100644 --- a/store/sql_preference_store.go +++ b/store/sql_preference_store.go @@ -326,3 +326,25 @@ func (s SqlPreferenceStore) Delete(userId, category, name string) StoreChannel { return storeChannel } + +func (s SqlPreferenceStore) DeleteCategory(userId string, category string) StoreChannel { + storeChannel := make(StoreChannel, 1) + + go func() { + result := StoreResult{} + + if _, err := s.GetMaster().Exec( + `DELETE FROM + Preferences + WHERE + UserId = :UserId + AND Category = :Category`, map[string]interface{}{"UserId": userId, "Category": category}); err != nil { + result.Err = model.NewLocAppError("SqlPreferenceStore.DeleteCategory", "store.sql_preference.delete.app_error", nil, err.Error()) + } + + storeChannel <- result + close(storeChannel) + }() + + return storeChannel +} diff --git a/store/sql_preference_store_test.go b/store/sql_preference_store_test.go index 8c6a2b6afb..fc1cf5f5bb 100644 --- a/store/sql_preference_store_test.go +++ b/store/sql_preference_store_test.go @@ -392,3 +392,38 @@ func TestPreferenceDelete(t *testing.T) { t.Fatal("should've returned no preferences") } } + +func TestPreferenceDeleteCategory(t *testing.T) { + Setup() + + category := model.NewId() + userId := model.NewId() + + preference1 := model.Preference{ + UserId: userId, + Category: category, + Name: model.NewId(), + Value: "value1a", + } + + preference2 := model.Preference{ + UserId: userId, + Category: category, + Name: model.NewId(), + Value: "value1a", + } + + Must(store.Preference().Save(&model.Preferences{preference1, preference2})) + + if prefs := Must(store.Preference().GetAll(userId)).(model.Preferences); len([]model.Preference(prefs)) != 2 { + t.Fatal("should've returned 2 preferences") + } + + if result := <-store.Preference().DeleteCategory(userId, category); result.Err != nil { + t.Fatal(result.Err) + } + + if prefs := Must(store.Preference().GetAll(userId)).(model.Preferences); len([]model.Preference(prefs)) != 0 { + t.Fatal("should've returned no preferences") + } +} diff --git a/store/sql_team_store.go b/store/sql_team_store.go index 3ec336be52..13b6baa1ab 100644 --- a/store/sql_team_store.go +++ b/store/sql_team_store.go @@ -583,6 +583,39 @@ func (s SqlTeamStore) GetTeamsForUser(userId string) StoreChannel { return storeChannel } +func (s SqlTeamStore) GetTeamsUnreadForUser(teamId, userId string) StoreChannel { + storeChannel := make(StoreChannel, 1) + + go func() { + result := StoreResult{} + + var members []*model.TeamUnread + _, err := s.GetReplica().Select(&members, + `SELECT + Channels.TeamId, + SUM(Channels.TotalMsgCount - ChannelMembers.MsgCount) as MsgCount, + SUM(ChannelMembers.MentionCount) as MentionCount + FROM + Channels, + ChannelMembers + WHERE + Channels.Id = ChannelMembers.ChannelId AND + ChannelMembers.UserId = :UserId AND Channels.TeamId != :TeamId + GROUP BY + Channels.TeamId`, map[string]interface{}{"UserId": userId, "TeamId": teamId}) + if err != nil { + result.Err = model.NewLocAppError("SqlTeamStore.GetTeamsUnreadForUser", "store.sql_team.get_unread.app_error", nil, "userId="+userId+" "+err.Error()) + } else { + result.Data = members + } + + storeChannel <- result + close(storeChannel) + }() + + return storeChannel +} + func (s SqlTeamStore) RemoveMember(teamId string, userId string) StoreChannel { storeChannel := make(StoreChannel, 1) diff --git a/store/sql_team_store_test.go b/store/sql_team_store_test.go index 0e472a961f..5e6abd102c 100644 --- a/store/sql_team_store_test.go +++ b/store/sql_team_store_test.go @@ -529,3 +529,50 @@ func TestTeamStoreMemberCount(t *testing.T) { } } } + +func TestMyTeamMembersUnread(t *testing.T) { + Setup() + + teamId1 := model.NewId() + teamId2 := model.NewId() + + uid := model.NewId() + m1 := &model.TeamMember{TeamId: teamId1, UserId: uid} + m2 := &model.TeamMember{TeamId: teamId2, UserId: uid} + Must(store.Team().SaveMember(m1)) + Must(store.Team().SaveMember(m2)) + + c1 := &model.Channel{TeamId: m1.TeamId, Name: model.NewId(), DisplayName: "Town Square", Type: model.CHANNEL_OPEN} + Must(store.Channel().Save(c1)) + c2 := &model.Channel{TeamId: m2.TeamId, Name: model.NewId(), DisplayName: "Town Square", Type: model.CHANNEL_OPEN} + Must(store.Channel().Save(c2)) + + cm1 := &model.ChannelMember{ChannelId: c1.Id, UserId: m1.UserId, NotifyProps: model.GetDefaultChannelNotifyProps()} + Must(store.Channel().SaveMember(cm1)) + cm2 := &model.ChannelMember{ChannelId: c2.Id, UserId: m2.UserId, NotifyProps: model.GetDefaultChannelNotifyProps()} + Must(store.Channel().SaveMember(cm2)) + + if r1 := <-store.Team().GetTeamsUnreadForUser("", uid); r1.Err != nil { + t.Fatal(r1.Err) + } else { + ms := r1.Data.([]*model.TeamUnread) + + if len(ms) != 2 { + t.Fatal("Should be the unreads for all the teams") + } + } + + if r2 := <-store.Team().GetTeamsUnreadForUser(teamId1, uid); r2.Err != nil { + t.Fatal(r2.Err) + } else { + ms := r2.Data.([]*model.TeamUnread) + + if len(ms) != 1 { + t.Fatal("Should be the unreads for just one team") + } + } + + if r1 := <-store.Team().RemoveAllMembersByUser(uid); r1.Err != nil { + t.Fatal(r1.Err) + } +} diff --git a/store/store.go b/store/store.go index b0cc09983f..05eb7f4e14 100644 --- a/store/store.go +++ b/store/store.go @@ -74,6 +74,7 @@ type TeamStore interface { GetTotalMemberCount(teamId string) StoreChannel GetActiveMemberCount(teamId string) StoreChannel GetTeamsForUser(userId string) StoreChannel + GetTeamsUnreadForUser(teamId, userId string) StoreChannel RemoveMember(teamId string, userId string) StoreChannel RemoveAllMembersByTeam(teamId string) StoreChannel RemoveAllMembersByUser(userId string) StoreChannel @@ -270,6 +271,7 @@ type PreferenceStore interface { GetCategory(userId string, category string) StoreChannel GetAll(userId string) StoreChannel Delete(userId, category, name string) StoreChannel + DeleteCategory(userId string, category string) StoreChannel PermanentDeleteByUser(userId string) StoreChannel IsFeatureEnabled(feature, userId string) StoreChannel } diff --git a/webapp/actions/global_actions.jsx b/webapp/actions/global_actions.jsx index d743b787bc..9d135dd26b 100644 --- a/webapp/actions/global_actions.jsx +++ b/webapp/actions/global_actions.jsx @@ -43,6 +43,7 @@ export function emitChannelClickEvent(channel) { ); } function switchToChannel(chan) { + const channelMember = ChannelStore.getMyMember(chan.id); const getMyChannelMembersPromise = AsyncClient.getChannelMember(chan.id, UserStore.getCurrentId()); getMyChannelMembersPromise.then(() => { @@ -56,6 +57,9 @@ export function emitChannelClickEvent(channel) { type: ActionTypes.CLICK_CHANNEL, name: chan.name, id: chan.id, + team_id: chan.team_id, + total_msg_count: chan.total_msg_count, + channelMember, prev: ChannelStore.getCurrentId() }); } @@ -443,7 +447,7 @@ export function viewLoggedIn() { PostStore.clearPendingPosts(); } -var lastTimeTypingSent = 0; +let lastTimeTypingSent = 0; export function emitLocalUserTypingEvent(channelId, parentId) { const t = Date.now(); if ((t - lastTimeTypingSent) > Constants.UPDATE_TYPING_MS) { @@ -534,3 +538,35 @@ export function emitBrowserFocus(focus) { focus }); } + +export function redirectUserToDefaultTeam() { + const teams = TeamStore.getAll(); + const teamMembers = TeamStore.getMyTeamMembers(); + let teamId = PreferenceStore.get('last', 'team'); + + if (!teams[teamId] && teamMembers.length > 0) { + let myTeams = []; + for (const index in teamMembers) { + if (teamMembers.hasOwnProperty(index)) { + const teamMember = teamMembers[index]; + myTeams.push(teams[teamMember.team_id]); + } + } + + if (myTeams.length > 0) { + myTeams = myTeams.sort((a, b) => a.display_name.localeCompare(b.display_name)); + teamId = myTeams[0].id; + } + } + + if (teams[teamId]) { + const channelId = PreferenceStore.get(teamId, 'channel'); + let channel = ChannelStore.getChannelById(channelId); + if (!channel) { + channel = 'town-square'; + } + browserHistory.push(`/${teams[teamId].name}/channels/${channel}`); + } else { + browserHistory.push('/select_team'); + } +} diff --git a/webapp/actions/post_actions.jsx b/webapp/actions/post_actions.jsx index 736aef033f..d1e69cda78 100644 --- a/webapp/actions/post_actions.jsx +++ b/webapp/actions/post_actions.jsx @@ -18,23 +18,30 @@ const ActionTypes = Constants.ActionTypes; const Preferences = Constants.Preferences; export function handleNewPost(post, msg) { + const teamId = TeamStore.getCurrentId(); + if (ChannelStore.getCurrentId() === post.channel_id) { if (window.isActive) { AsyncClient.updateLastViewedAt(null, false); } else { AsyncClient.getChannel(post.channel_id); } - } else if (msg && (TeamStore.getCurrentId() === msg.data.team_id || msg.data.channel_type === Constants.DM_CHANNEL)) { + } else if (msg && (teamId === msg.data.team_id || msg.data.channel_type === Constants.DM_CHANNEL)) { if (Client.teamId) { AsyncClient.getChannel(post.channel_id); } } - var websocketMessageProps = null; + let websocketMessageProps = null; if (msg) { websocketMessageProps = msg.data; } + const myTeams = TeamStore.getMyTeamMembers(); + if (msg.data.team_id !== teamId && myTeams.filter((m) => m.team_id === msg.data.team_id).length) { + AsyncClient.getMyTeamsUnread(teamId); + } + if (post.root_id && PostStore.getPost(post.channel_id, post.root_id) == null) { Client.getPost( post.channel_id, diff --git a/webapp/actions/websocket_actions.jsx b/webapp/actions/websocket_actions.jsx index ec433aab56..6c81a4ac98 100644 --- a/webapp/actions/websocket_actions.jsx +++ b/webapp/actions/websocket_actions.jsx @@ -6,6 +6,7 @@ import $ from 'jquery'; import UserStore from 'stores/user_store.jsx'; import TeamStore from 'stores/team_store.jsx'; import PostStore from 'stores/post_store.jsx'; +import PreferenceStore from 'stores/preference_store.jsx'; import ChannelStore from 'stores/channel_store.jsx'; import BrowserStore from 'stores/browser_store.jsx'; import ErrorStore from 'stores/error_store.jsx'; @@ -122,6 +123,10 @@ function handleEvent(msg) { handleLeaveTeamEvent(msg); break; + case SocketEvents.UPDATE_TEAM: + handleUpdateTeamEvent(msg); + break; + case SocketEvents.USER_ADDED: handleUserAddedEvent(msg); break; @@ -229,21 +234,37 @@ function handleNewUserEvent(msg) { AsyncClient.getUser(msg.data.user_id); AsyncClient.getChannelStats(); loadProfilesAndTeamMembersForDMSidebar(); + + if (msg.data.user_id === UserStore.getCurrentId()) { + AsyncClient.getMyTeamMembers(); + } } function handleLeaveTeamEvent(msg) { if (UserStore.getCurrentId() === msg.data.user_id) { TeamStore.removeMyTeamMember(msg.data.team_id); - // if they are on the team being removed redirect them to the root + // if they are on the team being removed redirect them to default team if (TeamStore.getCurrentId() === msg.data.team_id) { TeamStore.setCurrentId(''); Client.setTeamId(''); - browserHistory.push('/'); + PreferenceStore.deletePreference({ + category: 'last', + name: 'team', + value: msg.data.team_id + }); + GlobalActions.redirectUserToDefaultTeam(); } + } else { + UserStore.removeProfileFromTeam(msg.data.team_id, msg.data.user_id); + TeamStore.removeMemberInTeam(msg.data.team_id, msg.data.user_id); } } +function handleUpdateTeamEvent(msg) { + TeamStore.updateTeam(msg.data.team); +} + function handleDirectAddedEvent(msg) { AsyncClient.getChannel(msg.broadcast.channel_id); loadProfilesAndTeamMembersForDMSidebar(); diff --git a/webapp/client/client.jsx b/webapp/client/client.jsx index 370d40ac02..3ec36644f3 100644 --- a/webapp/client/client.jsx +++ b/webapp/client/client.jsx @@ -598,6 +598,30 @@ export default class Client { end(this.handleResponse.bind(this, 'getTeamMember', success, error)); } + getMyTeamMembers(success, error) { + request. + get(`${this.getTeamsRoute()}/members`). + set(this.defaultHeaders). + type('application/json'). + accept('application/json'). + end(this.handleResponse.bind(this, 'getMyTeamMembers', success, error)); + } + + getMyTeamsUnread(teamId, success, error) { + let url = `${this.getTeamsRoute()}/unread`; + + if (teamId) { + url += `?id=${encodeURIComponent(teamId)}`; + } + + request. + get(url). + set(this.defaultHeaders). + type('application/json'). + accept('application/json'). + end(this.handleResponse.bind(this, 'getMyTeamsUnread', success, error)); + } + getTeamMembersByIds(teamId, userIds, success, error) { request. post(`${this.getTeamNeededRoute(teamId)}/members/ids`). diff --git a/webapp/components/admin_console/admin_navbar_dropdown.jsx b/webapp/components/admin_console/admin_navbar_dropdown.jsx index f20451b4b3..5b65868e9b 100644 --- a/webapp/components/admin_console/admin_navbar_dropdown.jsx +++ b/webapp/components/admin_console/admin_navbar_dropdown.jsx @@ -50,13 +50,14 @@ export default class AdminNavbarDropdown extends React.Component { } render() { - var teams = []; + const teams = []; + let switchTeams; if (this.state.teamMembers && this.state.teamMembers.length > 0) { - for (var index in this.state.teamMembers) { + for (const index in this.state.teamMembers) { if (this.state.teamMembers.hasOwnProperty(index)) { - var teamMember = this.state.teamMembers[index]; - var team = this.state.teams[teamMember.team_id]; + const teamMember = this.state.teamMembers[index]; + const team = this.state.teams[teamMember.team_id]; teams.push(