From 28666d1c99ce28241a9ab9e8d0372de15273647a Mon Sep 17 00:00:00 2001
From: Karishma Chadha <kchadha@scratch.mit.edu>
Date: Fri, 23 Feb 2018 00:06:00 -0500
Subject: [PATCH] Improvements to error state: input outline shows with or
 without focus, and added new error div which shows if there's an error, but
 goes away if the user starts changing what they had submitted in the input.
 Removing a lot of code surrounding the tooltip which has now become
 unnecessary.

---
 src/components/import-error/import-error.css |  61 ---------
 src/components/import-error/import-error.jsx | 131 -------------------
 src/components/import-input/import-input.jsx |  58 --------
 src/components/import-modal/import-modal.css |  31 +++--
 src/components/import-modal/import-modal.jsx |  29 ++--
 src/containers/import-modal.jsx              |   4 +-
 6 files changed, 45 insertions(+), 269 deletions(-)
 delete mode 100644 src/components/import-error/import-error.css
 delete mode 100644 src/components/import-error/import-error.jsx
 delete mode 100644 src/components/import-input/import-input.jsx

diff --git a/src/components/import-error/import-error.css b/src/components/import-error/import-error.css
deleted file mode 100644
index 4ffac015f..000000000
--- a/src/components/import-error/import-error.css
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * NOTE: the copious use of `important` is needed to overwrite
- * the default tooltip styling, and is required by the 3rd party
- * library being used, `react-tooltip`
- */
-
-@import "../../css/colors.css";
-
-.import-error {
-    background-color: $data-primary !important;
-    border: 1px solid hsla(0, 0%, 0%, .1) !important;
-    border-radius: .25rem !important;
-    box-shadow: 0 0 .5rem hsla(0, 0%, 0%, .25) !important;
-    padding: .75rem 1rem !important;
-    font-family: "Helvetica Neue", Helvetica, Arial, sans-serif !important;
-    font-size: 1rem !important;
-    line-height: 1.25rem !important;
-    z-index: 100 !important;
-}
-
-.import-error:after {
-    content: "";
-    border-top: 1px solid hsla(0, 0%, 0%, .1) !important;
-    border-left: 0 !important;
-    border-bottom: 0 !important;
-    border-right: 1px solid hsla(0, 0%, 0%, .1) !important;
-    border-radius: .25rem;
-    background-color: $data-primary !important;
-    height: 1rem !important;
-    width: 1rem !important;
-}
-
-.show,
-.show:before,
-.show:after {
-    opacity: 1 !important;
-}
-
-.left:after {
-    margin-top: -.5rem !important;
-    right: -.5rem !important;
-    transform: rotate(45deg) !important;
-}
-
-.right:after {
-    margin-top: -.5rem !important;
-    left: -.5rem !important;
-    transform: rotate(-135deg) !important;
-}
-
-.top:after {
-    margin-right: -.5rem !important;
-    bottom: -.5rem !important;
-    transform: rotate(135deg) !important;
-}
-
-.bottom:after {
-    margin-left: -.5rem !important;
-    top: -.5rem !important;
-    transform: rotate(-45deg) !important;
-}
diff --git a/src/components/import-error/import-error.jsx b/src/components/import-error/import-error.jsx
deleted file mode 100644
index af677e4a2..000000000
--- a/src/components/import-error/import-error.jsx
+++ /dev/null
@@ -1,131 +0,0 @@
-import bindAll from 'lodash.bindall';
-import classNames from 'classnames';
-import {defineMessages, injectIntl, FormattedMessage} from 'react-intl';
-import PropTypes from 'prop-types';
-import React from 'react';
-import ReactTooltip from 'react-tooltip';
-
-import styles from './import-error.css';
-
-// TODO store different error messages depending on the situation (?) and
-// needs to use intl lib for localization support
-
-// TODO error tooltip should be always visible in the error state,
-// instead of popping up hen hovering over the input
-
-const messages = defineMessages({
-    invalidLink: {
-        id: 'gui.importError.invalidLink',
-        defaultMessage: 'Uh oh, that link doesn\'t look quite right.',
-        description: 'Invalid link error message'
-    }
-});
-
-class ImportErrorContent extends React.Component {
-    constructor (props) {
-        super(props);
-        bindAll(this, [
-            'setHide',
-            'setShow',
-            'getContent'
-        ]);
-        this.state = {
-            isShowing: true
-        };
-    }
-    setShow () {
-        // needed to set the opacity to 1, since the default is .9 on show
-        this.setState({isShowing: true});
-    }
-    setHide () {
-        this.setState({isShowing: false});
-    }
-    getContent () {
-        const messageId = this.props.errorMessage;
-        return (
-            <p>
-                <FormattedMessage
-                    {...messages[`${messageId}`]}
-                />
-            </p>
-        );
-    }
-    render () {
-        return (
-            <ReactTooltip
-                afterHide={this.setHide}
-                afterShow={this.setShow}
-                className={classNames(
-                    styles.importError,
-                    this.props.className,
-                    {
-                        [styles.show]: (this.state.isShowing),
-                        [styles.left]: (this.props.place === 'left'),
-                        [styles.right]: (this.props.place === 'right'),
-                        [styles.top]: (this.props.place === 'top'),
-                        [styles.bottom]: (this.props.place === 'bottom')
-                    }
-                )}
-                getContent={this.getContent}
-                id={this.props.tooltipId}
-            />
-        );
-    }
-}
-
-ImportErrorContent.propTypes = {
-    className: PropTypes.string,
-    errorMessage: PropTypes.string.isRequired,
-    place: PropTypes.oneOf(['top', 'right', 'bottom', 'left']),
-    tooltipId: PropTypes.string.isRequired
-
-};
-
-ImportErrorContent.defaultProps = {
-    place: 'bottom'
-};
-
-const ImportError = injectIntl(ImportErrorContent);
-
-const ImportErrorTooltip = props => (
-    <div className={props.className}>
-        <div
-            data-delay-hide={props.delayHide}
-            data-delay-show={props.delayShow}
-            data-effect="solid"
-            data-for={props.tooltipId}
-            data-place={props.place}
-            data-tip="tooltip"
-        >
-            {props.children}
-        </div>
-        <ImportError
-            className={props.tooltipClassName}
-            errorMessage={props.errorMessage}
-            place={props.place}
-            tooltipId={props.tooltipId}
-        />
-    </div>
-);
-
-ImportErrorTooltip.propTypes = {
-    children: PropTypes.node.isRequired,
-    className: PropTypes.string,
-    delayHide: PropTypes.number,
-    delayShow: PropTypes.number,
-    errorMessage: PropTypes.string.isRequired,
-    place: PropTypes.oneOf(['top', 'right', 'bottom', 'left']),
-    tooltipClassName: PropTypes.string,
-    tooltipId: PropTypes.string.isRequired
-
-};
-
-ImportErrorTooltip.defaultProps = {
-    delayHide: 0,
-    delayShow: 0
-};
-
-export {
-    ImportError as ImportErrorComponent,
-    ImportErrorTooltip
-};
diff --git a/src/components/import-input/import-input.jsx b/src/components/import-input/import-input.jsx
deleted file mode 100644
index 21ea902a0..000000000
--- a/src/components/import-input/import-input.jsx
+++ /dev/null
@@ -1,58 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-
-import {ImportErrorTooltip} from '../import-error/import-error.jsx';
-
-
-// TODO error tooltip needs to go around both the input and the button
-// error tooltip should also be always visible
-class ImportInput extends React.Component {
-    render () {
-        let input = null;
-        if (this.props.hasValidationError) {
-            input = (
-                <ImportErrorTooltip
-                    className={this.props.errorDivClassName}
-                    errorMessage={this.props.errorMessage}
-                    place="bottom"
-                    tooltipId="import-input-error"
-                >
-                    <input
-                        autoFocus
-                        className={this.props.badClassName}
-                        placeholder={this.props.placeholder}
-                        value={this.props.inputValue}
-                        onChange={this.props.onChange}
-                        onKeyPress={this.props.onKeyPress}
-                    />
-                </ImportErrorTooltip>
-            );
-        } else {
-            input = (
-                <input
-                    autoFocus
-                    className={this.props.okClassName}
-                    placeholder={this.props.placeholder}
-                    value={this.props.inputValue}
-                    onChange={this.props.onChange}
-                    onKeyPress={this.props.onKeyPress}
-                />
-            );
-        }
-        return input;
-    }
-}
-
-ImportInput.propTypes = {
-    badClassName: PropTypes.string,
-    errorDivClassName: PropTypes.string,
-    errorMessage: PropTypes.string.isRequired,
-    hasValidationError: PropTypes.bool.isRequired,
-    inputValue: PropTypes.string.isRequired,
-    okClassName: PropTypes.string,
-    onChange: PropTypes.func.isRequired,
-    onKeyPress: PropTypes.func.isRequired,
-    placeholder: PropTypes.string
-};
-
-export default ImportInput;
diff --git a/src/components/import-modal/import-modal.css b/src/components/import-modal/import-modal.css
index 8dd6f80ba..8ffbcb3c6 100644
--- a/src/components/import-modal/import-modal.css
+++ b/src/components/import-modal/import-modal.css
@@ -98,12 +98,6 @@ $sides: 20rem;
     justify-content: center;
 }
 
-.input-row div.error-div {
-    margin: 0;
-    width: 100%;
-    padding: 0;
-}
-
 .input-row input {
     width: 100%;
     padding: 0 1rem;
@@ -117,13 +111,13 @@ $sides: 20rem;
     color: rgba(87,94,117,0.5);
 }
 
-.input-row input.ok-input:focus {
+.input-row input.ok-input {
     outline: none;
     border: 1px solid $motion-primary;
     border-radius: 0.25rem
 }
 
-.input-row input.bad-input:focus {
+.input-row input.bad-input {
     outline: none;
     border: 1px solid $data-primary;
     border-radius: 0.25rem
@@ -136,6 +130,7 @@ $sides: 20rem;
     cursor: pointer;
     border: 1px solid $import-primary;
     border-radius: 0.25rem;
+    outline: none;
 }
 
 .input-row button.ok-button {
@@ -143,6 +138,26 @@ $sides: 20rem;
     color: white;
 }
 
+.empty-row {
+    margin: 0;
+}
+
+.error-row {
+    margin: 1.5rem 0;
+    text-align: center;
+    display: flex;
+    justify-content: center;
+}
+.error-row div {
+    background: $data-primary;
+    opacity: 0.8;
+    color: white;
+    padding: 0.5rem 1rem;
+    font-size: .5rem;
+    border: 1px solid $data-primary;
+    border-radius: 0.25rem;
+}
+
 /* Confirmation buttons at the bottom of the modal */
 .button-row {
     margin: 1.5rem 0;
diff --git a/src/components/import-modal/import-modal.jsx b/src/components/import-modal/import-modal.jsx
index 03a1aef8f..87c396109 100644
--- a/src/components/import-modal/import-modal.jsx
+++ b/src/components/import-modal/import-modal.jsx
@@ -6,7 +6,6 @@ import {defineMessages, injectIntl, intlShape, FormattedMessage} from 'react-int
 import classNames from 'classnames';
 
 import CloseButton from '../close-button/close-button.jsx';
-import ImportInput from '../import-input/import-input.jsx';
 
 import styles from './import-modal.css';
 
@@ -21,6 +20,11 @@ const messages = defineMessages({
             'Enter a link to one of your shared Scratch projects. Changes made in this 3.0 Preview will not be saved.',
         description: 'Import project message',
         id: 'gui.importInfo.message'
+    },
+    invalidFormatError: {
+        id: 'gui.importInfo.invalidFormatError',
+        defaultMessage: 'Uh oh, that project link or id doesn\'t look quite right.',
+        description: 'Invalid project link or id message'
     }
 });
 
@@ -65,16 +69,12 @@ const ImportModal = ({intl, ...props}) => (
             <p>
                 {intl.formatMessage({...messages.formDescription})}
             </p>
-
             <Box className={styles.inputRow}>
-                <ImportInput
-                    badClassName={styles.badInput}
-                    errorDivClassName={styles.errorDiv}
-                    errorMessage={props.errorMessage}
-                    hasValidationError={props.hasValidationError}
-                    inputValue={props.inputValue}
-                    okClassName={styles.okInput}
+                <input
+                    autoFocus
+                    className={props.hasValidationError ? styles.badInput : styles.okInput}
                     placeholder={props.placeholder}
+                    value={props.inputValue}
                     onChange={props.onChange}
                     onKeyPress={props.onKeyPress}
                 />
@@ -90,6 +90,17 @@ const ImportModal = ({intl, ...props}) => (
                     />
                 </button>
             </Box>
+            <Box className={props.hasValidationError ? styles.errorRow : styles.emptyRow}>
+                {props.hasValidationError ?
+                    <div className={styles.importErrorDiv}>
+                        <p>
+                            {/* intl.formatMessage({...messages.invalidLink})*/}
+                            <FormattedMessage
+                                {...messages[`${props.errorMessage}`]}
+                            />
+                        </p>
+                    </div> : null}
+            </Box>
             <Box className={styles.buttonRow}>
                 <button
                     className={styles.noButton}
diff --git a/src/containers/import-modal.jsx b/src/containers/import-modal.jsx
index e3112da07..6bc667440 100644
--- a/src/containers/import-modal.jsx
+++ b/src/containers/import-modal.jsx
@@ -43,11 +43,11 @@ class ImportModal extends React.Component {
             // TODO handle error messages and error states
             this.setState({
                 hasValidationError: true,
-                errorMessage: `invalidLink`});
+                errorMessage: `invalidFormatError`});
         }
     }
     handleChange (e) {
-        this.setState({inputValue: e.target.value});
+        this.setState({inputValue: e.target.value, hasValidationError: false});
     }
     validate (input) {
         const urlMatches = input.match(/^(https:\/\/)?scratch\.mit\.edu\/projects\/(\d+)(\/?|(\/#editor)?)$/);
-- 
GitLab