diff options
Diffstat (limited to 'webapp/components')
24 files changed, 158 insertions, 81 deletions
diff --git a/webapp/components/admin_console/admin_sidebar_header.jsx b/webapp/components/admin_console/admin_sidebar_header.jsx index 86c2c6b0f..5725551bf 100644 --- a/webapp/components/admin_console/admin_sidebar_header.jsx +++ b/webapp/components/admin_console/admin_sidebar_header.jsx @@ -42,7 +42,7 @@ export default class SidebarHeader extends React.Component { profilePicture = ( <img className='user__picture' - src={Client.getUsersRoute() + '/' + me.id + '/image?time=' + me.update_at} + src={Client.getUsersRoute() + '/' + me.id + '/image?time=' + me.last_picture_update} /> ); } diff --git a/webapp/components/admin_console/logs.jsx b/webapp/components/admin_console/logs.jsx index 8dc0c1e2e..5846c91db 100644 --- a/webapp/components/admin_console/logs.jsx +++ b/webapp/components/admin_console/logs.jsx @@ -24,12 +24,14 @@ export default class Logs extends React.Component { componentDidMount() { AdminStore.addLogChangeListener(this.onLogListenerChange); AsyncClient.getLogs(); + this.refs.logPanel.focus(); } componentDidUpdate() { // Scroll Down to get the latest logs var node = this.refs.logPanel; node.scrollTop = node.scrollHeight; + node.focus(); } componentWillUnmount() { @@ -100,6 +102,7 @@ export default class Logs extends React.Component { /> </button> <div + tabIndex='-1' ref='logPanel' className='log__panel' > diff --git a/webapp/components/logged_in.jsx b/webapp/components/logged_in.jsx index 841061d48..9282e74ca 100644 --- a/webapp/components/logged_in.jsx +++ b/webapp/components/logged_in.jsx @@ -4,7 +4,6 @@ import LoadingScreen from 'components/loading_screen.jsx'; import UserStore from 'stores/user_store.jsx'; -import BrowserStore from 'stores/browser_store.jsx'; import PreferenceStore from 'stores/preference_store.jsx'; import * as GlobalActions from 'actions/global_actions.jsx'; @@ -29,30 +28,6 @@ export default class LoggedIn extends React.Component { this.onUserChanged = this.onUserChanged.bind(this); this.setupUser = this.setupUser.bind(this); - // Force logout of all tabs if one tab is logged out - $(window).bind('storage', (e) => { - // when one tab on a browser logs out, it sets __logout__ in localStorage to trigger other tabs to log out - if (e.originalEvent.key === '__logout__' && e.originalEvent.storageArea === localStorage && e.originalEvent.newValue) { - // make sure it isn't this tab that is sending the logout signal (only necessary for IE11) - if (BrowserStore.isSignallingLogout(e.originalEvent.newValue)) { - return; - } - - console.log('detected logout from a different tab'); //eslint-disable-line no-console - GlobalActions.emitUserLoggedOutEvent('/', false); - } - - if (e.originalEvent.key === '__login__' && e.originalEvent.storageArea === localStorage && e.originalEvent.newValue) { - // make sure it isn't this tab that is sending the logout signal (only necessary for IE11) - if (BrowserStore.isSignallingLogin(e.originalEvent.newValue)) { - return; - } - - console.log('detected login from a different tab'); //eslint-disable-line no-console - location.reload(); - } - }); - // Because current CSS requires the root tag to have specific stuff $('#root').attr('class', 'channel-view'); diff --git a/webapp/components/popover_list_members.jsx b/webapp/components/popover_list_members.jsx index 9cea3922a..a0b36cdc3 100644 --- a/webapp/components/popover_list_members.jsx +++ b/webapp/components/popover_list_members.jsx @@ -96,7 +96,7 @@ export default class PopoverListMembers extends React.Component { key={'popover-member-' + i} > <ProfilePicture - src={`${Client.getUsersRoute()}/${m.id}/image?time=${m.update_at}`} + src={`${Client.getUsersRoute()}/${m.id}/image?time=${m.last_picture_update}`} width='26' height='26' /> diff --git a/webapp/components/post_view/components/post.jsx b/webapp/components/post_view/components/post.jsx index f052ac4ae..03075a3fb 100644 --- a/webapp/components/post_view/components/post.jsx +++ b/webapp/components/post_view/components/post.jsx @@ -150,10 +150,10 @@ export default class Post extends React.Component { } let timestamp = 0; - if (!this.props.user || this.props.user.update_at == null) { - timestamp = this.props.currentUser.update_at; + if (!this.props.user || this.props.user.last_picture_update == null) { + timestamp = this.props.currentUser.last_picture_update; } else { - timestamp = this.props.user.update_at; + timestamp = this.props.user.last_picture_update; } let sameUserClass = ''; diff --git a/webapp/components/post_view/components/post_message_container.jsx b/webapp/components/post_view/components/post_message_container.jsx index 2d17e74c4..4e27cd29a 100644 --- a/webapp/components/post_view/components/post_message_container.jsx +++ b/webapp/components/post_view/components/post_message_container.jsx @@ -89,7 +89,7 @@ export default class PostMessageContainer extends React.Component { return ( <PostMessageView options={this.props.options} - message={this.props.post.message} + post={this.props.post} emojis={this.state.emojis} enableFormatting={this.state.enableFormatting} mentionKeys={this.state.mentionKeys} diff --git a/webapp/components/post_view/components/post_message_view.jsx b/webapp/components/post_view/components/post_message_view.jsx index 24f96a8d9..eff791aec 100644 --- a/webapp/components/post_view/components/post_message_view.jsx +++ b/webapp/components/post_view/components/post_message_view.jsx @@ -2,14 +2,16 @@ // See License.txt for license information. import React from 'react'; +import {FormattedMessage} from 'react-intl'; import * as TextFormatting from 'utils/text_formatting.jsx'; import * as Utils from 'utils/utils.jsx'; +import * as PostUtils from 'utils/post_utils.jsx'; export default class PostMessageView extends React.Component { static propTypes = { options: React.PropTypes.object.isRequired, - message: React.PropTypes.string.isRequired, + post: React.PropTypes.object.isRequired, emojis: React.PropTypes.object.isRequired, enableFormatting: React.PropTypes.bool.isRequired, mentionKeys: React.PropTypes.arrayOf(React.PropTypes.string).isRequired, @@ -23,7 +25,7 @@ export default class PostMessageView extends React.Component { return true; } - if (nextProps.message !== this.props.message) { + if (nextProps.post.message !== this.props.post.message) { return true; } @@ -47,9 +49,28 @@ export default class PostMessageView extends React.Component { return false; } + editedIndicator() { + return ( + PostUtils.isEdited(this.props.post) ? + <span className='edited'> + <FormattedMessage + id='post_message_view.edited' + defaultMessage='(edited)' + /> + </span> : + '' + ); + } + render() { if (!this.props.enableFormatting) { - return <span>{this.props.message}</span>; + return ( + <span> + {this.props.post.message} + + {this.editedIndicator()} + </span> + ); } const options = Object.assign({}, this.props.options, { @@ -62,10 +83,13 @@ export default class PostMessageView extends React.Component { }); return ( - <span - onClick={Utils.handleFormattedTextClick} - dangerouslySetInnerHTML={{__html: TextFormatting.formatText(this.props.message, options)}} - /> + <div> + <span + onClick={Utils.handleFormattedTextClick} + dangerouslySetInnerHTML={{__html: TextFormatting.formatText(this.props.post.message, options)}} + /> + {this.editedIndicator()} + </div> ); } } diff --git a/webapp/components/profile_popover.jsx b/webapp/components/profile_popover.jsx index 7cb2f7261..22cf60004 100644 --- a/webapp/components/profile_popover.jsx +++ b/webapp/components/profile_popover.jsx @@ -83,6 +83,9 @@ export default class ProfilePopover extends React.Component { openDirectChannelToUser( user, (channel) => { + if (Utils.isMobile()) { + GlobalActions.emitCloseRightHandSide(); + } this.setState({loadingDMChannel: -1}); if (this.props.hide) { this.props.hide(); @@ -185,34 +188,34 @@ export default class ProfilePopover extends React.Component { const fullname = Utils.getFullName(this.props.user); if (fullname) { dataContent.push( - <div - data-toggle='tooltip' - title={fullname} - key='user-popover-fullname' + <OverlayTrigger + delayShow={Constants.WEBRTC_TIME_DELAY} + placement='top' + overlay={<Tooltip id='fullNameTooltip'>{fullname}</Tooltip>} > - <p - className='text-nowrap' + <div + className='overflow--ellipsis text-nowrap padding-bottom' > {fullname} - </p> - </div> + </div> + </OverlayTrigger> ); } if (this.props.user.position) { const position = this.props.user.position.substring(0, Constants.MAX_POSITION_LENGTH); dataContent.push( - <div - data-toggle='tooltip' - title={position} - key='user-popover-position' + <OverlayTrigger + delayShow={Constants.WEBRTC_TIME_DELAY} + placement='top' + overlay={<Tooltip id='positionTooltip'>{position}</Tooltip>} > - <p - className='text-nowrap' + <div + className='overflow--ellipsis text-nowrap padding-bottom' > {position} - </p> - </div> + </div> + </OverlayTrigger> ); } diff --git a/webapp/components/rhs_comment.jsx b/webapp/components/rhs_comment.jsx index 8b7642fd8..f83574496 100644 --- a/webapp/components/rhs_comment.jsx +++ b/webapp/components/rhs_comment.jsx @@ -239,7 +239,7 @@ export default class RhsComment extends React.Component { currentUserCss = 'current--user'; } - var timestamp = this.props.currentUser.update_at; + var timestamp = this.props.currentUser.last_picture_update; let status = this.props.status; if (post.props && post.props.from_webhook === 'true') { diff --git a/webapp/components/rhs_root_post.jsx b/webapp/components/rhs_root_post.jsx index 95f5fc1ac..235ed8db7 100644 --- a/webapp/components/rhs_root_post.jsx +++ b/webapp/components/rhs_root_post.jsx @@ -99,7 +99,7 @@ export default class RhsRootPost extends React.Component { var isOwner = this.props.currentUser.id === post.user_id; var isAdmin = TeamStore.isTeamAdminForCurrentTeam() || UserStore.isSystemAdminForCurrentUser(); const isSystemMessage = post.type && post.type.startsWith(Constants.SYSTEM_MESSAGE_PREFIX); - var timestamp = user ? user.update_at : 0; + var timestamp = user ? user.last_picture_update : 0; var channel = ChannelStore.get(post.channel_id); const flagIcon = Constants.FLAG_ICON_SVG; diff --git a/webapp/components/root.jsx b/webapp/components/root.jsx index be50c7d48..465df5d79 100644 --- a/webapp/components/root.jsx +++ b/webapp/components/root.jsx @@ -8,11 +8,12 @@ import Client from 'client/web_client.jsx'; import {IntlProvider} from 'react-intl'; import React from 'react'; - import FastClick from 'fastclick'; +import $ from 'jquery'; import {browserHistory} from 'react-router/es6'; import UserStore from 'stores/user_store.jsx'; +import BrowserStore from 'stores/browser_store.jsx'; export default class Root extends React.Component { constructor(props) { @@ -35,6 +36,30 @@ export default class Root extends React.Component { } /*eslint-enable */ + // Force logout of all tabs if one tab is logged out + $(window).bind('storage', (e) => { + // when one tab on a browser logs out, it sets __logout__ in localStorage to trigger other tabs to log out + if (e.originalEvent.key === '__logout__' && e.originalEvent.storageArea === localStorage && e.originalEvent.newValue) { + // make sure it isn't this tab that is sending the logout signal (only necessary for IE11) + if (BrowserStore.isSignallingLogout(e.originalEvent.newValue)) { + return; + } + + console.log('detected logout from a different tab'); //eslint-disable-line no-console + GlobalActions.emitUserLoggedOutEvent('/', false); + } + + if (e.originalEvent.key === '__login__' && e.originalEvent.storageArea === localStorage && e.originalEvent.newValue) { + // make sure it isn't this tab that is sending the logout signal (only necessary for IE11) + if (BrowserStore.isSignallingLogin(e.originalEvent.newValue)) { + return; + } + + console.log('detected login from a different tab'); //eslint-disable-line no-console + location.reload(); + } + }); + // Fastclick FastClick.attach(document.body); } diff --git a/webapp/components/search_results.jsx b/webapp/components/search_results.jsx index a0245b7e4..86d1bac1d 100644 --- a/webapp/components/search_results.jsx +++ b/webapp/components/search_results.jsx @@ -124,6 +124,12 @@ export default class SearchResults extends React.Component { window.removeEventListener('resize', this.handleResize); } + componentDidUpdate(prevProps, prevState) { + if (this.state.searchTerm !== prevState.searchTerm) { + this.resize(); + } + } + handleResize() { this.setState({ windowWidth: Utils.windowWidth(), diff --git a/webapp/components/search_results_item.jsx b/webapp/components/search_results_item.jsx index 76681959e..be62653c0 100644 --- a/webapp/components/search_results_item.jsx +++ b/webapp/components/search_results_item.jsx @@ -62,7 +62,7 @@ export default class SearchResultsItem extends React.Component { render() { let channelName = null; const channel = this.props.channel; - const timestamp = UserStore.getCurrentUser().update_at; + const timestamp = UserStore.getCurrentUser().last_picture_update; const user = this.props.user || {}; const post = this.props.post; const flagIcon = Constants.FLAG_ICON_SVG; @@ -285,7 +285,7 @@ export default class SearchResultsItem extends React.Component { </li> {rhsControls} </ul> - <div className='search-item-snippet'> + <div className='search-item-snippet post__body'> {message} </div> </div> diff --git a/webapp/components/setting_item_max.jsx b/webapp/components/setting_item_max.jsx index 904e6c8d1..5971ce584 100644 --- a/webapp/components/setting_item_max.jsx +++ b/webapp/components/setting_item_max.jsx @@ -49,7 +49,7 @@ export default class SettingItemMax extends React.Component { submit = ( <input type='submit' - className='btn btn-sm btn-primary' + className='btn btn-sm btn-primary pull-right' href='#' onClick={this.props.submit} value={Utils.localizeMessage('setting_item_max.save', 'Save')} @@ -88,7 +88,7 @@ export default class SettingItemMax extends React.Component { {clientError} {submit} <a - className='btn btn-sm theme' + className='btn btn-sm pull-right' href='#' onClick={this.props.updateSection} > diff --git a/webapp/components/setting_picture.jsx b/webapp/components/setting_picture.jsx index b74ee8eb7..d1ff60c6a 100644 --- a/webapp/components/setting_picture.jsx +++ b/webapp/components/setting_picture.jsx @@ -73,7 +73,7 @@ export default class SettingPicture extends React.Component { /> ); } else { - var confirmButtonClass = 'btn btn-sm'; + var confirmButtonClass = 'btn btn-sm pull-right'; if (this.props.submitActive) { confirmButtonClass += ' btn-primary'; } else { @@ -132,7 +132,7 @@ export default class SettingPicture extends React.Component { </span> {confirmButton} <a - className='btn btn-sm theme' + className='btn btn-sm theme pull-right' href='#' onClick={self.props.updateSection} > diff --git a/webapp/components/sidebar_header.jsx b/webapp/components/sidebar_header.jsx index a5fbd2659..ded3b5d1a 100644 --- a/webapp/components/sidebar_header.jsx +++ b/webapp/components/sidebar_header.jsx @@ -10,7 +10,7 @@ import * as Utils from 'utils/utils.jsx'; import SidebarHeaderDropdown from './sidebar_header_dropdown.jsx'; import {Tooltip, OverlayTrigger} from 'react-bootstrap'; -import {Preferences, TutorialSteps} from 'utils/constants.jsx'; +import {Preferences, TutorialSteps, OVERLAY_TIME_DELAY} from 'utils/constants.jsx'; import {createMenuTip} from 'components/tutorial/tutorial_tip.jsx'; export default class SidebarHeader extends React.Component { @@ -59,7 +59,7 @@ export default class SidebarHeader extends React.Component { profilePicture = ( <img className='user__picture' - src={Client.getUsersRoute() + '/' + me.id + '/image?time=' + me.update_at} + src={Client.getUsersRoute() + '/' + me.id + '/image?time=' + me.last_picture_update} /> ); } @@ -78,7 +78,7 @@ export default class SidebarHeader extends React.Component { teamNameWithToolTip = ( <OverlayTrigger trigger={['hover', 'focus']} - delayShow={1000} + delayShow={OVERLAY_TIME_DELAY} placement='bottom' overlay={<Tooltip id='team-name__tooltip'>{this.props.teamDescription}</Tooltip>} ref='descriptionOverlay' @@ -91,16 +91,13 @@ export default class SidebarHeader extends React.Component { return ( <div className='team__header theme'> {tutorialTip} - <a - href='#' - onClick={this.toggleDropdown} - > + <div> {profilePicture} <div className='header__info'> <div className='user__name'>{'@' + me.username}</div> {teamNameWithToolTip} </div> - </a> + </div> <SidebarHeaderDropdown ref='dropdown' teamType={this.props.teamType} diff --git a/webapp/components/suggestion/at_mention_provider.jsx b/webapp/components/suggestion/at_mention_provider.jsx index 9263c6e50..f90266d95 100644 --- a/webapp/components/suggestion/at_mention_provider.jsx +++ b/webapp/components/suggestion/at_mention_provider.jsx @@ -70,7 +70,7 @@ class AtMentionSuggestion extends Suggestion { icon = ( <img className='mention__image' - src={Client.getUsersRoute() + '/' + user.id + '/image?time=' + user.update_at} + src={Client.getUsersRoute() + '/' + user.id + '/image?time=' + user.last_picture_update} /> ); } diff --git a/webapp/components/suggestion/search_user_provider.jsx b/webapp/components/suggestion/search_user_provider.jsx index bff59ace8..70808ca26 100644 --- a/webapp/components/suggestion/search_user_provider.jsx +++ b/webapp/components/suggestion/search_user_provider.jsx @@ -41,7 +41,7 @@ class SearchUserSuggestion extends Suggestion { <i className='fa fa fa-plus-square'/> <img className='profile-img rounded' - src={Client.getUsersRoute() + '/' + item.id + '/image?time=' + item.update_at} + src={Client.getUsersRoute() + '/' + item.id + '/image?time=' + item.last_picture_update} /> <div className='mention--align'> <span> diff --git a/webapp/components/suggestion/switch_channel_provider.jsx b/webapp/components/suggestion/switch_channel_provider.jsx index 301974b9a..0bc30a79f 100644 --- a/webapp/components/suggestion/switch_channel_provider.jsx +++ b/webapp/components/suggestion/switch_channel_provider.jsx @@ -35,7 +35,7 @@ class SwitchChannelSuggestion extends Suggestion { <div className='pull-left'> <img className='mention__image' - src={Client.getUsersRoute() + '/' + item.id + '/image?time=' + item.update_at} + src={Client.getUsersRoute() + '/' + item.id + '/image?time=' + item.last_picture_update} /> </div> ); diff --git a/webapp/components/user_list_row.jsx b/webapp/components/user_list_row.jsx index ff381a30b..3a13ccb66 100644 --- a/webapp/components/user_list_row.jsx +++ b/webapp/components/user_list_row.jsx @@ -64,7 +64,7 @@ export default function UserListRow({user, extraInfo, actions, actionProps, acti className='more-modal__row' > <ProfilePicture - src={`${Client.getUsersRoute()}/${user.id}/image?time=${user.update_at}`} + src={`${Client.getUsersRoute()}/${user.id}/image?time=${user.last_picture_update}`} status={status} width='32' height='32' diff --git a/webapp/components/user_profile.jsx b/webapp/components/user_profile.jsx index d0267c0d8..d9bd5c378 100644 --- a/webapp/components/user_profile.jsx +++ b/webapp/components/user_profile.jsx @@ -56,7 +56,7 @@ export default class UserProfile extends React.Component { let profileImg = ''; if (this.props.user) { name = Utils.displayUsername(this.props.user.id); - profileImg = Client.getUsersRoute() + '/' + this.props.user.id + '/image?time=' + this.props.user.update_at; + profileImg = Client.getUsersRoute() + '/' + this.props.user.id + '/image?time=' + this.props.user.last_picture_update; } if (this.props.overwriteName) { diff --git a/webapp/components/user_settings/user_settings_security.jsx b/webapp/components/user_settings/user_settings_security.jsx index 3484b8183..e936f5b96 100644 --- a/webapp/components/user_settings/user_settings_security.jsx +++ b/webapp/components/user_settings/user_settings_security.jsx @@ -14,6 +14,8 @@ import * as AsyncClient from 'utils/async_client.jsx'; import * as Utils from 'utils/utils.jsx'; import Constants from 'utils/constants.jsx'; +import {updatePassword} from 'actions/user_actions.jsx'; + import $ from 'jquery'; import React from 'react'; import {FormattedMessage, FormattedTime, FormattedDate} from 'react-intl'; @@ -91,7 +93,7 @@ export default class SecurityTab extends React.Component { return; } - Client.updatePassword( + updatePassword( user.id, currentPassword, newPassword, @@ -425,6 +427,34 @@ export default class SecurityTab extends React.Component { </div> </div> ); + } else if (this.props.user.auth_service === Constants.GOOGLE_SERVICE) { + inputs.push( + <div + key='oauthEmailInfo' + className='form-group' + > + <div className='setting-list__hint'> + <FormattedMessage + id='user.settings.security.passwordGoogleCantUpdate' + defaultMessage='Login occurs through Google Apps. Password cannot be updated.' + /> + </div> + </div> + ); + } else if (this.props.user.auth_service === Constants.OFFICE365_SERVICE) { + inputs.push( + <div + key='oauthEmailInfo' + className='form-group' + > + <div className='setting-list__hint'> + <FormattedMessage + id='user.settings.security.passwordOffice365CantUpdate' + defaultMessage='Login occurs through Office 365. Password cannot be updated.' + /> + </div> + </div> + ); } updateSectionStatus = function resetSection(e) { @@ -502,6 +532,20 @@ export default class SecurityTab extends React.Component { defaultMessage='Login done through SAML' /> ); + } else if (this.props.user.auth_service === Constants.GOOGLE_SERVICE) { + describe = ( + <FormattedMessage + id='user.settings.security.loginGoogle' + defaultMessage='Login done through Google Apps' + /> + ); + } else if (this.props.user.auth_service === Constants.OFFICE365_SERVICE) { + describe = ( + <FormattedMessage + id='user.settings.security.loginOffice365' + defaultMessage='Login done through Office 365' + /> + ); } updateSectionStatus = function updateSection() { diff --git a/webapp/components/webrtc/components/webrtc_notification.jsx b/webapp/components/webrtc/components/webrtc_notification.jsx index 5456d6cb8..f69e731f8 100644 --- a/webapp/components/webrtc/components/webrtc_notification.jsx +++ b/webapp/components/webrtc/components/webrtc_notification.jsx @@ -197,7 +197,7 @@ export default class WebrtcNotification extends React.Component { const user = this.state.userCalling; if (user) { const username = Utils.displayUsername(user.id); - const profileImgSrc = Client.getUsersRoute() + '/' + user.id + '/image?time=' + (user.update_at || new Date().getTime()); + const profileImgSrc = Client.getUsersRoute() + '/' + user.id + '/image?time=' + (user.last_picture_update || new Date().getTime()); const profileImg = ( <img className='user-popover__image' diff --git a/webapp/components/webrtc/webrtc_controller.jsx b/webapp/components/webrtc/webrtc_controller.jsx index 94e5b3475..03953a19a 100644 --- a/webapp/components/webrtc/webrtc_controller.jsx +++ b/webapp/components/webrtc/webrtc_controller.jsx @@ -81,14 +81,14 @@ export default class WebrtcController extends React.Component { const currentUser = UserStore.getCurrentUser(); const remoteUser = UserStore.getProfile(props.userId); - const remoteUserImage = Client.getUsersRoute() + '/' + remoteUser.id + '/image?time=' + remoteUser.update_at; + const remoteUserImage = Client.getUsersRoute() + '/' + remoteUser.id + '/image?time=' + remoteUser.last_picture_update; this.state = { windowWidth: Utils.windowWidth(), windowHeight: Utils.windowHeight(), channelId: ChannelStore.getCurrentId(), currentUser, - currentUserImage: Client.getUsersRoute() + '/' + currentUser.id + '/image?time=' + currentUser.update_at, + currentUserImage: Client.getUsersRoute() + '/' + currentUser.id + '/image?time=' + currentUser.last_picture_update, remoteUserImage, localMediaLoaded: false, isPaused: false, @@ -130,7 +130,7 @@ export default class WebrtcController extends React.Component { (nextProps.userId !== this.props.userId) || (nextProps.isCaller !== this.props.isCaller)) { const remoteUser = UserStore.getProfile(nextProps.userId); - const remoteUserImage = Client.getUsersRoute() + '/' + remoteUser.id + '/image?time=' + remoteUser.update_at; + const remoteUserImage = Client.getUsersRoute() + '/' + remoteUser.id + '/image?time=' + remoteUser.last_picture_update; this.setState({ error: null, remoteUserImage |