mirror of https://github.com/vector-im/riot-web
				
				
				
			Move status context menu to its own component
This fixes a lot of the state bugs such as buttons not updating, etc. This commit also adds the border around the avatar to indicate a status is set.pull/21833/head
							parent
							
								
									99f5b9e39b
								
							
						
					
					
						commit
						b0b7932f5f
					
				| 
						 | 
				
			
			@ -27,6 +27,7 @@
 | 
			
		|||
@import "./views/avatars/_MemberStatusMessageAvatar.scss";
 | 
			
		||||
@import "./views/context_menus/_MessageContextMenu.scss";
 | 
			
		||||
@import "./views/context_menus/_RoomTileContextMenu.scss";
 | 
			
		||||
@import "./views/context_menus/_StatusMessageContextMenu.scss";
 | 
			
		||||
@import "./views/context_menus/_TagTileContextMenu.scss";
 | 
			
		||||
@import "./views/dialogs/_BugReportDialog.scss";
 | 
			
		||||
@import "./views/dialogs/_ChangelogDialog.scss";
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,38 +14,7 @@ See the License for the specific language governing permissions and
 | 
			
		|||
limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
.mx_MemberStatusMessageAvatar_contextMenu_message {
 | 
			
		||||
    display: inline-block;
 | 
			
		||||
    border-radius: 3px 0 0 3px;
 | 
			
		||||
    border: 1px solid $input-border-color;
 | 
			
		||||
    font-size: 13px;
 | 
			
		||||
    padding: 7px 7px 7px 9px;
 | 
			
		||||
    width: 135px;
 | 
			
		||||
    background-color: $primary-bg-color !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.mx_MemberStatusMessageAvatar_contextMenu_submit {
 | 
			
		||||
    display: inline-block;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.mx_MemberStatusMessageAvatar_contextMenu_submit img {
 | 
			
		||||
    vertical-align: middle;
 | 
			
		||||
    margin-left: 8px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.mx_MemberStatusMessageAvatar_contextMenu hr {
 | 
			
		||||
    border: 0.5px solid $menu-border-color;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.mx_MemberStatusMessageAvatar_contextMenu_clearIcon {
 | 
			
		||||
    margin: 5px 15px 5px 5px;
 | 
			
		||||
    vertical-align: middle;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.mx_MemberStatusMessageAvatar_contextMenu_clear {
 | 
			
		||||
    padding: 2px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.mx_MemberStatusMessageAvatar_contextMenu_hasStatus .mx_MemberStatusMessageAvatar_contextMenu_clear {
 | 
			
		||||
    color: $warning-color;
 | 
			
		||||
.mx_MemberStatusMessageAvatar_hasStatus {
 | 
			
		||||
    border: 2px solid $accent-color;
 | 
			
		||||
    border-radius: 40px;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,51 @@
 | 
			
		|||
/*
 | 
			
		||||
Copyright 2018 New Vector Ltd
 | 
			
		||||
 | 
			
		||||
Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
you may not use this file except in compliance with the License.
 | 
			
		||||
You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
See the License for the specific language governing permissions and
 | 
			
		||||
limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
.mx_StatusMessageContextMenu_message {
 | 
			
		||||
    display: inline-block;
 | 
			
		||||
    border-radius: 3px 0 0 3px;
 | 
			
		||||
    border: 1px solid $input-border-color;
 | 
			
		||||
    font-size: 13px;
 | 
			
		||||
    padding: 7px 7px 7px 9px;
 | 
			
		||||
    width: 135px;
 | 
			
		||||
    background-color: $primary-bg-color !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.mx_StatusMessageContextMenu_submit {
 | 
			
		||||
    display: inline-block;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.mx_StatusMessageContextMenu_submit img {
 | 
			
		||||
    vertical-align: middle;
 | 
			
		||||
    margin-left: 8px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.mx_StatusMessageContextMenu hr {
 | 
			
		||||
    border: 0.5px solid $menu-border-color;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.mx_StatusMessageContextMenu_clearIcon {
 | 
			
		||||
    margin: 5px 15px 5px 5px;
 | 
			
		||||
    vertical-align: middle;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.mx_StatusMessageContextMenu_clear {
 | 
			
		||||
    padding: 2px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.mx_StatusMessageContextMenu_hasStatus .mx_StatusMessageContextMenu_clear {
 | 
			
		||||
    color: $warning-color;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -16,22 +16,18 @@ limitations under the License.
 | 
			
		|||
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import PropTypes from 'prop-types';
 | 
			
		||||
import { _t } from '../../../languageHandler';
 | 
			
		||||
import MatrixClientPeg from '../../../MatrixClientPeg';
 | 
			
		||||
import AccessibleButton from '../elements/AccessibleButton';
 | 
			
		||||
import MemberAvatar from '../avatars/MemberAvatar';
 | 
			
		||||
import classNames from 'classnames';
 | 
			
		||||
import * as ContextualMenu from "../../structures/ContextualMenu";
 | 
			
		||||
import GenericElementContextMenu from "../context_menus/GenericElementContextMenu";
 | 
			
		||||
import StatusMessageContextMenu from "../context_menus/StatusMessageContextMenu";
 | 
			
		||||
 | 
			
		||||
export default class MemberStatusMessageAvatar extends React.Component {
 | 
			
		||||
    constructor(props, context) {
 | 
			
		||||
        super(props, context);
 | 
			
		||||
        this._onRoomStateEvents = this._onRoomStateEvents.bind(this);
 | 
			
		||||
        this._onClick = this._onClick.bind(this);
 | 
			
		||||
        this._onClearClick = this._onClearClick.bind(this);
 | 
			
		||||
        this._onSubmit = this._onSubmit.bind(this);
 | 
			
		||||
        this._onStatusChange = this._onStatusChange.bind(this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    componentWillMount() {
 | 
			
		||||
| 
						 | 
				
			
			@ -75,64 +71,16 @@ export default class MemberStatusMessageAvatar extends React.Component {
 | 
			
		|||
        let y = elementRect.top + (elementRect.height / 2) + window.pageYOffset;
 | 
			
		||||
        y = y - (chevronOffset + 4); // where 4 is 1/4 the height of the chevron
 | 
			
		||||
 | 
			
		||||
        const contextMenu = this._renderContextMenu();
 | 
			
		||||
 | 
			
		||||
        ContextualMenu.createMenu(GenericElementContextMenu, {
 | 
			
		||||
        ContextualMenu.createMenu(StatusMessageContextMenu, {
 | 
			
		||||
            chevronOffset: chevronOffset,
 | 
			
		||||
            chevronFace: 'bottom',
 | 
			
		||||
            left: x,
 | 
			
		||||
            top: y,
 | 
			
		||||
            menuWidth: 190,
 | 
			
		||||
            element: contextMenu,
 | 
			
		||||
            user: this.props.member.user,
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async _onClearClick(e) {
 | 
			
		||||
        await MatrixClientPeg.get().setStatusMessage("");
 | 
			
		||||
        this.setState({message: ""});
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _onSubmit(e) {
 | 
			
		||||
        e.preventDefault();
 | 
			
		||||
        MatrixClientPeg.get().setStatusMessage(this.state.message);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _onStatusChange(e) {
 | 
			
		||||
        this.setState({message: e.target.value});
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _renderContextMenu() {
 | 
			
		||||
        const form = <form className="mx_MemberStatusMessageAvatar_contextMenu_form" onSubmit={this._onSubmit}>
 | 
			
		||||
            <input type="text" key="message" placeholder={_t("Set a new status...")}
 | 
			
		||||
                   className="mx_MemberStatusMessageAvatar_contextMenu_message"
 | 
			
		||||
                   defaultValue={this.state.message} onChange={this._onStatusChange} maxLength="60"
 | 
			
		||||
            />
 | 
			
		||||
            <AccessibleButton onClick={this._onSubmit} element="div" className="mx_MemberStatusMessageAvatar_contextMenu_submit">
 | 
			
		||||
                <img src="img/icons-checkmark.svg" width="22" height="22" />
 | 
			
		||||
            </AccessibleButton>
 | 
			
		||||
        </form>;
 | 
			
		||||
 | 
			
		||||
        const clearIcon = this.state.message ? "img/cancel-red.svg" : "img/cancel.svg";
 | 
			
		||||
        const clearButton = <AccessibleButton onClick={this._onClearClick} disabled={!this.state.message}
 | 
			
		||||
                                              className="mx_MemberStatusMessageAvatar_contextMenu_clear">
 | 
			
		||||
            <img src={clearIcon} alt={_t('Clear status')} width="12" height="12"
 | 
			
		||||
                 className="mx_filterFlipColor mx_MemberStatusMessageAvatar_contextMenu_clearIcon"
 | 
			
		||||
            />
 | 
			
		||||
            <span>{_t("Clear status")}</span>
 | 
			
		||||
        </AccessibleButton>;
 | 
			
		||||
 | 
			
		||||
        const menuClasses = classNames({
 | 
			
		||||
            "mx_MemberStatusMessageAvatar_contextMenu": true,
 | 
			
		||||
            "mx_MemberStatusMessageAvatar_contextMenu_hasStatus": this.state.message,
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        return <div className={menuClasses}>
 | 
			
		||||
            { form }
 | 
			
		||||
            <hr />
 | 
			
		||||
            { clearButton }
 | 
			
		||||
        </div>;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    render() {
 | 
			
		||||
        const hasStatus = this.props.member.user ? !!this.props.member.user.statusMessage : false;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -145,8 +93,7 @@ export default class MemberStatusMessageAvatar extends React.Component {
 | 
			
		|||
            <MemberAvatar member={this.props.member}
 | 
			
		||||
                          width={this.props.width}
 | 
			
		||||
                          height={this.props.height}
 | 
			
		||||
                          resizeMethod={this.props.resizeMethod}
 | 
			
		||||
            />
 | 
			
		||||
                          resizeMethod={this.props.resizeMethod} />
 | 
			
		||||
        </AccessibleButton>;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,84 @@
 | 
			
		|||
/*
 | 
			
		||||
Copyright 2018 New Vector Ltd
 | 
			
		||||
 | 
			
		||||
Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
you may not use this file except in compliance with the License.
 | 
			
		||||
You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
See the License for the specific language governing permissions and
 | 
			
		||||
limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import PropTypes from 'prop-types';
 | 
			
		||||
import { _t } from '../../../languageHandler';
 | 
			
		||||
import MatrixClientPeg from '../../../MatrixClientPeg';
 | 
			
		||||
import AccessibleButton from '../elements/AccessibleButton';
 | 
			
		||||
import classNames from 'classnames';
 | 
			
		||||
 | 
			
		||||
export default class StatusMessageContextMenu extends React.Component {
 | 
			
		||||
    constructor(props, context) {
 | 
			
		||||
        super(props, context);
 | 
			
		||||
        this._onClearClick = this._onClearClick.bind(this);
 | 
			
		||||
        this._onSubmit = this._onSubmit.bind(this);
 | 
			
		||||
        this._onStatusChange = this._onStatusChange.bind(this);
 | 
			
		||||
 | 
			
		||||
        this.state = {
 | 
			
		||||
            message: props.user ? props.user.statusMessage : "",
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async _onClearClick(e) {
 | 
			
		||||
        await MatrixClientPeg.get().setStatusMessage("");
 | 
			
		||||
        this.setState({message: ""});
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _onSubmit(e) {
 | 
			
		||||
        e.preventDefault();
 | 
			
		||||
        MatrixClientPeg.get().setStatusMessage(this.state.message);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _onStatusChange(e) {
 | 
			
		||||
        this.setState({message: e.target.value});
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    render() {
 | 
			
		||||
        const form = <form className="mx_StatusMessageContextMenu_form" onSubmit={this._onSubmit}>
 | 
			
		||||
            <input type="text" key="message" placeholder={_t("Set a new status...")} autoFocus={true}
 | 
			
		||||
                   className="mx_StatusMessageContextMenu_message"
 | 
			
		||||
                   value={this.state.message} onChange={this._onStatusChange} maxLength="60" />
 | 
			
		||||
            <AccessibleButton onClick={this._onSubmit} element="div" className="mx_StatusMessageContextMenu_submit">
 | 
			
		||||
                <img src="img/icons-checkmark.svg" width="22" height="22" />
 | 
			
		||||
            </AccessibleButton>
 | 
			
		||||
        </form>;
 | 
			
		||||
 | 
			
		||||
        const clearIcon = this.state.message ? "img/cancel-red.svg" : "img/cancel.svg";
 | 
			
		||||
        const clearButton = <AccessibleButton onClick={this._onClearClick} disabled={!this.state.message}
 | 
			
		||||
                                              className="mx_StatusMessageContextMenu_clear">
 | 
			
		||||
            <img src={clearIcon} alt={_t('Clear status')} width="12" height="12"
 | 
			
		||||
                 className="mx_filterFlipColor mx_StatusMessageContextMenu_clearIcon" />
 | 
			
		||||
            <span>{_t("Clear status")}</span>
 | 
			
		||||
        </AccessibleButton>;
 | 
			
		||||
 | 
			
		||||
        const menuClasses = classNames({
 | 
			
		||||
            "mx_StatusMessageContextMenu": true,
 | 
			
		||||
            "mx_StatusMessageContextMenu_hasStatus": this.state.message,
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        return <div className={menuClasses}>
 | 
			
		||||
            { form }
 | 
			
		||||
            <hr />
 | 
			
		||||
            { clearButton }
 | 
			
		||||
        </div>;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
StatusMessageContextMenu.propTypes = {
 | 
			
		||||
    // js-sdk User object. Not required because it might not exist.
 | 
			
		||||
    user: PropTypes.object,
 | 
			
		||||
};
 | 
			
		||||
		Loading…
	
		Reference in New Issue