From 4c2b58892606d7ff752f60af2bd3ef2c152c0ffb Mon Sep 17 00:00:00 2001 From: Paul Kaplan Date: Fri, 18 Jun 2021 11:09:37 -0400 Subject: [PATCH 1/4] Include react-hooks eslint plugin to prevent hooks usage errors. I'm including this now because when implementing the studio follow error messaging, I made a mistake (conditionally calling useState) that was tough to track down, and this linter plugin prevents that. --- package-lock.json | 6 ++++++ package.json | 1 + src/.eslintrc.js | 5 +++-- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6aef69cbd..04f4524ed 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7613,6 +7613,12 @@ } } }, + "eslint-plugin-react-hooks": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.2.0.tgz", + "integrity": "sha512-623WEiZJqxR7VdxFCKLI6d6LLpwJkGPYKODnkH3D7WpOG5KM8yWueBd8TLsNAetEJNF5iJmolaAKO3F8yzyVBQ==", + "dev": true + }, "eslint-scope": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", diff --git a/package.json b/package.json index 861b236a0..f0cfa1647 100644 --- a/package.json +++ b/package.json @@ -86,6 +86,7 @@ "eslint-config-scratch": "7.0.0", "eslint-plugin-json": "2.0.1", "eslint-plugin-react": "7.14.2", + "eslint-plugin-react-hooks": "^4.2.0", "fastly": "1.2.1", "formik": "1.5.4", "formsy-react": "1.1.4", diff --git a/src/.eslintrc.js b/src/.eslintrc.js index 81246be59..f8107fee1 100644 --- a/src/.eslintrc.js +++ b/src/.eslintrc.js @@ -7,7 +7,7 @@ module.exports = { globals: { process: true }, - plugins: ['json'], + plugins: ['json', 'react-hooks'], settings: { react: { version: 'detect' @@ -17,6 +17,7 @@ module.exports = { 'camelcase': [2, { properties: 'never', // This is from the base `scratch` config allow: ['^UNSAFE_'] // Allow until migrated to new lifecycle methods - }] + }], + 'react-hooks/rules-of-hooks': 'error' } }; From fa8aff583723ec92fa711e4ee42aa49713dfdc5a Mon Sep 17 00:00:00 2001 From: Paul Kaplan Date: Fri, 18 Jun 2021 11:27:00 -0400 Subject: [PATCH 2/4] Replace debug error on StudioFollow --- src/views/studio/l10n.json | 3 +++ src/views/studio/studio-follow.jsx | 40 ++++++++++++++++++++++++------ src/views/studio/studio.scss | 2 ++ 3 files changed, 37 insertions(+), 8 deletions(-) diff --git a/src/views/studio/l10n.json b/src/views/studio/l10n.json index 5034b1081..a01d5d54e 100644 --- a/src/views/studio/l10n.json +++ b/src/views/studio/l10n.json @@ -18,6 +18,9 @@ "studio.updateErrors.thumbnailTooLarge": "Maximum file size is 512 KB and less than 500x500 pixels.", "studio.updateErrors.thumbnailInvalid": "Upload a valid image. The file you uploaded was either not an image or a corrupted image.", + "studio.followErrors.confirmEmail": "Please confirm your email address first", + "studio.followErrors.generic": "Something went wrong following the studio", + "studio.projectsHeader": "Projects", "studio.addProjectsHeader": "Add Projects", "studio.addProject": "Add", diff --git a/src/views/studio/studio-follow.jsx b/src/views/studio/studio-follow.jsx index 2a4349fb2..4d89482b9 100644 --- a/src/views/studio/studio-follow.jsx +++ b/src/views/studio/studio-follow.jsx @@ -1,15 +1,24 @@ /* eslint-disable react/jsx-no-bind */ -import React from 'react'; +import React, {useState} from 'react'; import PropTypes from 'prop-types'; import {connect} from 'react-redux'; import {FormattedMessage} from 'react-intl'; +import onClickOutside from 'react-onclickoutside'; import {selectIsFollowing} from '../../redux/studio'; import {selectCanFollowStudio} from '../../redux/studio-permissions'; import { - mutateFollowingStudio, selectIsMutatingFollowing, selectFollowingMutationError + mutateFollowingStudio, selectIsMutatingFollowing, selectFollowingMutationError, Errors } from '../../redux/studio-mutations'; import classNames from 'classnames'; +import ValidationMessage from '../../components/forms/validation-message.jsx'; + +const errorToMessageId = error => { + switch (error) { + case Errors.PERMISSION: return 'studio.followErrors.confirmEmail'; + default: return 'studio.followErrors.generic'; + } +}; const StudioFollow = ({ canFollow, @@ -18,16 +27,24 @@ const StudioFollow = ({ followingError, handleFollow }) => { - if (!canFollow) return null; const fieldClassName = classNames('button', 'studio-follow-button', { 'mod-mutating': isMutating }); + const [hideValidationMessage, setHideValidationMessage] = useState(false); + + StudioFollow.handleClickOutside = () => { + setHideValidationMessage(true); + }; + if (!canFollow) return null; return ( - +
- {followingError &&
Error mutating following: {followingError}
} - + {followingError && !hideValidationMessage && } + />} +
); }; @@ -48,6 +68,10 @@ StudioFollow.propTypes = { handleFollow: PropTypes.func }; +const clickOutsideConfig = { + handleClickOutside: () => StudioFollow.handleClickOutside +}; + export default connect( state => ({ canFollow: selectCanFollowStudio(state), @@ -58,4 +82,4 @@ export default connect( { handleFollow: mutateFollowingStudio } -)(StudioFollow); +)(onClickOutside(StudioFollow, clickOutsideConfig)); diff --git a/src/views/studio/studio.scss b/src/views/studio/studio.scss index 7c9d0d93f..291bd84ec 100644 --- a/src/views/studio/studio.scss +++ b/src/views/studio/studio.scss @@ -169,6 +169,8 @@ $radius: 8px; padding-bottom: 14px; font-size: 14px; margin: 0; + width: 100%; + box-sizing: border-box; } } From ae202c7bcd1293c42c37c890ab2dacc226e274a9 Mon Sep 17 00:00:00 2001 From: Paul Kaplan Date: Fri, 18 Jun 2021 11:49:57 -0400 Subject: [PATCH 3/4] Remove Debug component in studios --- src/views/studio/debug.jsx | 18 ------------------ src/views/studio/l10n.json | 6 ++++++ src/views/studio/studio-activity.jsx | 14 +++++++++----- src/views/studio/studio-curators.jsx | 14 +++++++++----- src/views/studio/studio-managers.jsx | 14 +++++++++----- src/views/studio/studio-projects.jsx | 20 +++++++++++++------- src/views/studio/studio.scss | 7 +++++++ 7 files changed, 53 insertions(+), 40 deletions(-) delete mode 100644 src/views/studio/debug.jsx diff --git a/src/views/studio/debug.jsx b/src/views/studio/debug.jsx deleted file mode 100644 index 3b037079e..000000000 --- a/src/views/studio/debug.jsx +++ /dev/null @@ -1,18 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; - -const Debug = ({label, data}) => (
- {label} - -
-            {JSON.stringify(data, null, '  ')}
-        
-
-
); - -Debug.propTypes = { - label: PropTypes.string, - data: PropTypes.any // eslint-disable-line react/forbid-prop-types -}; - -export default Debug; diff --git a/src/views/studio/l10n.json b/src/views/studio/l10n.json index a01d5d54e..4c7550b82 100644 --- a/src/views/studio/l10n.json +++ b/src/views/studio/l10n.json @@ -21,6 +21,12 @@ "studio.followErrors.confirmEmail": "Please confirm your email address first", "studio.followErrors.generic": "Something went wrong following the studio", + "studio.sectionLoadError.projectsHeadline": "Something went wrong loading projects", + "studio.sectionLoadError.curatorsHeadline": "Something went wrong loading curators", + "studio.sectionLoadError.managersHeadline": "Something went wrong loading managers", + "studio.sectionLoadError.activityHeadline": "Something went wrong loading managers", + "studio.sectionLoadError.tryAgain": "Try again", + "studio.projectsHeader": "Projects", "studio.addProjectsHeader": "Add Projects", "studio.addProject": "Add", diff --git a/src/views/studio/studio-activity.jsx b/src/views/studio/studio-activity.jsx index 519dbb2d5..ef65c406c 100644 --- a/src/views/studio/studio-activity.jsx +++ b/src/views/studio/studio-activity.jsx @@ -6,7 +6,6 @@ import {connect} from 'react-redux'; import {activity} from './lib/redux-modules'; import {loadActivity} from './lib/studio-activity-actions'; -import Debug from './debug.jsx'; import classNames from 'classnames'; import SocialMessage from '../../components/social-message/social-message.jsx'; @@ -181,10 +180,15 @@ const StudioActivity = ({items, loading, error, moreToLoad, onLoadMore}) => {

{loading &&
Loading...
} - {error && } + {error &&
+

+ +
}
    diff --git a/src/views/studio/studio-curators.jsx b/src/views/studio/studio-curators.jsx index 687a8e2c3..7c684cdd9 100644 --- a/src/views/studio/studio-curators.jsx +++ b/src/views/studio/studio-curators.jsx @@ -5,7 +5,6 @@ import {FormattedMessage} from 'react-intl'; import classNames from 'classnames'; import {curators} from './lib/redux-modules'; -import Debug from './debug.jsx'; import {CuratorTile} from './studio-member-tile.jsx'; import CuratorInviter from './studio-curator-inviter.jsx'; import {loadCurators} from './lib/studio-member-actions'; @@ -28,10 +27,15 @@ const StudioCurators = ({

    {canInviteCurators && } - {error && } + {error &&
    +

    + +
    }
    {items.length === 0 && !loading ? (
    diff --git a/src/views/studio/studio-managers.jsx b/src/views/studio/studio-managers.jsx index fcba3f62d..bab204c1b 100644 --- a/src/views/studio/studio-managers.jsx +++ b/src/views/studio/studio-managers.jsx @@ -12,7 +12,6 @@ import { selectStudioHasReachedManagerThreshold } from '../../redux/studio.js'; import {loadManagers} from './lib/studio-member-actions'; -import Debug from './debug.jsx'; import {ManagerTile} from './studio-member-tile.jsx'; import StudioInfoBox from './studio-info-box.jsx'; import AlertProvider from '../../components/alert/alert-provider.jsx'; @@ -85,10 +84,15 @@ const StudioManagers = ({
    }
    - {error && } + {error &&
    +

    + +
    }
    {items.map(item => ( { if (items.length === 0) onLoadMore(); }, []); - + return (
    @@ -49,12 +48,19 @@ const StudioProjects = ({ } {canAddProjects && } - {error && } + + {error &&
    +

    + +
    } +
    - {items.length === 0 && !loading ? ( + {items.length === 0 && !loading && !error ? (
    {canAddProjects ? ( diff --git a/src/views/studio/studio.scss b/src/views/studio/studio.scss index 291bd84ec..eb7aaf28c 100644 --- a/src/views/studio/studio.scss +++ b/src/views/studio/studio.scss @@ -174,6 +174,13 @@ $radius: 8px; } } +.studio-section-load-error { + margin-top: 2rem; + padding: 1rem; + flex-direction: column; + text-align: center; +} + .studio-tab-nav { border-bottom: 1px solid $active-dark-gray; padding-bottom: 8px; From 10bcc2319aa46b3c6bf5c420514f23d936cecab8 Mon Sep 17 00:00:00 2001 From: Paul Kaplan Date: Fri, 18 Jun 2021 14:59:32 -0400 Subject: [PATCH 4/4] Fix typo in translation string --- src/views/studio/l10n.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/views/studio/l10n.json b/src/views/studio/l10n.json index 4c7550b82..0f27cafbf 100644 --- a/src/views/studio/l10n.json +++ b/src/views/studio/l10n.json @@ -24,7 +24,7 @@ "studio.sectionLoadError.projectsHeadline": "Something went wrong loading projects", "studio.sectionLoadError.curatorsHeadline": "Something went wrong loading curators", "studio.sectionLoadError.managersHeadline": "Something went wrong loading managers", - "studio.sectionLoadError.activityHeadline": "Something went wrong loading managers", + "studio.sectionLoadError.activityHeadline": "Something went wrong loading activity", "studio.sectionLoadError.tryAgain": "Try again", "studio.projectsHeader": "Projects",