import Component from 'flarum/Component'; import avatar from 'flarum/helpers/avatar'; import icon from 'flarum/helpers/icon'; import listItems from 'flarum/helpers/listItems'; import ItemList from 'flarum/utils/ItemList'; import Button from 'flarum/components/Button'; import LoadingIndicator from 'flarum/components/LoadingIndicator'; /** * The `AvatarEditor` component displays a user's avatar along with a dropdown * menu which allows the user to upload/remove the avatar. * * ### Props * * - `className` * - `user` */ export default class AvatarEditor extends Component { constructor(...args) { super(...args); /** * Whether or not an avatar upload is in progress. * * @type {Boolean} */ this.loading = false; } static initProps(props) { super.initProps(props); props.className = props.className || ''; } view() { const user = this.props.user; return (
{avatar(user)} {this.loading ? LoadingIndicator.component() : icon('pencil')}
); } /** * Get the items in the edit avatar dropdown menu. * * @return {ItemList} */ controlItems() { const items = new ItemList(); items.add('upload', Button.component({ icon: 'upload', children: app.trans('core.upload'), onclick: this.upload.bind(this) }) ); items.add('remove', Button.component({ icon: 'times', children: app.trans('core.remove'), onclick: this.remove.bind(this) }) ); return items; } /** * If the user doesn't have an avatar, there's no point in showing the * controls dropdown, because only one option would be viable: uploading. * Thus, when the avatar editor's dropdown toggle button is clicked, we prompt * the user to upload an avatar immediately. * * @param {Event} e */ quickUpload(e) { if (!this.props.user.avatarUrl()) { e.preventDefault(); e.stopPropagation(); this.upload(); } } /** * Prompt the user to upload a new avatar. */ upload() { if (this.loading) return; // Create a hidden HTML input element and click on it so the user can select // an avatar file. Once they have, we will upload it via the API. const user = this.props.user; const $input = $(''); $input.appendTo('body').hide().click().on('change', e => { const data = new FormData(); data.append('avatar', $(e.target)[0].files[0]); this.loading = true; m.redraw(); app.request({ method: 'POST', url: app.forum.attribute('apiUrl') + '/users/' + user.id() + '/avatar', serialize: raw => raw, data }).then( this.success.bind(this), this.failure.bind(this) ); }); } /** * Remove the user's avatar. */ remove() { const user = this.props.user; this.loading = true; m.redraw(); app.request({ method: 'DELETE', url: app.forum.attribute('apiUrl') + '/users/' + user.id() + '/avatar' }).then( this.success.bind(this), this.failure.bind(this) ); } /** * After a successful upload/removal, push the updated user data into the * store, and force a recomputation of the user's avatar color. * * @param {Object} response * @protected */ success(response) { app.store.pushPayload(response); delete this.props.user.avatarColor; this.loading = false; m.redraw(); } /** * If avatar upload/removal fails, stop loading. * * @param {Object} response * @protected */ failure() { this.loading = false; } }