about summary refs log tree commit diff
diff options
context:
space:
mode:
authorThibaut Girka <thib@sitedethib.com>2019-04-21 12:09:52 +0200
committerThibG <thib@sitedethib.com>2019-04-22 20:15:47 +0200
commita243567a3e6100d65477162308e2c1bb5e056c21 (patch)
treee308927e5453acd62e09f6b6de05c269c362d5b8
parentc5f49a92dce9157debf3a68487dd30b6f0af6c4a (diff)
ComposerUploadForm → UploadForm + UploadFormContainer
-rw-r--r--app/javascript/flavours/glitch/features/compose/components/compose_form.js28
-rw-r--r--app/javascript/flavours/glitch/features/compose/components/upload.js131
-rw-r--r--app/javascript/flavours/glitch/features/compose/components/upload_form.js28
-rw-r--r--app/javascript/flavours/glitch/features/compose/components/upload_progress.js42
-rw-r--r--app/javascript/flavours/glitch/features/compose/containers/compose_form_container.js12
-rw-r--r--app/javascript/flavours/glitch/features/compose/containers/upload_container.js31
-rw-r--r--app/javascript/flavours/glitch/features/compose/containers/upload_form_container.js8
-rw-r--r--app/javascript/flavours/glitch/features/compose/containers/upload_progress_container.js9
-rw-r--r--app/javascript/flavours/glitch/features/composer/upload_form/index.js60
-rw-r--r--app/javascript/flavours/glitch/features/composer/upload_form/item/index.js202
-rw-r--r--app/javascript/flavours/glitch/features/composer/upload_form/progress/index.js52
11 files changed, 251 insertions, 352 deletions
diff --git a/app/javascript/flavours/glitch/features/compose/components/compose_form.js b/app/javascript/flavours/glitch/features/compose/components/compose_form.js
index ccbcba571..ecd1aed69 100644
--- a/app/javascript/flavours/glitch/features/compose/components/compose_form.js
+++ b/app/javascript/flavours/glitch/features/compose/components/compose_form.js
@@ -8,7 +8,7 @@ import ImmutablePureComponent from 'react-immutable-pure-component';
 import ComposerOptions from '../../composer/options';
 import ComposerPublisher from '../../composer/publisher';
 import ComposerTextarea from '../../composer/textarea';
-import ComposerUploadForm from '../../composer/upload_form';
+import UploadFormContainer from '../containers/upload_form_container';
 import PollFormContainer from '../containers/poll_form_container';
 import WarningContainer from '../containers/warning_container';
 import ReplyIndicatorContainer from '../containers/reply_indicator_container';
@@ -48,7 +48,6 @@ class ComposeForm extends ImmutablePureComponent {
     media: ImmutablePropTypes.list,
     preselectDate: PropTypes.instanceOf(Date),
     privacy: PropTypes.string,
-    progress: PropTypes.number,
     resetFileKey: PropTypes.number,
     sideArm: PropTypes.string,
     sensitive: PropTypes.bool,
@@ -65,7 +64,6 @@ class ComposeForm extends ImmutablePureComponent {
 
     //  Dispatch props.
     onChangeAdvancedOption: PropTypes.func,
-    onChangeDescription: PropTypes.func,
     onChangeSensitivity: PropTypes.func,
     onChangeSpoilerText: PropTypes.func,
     onChangeSpoilerness: PropTypes.func,
@@ -80,7 +78,6 @@ class ComposeForm extends ImmutablePureComponent {
     onOpenDoodleModal: PropTypes.func,
     onSelectSuggestion: PropTypes.func,
     onSubmit: PropTypes.func,
-    onUndoUpload: PropTypes.func,
     onUnmount: PropTypes.func,
     onUpload: PropTypes.func,
     onMediaDescriptionConfirm: PropTypes.func,
@@ -185,11 +182,6 @@ class ComposeForm extends ImmutablePureComponent {
     }
   }
 
-  //  Sets a reference to the upload form.
-  handleRefUploadForm = (uploadFormComponent) => {
-    this.uploadForm = uploadFormComponent;
-  }
-
   //  Sets a reference to the textarea.
   handleRefTextarea = (textareaComponent) => {
     if (textareaComponent) {
@@ -283,7 +275,6 @@ class ComposeForm extends ImmutablePureComponent {
       handleSecondarySubmit,
       handleSelect,
       handleSubmit,
-      handleRefUploadForm,
       handleRefTextarea,
     } = this;
     const {
@@ -299,7 +290,6 @@ class ComposeForm extends ImmutablePureComponent {
       media,
       poll,
       onChangeAdvancedOption,
-      onChangeDescription,
       onChangeSensitivity,
       onChangeSpoilerness,
       onChangeText,
@@ -310,11 +300,8 @@ class ComposeForm extends ImmutablePureComponent {
       onFetchSuggestions,
       onOpenActionsModal,
       onOpenDoodleModal,
-      onOpenFocalPointModal,
-      onUndoUpload,
       onUpload,
       privacy,
-      progress,
       resetFileKey,
       sensitive,
       showSearch,
@@ -370,18 +357,7 @@ class ComposeForm extends ImmutablePureComponent {
           value={text}
         />
         <div className='compose-form__modifiers'>
-          {isUploading || media && media.size ? (
-            <ComposerUploadForm
-              intl={intl}
-              media={media}
-              onChangeDescription={onChangeDescription}
-              onOpenFocalPointModal={onOpenFocalPointModal}
-              onRemove={onUndoUpload}
-              progress={progress}
-              uploading={isUploading}
-              handleRef={handleRefUploadForm}
-            />
-          ) : null}
+          <UploadFormContainer />
           <PollFormContainer />
         </div>
         <ComposerOptions
diff --git a/app/javascript/flavours/glitch/features/compose/components/upload.js b/app/javascript/flavours/glitch/features/compose/components/upload.js
new file mode 100644
index 000000000..84edf664e
--- /dev/null
+++ b/app/javascript/flavours/glitch/features/compose/components/upload.js
@@ -0,0 +1,131 @@
+import React from 'react';
+import ImmutablePropTypes from 'react-immutable-proptypes';
+import PropTypes from 'prop-types';
+import Motion from 'flavours/glitch/util/optional_motion';
+import spring from 'react-motion/lib/spring';
+import ImmutablePureComponent from 'react-immutable-pure-component';
+import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
+import classNames from 'classnames';
+import Icon from 'flavours/glitch/components/icon';
+import { isUserTouching } from 'flavours/glitch/util/is_mobile';
+
+const messages = defineMessages({
+  description: { id: 'upload_form.description', defaultMessage: 'Describe for the visually impaired' },
+});
+
+//  The component.
+export default @injectIntl
+class Upload extends ImmutablePureComponent {
+
+  static contextTypes = {
+    router: PropTypes.object,
+  };
+
+  static propTypes = {
+    media: ImmutablePropTypes.map.isRequired,
+    intl: PropTypes.object.isRequired,
+    onUndo: PropTypes.func.isRequired,
+    onDescriptionChange: PropTypes.func.isRequired,
+    onOpenFocalPoint: PropTypes.func.isRequired,
+    onSubmit: PropTypes.func.isRequired,
+  };
+
+  state = {
+    hovered: false,
+    focused: false,
+    dirtyDescription: null,
+  };
+
+  handleKeyDown = (e) => {
+    if (e.keyCode === 13 && (e.ctrlKey || e.metaKey)) {
+      this.handleSubmit();
+    }
+  }
+
+  handleSubmit = () => {
+    this.handleInputBlur();
+    this.props.onSubmit(this.context.router.history);
+  }
+
+  handleUndoClick = e => {
+    e.stopPropagation();
+    this.props.onUndo(this.props.media.get('id'));
+  }
+
+  handleFocalPointClick = e => {
+    e.stopPropagation();
+    this.props.onOpenFocalPoint(this.props.media.get('id'));
+  }
+
+  handleInputChange = e => {
+    this.setState({ dirtyDescription: e.target.value });
+  }
+
+  handleMouseEnter = () => {
+    this.setState({ hovered: true });
+  }
+
+  handleMouseLeave = () => {
+    this.setState({ hovered: false });
+  }
+
+  handleInputFocus = () => {
+    this.setState({ focused: true });
+  }
+
+  handleClick = () => {
+    this.setState({ focused: true });
+  }
+
+  handleInputBlur = () => {
+    const { dirtyDescription } = this.state;
+
+    this.setState({ focused: false, dirtyDescription: null });
+
+    if (dirtyDescription !== null) {
+      this.props.onDescriptionChange(this.props.media.get('id'), dirtyDescription);
+    }
+  }
+
+  render () {
+    const { intl, media } = this.props;
+    const active          = this.state.hovered || this.state.focused || isUserTouching();
+    const description     = this.state.dirtyDescription || (this.state.dirtyDescription !== '' && media.get('description')) || '';
+    const computedClass   = classNames('composer--upload_form--item', { active });
+    const focusX = media.getIn(['meta', 'focus', 'x']);
+    const focusY = media.getIn(['meta', 'focus', 'y']);
+    const x = ((focusX /  2) + .5) * 100;
+    const y = ((focusY / -2) + .5) * 100;
+
+    return (
+      <div className={computedClass} tabIndex='0' onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave} onClick={this.handleClick} role='button'>
+        <Motion defaultStyle={{ scale: 0.8 }} style={{ scale: spring(1, { stiffness: 180, damping: 12, }) }}>
+          {({ scale }) => (
+            <div style={{ transform: `scale(${scale})`, backgroundImage: `url(${media.get('preview_url')})`, backgroundPosition: `${x}% ${y}%` }}>
+              <div className={classNames('composer--upload_form--actions', { active })}>
+                <button className='icon-button' onClick={this.handleUndoClick}><Icon icon='times' /> <FormattedMessage id='upload_form.undo' defaultMessage='Delete' /></button>
+                {media.get('type') === 'image' && <button className='icon-button' onClick={this.handleFocalPointClick}><Icon id='crosshairs' /> <FormattedMessage id='upload_form.focus' defaultMessage='Crop' /></button>}
+              </div>
+
+              <div className={classNames('composer--upload_form--description', { active })}>
+                <label>
+                  <span style={{ display: 'none' }}>{intl.formatMessage(messages.description)}</span>
+                  <textarea
+                    placeholder={intl.formatMessage(messages.description)}
+                    value={description}
+                    maxLength={420}
+                    onFocus={this.handleInputFocus}
+                    onChange={this.handleInputChange}
+                    onBlur={this.handleInputBlur}
+                    onKeyDown={this.handleKeyDown}
+                  />
+                </label>
+              </div>
+            </div>
+          )}
+        </Motion>
+      </div>
+    );
+  }
+
+}
diff --git a/app/javascript/flavours/glitch/features/compose/components/upload_form.js b/app/javascript/flavours/glitch/features/compose/components/upload_form.js
new file mode 100644
index 000000000..a126cc7e4
--- /dev/null
+++ b/app/javascript/flavours/glitch/features/compose/components/upload_form.js
@@ -0,0 +1,28 @@
+import React from 'react';
+import ImmutablePropTypes from 'react-immutable-proptypes';
+import UploadProgressContainer from '../containers/upload_progress_container';
+import ImmutablePureComponent from 'react-immutable-pure-component';
+import UploadContainer from '../containers/upload_container';
+
+export default class UploadForm extends ImmutablePureComponent {
+  static propTypes = {
+    mediaIds: ImmutablePropTypes.list.isRequired,
+  };
+
+  render () {
+    const { mediaIds } = this.props;
+
+    return (
+      <div className='composer--upload_form'>
+        <UploadProgressContainer />
+
+        <div className='content'>
+          {mediaIds.map(id => (
+            <UploadContainer id={id} key={id} />
+          ))}
+        </div>
+      </div>
+    );
+  }
+
+}
diff --git a/app/javascript/flavours/glitch/features/compose/components/upload_progress.js b/app/javascript/flavours/glitch/features/compose/components/upload_progress.js
new file mode 100644
index 000000000..264c563f2
--- /dev/null
+++ b/app/javascript/flavours/glitch/features/compose/components/upload_progress.js
@@ -0,0 +1,42 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import Motion from 'flavours/glitch/util/optional_motion';
+import spring from 'react-motion/lib/spring';
+import { FormattedMessage } from 'react-intl';
+import Icon from 'flavours/glitch/components/icon';
+
+export default class UploadProgress extends React.PureComponent {
+
+  static propTypes = {
+    active: PropTypes.bool,
+    progress: PropTypes.number,
+  };
+
+  render () {
+    const { active, progress } = this.props;
+
+    if (!active) {
+      return null;
+    }
+
+    return (
+      <div className='composer--upload_form--progress'>
+        <Icon icon='upload' />
+
+        <div className='message'>
+          <FormattedMessage id='upload_progress.label' defaultMessage='Uploading...' />
+
+          <div className='backdrop'>
+            <Motion defaultStyle={{ width: 0 }} style={{ width: spring(progress) }}>
+              {({ width }) =>
+                (<div className='tracker' style={{ width: `${width}%` }}
+                />)
+              }
+            </Motion>
+          </div>
+        </div>
+      </div>
+    );
+  }
+
+}
diff --git a/app/javascript/flavours/glitch/features/compose/containers/compose_form_container.js b/app/javascript/flavours/glitch/features/compose/containers/compose_form_container.js
index 3293cc226..4716d9435 100644
--- a/app/javascript/flavours/glitch/features/compose/containers/compose_form_container.js
+++ b/app/javascript/flavours/glitch/features/compose/containers/compose_form_container.js
@@ -7,14 +7,12 @@ import {
   changeComposeSpoilerText,
   changeComposeSpoilerness,
   changeComposeVisibility,
-  changeUploadCompose,
   clearComposeSuggestions,
   fetchComposeSuggestions,
   insertEmojiCompose,
   mountCompose,
   selectComposeSuggestion,
   submitCompose,
-  undoUploadCompose,
   unmountCompose,
   uploadCompose,
 } from 'flavours/glitch/actions/compose';
@@ -66,7 +64,6 @@ function mapStateToProps (state) {
     media: state.getIn(['compose', 'media_attachments']),
     preselectDate: state.getIn(['compose', 'preselectDate']),
     privacy: state.getIn(['compose', 'privacy']),
-    progress: state.getIn(['compose', 'progress']),
     resetFileKey: state.getIn(['compose', 'resetFileKey']),
     sideArm: sideArmPrivacy,
     sensitive: state.getIn(['compose', 'sensitive']),
@@ -89,9 +86,6 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
   onChangeAdvancedOption(option, value) {
     dispatch(changeComposeAdvancedOption(option, value));
   },
-  onChangeDescription(id, description) {
-    dispatch(changeUploadCompose(id, { description }));
-  },
   onChangeSensitivity() {
     dispatch(changeComposeSensitivity());
   },
@@ -137,9 +131,6 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
   onOpenDoodleModal() {
     dispatch(openModal('DOODLE', { noEsc: true }));
   },
-  onOpenFocalPointModal(id) {
-    dispatch(openModal('FOCAL_POINT', { id }));
-  },
   onSelectSuggestion(position, token, suggestion) {
     dispatch(selectComposeSuggestion(position, token, suggestion));
   },
@@ -154,9 +145,6 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
   onSubmit(routerHistory) {
     dispatch(submitCompose(routerHistory));
   },
-  onUndoUpload(id) {
-    dispatch(undoUploadCompose(id));
-  },
   onUnmount() {
     dispatch(unmountCompose());
   },
diff --git a/app/javascript/flavours/glitch/features/compose/containers/upload_container.js b/app/javascript/flavours/glitch/features/compose/containers/upload_container.js
new file mode 100644
index 000000000..d6bff63ac
--- /dev/null
+++ b/app/javascript/flavours/glitch/features/compose/containers/upload_container.js
@@ -0,0 +1,31 @@
+import { connect } from 'react-redux';
+import Upload from '../components/upload';
+import { undoUploadCompose, changeUploadCompose } from 'flavours/glitch/actions/compose';
+import { openModal } from 'flavours/glitch/actions/modal';
+import { submitCompose } from 'flavours/glitch/actions/compose';
+
+const mapStateToProps = (state, { id }) => ({
+  media: state.getIn(['compose', 'media_attachments']).find(item => item.get('id') === id),
+});
+
+const mapDispatchToProps = dispatch => ({
+
+  onUndo: id => {
+    dispatch(undoUploadCompose(id));
+  },
+
+  onDescriptionChange: (id, description) => {
+    dispatch(changeUploadCompose(id, { description }));
+  },
+
+  onOpenFocalPoint: id => {
+    dispatch(openModal('FOCAL_POINT', { id }));
+  },
+
+  onSubmit (router) {
+    dispatch(submitCompose(router));
+  },
+
+});
+
+export default connect(mapStateToProps, mapDispatchToProps)(Upload);
diff --git a/app/javascript/flavours/glitch/features/compose/containers/upload_form_container.js b/app/javascript/flavours/glitch/features/compose/containers/upload_form_container.js
new file mode 100644
index 000000000..a6798bf51
--- /dev/null
+++ b/app/javascript/flavours/glitch/features/compose/containers/upload_form_container.js
@@ -0,0 +1,8 @@
+import { connect } from 'react-redux';
+import UploadForm from '../components/upload_form';
+
+const mapStateToProps = state => ({
+  mediaIds: state.getIn(['compose', 'media_attachments']).map(item => item.get('id')),
+});
+
+export default connect(mapStateToProps)(UploadForm);
diff --git a/app/javascript/flavours/glitch/features/compose/containers/upload_progress_container.js b/app/javascript/flavours/glitch/features/compose/containers/upload_progress_container.js
new file mode 100644
index 000000000..0cfee96da
--- /dev/null
+++ b/app/javascript/flavours/glitch/features/compose/containers/upload_progress_container.js
@@ -0,0 +1,9 @@
+import { connect } from 'react-redux';
+import UploadProgress from '../components/upload_progress';
+
+const mapStateToProps = state => ({
+  active: state.getIn(['compose', 'is_uploading']),
+  progress: state.getIn(['compose', 'progress']),
+});
+
+export default connect(mapStateToProps)(UploadProgress);
diff --git a/app/javascript/flavours/glitch/features/composer/upload_form/index.js b/app/javascript/flavours/glitch/features/composer/upload_form/index.js
deleted file mode 100644
index c2ff66623..000000000
--- a/app/javascript/flavours/glitch/features/composer/upload_form/index.js
+++ /dev/null
@@ -1,60 +0,0 @@
-//  Package imports.
-import classNames from 'classnames';
-import PropTypes from 'prop-types';
-import React from 'react';
-import ImmutablePropTypes from 'react-immutable-proptypes';
-
-//  Components.
-import ComposerUploadFormItem from './item';
-import ComposerUploadFormProgress from './progress';
-
-//  The component.
-export default function ComposerUploadForm ({
-  intl,
-  media,
-  onChangeDescription,
-  onOpenFocalPointModal,
-  onRemove,
-  progress,
-  uploading,
-  handleRef,
-}) {
-  const computedClass = classNames('composer--upload_form', { uploading });
-
-  //  The result.
-  return (
-    <div className={computedClass} ref={handleRef}>
-      {uploading ? <ComposerUploadFormProgress progress={progress} /> : null}
-      {media ? (
-        <div className='content'>
-          {media.map(item => (
-            <ComposerUploadFormItem
-              description={item.get('description')}
-              key={item.get('id')}
-              id={item.get('id')}
-              intl={intl}
-              focusX={item.getIn(['meta', 'focus', 'x'])}
-              focusY={item.getIn(['meta', 'focus', 'y'])}
-              mediaType={item.get('type')}
-              preview={item.get('preview_url')}
-              onChangeDescription={onChangeDescription}
-              onOpenFocalPointModal={onOpenFocalPointModal}
-              onRemove={onRemove}
-            />
-          ))}
-        </div>
-      ) : null}
-    </div>
-  );
-}
-
-//  Props.
-ComposerUploadForm.propTypes = {
-  intl: PropTypes.object.isRequired,
-  media: ImmutablePropTypes.list,
-  onChangeDescription: PropTypes.func.isRequired,
-  onRemove: PropTypes.func.isRequired,
-  progress: PropTypes.number,
-  uploading: PropTypes.bool,
-  handleRef: PropTypes.func,
-};
diff --git a/app/javascript/flavours/glitch/features/composer/upload_form/item/index.js b/app/javascript/flavours/glitch/features/composer/upload_form/item/index.js
deleted file mode 100644
index 4f5f66f04..000000000
--- a/app/javascript/flavours/glitch/features/composer/upload_form/item/index.js
+++ /dev/null
@@ -1,202 +0,0 @@
-//  Package imports.
-import classNames from 'classnames';
-import PropTypes from 'prop-types';
-import React from 'react';
-import {
-  FormattedMessage,
-  defineMessages,
-} from 'react-intl';
-import spring from 'react-motion/lib/spring';
-
-//  Components.
-import IconButton from 'flavours/glitch/components/icon_button';
-
-//  Utils.
-import Motion from 'flavours/glitch/util/optional_motion';
-import { assignHandlers } from 'flavours/glitch/util/react_helpers';
-import { isUserTouching } from 'flavours/glitch/util/is_mobile';
-
-//  Messages.
-const messages = defineMessages({
-  undo: {
-    defaultMessage: 'Undo',
-    id: 'upload_form.undo',
-  },
-  description: {
-    defaultMessage: 'Describe for the visually impaired',
-    id: 'upload_form.description',
-  },
-  crop: {
-    defaultMessage: 'Crop',
-    id: 'upload_form.focus',
-  },
-});
-
-//  Handlers.
-const handlers = {
-
-  //  On blur, we save the description for the media item.
-  handleBlur () {
-    const {
-      id,
-      onChangeDescription,
-    } = this.props;
-    const { dirtyDescription } = this.state;
-
-    this.setState({ dirtyDescription: null, focused: false });
-
-    if (id && onChangeDescription && dirtyDescription !== null) {
-      onChangeDescription(id, dirtyDescription);
-    }
-  },
-
-  //  When the value of our description changes, we store it in the
-  //  temp value `dirtyDescription` in our state.
-  handleChange ({ target: { value } }) {
-    this.setState({ dirtyDescription: value });
-  },
-
-  //  Records focus on the media item.
-  handleFocus () {
-    this.setState({ focused: true });
-  },
-
-  //  Records the start of a hover over the media item.
-  handleMouseEnter () {
-    this.setState({ hovered: true });
-  },
-
-  //  Records the end of a hover over the media item.
-  handleMouseLeave () {
-    this.setState({ hovered: false });
-  },
-
-  //  Removes the media item.
-  handleRemove () {
-    const {
-      id,
-      onRemove,
-    } = this.props;
-    if (id && onRemove) {
-      onRemove(id);
-    }
-  },
-
-  //  Opens the focal point modal.
-  handleFocalPointClick () {
-    const {
-      id,
-      onOpenFocalPointModal,
-    } = this.props;
-    if (id && onOpenFocalPointModal) {
-      onOpenFocalPointModal(id);
-    }
-  },
-};
-
-//  The component.
-export default class ComposerUploadFormItem extends React.PureComponent {
-
-  //  Constructor.
-  constructor (props) {
-    super(props);
-    assignHandlers(this, handlers);
-    this.state = {
-      hovered: false,
-      focused: false,
-      dirtyDescription: null,
-    };
-  }
-
-  //  Rendering.
-  render () {
-    const {
-      handleBlur,
-      handleChange,
-      handleFocus,
-      handleMouseEnter,
-      handleMouseLeave,
-      handleRemove,
-      handleFocalPointClick,
-    } = this.handlers;
-    const {
-      intl,
-      preview,
-      focusX,
-      focusY,
-      mediaType,
-    } = this.props;
-    const {
-      focused,
-      hovered,
-      dirtyDescription,
-    } = this.state;
-    const active = hovered || focused || isUserTouching();
-    const computedClass = classNames('composer--upload_form--item', { active });
-    const x = ((focusX /  2) + .5) * 100;
-    const y = ((focusY / -2) + .5) * 100;
-    const description = dirtyDescription || (dirtyDescription !== '' && this.props.description) || '';
-
-    //  The result.
-    return (
-      <div
-        className={computedClass}
-        onMouseEnter={handleMouseEnter}
-        onMouseLeave={handleMouseLeave}
-      >
-        <Motion
-          defaultStyle={{ scale: 0.8 }}
-          style={{
-            scale: spring(1, {
-              stiffness: 180,
-              damping: 12,
-            }),
-          }}
-        >
-          {({ scale }) => (
-            <div
-              style={{
-                transform: `scale(${scale})`,
-                backgroundImage: preview ? `url(${preview})` : null,
-                backgroundPosition: `${x}% ${y}%`
-              }}
-            >
-              <div className={classNames('composer--upload_form--actions', { active })}>
-                <button className='icon-button' onClick={handleRemove}>
-                  <i className='fa fa-times' /> <FormattedMessage {...messages.undo} />
-                </button>
-                {mediaType === 'image' && <button className='icon-button' onClick={handleFocalPointClick}><i className='fa fa-crosshairs' /> <FormattedMessage {...messages.crop} /></button>}
-              </div>
-              <label>
-                <span style={{ display: 'none' }}><FormattedMessage {...messages.description} /></span>
-                <textarea
-                  maxLength={420}
-                  onBlur={handleBlur}
-                  onChange={handleChange}
-                  onFocus={handleFocus}
-                  placeholder={intl.formatMessage(messages.description)}
-                  value={description}
-                />
-              </label>
-            </div>
-          )}
-        </Motion>
-      </div>
-    );
-  }
-
-}
-
-//  Props.
-ComposerUploadFormItem.propTypes = {
-  description: PropTypes.string,
-  id: PropTypes.string,
-  intl: PropTypes.object.isRequired,
-  onChangeDescription: PropTypes.func.isRequired,
-  onOpenFocalPointModal: PropTypes.func.isRequired,
-  onRemove: PropTypes.func.isRequired,
-  focusX: PropTypes.number,
-  focusY: PropTypes.number,
-  mediaType: PropTypes.string,
-  preview: PropTypes.string,
-};
diff --git a/app/javascript/flavours/glitch/features/composer/upload_form/progress/index.js b/app/javascript/flavours/glitch/features/composer/upload_form/progress/index.js
deleted file mode 100644
index 8c4b0eea6..000000000
--- a/app/javascript/flavours/glitch/features/composer/upload_form/progress/index.js
+++ /dev/null
@@ -1,52 +0,0 @@
-//  Package imports.
-import PropTypes from 'prop-types';
-import React from 'react';
-import {
-  defineMessages,
-  FormattedMessage,
-} from 'react-intl';
-import spring from 'react-motion/lib/spring';
-
-//  Components.
-import Icon from 'flavours/glitch/components/icon';
-
-//  Utils.
-import Motion from 'flavours/glitch/util/optional_motion';
-
-//  Messages.
-const messages = defineMessages({
-  upload: {
-    defaultMessage: 'Uploading...',
-    id: 'upload_progress.label',
-  },
-});
-
-//  The component.
-export default function ComposerUploadFormProgress ({ progress }) {
-
-  //  The result.
-  return (
-    <div className='composer--upload_form--progress'>
-      <Icon icon='upload' />
-      <div className='message'>
-        <FormattedMessage {...messages.upload} />
-        <div className='backdrop'>
-          <Motion
-            defaultStyle={{ width: 0 }}
-            style={{ width: spring(progress) }}
-          >
-            {({ width }) =>
-              (<div
-                className='tracker'
-                style={{ width: `${width}%` }}
-              />)
-            }
-          </Motion>
-        </div>
-      </div>
-    </div>
-  );
-}
-
-//  Props.
-ComposerUploadFormProgress.propTypes = { progress: PropTypes.number };