From e118dda13adfa32e1d8d48f6be3edc851c9c1ca0 Mon Sep 17 00:00:00 2001 From: Oliver Eyton-Williams Date: Mon, 2 Aug 2021 15:39:40 +0200 Subject: [PATCH] fix: order imports and remove circular dependencies (#41824) * fix: remove circular dependency redux depended on templates/Challenges/redux and vice versa. This meant that import order mattered and confusing bugs could arise. (cherry picked from commit 7d67a4e70922bbb3051f2f9982dcc69e240d43dc) * feat: require imports to be in alphabetical order Import order generally does not matter, but there are edge cases (circular imports and css imports, for example) where changing order changes behaviour (cherry picked from commit b8d1393a91ec6e068caf8e8498a5c95df68c2b2c) * chore: order imports * fix: lift up challenge description + title comps This brings the classic Show closer to the others as they now all create the description and title components * fix: remove donation-saga/index circular import (cherry picked from commit 51a44ca668a700786d2744feffeae4fdba5fd207) * refactor: extract action-types from settings (cherry picked from commit 25e26124d691c84a0d0827d41dafb761c686fadd) * fix: lint errors * feat: prevent useless renames --- .eslintrc-base.json | 2 + .../src/common/models/User-Credential.js | 4 +- api-server/src/common/models/User-Identity.js | 4 +- api-server/src/common/models/user.js | 39 ++- api-server/src/development-start.js | 2 +- api-server/src/production-start.js | 2 +- api-server/src/server/boot/authentication.js | 8 +- api-server/src/server/boot/certificate.js | 18 +- api-server/src/server/boot/challenge.js | 6 +- api-server/src/server/boot/donate.js | 2 +- api-server/src/server/boot/settings.js | 6 +- api-server/src/server/boot/user.js | 12 +- api-server/src/server/component-passport.js | 8 +- api-server/src/server/index.js | 4 +- .../server/middlewares/constant-headers.js | 2 +- .../src/server/middlewares/passport-login.js | 2 +- .../middlewares/request-authorization.js | 8 +- .../middlewares/request-authorization.test.js | 2 +- api-server/src/server/middlewares/sessions.js | 2 +- api-server/src/server/models/donation.js | 2 +- api-server/src/server/passport-providers.js | 2 +- api-server/src/server/rss/index.js | 2 +- api-server/src/server/utils/donation.test.js | 16 +- .../src/server/utils/getSetAccessToken.js | 2 +- .../server/utils/getSetAccessToken.test.js | 4 +- .../src/server/utils/publicUserProps.js | 2 +- api-server/src/server/utils/redirection.js | 2 +- api-server/src/server/utils/rx.js | 4 +- api-server/src/server/utils/user-stats.js | 8 +- .../src/server/utils/user-stats.test.js | 2 +- client/gatsby-browser.js | 10 +- client/gatsby-node.js | 8 +- client/gatsby-ssr.js | 4 +- client/i18n/schema-validation.js | 8 +- client/i18n/validate-keys.js | 4 +- client/src/analytics/index.tsx | 2 +- client/src/assets/icons/index.tsx | 14 +- client/src/assets/images/components/index.tsx | 6 +- .../client-only-routes/show-certification.tsx | 32 +-- .../show-profile-or-four-oh-four.tsx | 8 +- .../client-only-routes/show-project-links.tsx | 17 +- .../src/client-only-routes/show-settings.tsx | 29 ++- .../client-only-routes/show-unsubscribed.tsx | 4 +- client/src/client-only-routes/show-user.tsx | 8 +- client/src/client/workers/test-evaluator.js | 2 +- .../components/Donation/DonateCompletion.js | 6 +- client/src/components/Donation/DonateForm.js | 14 +- .../src/components/Donation/DonationModal.js | 23 +- .../Donation/PayPalButtonScriptLoader.js | 4 +- .../src/components/Donation/PaypalButton.js | 9 +- client/src/components/Flash/index.tsx | 6 +- client/src/components/Flash/redux/index.ts | 2 +- client/src/components/FourOhFour/index.tsx | 4 +- client/src/components/Header/Header.test.js | 9 +- .../components/Header/components/Login.tsx | 6 +- .../Header/components/auth-or-profile.tsx | 2 +- .../Header/components/nav-links.tsx | 14 +- .../Header/components/universal-nav.tsx | 6 +- .../Header/components/user-state.tsx | 8 +- client/src/components/Intro/Intro.test.js | 2 +- .../Intro/components/IntroDescription.js | 4 +- client/src/components/Intro/index.js | 8 +- client/src/components/Map/Map.test.js | 6 +- client/src/components/Map/index.js | 11 +- .../components/SolutionViewer/ProjectModal.js | 6 +- .../SolutionViewer/SolutionViewer.js | 4 +- .../components/app-mount-notifier.test.tsx | 6 +- client/src/components/app-mount-notifier.tsx | 4 +- client/src/components/formHelpers/Form.js | 2 +- .../src/components/formHelpers/Form.test.js | 2 +- .../src/components/formHelpers/FormFields.js | 8 +- .../formHelpers/block-save-button.test.tsx | 2 +- .../formHelpers/block-save-button.tsx | 2 +- .../formHelpers/block-save-wrapper.test.tsx | 2 +- .../components/helpers/avatar-renderer.tsx | 8 +- .../helpers/form/block-save-button.tsx | 2 +- .../src/components/helpers/full-width-row.tsx | 2 +- client/src/components/helpers/link.tsx | 2 +- client/src/components/helpers/loader.test.tsx | 2 +- .../src/components/helpers/slim-width-row.tsx | 2 +- .../src/components/helpers/toggle-button.tsx | 4 +- client/src/components/landing/Landing.test.js | 2 +- .../components/landing/components/AsSeenIn.js | 4 +- .../landing/components/BigCallToAction.js | 4 +- .../landing/components/CampersImage.js | 8 +- .../landing/components/Certifications.js | 8 +- .../landing/components/LandingTop.js | 10 +- .../landing/components/Testimonials.js | 10 +- client/src/components/landing/index.js | 10 +- .../src/components/layouts/Certification.js | 6 +- client/src/components/layouts/Default.js | 29 ++- client/src/components/layouts/learn.tsx | 6 +- .../src/components/profile/Profile.test.tsx | 2 +- client/src/components/profile/Profile.tsx | 4 +- .../components/profile/components/Camper.tsx | 13 +- .../profile/components/Certifications.tsx | 8 +- .../profile/components/HeatMap.test.tsx | 2 +- .../components/profile/components/HeatMap.tsx | 15 +- .../profile/components/Portfolio.tsx | 2 +- .../profile/components/SocialIcons.tsx | 6 +- .../profile/components/TimeLine.test.tsx | 4 +- .../profile/components/TimeLine.tsx | 22 +- client/src/components/redirect-home.ts | 2 +- .../components/search/WithInstantSearch.js | 19 +- .../search/searchBar/search-bar.tsx | 10 +- .../search/searchBar/search-hits.tsx | 8 +- .../search/searchBar/search-suggestion.tsx | 2 +- .../search/searchPage/search-page-hits.tsx | 2 +- .../src/components/settings/Certification.js | 12 +- .../components/settings/Certification.test.js | 2 +- .../src/components/settings/Honesty.test.js | 4 +- client/src/components/settings/about.tsx | 6 +- .../src/components/settings/danger-zone.tsx | 6 +- .../src/components/settings/delete-modal.tsx | 2 +- client/src/components/settings/email.tsx | 12 +- client/src/components/settings/honesty.tsx | 4 +- client/src/components/settings/internet.tsx | 8 +- client/src/components/settings/portfolio.tsx | 8 +- client/src/components/settings/privacy.tsx | 10 +- .../src/components/settings/reset-modal.tsx | 2 +- client/src/components/settings/theme.tsx | 2 +- .../components/settings/toggle-setting.tsx | 4 +- client/src/components/settings/username.tsx | 12 +- client/src/pages/404.tsx | 4 +- client/src/pages/certification.tsx | 4 +- client/src/pages/challenges.test.ts | 2 +- client/src/pages/challenges.tsx | 2 +- client/src/pages/donate.tsx | 10 +- client/src/pages/email-sign-up.tsx | 19 +- client/src/pages/learn.tsx | 10 +- client/src/pages/settings.tsx | 4 +- client/src/pages/unsubscribed.tsx | 4 +- client/src/pages/update-email.tsx | 18 +- client/src/pages/user.tsx | 4 +- client/src/redux/accept-terms-saga.js | 4 +- client/src/redux/action-types.js | 33 +++ client/src/redux/app-mount-saga.js | 2 +- client/src/redux/createStore.js | 9 +- client/src/redux/donation-saga.js | 7 +- client/src/redux/error-saga.js | 4 +- client/src/redux/failed-updates-epic.js | 18 +- client/src/redux/failed-updates-epic.test.js | 8 +- client/src/redux/fetch-user-saga.js | 4 +- client/src/redux/ga-saga.test.js | 10 +- client/src/redux/hard-go-to-epic.js | 4 +- client/src/redux/index.js | 187 ++++++-------- client/src/redux/report-user-saga.js | 4 +- client/src/redux/rootEpic.js | 2 +- client/src/redux/rootReducer.js | 16 +- client/src/redux/rootSaga.js | 4 +- client/src/redux/settings/action-types.js | 19 ++ client/src/redux/settings/danger-zone-saga.js | 7 +- client/src/redux/settings/index.js | 20 +- client/src/redux/settings/settings-sagas.js | 18 +- .../src/redux/settings/update-email-saga.js | 2 +- client/src/redux/show-cert-saga.js | 2 +- client/src/redux/update-complete-epic.js | 3 +- .../templates/Challenges/classic/ActionRow.js | 4 +- .../Challenges/classic/DesktopLayout.js | 8 +- .../Challenges/classic/EditorTabs.js | 2 +- .../Challenges/classic/MobileLayout.js | 14 +- .../Challenges/classic/MultifileEditor.js | 2 +- .../src/templates/Challenges/classic/Show.tsx | 69 +++-- .../templates/Challenges/classic/editor.tsx | 39 ++- .../templates/Challenges/codeally/show.tsx | 8 +- .../Challenges/components/HelpModal.js | 12 +- .../Challenges/components/Hotkeys.tsx | 2 +- .../Challenges/components/Preview.js | 6 +- .../Challenges/components/ResetModal.tsx | 10 +- .../Challenges/components/Side-Panel.js | 66 ++--- .../Challenges/components/Test-Suite.js | 4 +- .../Challenges/components/Tool-Panel.js | 11 +- .../Challenges/components/VideoModal.js | 10 +- .../Challenges/components/bread-crumb.tsx | 2 +- .../Challenges/components/challenge-title.tsx | 9 +- .../components/completion-modal-body.test.tsx | 2 +- .../components/completion-modal-body.tsx | 4 +- .../components/completion-modal.tsx | 25 +- .../Challenges/components/output.tsx | 2 +- .../Challenges/components/prism-formatted.tsx | 2 +- .../Challenges/projects/backend/Show.tsx | 38 +-- .../Challenges/projects/frontend/Show.tsx | 22 +- .../Challenges/projects/solution-form.tsx | 2 +- .../Challenges/projects/tool-panel.tsx | 6 +- .../Challenges/rechallenge/transformers.js | 10 +- .../Challenges/redux/action-types.js | 48 ++++ .../Challenges/redux/code-lock-epic.js | 7 +- .../Challenges/redux/code-storage-epic.js | 22 +- .../Challenges/redux/completion-epic.js | 36 +-- .../Challenges/redux/create-question-epic.js | 10 +- .../redux/execute-challenge-saga.js | 31 ++- .../src/templates/Challenges/redux/index.js | 237 ++++++++---------- .../src/templates/Challenges/utils/build.js | 19 +- .../Challenges/utils/getTargetEditor.js | 2 +- .../src/templates/Challenges/video/Show.tsx | 22 +- client/src/templates/Introduction/Intro.js | 12 +- .../templates/Introduction/SuperBlockIntro.js | 24 +- .../Introduction/components/Block.js | 22 +- .../Introduction/components/CertChallenge.js | 24 +- .../components/CertificationCard.js | 12 +- .../Introduction/components/Challenges.js | 14 +- .../Introduction/components/ClaimCertSteps.js | 8 +- .../components/SuperBlockIntro.js | 4 +- client/src/utils/ajax.ts | 2 +- client/src/utils/curriculum-helpers.test.ts | 4 +- client/src/utils/curriculum-helpers.ts | 2 +- client/src/utils/handled-error.test.ts | 2 +- client/src/utils/handled-error.ts | 7 +- client/utils/buildChallenges.js | 4 +- client/utils/gatsby/layoutSelector.test.js | 6 +- client/utils/tags.js | 2 +- client/webpack-workers.js | 6 +- curriculum/getChallenges.js | 17 +- curriculum/gulpfile.js | 2 +- curriculum/test/test-challenges.js | 71 +++--- curriculum/test/utils/mongoIds.js | 2 +- .../test/utils/plugins/get-css-comments.js | 2 +- .../utils/plugins/get-script-js-comments.js | 2 +- .../create-next-step.js | 2 +- .../create-project.ts | 6 +- tools/challenge-helper-scripts/utils.js | 6 +- tools/challenge-helper-scripts/utils.test.js | 4 +- tools/challenge-parser/parser/index.js | 16 +- .../parser/plugins/add-frontmatter.js | 2 +- .../parser/plugins/add-seed.js | 6 +- .../parser/plugins/add-seed.test.js | 22 +- .../parser/plugins/add-solution.js | 6 +- .../parser/plugins/add-solution.test.js | 4 +- .../parser/plugins/add-tests.test.js | 2 +- .../parser/plugins/add-text.test.js | 2 +- .../parser/plugins/replace-imports.js | 6 +- .../parser/plugins/replace-imports.test.js | 8 +- .../parser/plugins/restore-directives.js | 4 +- .../parser/plugins/restore-directives.test.js | 4 +- .../parser/plugins/table-and-strikethrough.js | 2 +- .../parser/plugins/utils/between-headings.js | 2 +- .../plugins/utils/between-headings.test.js | 6 +- .../parser/plugins/utils/get-file-visitor.js | 2 +- .../parser/plugins/utils/get-id.test.js | 2 +- .../parser/plugins/utils/mdast-to-html.js | 2 +- .../plugins/utils/mdast-to-html.test.js | 4 +- .../parser/tools/full-parse.js | 2 +- .../parser/tools/generate-ast.js | 2 +- .../parser/tools/inspect-ast.js | 4 +- .../challenge-parser/parser/tools/parse-md.js | 2 +- .../translation-parser/index.test.js | 8 +- .../crowdin/actions/convert-chinese/index.js | 2 +- .../actions/hide-specific-string/index.js | 2 +- tools/crowdin/utils/dirs.js | 4 +- tools/crowdin/utils/files.js | 2 +- tools/scripts/build/build-curriculum.js | 2 +- tools/scripts/build/ensure-env.js | 2 +- tools/scripts/lint/index.js | 2 +- tools/scripts/seed/seedAuthUser.js | 11 +- tools/ui-components/rollup.config.js | 4 +- tools/ui-components/src/button.js | 2 +- tools/ui-components/src/button.test.js | 2 +- tools/ui-components/src/color-system.js | 2 +- utils/sort-files.test.js | 2 +- 259 files changed, 1269 insertions(+), 1303 deletions(-) create mode 100644 client/src/redux/action-types.js create mode 100644 client/src/redux/settings/action-types.js create mode 100644 client/src/templates/Challenges/redux/action-types.js diff --git a/.eslintrc-base.json b/.eslintrc-base.json index fb9225b7ff7..6941a96a201 100644 --- a/.eslintrc-base.json +++ b/.eslintrc-base.json @@ -32,6 +32,7 @@ "import/newline-after-import": 2, "import/no-duplicates": 2, "import/no-unresolved": [2, { "commonjs": true }], + "import/order": [2, { "alphabetize": { "order": "asc" } }], "import/unambiguous": 2, "import/no-anonymous-default-export": 2, "jsx-quotes": [2, "prefer-single"], @@ -122,6 +123,7 @@ "no-unused-expressions": 2, "no-unused-vars": 2, "no-use-before-define": 0, + "no-useless-rename": 2, "no-void": 0, "no-warning-comments": [2, { "terms": ["fixme"], "location": "start" }], "no-with": 2, diff --git a/api-server/src/common/models/User-Credential.js b/api-server/src/common/models/User-Credential.js index 8a6d44af606..1e5688d5e0a 100644 --- a/api-server/src/common/models/User-Credential.js +++ b/api-server/src/common/models/User-Credential.js @@ -1,11 +1,11 @@ -import { Observable } from 'rx'; import debug from 'debug'; +import { Observable } from 'rx'; -import { observeMethod, observeQuery } from '../../server/utils/rx'; import { createUserUpdatesFromProfile, getSocialProvider } from '../../server/utils/auth'; +import { observeMethod, observeQuery } from '../../server/utils/rx'; const log = debug('fcc:models:UserCredential'); module.exports = function (UserCredential) { diff --git a/api-server/src/common/models/User-Identity.js b/api-server/src/common/models/User-Identity.js index 67e2718ea86..8905c2edb69 100644 --- a/api-server/src/common/models/User-Identity.js +++ b/api-server/src/common/models/User-Identity.js @@ -1,10 +1,10 @@ +import dedent from 'dedent'; import { Observable } from 'rx'; // import debug from 'debug'; -import dedent from 'dedent'; import { isEmail } from 'validator'; -import { observeMethod, observeQuery } from '../../server/utils/rx'; import { wrapHandledError } from '../../server/utils/create-handled-error.js'; +import { observeMethod, observeQuery } from '../../server/utils/rx'; // const log = debug('fcc:models:userIdent'); diff --git a/api-server/src/common/models/user.js b/api-server/src/common/models/user.js index 90ce86ab133..38da2a3e3ba 100644 --- a/api-server/src/common/models/user.js +++ b/api-server/src/common/models/user.js @@ -5,18 +5,31 @@ * */ +import badwordFilter from 'bad-words'; +import debugFactory from 'debug'; +import dedent from 'dedent'; +import _ from 'lodash'; +import moment from 'moment'; +import generate from 'nanoid/generate'; import { Observable } from 'rx'; import uuid from 'uuid/v4'; -import moment from 'moment'; -import dedent from 'dedent'; -import debugFactory from 'debug'; import { isEmail } from 'validator'; -import _ from 'lodash'; -import generate from 'nanoid/generate'; -import badwordFilter from 'bad-words'; +import { blocklistedUsernames } from '../../../../config/constants'; import { apiLocation } from '../../../../config/env.json'; +import { wrapHandledError } from '../../server/utils/create-handled-error.js'; +import { + setAccessTokenToResponse, + removeCookies +} from '../../server/utils/getSetAccessToken'; +import { + normaliseUserFields, + getProgress, + publicUserProps +} from '../../server/utils/publicUserProps'; +import { saveUser, observeMethod } from '../../server/utils/rx.js'; +import { getEmailSender } from '../../server/utils/url-utils'; import { fixCompletedChallengeItem, getEncodedEmail, @@ -26,20 +39,6 @@ import { renderSignInEmail } from '../utils'; -import { blocklistedUsernames } from '../../../../config/constants'; -import { wrapHandledError } from '../../server/utils/create-handled-error.js'; -import { saveUser, observeMethod } from '../../server/utils/rx.js'; -import { getEmailSender } from '../../server/utils/url-utils'; -import { - normaliseUserFields, - getProgress, - publicUserProps -} from '../../server/utils/publicUserProps'; -import { - setAccessTokenToResponse, - removeCookies -} from '../../server/utils/getSetAccessToken'; - const log = debugFactory('fcc:models:user'); const BROWNIEPOINTS_TIMEOUT = [1, 'hour']; const nanoidCharSet = diff --git a/api-server/src/development-start.js b/api-server/src/development-start.js index dbae1cd7660..1110b7196fc 100644 --- a/api-server/src/development-start.js +++ b/api-server/src/development-start.js @@ -1,9 +1,9 @@ const path = require('path'); require('dotenv').config({ path: path.resolve(__dirname, '../../.env') }); +const createDebugger = require('debug'); const nodemon = require('nodemon'); const SmeeClient = require('smee-client'); -const createDebugger = require('debug'); const log = createDebugger('fcc:start:development'); diff --git a/api-server/src/production-start.js b/api-server/src/production-start.js index 6d05d65c1a2..ac389b26355 100644 --- a/api-server/src/production-start.js +++ b/api-server/src/production-start.js @@ -1,6 +1,6 @@ // this ensures node understands the future -const _ = require('lodash'); const createDebugger = require('debug'); +const _ = require('lodash'); const log = createDebugger('fcc:server:production-start'); const startTime = Date.now(); diff --git a/api-server/src/server/boot/authentication.js b/api-server/src/server/boot/authentication.js index 45fc4f29f70..a662fe4d1d3 100644 --- a/api-server/src/server/boot/authentication.js +++ b/api-server/src/server/boot/authentication.js @@ -1,20 +1,20 @@ -import passport from 'passport'; import dedent from 'dedent'; import { check } from 'express-validator'; -import { isEmail } from 'validator'; import jwt from 'jsonwebtoken'; +import passport from 'passport'; +import { isEmail } from 'validator'; import { jwtSecret } from '../../../../config/secrets'; +import { decodeEmail } from '../../common/utils'; import { createPassportCallbackAuthenticator, devSaveResponseAuthCookies, devLoginRedirect } from '../component-passport'; -import { ifUserRedirectTo, ifNoUserRedirectHome } from '../utils/middleware'; import { wrapHandledError } from '../utils/create-handled-error.js'; import { removeCookies } from '../utils/getSetAccessToken'; -import { decodeEmail } from '../../common/utils'; +import { ifUserRedirectTo, ifNoUserRedirectHome } from '../utils/middleware'; import { getRedirectParams } from '../utils/redirection'; const passwordlessGetValidators = [ diff --git a/api-server/src/server/boot/certificate.js b/api-server/src/server/boot/certificate.js index 74fa545d867..e5c5fcb371d 100644 --- a/api-server/src/server/boot/certificate.js +++ b/api-server/src/server/boot/certificate.js @@ -1,17 +1,10 @@ +import path from 'path'; +import debug from 'debug'; +import dedent from 'dedent'; import _ from 'lodash'; import loopback from 'loopback'; -import path from 'path'; -import dedent from 'dedent'; import { Observable } from 'rx'; -import debug from 'debug'; import { isEmail } from 'validator'; -import { reportError } from '../middlewares/sentry-error-handler.js'; - -import { ifNoUser401 } from '../utils/middleware'; -import { observeQuery } from '../utils/rx'; - -import { getChallenges } from '../utils/get-curriculum'; - import { completionHours, certTypes, @@ -22,6 +15,11 @@ import { oldDataVizId, superBlockCertTypeMap } from '../../../../config/certification-settings'; +import { reportError } from '../middlewares/sentry-error-handler.js'; + +import { getChallenges } from '../utils/get-curriculum'; +import { ifNoUser401 } from '../utils/middleware'; +import { observeQuery } from '../utils/rx'; const { legacyFrontEndChallengeId, diff --git a/api-server/src/server/boot/challenge.js b/api-server/src/server/boot/challenge.js index 98c3a0f64cf..dd9b771db59 100644 --- a/api-server/src/server/boot/challenge.js +++ b/api-server/src/server/boot/challenge.js @@ -4,17 +4,17 @@ * a db migration to fix all completedChallenges * */ -import { Observable } from 'rx'; -import { isEmpty, pick, omit, find, uniqBy } from 'lodash'; import debug from 'debug'; import dedent from 'dedent'; +import { isEmpty, pick, omit, find, uniqBy } from 'lodash'; import { ObjectID } from 'mongodb'; +import { Observable } from 'rx'; import isNumeric from 'validator/lib/isNumeric'; import isURL from 'validator/lib/isURL'; -import { ifNoUserSend } from '../utils/middleware'; import { fixCompletedChallengeItem } from '../../common/utils'; import { getChallenges } from '../utils/get-curriculum'; +import { ifNoUserSend } from '../utils/middleware'; import { getRedirectParams, normalizeParams, diff --git a/api-server/src/server/boot/donate.js b/api-server/src/server/boot/donate.js index 099908de47c..4bdd7802b98 100644 --- a/api-server/src/server/boot/donate.js +++ b/api-server/src/server/boot/donate.js @@ -1,11 +1,11 @@ import debug from 'debug'; +import keys from '../../../../config/secrets'; import { getAsyncPaypalToken, verifyWebHook, updateUser, verifyWebHookType } from '../utils/donation'; -import keys from '../../../../config/secrets'; const log = debug('fcc:boot:donate'); diff --git a/api-server/src/server/boot/settings.js b/api-server/src/server/boot/settings.js index d3d02d6c597..26de9e4050e 100644 --- a/api-server/src/server/boot/settings.js +++ b/api-server/src/server/boot/settings.js @@ -1,10 +1,10 @@ import debug from 'debug'; import { check } from 'express-validator'; -import { ifNoUser401, createValidatorErrorHandler } from '../utils/middleware'; -import { themes } from '../../common/utils/themes.js'; -import { alertTypes } from '../../common/utils/flash.js'; import { isValidUsername } from '../../../../utils/validate'; +import { alertTypes } from '../../common/utils/flash.js'; +import { themes } from '../../common/utils/themes.js'; +import { ifNoUser401, createValidatorErrorHandler } from '../utils/middleware'; const log = debug('fcc:boot:settings'); diff --git a/api-server/src/server/boot/user.js b/api-server/src/server/boot/user.js index 1caec372ffb..24ae6213bc1 100644 --- a/api-server/src/server/boot/user.js +++ b/api-server/src/server/boot/user.js @@ -1,19 +1,19 @@ -import dedent from 'dedent'; import debugFactory from 'debug'; +import dedent from 'dedent'; +import { body } from 'express-validator'; import { pick } from 'lodash'; import { Observable } from 'rx'; -import { body } from 'express-validator'; +import { fixCompletedChallengeItem } from '../../common/utils'; +import { removeCookies } from '../utils/getSetAccessToken'; +import { ifNoUser401, ifNoUserRedirectHome } from '../utils/middleware'; import { getProgress, normaliseUserFields, userPropsForSession } from '../utils/publicUserProps'; -import { fixCompletedChallengeItem } from '../../common/utils'; -import { ifNoUser401, ifNoUserRedirectHome } from '../utils/middleware'; -import { removeCookies } from '../utils/getSetAccessToken'; -import { trimTags } from '../utils/validators'; import { getRedirectParams } from '../utils/redirection'; +import { trimTags } from '../utils/validators'; const log = debugFactory('fcc:boot:user'); const sendNonUserToHome = ifNoUserRedirectHome(); diff --git a/api-server/src/server/component-passport.js b/api-server/src/server/component-passport.js index 568387d638e..e8d9d087b55 100644 --- a/api-server/src/server/component-passport.js +++ b/api-server/src/server/component-passport.js @@ -1,12 +1,13 @@ -import passport from 'passport'; // eslint-disable-next-line import { // prettier ignore PassportConfigurator } from '@freecodecamp/loopback-component-passport'; import dedent from 'dedent'; +import passport from 'passport'; -import { getUserById } from './utils/user-stats'; +import { availableLangs } from '../../../config/i18n/all-langs'; +import { jwtSecret } from '../../../config/secrets'; import passportProviders from './passport-providers'; import { setAccessTokenToResponse } from './utils/getSetAccessToken'; import { @@ -15,8 +16,7 @@ import { getRedirectParams, haveSamePath } from './utils/redirection'; -import { jwtSecret } from '../../../config/secrets'; -import { availableLangs } from '../../../config/i18n/all-langs'; +import { getUserById } from './utils/user-stats'; const passportOptions = { emailOptional: true, diff --git a/api-server/src/server/index.js b/api-server/src/server/index.js index 7d56e114744..8d047438310 100644 --- a/api-server/src/server/index.js +++ b/api-server/src/server/index.js @@ -1,12 +1,12 @@ const path = require('path'); require('dotenv').config({ path: path.resolve(__dirname, '../../../.env') }); +const Sentry = require('@sentry/node'); +const createDebugger = require('debug'); const _ = require('lodash'); const loopback = require('loopback'); const boot = require('loopback-boot'); -const createDebugger = require('debug'); const morgan = require('morgan'); -const Sentry = require('@sentry/node'); const { sentry } = require('../../../config/secrets'); const { setupPassport } = require('./component-passport'); diff --git a/api-server/src/server/middlewares/constant-headers.js b/api-server/src/server/middlewares/constant-headers.js index 2daef389190..a26a2f71ebb 100644 --- a/api-server/src/server/middlewares/constant-headers.js +++ b/api-server/src/server/middlewares/constant-headers.js @@ -1,5 +1,5 @@ -import { homeLocation } from '../../../../config/env.json'; import { allowedOrigins } from '../../../../config/cors-settings'; +import { homeLocation } from '../../../../config/env.json'; export default function constantHeaders() { return function (req, res, next) { diff --git a/api-server/src/server/middlewares/passport-login.js b/api-server/src/server/middlewares/passport-login.js index 0bb4e1fa424..d58b8df13aa 100644 --- a/api-server/src/server/middlewares/passport-login.js +++ b/api-server/src/server/middlewares/passport-login.js @@ -1,6 +1,6 @@ import _ from 'lodash'; -import { Observable } from 'rx'; import { login } from 'passport/lib/http/request'; +import { Observable } from 'rx'; // make login polymorphic // if supplied callback it works as normal diff --git a/api-server/src/server/middlewares/request-authorization.js b/api-server/src/server/middlewares/request-authorization.js index 18e0f88289c..8d5970e7bb6 100644 --- a/api-server/src/server/middlewares/request-authorization.js +++ b/api-server/src/server/middlewares/request-authorization.js @@ -1,15 +1,15 @@ import { isEmpty } from 'lodash'; -import { getUserById as _getUserById } from '../utils/user-stats'; +import { jwtSecret as _jwtSecret } from '../../../../config/secrets'; + +import { wrapHandledError } from '../utils/create-handled-error'; import { getAccessTokenFromRequest, errorTypes, authHeaderNS } from '../utils/getSetAccessToken'; -import { jwtSecret as _jwtSecret } from '../../../../config/secrets'; - -import { wrapHandledError } from '../utils/create-handled-error'; import { getRedirectParams } from '../utils/redirection'; +import { getUserById as _getUserById } from '../utils/user-stats'; const authRE = /^\/auth\//; const confirmEmailRE = /^\/confirm-email$/; diff --git a/api-server/src/server/middlewares/request-authorization.test.js b/api-server/src/server/middlewares/request-authorization.test.js index 8bd139000d1..593d5930ed9 100644 --- a/api-server/src/server/middlewares/request-authorization.test.js +++ b/api-server/src/server/middlewares/request-authorization.test.js @@ -1,7 +1,7 @@ -import { mockReq as mockRequest, mockRes } from '../boot_tests/challenge.test'; import jwt from 'jsonwebtoken'; import { homeLocation } from '../../../../config/env.json'; +import { mockReq as mockRequest, mockRes } from '../boot_tests/challenge.test'; import createRequestAuthorization, { isAllowedPath } from './request-authorization'; diff --git a/api-server/src/server/middlewares/sessions.js b/api-server/src/server/middlewares/sessions.js index cc488cd7900..219ed97724a 100644 --- a/api-server/src/server/middlewares/sessions.js +++ b/api-server/src/server/middlewares/sessions.js @@ -1,5 +1,5 @@ -import session from 'express-session'; import MongoStoreFactory from 'connect-mongo'; +import session from 'express-session'; const MongoStore = MongoStoreFactory(session); const sessionSecret = process.env.SESSION_SECRET; diff --git a/api-server/src/server/models/donation.js b/api-server/src/server/models/donation.js index 0cf543c0b2b..ae9bd7f6081 100644 --- a/api-server/src/server/models/donation.js +++ b/api-server/src/server/models/donation.js @@ -1,5 +1,5 @@ -import { Observable } from 'rx'; import debug from 'debug'; +import { Observable } from 'rx'; import { reportError } from '../middlewares/sentry-error-handler.js'; import InMemoryCache from '../utils/in-memory-cache'; diff --git a/api-server/src/server/passport-providers.js b/api-server/src/server/passport-providers.js index 092e8ef323a..e6938162c41 100644 --- a/api-server/src/server/passport-providers.js +++ b/api-server/src/server/passport-providers.js @@ -1,5 +1,5 @@ -import { auth0 } from '../../../config/secrets'; import { homeLocation, apiLocation } from '../../../config/env.json'; +import { auth0 } from '../../../config/secrets'; const { clientID, clientSecret, domain } = auth0; diff --git a/api-server/src/server/rss/index.js b/api-server/src/server/rss/index.js index 1112970ba42..c6f59b74fea 100644 --- a/api-server/src/server/rss/index.js +++ b/api-server/src/server/rss/index.js @@ -1,6 +1,6 @@ -import _ from 'lodash'; import compareDesc from 'date-fns/compare_desc'; import debug from 'debug'; +import _ from 'lodash'; import { getLybsynFeed } from './lybsyn'; diff --git a/api-server/src/server/utils/donation.test.js b/api-server/src/server/utils/donation.test.js index 8dc43098ee1..b30f8f5f448 100644 --- a/api-server/src/server/utils/donation.test.js +++ b/api-server/src/server/utils/donation.test.js @@ -1,14 +1,6 @@ /* eslint-disable camelcase */ import axios from 'axios'; import keys from '../../../../config/secrets'; -import { - getAsyncPaypalToken, - verifyWebHook, - updateUser, - capitalizeKeys, - createDonationObj -} from './donation'; -import { mockActivationHook, mockCancellationHook } from './__mocks__/donation'; import { mockApp, createDonationMockFn, @@ -16,6 +8,14 @@ import { updateDonationAttr, updateUserAttr } from '../boot_tests/fixtures'; +import { mockActivationHook, mockCancellationHook } from './__mocks__/donation'; +import { + getAsyncPaypalToken, + verifyWebHook, + updateUser, + capitalizeKeys, + createDonationObj +} from './donation'; jest.mock('axios'); diff --git a/api-server/src/server/utils/getSetAccessToken.js b/api-server/src/server/utils/getSetAccessToken.js index a7ffe8bfa91..bf19cddedff 100644 --- a/api-server/src/server/utils/getSetAccessToken.js +++ b/api-server/src/server/utils/getSetAccessToken.js @@ -1,5 +1,5 @@ -import jwt from 'jsonwebtoken'; import { isBefore } from 'date-fns'; +import jwt from 'jsonwebtoken'; import { jwtSecret as _jwtSecret } from '../../../../config/secrets'; diff --git a/api-server/src/server/utils/getSetAccessToken.test.js b/api-server/src/server/utils/getSetAccessToken.test.js index 477948eb9a0..768d0ea0d0b 100644 --- a/api-server/src/server/utils/getSetAccessToken.test.js +++ b/api-server/src/server/utils/getSetAccessToken.test.js @@ -1,11 +1,11 @@ +import jwt from 'jsonwebtoken'; +import { mockReq, mockRes } from '../boot_tests/challenge.test'; import { getAccessTokenFromRequest, errorTypes, setAccessTokenToResponse, removeCookies } from './getSetAccessToken'; -import { mockReq, mockRes } from '../boot_tests/challenge.test'; -import jwt from 'jsonwebtoken'; describe('getSetAccessToken', () => { const validJWTSecret = 'this is a super secret string'; diff --git a/api-server/src/server/utils/publicUserProps.js b/api-server/src/server/utils/publicUserProps.js index 6c1282bedf8..e73e1be05d8 100644 --- a/api-server/src/server/utils/publicUserProps.js +++ b/api-server/src/server/utils/publicUserProps.js @@ -1,11 +1,11 @@ import { isURL } from 'validator'; -import { addPlaceholderImage } from './'; import { prepUniqueDaysByHours, calcCurrentStreak, calcLongestStreak } from '../utils/user-stats'; +import { addPlaceholderImage } from './'; export const publicUserProps = [ 'about', diff --git a/api-server/src/server/utils/redirection.js b/api-server/src/server/utils/redirection.js index de441ee625d..326d9c1c45b 100644 --- a/api-server/src/server/utils/redirection.js +++ b/api-server/src/server/utils/redirection.js @@ -1,9 +1,9 @@ const jwt = require('jsonwebtoken'); -const { availableLangs } = require('../../../../config/i18n/all-langs'); const { allowedOrigins } = require('../../../../config/cors-settings'); // homeLocation is being used as a fallback here. If the one provided by the // client is invalid we default to this. const { homeLocation } = require('../../../../config/env.json'); +const { availableLangs } = require('../../../../config/i18n/all-langs'); function getReturnTo(encryptedParams, secret, _homeLocation = homeLocation) { let params; diff --git a/api-server/src/server/utils/rx.js b/api-server/src/server/utils/rx.js index 331a18f728a..de1cd7d40bf 100644 --- a/api-server/src/server/utils/rx.js +++ b/api-server/src/server/utils/rx.js @@ -1,6 +1,6 @@ -import Rx, { AsyncSubject, Observable } from 'rx'; -import moment from 'moment'; import debugFactory from 'debug'; +import moment from 'moment'; +import Rx, { AsyncSubject, Observable } from 'rx'; const debug = debugFactory('fcc:rxUtils'); diff --git a/api-server/src/server/utils/user-stats.js b/api-server/src/server/utils/user-stats.js index 9e154af5a65..95203071b98 100644 --- a/api-server/src/server/utils/user-stats.js +++ b/api-server/src/server/utils/user-stats.js @@ -1,11 +1,11 @@ -import loopback from 'loopback'; +import { isEmpty } from 'lodash'; import compose from 'lodash/fp/compose'; +import forEachRight from 'lodash/fp/forEachRight'; +import last from 'lodash/fp/last'; import map from 'lodash/fp/map'; import sortBy from 'lodash/fp/sortBy'; import trans from 'lodash/fp/transform'; -import last from 'lodash/fp/last'; -import forEachRight from 'lodash/fp/forEachRight'; -import { isEmpty } from 'lodash'; +import loopback from 'loopback'; import moment from 'moment-timezone'; import { dayCount } from '../utils/date-utils'; diff --git a/api-server/src/server/utils/user-stats.test.js b/api-server/src/server/utils/user-stats.test.js index 321622509fd..5b66caa26f5 100644 --- a/api-server/src/server/utils/user-stats.test.js +++ b/api-server/src/server/utils/user-stats.test.js @@ -1,12 +1,12 @@ import moment from 'moment-timezone'; +import { mockUserID, mockApp, mockUser } from '../boot_tests/fixtures'; import { prepUniqueDaysByHours, calcCurrentStreak, calcLongestStreak, getUserById } from './user-stats'; -import { mockUserID, mockApp, mockUser } from '../boot_tests/fixtures'; jest.useFakeTimers('modern'); const PST = 'America/Los_Angeles'; diff --git a/client/gatsby-browser.js b/client/gatsby-browser.js index 0a4074c55d8..e2292ec15cc 100644 --- a/client/gatsby-browser.js +++ b/client/gatsby-browser.js @@ -1,12 +1,12 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import { Provider } from 'react-redux'; -import { I18nextProvider } from 'react-i18next'; import cookies from 'browser-cookies'; +import PropTypes from 'prop-types'; +import React from 'react'; +import { I18nextProvider } from 'react-i18next'; +import { Provider } from 'react-redux'; import i18n from './i18n/config'; -import { createStore } from './src/redux/createStore'; import AppMountNotifier from './src/components/app-mount-notifier'; +import { createStore } from './src/redux/createStore'; import layoutSelector from './utils/gatsby/layout-selector'; const store = createStore(); diff --git a/client/gatsby-node.js b/client/gatsby-node.js index 86e3ad012da..4d4fa4d4069 100644 --- a/client/gatsby-node.js +++ b/client/gatsby-node.js @@ -1,10 +1,10 @@ -const env = require('../config/env.json'); -const webpack = require('webpack'); - const { createFilePath } = require('gatsby-source-filesystem'); // TODO: ideally we'd remove lodash and just use lodash-es, but we can't require // es modules here. const uniq = require('lodash/uniq'); +const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin'); +const webpack = require('webpack'); +const env = require('../config/env.json'); const { blockNameify } = require('../utils/block-nameify'); const { @@ -165,8 +165,6 @@ exports.createPages = function createPages({ graphql, actions, reporter }) { }); }; -const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin'); - exports.onCreateWebpackConfig = ({ stage, actions }) => { const newPlugins = [ // We add the shims of the node globals to the global scope diff --git a/client/gatsby-ssr.js b/client/gatsby-ssr.js index b488ead6aba..c0c0fd3ccaf 100644 --- a/client/gatsby-ssr.js +++ b/client/gatsby-ssr.js @@ -1,7 +1,7 @@ -import React from 'react'; import PropTypes from 'prop-types'; -import { Provider } from 'react-redux'; +import React from 'react'; import { I18nextProvider } from 'react-i18next'; +import { Provider } from 'react-redux'; import i18n from './i18n/config'; import { createStore } from './src/redux/createStore'; diff --git a/client/i18n/schema-validation.js b/client/i18n/schema-validation.js index f7e77a39569..d6efa04f84c 100644 --- a/client/i18n/schema-validation.js +++ b/client/i18n/schema-validation.js @@ -1,11 +1,11 @@ const path = require('path'); const { availableLangs } = require('../../config/i18n/all-langs'); +const introSchema = require('./locales/english/intro.json'); +const linksSchema = require('./locales/english/links.json'); +const metaTagsSchema = require('./locales/english/meta-tags.json'); +const motivationSchema = require('./locales/english/motivation.json'); const translationsSchema = require('./locales/english/translations.json'); const trendingSchema = require('./locales/english/trending.json'); -const motivationSchema = require('./locales/english/motivation.json'); -const introSchema = require('./locales/english/intro.json'); -const metaTagsSchema = require('./locales/english/meta-tags.json'); -const linksSchema = require('./locales/english/links.json'); /** * Flattens a nested object structure into a single diff --git a/client/i18n/validate-keys.js b/client/i18n/validate-keys.js index f2e9bbdb031..264c0c16012 100644 --- a/client/i18n/validate-keys.js +++ b/client/i18n/validate-keys.js @@ -1,11 +1,11 @@ const fs = require('fs'); const path = require('path'); -const translationsObject = require('./locales/english/translations.json'); const introObject = require('./locales/english/intro.json'); +const linksObject = require('./locales/english/links.json'); const metaObject = require('./locales/english/meta-tags.json'); const motivationObject = require('./locales/english/motivation.json'); +const translationsObject = require('./locales/english/translations.json'); const trendingObject = require('./locales/english/trending.json'); -const linksObject = require('./locales/english/links.json'); /** * Function to flatten a nested object. Written specifically for diff --git a/client/src/analytics/index.tsx b/client/src/analytics/index.tsx index 670e4472393..79791770228 100644 --- a/client/src/analytics/index.tsx +++ b/client/src/analytics/index.tsx @@ -1,9 +1,9 @@ import ReactGA from 'react-ga'; -import envData from '../../../config/env.json'; import { devAnalyticsId, prodAnalyticsId } from '../../../config/analytics-settings'; +import envData from '../../../config/env.json'; const { deploymentEnv } = envData; diff --git a/client/src/assets/icons/index.tsx b/client/src/assets/icons/index.tsx index 3fe4a33b3d1..5802bb0430d 100644 --- a/client/src/assets/icons/index.tsx +++ b/client/src/assets/icons/index.tsx @@ -1,15 +1,15 @@ import React from 'react'; -import ResponsiveDesign from './responsive-design'; +import APIIcon from './API-icon'; +import D3Icon from './D3-icon'; import JavaScriptIcon from './JavaScript-icon'; import ReactIcon from './React-icon'; -import D3Icon from './D3-icon'; -import APIIcon from './API-icon'; -import Clipboard from './clipboard'; -import PythonIcon from './python-icon'; -import Analytics from './analytics'; -import Shield from './shield'; import TensorflowIcon from './Tensorflow-icon'; import Algorithm from './algorithm'; +import Analytics from './analytics'; +import Clipboard from './clipboard'; +import PythonIcon from './python-icon'; +import ResponsiveDesign from './responsive-design'; +import Shield from './shield'; const iconMap = { 'responsive-web-design': ResponsiveDesign, diff --git a/client/src/assets/images/components/index.tsx b/client/src/assets/images/components/index.tsx index 88148056d1f..f254ef71606 100644 --- a/client/src/assets/images/components/index.tsx +++ b/client/src/assets/images/components/index.tsx @@ -1,9 +1,9 @@ -import AppleLogo from './apple-logo'; import AmazonLogo from './amazon-logo'; +import AppleLogo from './apple-logo'; +import AsSeenInText from './as-seen-in-text'; +import GoogleLogo from './google-logo'; import MicrosoftLogo from './microsoft-logo'; import SpotifyLogo from './spotify-logo'; -import GoogleLogo from './google-logo'; -import AsSeenInText from './as-seen-in-text'; export { AmazonLogo, diff --git a/client/src/client-only-routes/show-certification.tsx b/client/src/client-only-routes/show-certification.tsx index 72c910305cb..3a4b16963b2 100644 --- a/client/src/client-only-routes/show-certification.tsx +++ b/client/src/client-only-routes/show-certification.tsx @@ -1,14 +1,19 @@ -import React, { useEffect, useState } from 'react'; -import { bindActionCreators, Dispatch } from 'redux'; -import { connect } from 'react-redux'; -import { createSelector } from 'reselect'; import { Grid, Row, Col, Image, Button } from '@freecodecamp/react-bootstrap'; +import { isEmpty } from 'lodash-es'; +import React, { useEffect, useState } from 'react'; +import { Trans, useTranslation } from 'react-i18next'; +import { connect } from 'react-redux'; +import { bindActionCreators, Dispatch } from 'redux'; +import { createSelector } from 'reselect'; -import ShowProjectLinks from './show-project-links'; +import envData from '../../../config/env.json'; +import { langCodes } from '../../../config/i18n/all-langs'; import FreeCodeCampLogo from '../assets/icons/FreeCodeCamp-logo'; import DonateForm from '../components/Donation/DonateForm'; -import { Trans, useTranslation } from 'react-i18next'; +import { createFlashMessage } from '../components/Flash/redux'; +import { Loader, Spacer } from '../components/helpers'; +import RedirectHome from '../components/redirect-home'; import { showCertSelector, showCertFetchStateSelector, @@ -20,17 +25,12 @@ import { userByNameSelector, fetchProfileForUser } from '../redux'; -import { certMap } from '../resources/cert-and-project-map'; -import { createFlashMessage } from '../components/Flash/redux'; -import standardErrorMessage from '../utils/standard-error-message'; -import reallyWeirdErrorMessage from '../utils/really-weird-error-message'; -import { langCodes } from '../../../config/i18n/all-langs'; -import envData from '../../../config/env.json'; - -import RedirectHome from '../components/redirect-home'; -import { Loader, Spacer } from '../components/helpers'; -import { isEmpty } from 'lodash-es'; import { UserType } from '../redux/prop-types'; +import { certMap } from '../resources/cert-and-project-map'; +import reallyWeirdErrorMessage from '../utils/really-weird-error-message'; +import standardErrorMessage from '../utils/standard-error-message'; + +import ShowProjectLinks from './show-project-links'; const { clientLocale } = envData as { clientLocale: keyof typeof langCodes }; diff --git a/client/src/client-only-routes/show-profile-or-four-oh-four.tsx b/client/src/client-only-routes/show-profile-or-four-oh-four.tsx index 838290f56e6..a8cf25b2c56 100644 --- a/client/src/client-only-routes/show-profile-or-four-oh-four.tsx +++ b/client/src/client-only-routes/show-profile-or-four-oh-four.tsx @@ -1,17 +1,17 @@ +import { isEmpty } from 'lodash-es'; import React, { Component } from 'react'; import { connect } from 'react-redux'; -import { isEmpty } from 'lodash-es'; +import { isBrowser } from '../../utils/index'; +import FourOhFour from '../components/FourOhFour'; import Loader from '../components/helpers/loader'; +import Profile from '../components/profile/Profile'; import { userByNameSelector, userProfileFetchStateSelector, fetchProfileForUser, usernameSelector } from '../redux'; -import FourOhFour from '../components/FourOhFour'; -import Profile from '../components/profile/Profile'; -import { isBrowser } from '../../utils/index'; import { UserType } from '../redux/prop-types'; interface IShowProfileOrFourOhFourProps { diff --git a/client/src/client-only-routes/show-project-links.tsx b/client/src/client-only-routes/show-project-links.tsx index 8d345e239e1..29ca8ffdef9 100644 --- a/client/src/client-only-routes/show-project-links.tsx +++ b/client/src/client-only-routes/show-project-links.tsx @@ -1,19 +1,20 @@ +import { find, first } from 'lodash-es'; import React, { useState } from 'react'; import '../components/layouts/project-links.css'; -import { maybeUrlRE } from '../utils'; -import { Spacer, Link } from '../components/helpers'; -import { - projectMap, - legacyProjectMap -} from '../resources/cert-and-project-map'; -import ProjectModal from '../components/SolutionViewer/ProjectModal'; -import { find, first } from 'lodash-es'; import { Trans, useTranslation } from 'react-i18next'; +import ProjectModal from '../components/SolutionViewer/ProjectModal'; +import { Spacer, Link } from '../components/helpers'; import { ChallengeFileType, CompletedChallenge, UserType } from '../redux/prop-types'; +import { + projectMap, + legacyProjectMap +} from '../resources/cert-and-project-map'; + +import { maybeUrlRE } from '../utils'; interface IShowProjectLinksProps { certName: string; diff --git a/client/src/client-only-routes/show-settings.tsx b/client/src/client-only-routes/show-settings.tsx index b40ce6a3af9..76933b23b94 100644 --- a/client/src/client-only-routes/show-settings.tsx +++ b/client/src/client-only-routes/show-settings.tsx @@ -1,30 +1,29 @@ +import { Grid } from '@freecodecamp/react-bootstrap'; import React from 'react'; +import Helmet from 'react-helmet'; +import { useTranslation } from 'react-i18next'; import { connect } from 'react-redux'; import { createSelector } from 'reselect'; -import { Grid } from '@freecodecamp/react-bootstrap'; -import Helmet from 'react-helmet'; import envData from '../../../config/env.json'; +import { createFlashMessage } from '../components/Flash/redux'; +import { Loader, Spacer } from '../components/helpers'; +import Certification from '../components/settings/Certification'; +import About from '../components/settings/about'; +import DangerZone from '../components/settings/danger-zone'; +import Email from '../components/settings/email'; +import Honesty from '../components/settings/honesty'; +import Internet from '../components/settings/internet'; +import Portfolio from '../components/settings/portfolio'; +import Privacy from '../components/settings/privacy'; import { signInLoadingSelector, userSelector, isSignedInSelector, hardGoTo as navigate } from '../redux'; -import { submitNewAbout, updateUserFlag, verifyCert } from '../redux/settings'; -import { createFlashMessage } from '../components/Flash/redux'; -import { useTranslation } from 'react-i18next'; - -import { Loader, Spacer } from '../components/helpers'; -import About from '../components/settings/about'; -import Privacy from '../components/settings/privacy'; -import Email from '../components/settings/email'; -import Internet from '../components/settings/internet'; -import Portfolio from '../components/settings/portfolio'; -import Honesty from '../components/settings/honesty'; -import Certification from '../components/settings/Certification'; import { UserType } from '../redux/prop-types'; -import DangerZone from '../components/settings/danger-zone'; +import { submitNewAbout, updateUserFlag, verifyCert } from '../redux/settings'; const { apiLocation } = envData; diff --git a/client/src/client-only-routes/show-unsubscribed.tsx b/client/src/client-only-routes/show-unsubscribed.tsx index 4b228790125..0ddd3c02482 100644 --- a/client/src/client-only-routes/show-unsubscribed.tsx +++ b/client/src/client-only-routes/show-unsubscribed.tsx @@ -1,11 +1,11 @@ -import React from 'react'; import { Grid, Panel, Button } from '@freecodecamp/react-bootstrap'; +import React from 'react'; import Helmet from 'react-helmet'; import { useTranslation } from 'react-i18next'; import envData from '../../../config/env.json'; -import FullWidthRow from '../components/helpers/full-width-row'; import { Spacer } from '../components/helpers'; +import FullWidthRow from '../components/helpers/full-width-row'; const { apiLocation } = envData; diff --git a/client/src/client-only-routes/show-user.tsx b/client/src/client-only-routes/show-user.tsx index dd40a0c8785..ec3bc6b798a 100644 --- a/client/src/client-only-routes/show-user.tsx +++ b/client/src/client-only-routes/show-user.tsx @@ -1,6 +1,3 @@ -import React, { Component } from 'react'; -import { connect } from 'react-redux'; -import { createSelector } from 'reselect'; import { Panel, FormControl, @@ -10,18 +7,21 @@ import { Col, Row } from '@freecodecamp/react-bootstrap'; +import React, { Component } from 'react'; import Helmet from 'react-helmet'; import { TFunction, Trans, withTranslation } from 'react-i18next'; +import { connect } from 'react-redux'; +import { createSelector } from 'reselect'; import Login from '../components/Header/components/Login'; +import { Spacer, Loader, FullWidthRow } from '../components/helpers'; import { isSignedInSelector, userFetchStateSelector, userSelector, reportUser } from '../redux'; -import { Spacer, Loader, FullWidthRow } from '../components/helpers'; interface IShowUserProps { email: string; diff --git a/client/src/client/workers/test-evaluator.js b/client/src/client/workers/test-evaluator.js index 13adf0cb608..bc1189cbe78 100644 --- a/client/src/client/workers/test-evaluator.js +++ b/client/src/client/workers/test-evaluator.js @@ -1,10 +1,10 @@ import chai from 'chai'; import '@babel/polyfill'; import { toString as __toString } from 'lodash-es'; -import { format as __format } from '../../utils/format'; import curriculumHelpers, { removeJSComments } from '../../utils/curriculum-helpers'; +import { format as __format } from '../../utils/format'; const __utils = (() => { const MAX_LOGS_SIZE = 64 * 1024; diff --git a/client/src/components/Donation/DonateCompletion.js b/client/src/components/Donation/DonateCompletion.js index 1745109a4b2..892b47c82c3 100644 --- a/client/src/components/Donation/DonateCompletion.js +++ b/client/src/components/Donation/DonateCompletion.js @@ -1,8 +1,8 @@ -import React from 'react'; -import PropTypes from 'prop-types'; import { Alert, Button } from '@freecodecamp/react-bootstrap'; -import Spinner from 'react-spinkit'; +import PropTypes from 'prop-types'; +import React from 'react'; import { useTranslation } from 'react-i18next'; +import Spinner from 'react-spinkit'; import './Donation.css'; diff --git a/client/src/components/Donation/DonateForm.js b/client/src/components/Donation/DonateForm.js index 295bff1365f..61ab4cf1074 100644 --- a/client/src/components/Donation/DonateForm.js +++ b/client/src/components/Donation/DonateForm.js @@ -1,8 +1,4 @@ /* eslint-disable no-nested-ternary */ -import React, { Component } from 'react'; -import PropTypes from 'prop-types'; -import { connect } from 'react-redux'; -import { createSelector } from 'reselect'; import { Col, Row, @@ -11,7 +7,11 @@ import { ToggleButton, ToggleButtonGroup } from '@freecodecamp/react-bootstrap'; +import PropTypes from 'prop-types'; +import React, { Component } from 'react'; import { withTranslation } from 'react-i18next'; +import { connect } from 'react-redux'; +import { createSelector } from 'reselect'; import { amountsConfig, @@ -20,9 +20,6 @@ import { defaultDonation, modalDefaultDonation } from '../../../../config/donation-settings'; -import Spacer from '../helpers/spacer'; -import PaypalButton from './PaypalButton'; -import DonateCompletion from './DonateCompletion'; import { isSignedInSelector, signInLoadingSelector, @@ -32,6 +29,9 @@ import { defaultDonationFormState, userSelector } from '../../redux'; +import Spacer from '../helpers/spacer'; +import DonateCompletion from './DonateCompletion'; +import PaypalButton from './PaypalButton'; import './Donation.css'; diff --git a/client/src/components/Donation/DonationModal.js b/client/src/components/Donation/DonationModal.js index 12bbbbfd1b6..558a84e1cfa 100644 --- a/client/src/components/Donation/DonationModal.js +++ b/client/src/components/Donation/DonationModal.js @@ -1,25 +1,24 @@ /* eslint-disable max-len */ -import React, { useEffect } from 'react'; -import PropTypes from 'prop-types'; -import { bindActionCreators } from 'redux'; -import { connect } from 'react-redux'; -import { createSelector } from 'reselect'; import { Modal, Button, Col, Row } from '@freecodecamp/react-bootstrap'; -import { Spacer } from '../helpers'; -import Heart from '../../assets/icons/heart'; -import Cup from '../../assets/icons/cup'; -import DonateForm from './DonateForm'; -import { modalDefaultDonation } from '../../../../config/donation-settings'; +import PropTypes from 'prop-types'; +import React, { useEffect } from 'react'; import { useTranslation } from 'react-i18next'; +import { connect } from 'react-redux'; import { goToAnchor } from 'react-scrollable-anchor'; -import { isLocationSuperBlock } from '../../utils/path-parsers'; - +import { bindActionCreators } from 'redux'; +import { createSelector } from 'reselect'; +import { modalDefaultDonation } from '../../../../config/donation-settings'; +import Cup from '../../assets/icons/cup'; +import Heart from '../../assets/icons/heart'; import { closeDonationModal, isDonationModalOpenSelector, recentlyClaimedBlockSelector, executeGA } from '../../redux'; +import { isLocationSuperBlock } from '../../utils/path-parsers'; +import { Spacer } from '../helpers'; +import DonateForm from './DonateForm'; import './Donation.css'; diff --git a/client/src/components/Donation/PayPalButtonScriptLoader.js b/client/src/components/Donation/PayPalButtonScriptLoader.js index 45a033fa99b..ac73a54a68e 100644 --- a/client/src/components/Donation/PayPalButtonScriptLoader.js +++ b/client/src/components/Donation/PayPalButtonScriptLoader.js @@ -1,11 +1,11 @@ /* eslint-disable camelcase */ +import PropTypes from 'prop-types'; import React, { Component } from 'react'; import ReactDOM from 'react-dom'; -import PropTypes from 'prop-types'; -import { scriptLoader, scriptRemover } from '../../utils/script-loaders'; import { Loader } from '../../components/helpers'; +import { scriptLoader, scriptRemover } from '../../utils/script-loaders'; export class PayPalButtonScriptLoader extends Component { state = { isSdkLoaded: window.paypal && true, isSubscription: true }; diff --git a/client/src/components/Donation/PaypalButton.js b/client/src/components/Donation/PaypalButton.js index c2b15ca9ffd..1aacb89bcdf 100644 --- a/client/src/components/Donation/PaypalButton.js +++ b/client/src/components/Donation/PaypalButton.js @@ -1,18 +1,17 @@ /* eslint-disable camelcase */ -import React, { Component } from 'react'; import PropTypes from 'prop-types'; +import React, { Component } from 'react'; +import { withTranslation } from 'react-i18next'; import { connect } from 'react-redux'; import { createSelector } from 'reselect'; -import PayPalButtonScriptLoader from './PayPalButtonScriptLoader'; -import { withTranslation } from 'react-i18next'; - -import envData from '../../../../config/env.json'; import { paypalConfigurator, paypalConfigTypes } from '../../../../config/donation-settings'; +import envData from '../../../../config/env.json'; import { signInLoadingSelector, userSelector } from '../../redux'; +import PayPalButtonScriptLoader from './PayPalButtonScriptLoader'; const { paypalClientId, deploymentEnv } = envData; export class PaypalButton extends Component { diff --git a/client/src/components/Flash/index.tsx b/client/src/components/Flash/index.tsx index 01f7423541c..01f649cdbe6 100644 --- a/client/src/components/Flash/index.tsx +++ b/client/src/components/Flash/index.tsx @@ -1,8 +1,8 @@ -import React, { useState, useEffect } from 'react'; -import PropTypes from 'prop-types'; import { Alert } from '@freecodecamp/react-bootstrap'; -import { TransitionGroup, CSSTransition } from 'react-transition-group'; +import PropTypes from 'prop-types'; +import React, { useState, useEffect } from 'react'; import { useTranslation } from 'react-i18next'; +import { TransitionGroup, CSSTransition } from 'react-transition-group'; import './flash.css'; diff --git a/client/src/components/Flash/redux/index.ts b/client/src/components/Flash/redux/index.ts index e3c2f2fcf03..46059692a8f 100644 --- a/client/src/components/Flash/redux/index.ts +++ b/client/src/components/Flash/redux/index.ts @@ -1,5 +1,5 @@ -import { createAction, handleActions } from 'redux-actions'; import { nanoid } from 'nanoid'; +import { createAction, handleActions } from 'redux-actions'; import { createTypes } from '../../../utils/create-types'; diff --git a/client/src/components/FourOhFour/index.tsx b/client/src/components/FourOhFour/index.tsx index dbda4bb868b..34a8abc9a11 100644 --- a/client/src/components/FourOhFour/index.tsx +++ b/client/src/components/FourOhFour/index.tsx @@ -1,11 +1,11 @@ +import { Link } from 'gatsby'; import React from 'react'; import Helmet from 'react-helmet'; -import { Spacer } from '../helpers'; -import { Link } from 'gatsby'; import { useTranslation } from 'react-i18next'; import notFoundLogo from '../../assets/images/freeCodeCamp-404.svg'; import { randomQuote } from '../../utils/get-words'; +import { Spacer } from '../helpers'; import './404.css'; diff --git a/client/src/components/Header/Header.test.js b/client/src/components/Header/Header.test.js index 1e793aefbf1..748af6494e7 100644 --- a/client/src/components/Header/Header.test.js +++ b/client/src/components/Header/Header.test.js @@ -1,13 +1,12 @@ import React from 'react'; +import { useTranslation } from 'react-i18next'; import { create } from 'react-test-renderer'; import ShallowRenderer from 'react-test-renderer/shallow'; -import { UniversalNav } from './components/universal-nav'; -import { NavLinks } from './components/nav-links'; -import AuthOrProfile from './components/auth-or-profile'; - import envData from '../../../../config/env.json'; -import { useTranslation } from 'react-i18next'; +import AuthOrProfile from './components/auth-or-profile'; +import { NavLinks } from './components/nav-links'; +import { UniversalNav } from './components/universal-nav'; const { apiLocation } = envData; diff --git a/client/src/components/Header/components/Login.tsx b/client/src/components/Header/components/Login.tsx index 8b166d7c6d8..2bf96c08e23 100644 --- a/client/src/components/Header/components/Login.tsx +++ b/client/src/components/Header/components/Login.tsx @@ -1,11 +1,11 @@ +import { Button } from '@freecodecamp/react-bootstrap'; import React from 'react'; +import { useTranslation } from 'react-i18next'; import { connect } from 'react-redux'; import { createSelector } from 'reselect'; -import { Button } from '@freecodecamp/react-bootstrap'; -import { useTranslation } from 'react-i18next'; -import { isSignedInSelector } from '../../../redux'; import envData from '../../../../../config/env.json'; +import { isSignedInSelector } from '../../../redux'; import './login.css'; diff --git a/client/src/components/Header/components/auth-or-profile.tsx b/client/src/components/Header/components/auth-or-profile.tsx index b228a3806ad..22334f51840 100644 --- a/client/src/components/Header/components/auth-or-profile.tsx +++ b/client/src/components/Header/components/auth-or-profile.tsx @@ -3,8 +3,8 @@ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ // @ts-nocheck import React from 'react'; -import { Link, AvatarRenderer } from '../../helpers'; import { useTranslation } from 'react-i18next'; +import { Link, AvatarRenderer } from '../../helpers'; import Login from './Login'; export interface AuthOrProfileProps { diff --git a/client/src/components/Header/components/nav-links.tsx b/client/src/components/Header/components/nav-links.tsx index d6c99a83c3e..c7281d41b3f 100644 --- a/client/src/components/Header/components/nav-links.tsx +++ b/client/src/components/Header/components/nav-links.tsx @@ -8,10 +8,6 @@ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/restrict-template-expressions */ // @ts-nocheck -import React, { Component, Fragment } from 'react'; -import { connect } from 'react-redux'; -import { TFunction, withTranslation } from 'react-i18next'; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faCheck, faCheckSquare, @@ -19,15 +15,19 @@ import { faSquare, faExternalLinkAlt } from '@fortawesome/free-solid-svg-icons'; -import { Link } from '../../helpers'; -import { updateUserFlag } from '../../../redux/settings'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import React, { Component, Fragment } from 'react'; +import { TFunction, withTranslation } from 'react-i18next'; +import { connect } from 'react-redux'; import envData from '../../../../../config/env.json'; -import createLanguageRedirect from '../../create-language-redirect'; import { availableLangs, i18nextCodes, langDisplayNames } from '../../../../../config/i18n/all-langs'; +import { updateUserFlag } from '../../../redux/settings'; +import createLanguageRedirect from '../../create-language-redirect'; +import { Link } from '../../helpers'; const { clientLocale, radioLocation, apiLocation } = envData; diff --git a/client/src/components/Header/components/universal-nav.tsx b/client/src/components/Header/components/universal-nav.tsx index 701fda03fc4..9da7a223f1d 100644 --- a/client/src/components/Header/components/universal-nav.tsx +++ b/client/src/components/Header/components/universal-nav.tsx @@ -3,14 +3,14 @@ /* eslint-disable @typescript-eslint/ban-ts-comment */ /* eslint-disable react/prop-types */ // @ts-nocheck +import Loadable from '@loadable/component'; import React, { Ref } from 'react'; +import { isLanding } from '../../../utils/path-parsers'; import { Link, SkeletonSprite } from '../../helpers'; -import NavLogo from './nav-logo'; import MenuButton from './menu-button'; import NavLinks from './nav-links'; +import NavLogo from './nav-logo'; import './universal-nav.css'; -import { isLanding } from '../../../utils/path-parsers'; -import Loadable from '@loadable/component'; const SearchBar = Loadable(() => import('../../search/searchBar/search-bar')); const SearchBarOptimized = Loadable( diff --git a/client/src/components/Header/components/user-state.tsx b/client/src/components/Header/components/user-state.tsx index 72981789d03..54e6d3339a0 100644 --- a/client/src/components/Header/components/user-state.tsx +++ b/client/src/components/Header/components/user-state.tsx @@ -2,12 +2,12 @@ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ -import React from 'react'; -import { connect } from 'react-redux'; -import { createSelector } from 'reselect'; import { Link } from 'gatsby'; -import Spinner from 'react-spinkit'; +import React from 'react'; import { useTranslation } from 'react-i18next'; +import { connect } from 'react-redux'; +import Spinner from 'react-spinkit'; +import { createSelector } from 'reselect'; import { isSignedInSelector, userFetchStateSelector } from '../../../redux'; import Login from './Login'; diff --git a/client/src/components/Intro/Intro.test.js b/client/src/components/Intro/Intro.test.js index e638b653b8c..e332aaaa3ef 100644 --- a/client/src/components/Intro/Intro.test.js +++ b/client/src/components/Intro/Intro.test.js @@ -1,6 +1,6 @@ import React from 'react'; -import renderer from 'react-test-renderer'; import { Provider } from 'react-redux'; +import renderer from 'react-test-renderer'; import { createStore } from '../../redux/createStore'; import Intro from './'; diff --git a/client/src/components/Intro/components/IntroDescription.js b/client/src/components/Intro/components/IntroDescription.js index 04af9bb4c74..0e7586d52a4 100644 --- a/client/src/components/Intro/components/IntroDescription.js +++ b/client/src/components/Intro/components/IntroDescription.js @@ -1,7 +1,7 @@ import React from 'react'; -import { Link, Spacer } from '../../helpers'; -import envData from '../../../../../config/env.json'; import { Trans, useTranslation } from 'react-i18next'; +import envData from '../../../../../config/env.json'; +import { Link, Spacer } from '../../helpers'; import '../intro.css'; diff --git a/client/src/components/Intro/index.js b/client/src/components/Intro/index.js index 3e02b7ae7d7..f5ffb701d65 100644 --- a/client/src/components/Intro/index.js +++ b/client/src/components/Intro/index.js @@ -1,13 +1,13 @@ -import React from 'react'; import PropTypes from 'prop-types'; -import { Link, Spacer, Loader, FullWidthRow } from '../helpers'; +import React from 'react'; +import { Trans, useTranslation } from 'react-i18next'; import { randomQuote } from '../../utils/get-words'; +import Login from '../Header/components/Login'; +import { Link, Spacer, Loader, FullWidthRow } from '../helpers'; import CurrentChallengeLink from '../helpers/current-challenge-link'; import IntroDescription from './components/IntroDescription'; -import { Trans, useTranslation } from 'react-i18next'; import './intro.css'; -import Login from '../Header/components/Login'; const propTypes = { complete: PropTypes.bool, diff --git a/client/src/components/Map/Map.test.js b/client/src/components/Map/Map.test.js index 37e5c5bc338..947ecde5bd0 100644 --- a/client/src/components/Map/Map.test.js +++ b/client/src/components/Map/Map.test.js @@ -1,9 +1,9 @@ -import React from 'react'; -import { useStaticQuery } from 'gatsby'; import { render } from '@testing-library/react'; +import { useStaticQuery } from 'gatsby'; +import React from 'react'; -import { Map } from './'; import mockChallengeNodes from '../../__mocks__/challenge-nodes'; +import { Map } from './'; beforeEach(() => { useStaticQuery.mockImplementationOnce(() => ({ diff --git a/client/src/components/Map/index.js b/client/src/components/Map/index.js index cfdf208240f..6b7b761ffdb 100644 --- a/client/src/components/Map/index.js +++ b/client/src/components/Map/index.js @@ -1,14 +1,15 @@ -import React from 'react'; -import PropTypes from 'prop-types'; import { graphql, useStaticQuery } from 'gatsby'; import i18next from 'i18next'; +import PropTypes from 'prop-types'; +import React from 'react'; + +import envData from '../../../../config/env.json'; +import { isAuditedCert } from '../../../../utils/is-audited'; import { generateIconComponent } from '../../assets/icons'; -import { Link, Spacer } from '../helpers'; import LinkButton from '../../assets/icons/link-button'; +import { Link, Spacer } from '../helpers'; import './map.css'; -import { isAuditedCert } from '../../../../utils/is-audited'; -import envData from '../../../../config/env.json'; const { curriculumLocale } = envData; diff --git a/client/src/components/SolutionViewer/ProjectModal.js b/client/src/components/SolutionViewer/ProjectModal.js index 77836f94239..791b61d8a1e 100644 --- a/client/src/components/SolutionViewer/ProjectModal.js +++ b/client/src/components/SolutionViewer/ProjectModal.js @@ -1,8 +1,8 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import SolutionViewer from './SolutionViewer'; import { Button, Modal } from '@freecodecamp/react-bootstrap'; +import PropTypes from 'prop-types'; +import React from 'react'; import { useTranslation } from 'react-i18next'; +import SolutionViewer from './SolutionViewer'; const propTypes = { files: PropTypes.arrayOf( diff --git a/client/src/components/SolutionViewer/SolutionViewer.js b/client/src/components/SolutionViewer/SolutionViewer.js index 0e3ce7955d1..c380cde3c6b 100644 --- a/client/src/components/SolutionViewer/SolutionViewer.js +++ b/client/src/components/SolutionViewer/SolutionViewer.js @@ -1,7 +1,7 @@ -import React from 'react'; -import PropTypes from 'prop-types'; import { Panel } from '@freecodecamp/react-bootstrap'; import Prism from 'prismjs'; +import PropTypes from 'prop-types'; +import React from 'react'; const prismLang = { css: 'css', diff --git a/client/src/components/app-mount-notifier.test.tsx b/client/src/components/app-mount-notifier.test.tsx index 240a42dd71d..d0a43f2f27f 100644 --- a/client/src/components/app-mount-notifier.test.tsx +++ b/client/src/components/app-mount-notifier.test.tsx @@ -1,12 +1,12 @@ +import { render, waitFor } from '@testing-library/react'; import React from 'react'; import { I18nextProvider } from 'react-i18next'; -import { render, waitFor } from '@testing-library/react'; import { Provider } from 'react-redux'; import { i18nextCodes } from '../../../config/i18n/all-langs'; -import AppMountNotifier from './app-mount-notifier'; -import { createStore } from '../redux/createStore'; import i18nTestConfig from '../../i18n/configForTests'; +import { createStore } from '../redux/createStore'; +import AppMountNotifier from './app-mount-notifier'; jest.mock('react-ga'); jest.unmock('react-i18next'); diff --git a/client/src/components/app-mount-notifier.tsx b/client/src/components/app-mount-notifier.tsx index f3d6830feca..1b15347703d 100644 --- a/client/src/components/app-mount-notifier.tsx +++ b/client/src/components/app-mount-notifier.tsx @@ -1,8 +1,8 @@ import React, { useEffect } from 'react'; -import { bindActionCreators, Dispatch } from 'redux'; -import { connect } from 'react-redux'; import { Helmet } from 'react-helmet'; import { useTranslation } from 'react-i18next'; +import { connect } from 'react-redux'; +import { bindActionCreators, Dispatch } from 'redux'; import { appMount } from '../redux'; diff --git a/client/src/components/formHelpers/Form.js b/client/src/components/formHelpers/Form.js index e0115dba1ba..4910875baa1 100644 --- a/client/src/components/formHelpers/Form.js +++ b/client/src/components/formHelpers/Form.js @@ -1,5 +1,5 @@ -import React from 'react'; import PropTypes from 'prop-types'; +import React from 'react'; import { Form } from 'react-final-form'; import { diff --git a/client/src/components/formHelpers/Form.test.js b/client/src/components/formHelpers/Form.test.js index d61660efeee..d091d70c5e7 100644 --- a/client/src/components/formHelpers/Form.test.js +++ b/client/src/components/formHelpers/Form.test.js @@ -1,5 +1,5 @@ -import React from 'react'; import { render, fireEvent, screen } from '@testing-library/react'; +import React from 'react'; import Form from './Form'; diff --git a/client/src/components/formHelpers/FormFields.js b/client/src/components/formHelpers/FormFields.js index 1864462d125..4a4ef0921a9 100644 --- a/client/src/components/formHelpers/FormFields.js +++ b/client/src/components/formHelpers/FormFields.js @@ -1,7 +1,3 @@ -import React from 'react'; -import { kebabCase } from 'lodash-es'; -import normalizeUrl from 'normalize-url'; -import PropTypes from 'prop-types'; import { Alert, Col, @@ -10,6 +6,10 @@ import { FormGroup, HelpBlock } from '@freecodecamp/react-bootstrap'; +import { kebabCase } from 'lodash-es'; +import normalizeUrl from 'normalize-url'; +import PropTypes from 'prop-types'; +import React from 'react'; import { Field } from 'react-final-form'; import { editorValidator, diff --git a/client/src/components/formHelpers/block-save-button.test.tsx b/client/src/components/formHelpers/block-save-button.test.tsx index 7324bc006c9..e2193d5b509 100644 --- a/client/src/components/formHelpers/block-save-button.test.tsx +++ b/client/src/components/formHelpers/block-save-button.test.tsx @@ -1,5 +1,5 @@ -import React from 'react'; import { render, screen } from '@testing-library/react'; +import React from 'react'; import BlockSaveButton from './block-save-button'; diff --git a/client/src/components/formHelpers/block-save-button.tsx b/client/src/components/formHelpers/block-save-button.tsx index 86a2c622cce..1a57838e3c2 100644 --- a/client/src/components/formHelpers/block-save-button.tsx +++ b/client/src/components/formHelpers/block-save-button.tsx @@ -1,5 +1,5 @@ -import React from 'react'; import { Button } from '@freecodecamp/react-bootstrap'; +import React from 'react'; import { useTranslation } from 'react-i18next'; function BlockSaveButton(props?: Record): JSX.Element { diff --git a/client/src/components/formHelpers/block-save-wrapper.test.tsx b/client/src/components/formHelpers/block-save-wrapper.test.tsx index 93cd59dce51..25e9acff3bc 100644 --- a/client/src/components/formHelpers/block-save-wrapper.test.tsx +++ b/client/src/components/formHelpers/block-save-wrapper.test.tsx @@ -1,5 +1,5 @@ -import React from 'react'; import { render } from '@testing-library/react'; +import React from 'react'; import BlockSaveWrapper from './block-save-wrapper'; diff --git a/client/src/components/helpers/avatar-renderer.tsx b/client/src/components/helpers/avatar-renderer.tsx index fb847c83f9d..362390d3fdd 100644 --- a/client/src/components/helpers/avatar-renderer.tsx +++ b/client/src/components/helpers/avatar-renderer.tsx @@ -1,9 +1,9 @@ -import React, { useState, useEffect } from 'react'; import { Image } from '@freecodecamp/react-bootstrap'; -import DefaultAvatar from '../../assets/icons/default-avatar'; -import { defaultUserImage } from '../../../../config/misc'; -import { borderColorPicker } from '.'; +import React, { useState, useEffect } from 'react'; import { useTranslation } from 'react-i18next'; +import { defaultUserImage } from '../../../../config/misc'; +import DefaultAvatar from '../../assets/icons/default-avatar'; +import { borderColorPicker } from '.'; interface AvatarRendererProps { isDonating?: boolean; diff --git a/client/src/components/helpers/form/block-save-button.tsx b/client/src/components/helpers/form/block-save-button.tsx index 186d0dfbcc8..fc26e84fbd8 100644 --- a/client/src/components/helpers/form/block-save-button.tsx +++ b/client/src/components/helpers/form/block-save-button.tsx @@ -1,5 +1,5 @@ -import React from 'react'; import { Button } from '@freecodecamp/react-bootstrap'; +import React from 'react'; import { useTranslation } from 'react-i18next'; function BlockSaveButton({ diff --git a/client/src/components/helpers/full-width-row.tsx b/client/src/components/helpers/full-width-row.tsx index dfb3d4de312..798ced0a87e 100644 --- a/client/src/components/helpers/full-width-row.tsx +++ b/client/src/components/helpers/full-width-row.tsx @@ -1,5 +1,5 @@ -import React from 'react'; import { Row, Col } from '@freecodecamp/react-bootstrap'; +import React from 'react'; function FullWidthRow({ children, diff --git a/client/src/components/helpers/link.tsx b/client/src/components/helpers/link.tsx index ebb39fa1966..bc9dd2d672a 100644 --- a/client/src/components/helpers/link.tsx +++ b/client/src/components/helpers/link.tsx @@ -1,5 +1,5 @@ -import React from 'react'; import { Link as GatsbyLink } from 'gatsby'; +import React from 'react'; interface LinkProps { children?: React.ReactNode; diff --git a/client/src/components/helpers/loader.test.tsx b/client/src/components/helpers/loader.test.tsx index 78425d80a68..8708115747e 100644 --- a/client/src/components/helpers/loader.test.tsx +++ b/client/src/components/helpers/loader.test.tsx @@ -1,5 +1,5 @@ -import React from 'react'; import { render, cleanup, screen } from '@testing-library/react'; +import React from 'react'; import Loader from './loader'; diff --git a/client/src/components/helpers/slim-width-row.tsx b/client/src/components/helpers/slim-width-row.tsx index 983b6fe10ce..dc8ceb67ef6 100644 --- a/client/src/components/helpers/slim-width-row.tsx +++ b/client/src/components/helpers/slim-width-row.tsx @@ -1,5 +1,5 @@ -import React from 'react'; import { Row, Col } from '@freecodecamp/react-bootstrap'; +import React from 'react'; interface SlimWidthRowProps { children: JSX.ElementChildrenAttribute; diff --git a/client/src/components/helpers/toggle-button.tsx b/client/src/components/helpers/toggle-button.tsx index 76571754901..89e1892f2b3 100644 --- a/client/src/components/helpers/toggle-button.tsx +++ b/client/src/components/helpers/toggle-button.tsx @@ -1,12 +1,12 @@ -import React from 'react'; import { ToggleButtonGroup as BSBG, ToggleButton as TB } from '@freecodecamp/react-bootstrap'; +import React from 'react'; import './toggle-button.css'; -import ToggleCheck from '../../assets/icons/toggle-check'; import Spacer from '../../assets/icons/spacer'; +import ToggleCheck from '../../assets/icons/toggle-check'; interface ButtonProps { name: string; diff --git a/client/src/components/landing/Landing.test.js b/client/src/components/landing/Landing.test.js index 9e4e5a26b17..c34a120c8ae 100644 --- a/client/src/components/landing/Landing.test.js +++ b/client/src/components/landing/Landing.test.js @@ -1,8 +1,8 @@ import React from 'react'; import ShallowRenderer from 'react-test-renderer/shallow'; -import IndexPage from '../../pages'; import mockChallengeNodes from '../../__mocks__/challenge-nodes'; +import IndexPage from '../../pages'; jest.mock('../../analytics'); diff --git a/client/src/components/landing/components/AsSeenIn.js b/client/src/components/landing/components/AsSeenIn.js index 3461b5ac49b..9d1d93599ba 100644 --- a/client/src/components/landing/components/AsSeenIn.js +++ b/client/src/components/landing/components/AsSeenIn.js @@ -1,7 +1,7 @@ -import React from 'react'; import { Col, Row } from '@freecodecamp/react-bootstrap'; -import { AsSeenInText } from '../../../assets/images/components'; +import React from 'react'; import { useTranslation } from 'react-i18next'; +import { AsSeenInText } from '../../../assets/images/components'; const AsSeenIn = () => { const { t } = useTranslation(); diff --git a/client/src/components/landing/components/BigCallToAction.js b/client/src/components/landing/components/BigCallToAction.js index 62dff19f1ee..252953cab89 100644 --- a/client/src/components/landing/components/BigCallToAction.js +++ b/client/src/components/landing/components/BigCallToAction.js @@ -1,7 +1,7 @@ -import React from 'react'; import PropTypes from 'prop-types'; -import Login from '../../Header/components/Login'; +import React from 'react'; import { useTranslation } from 'react-i18next'; +import Login from '../../Header/components/Login'; const propTypes = { page: PropTypes.string diff --git a/client/src/components/landing/components/CampersImage.js b/client/src/components/landing/components/CampersImage.js index 20017619dcc..cda1a77ef14 100644 --- a/client/src/components/landing/components/CampersImage.js +++ b/client/src/components/landing/components/CampersImage.js @@ -1,9 +1,9 @@ -import React from 'react'; import PropTypes from 'prop-types'; -import Media from 'react-responsive'; -import { Spacer, ImageLoader } from '../../helpers'; -import wideImg from '../../../assets/images/landing/wide-image.png'; +import React from 'react'; import { useTranslation } from 'react-i18next'; +import Media from 'react-responsive'; +import wideImg from '../../../assets/images/landing/wide-image.png'; +import { Spacer, ImageLoader } from '../../helpers'; const propTypes = { page: PropTypes.string diff --git a/client/src/components/landing/components/Certifications.js b/client/src/components/landing/components/Certifications.js index 103a3e9aa11..d1af6cb5364 100644 --- a/client/src/components/landing/components/Certifications.js +++ b/client/src/components/landing/components/Certifications.js @@ -1,10 +1,10 @@ -import React from 'react'; -import PropTypes from 'prop-types'; import { Col, Row } from '@freecodecamp/react-bootstrap'; -import { Spacer } from '../../helpers'; -import BigCallToAction from './BigCallToAction'; +import PropTypes from 'prop-types'; +import React from 'react'; import { useTranslation } from 'react-i18next'; import Map from '../../Map/index'; +import { Spacer } from '../../helpers'; +import BigCallToAction from './BigCallToAction'; const propTypes = { page: PropTypes.string diff --git a/client/src/components/landing/components/LandingTop.js b/client/src/components/landing/components/LandingTop.js index 9e94d40b1a2..a7be1cab318 100644 --- a/client/src/components/landing/components/LandingTop.js +++ b/client/src/components/landing/components/LandingTop.js @@ -1,7 +1,7 @@ -import React from 'react'; -import PropTypes from 'prop-types'; import { Col, Row } from '@freecodecamp/react-bootstrap'; -import { Spacer } from '../../helpers'; +import PropTypes from 'prop-types'; +import React from 'react'; +import { useTranslation } from 'react-i18next'; import { AmazonLogo, AppleLogo, @@ -9,9 +9,9 @@ import { SpotifyLogo, GoogleLogo } from '../../../assets/images/components'; -import CampersImage from './CampersImage'; +import { Spacer } from '../../helpers'; import BigCallToAction from './BigCallToAction'; -import { useTranslation } from 'react-i18next'; +import CampersImage from './CampersImage'; const propTypes = { page: PropTypes.string diff --git a/client/src/components/landing/components/Testimonials.js b/client/src/components/landing/components/Testimonials.js index a4fc310de50..ff6e0fec5fd 100644 --- a/client/src/components/landing/components/Testimonials.js +++ b/client/src/components/landing/components/Testimonials.js @@ -1,11 +1,11 @@ -import React from 'react'; import PropTypes from 'prop-types'; +import React from 'react'; -import { ImageLoader } from '../../helpers'; -import shawnImg from '../../../assets/images/landing/Shawn.png'; -import sarahImg from '../../../assets/images/landing/Sarah.png'; -import emmaImg from '../../../assets/images/landing/Emma.png'; import { Trans, useTranslation } from 'react-i18next'; +import emmaImg from '../../../assets/images/landing/Emma.png'; +import sarahImg from '../../../assets/images/landing/Sarah.png'; +import shawnImg from '../../../assets/images/landing/Shawn.png'; +import { ImageLoader } from '../../helpers'; const propTypes = { page: PropTypes.string diff --git a/client/src/components/landing/index.js b/client/src/components/landing/index.js index e0a6c6f015c..aff37de6ae8 100644 --- a/client/src/components/landing/index.js +++ b/client/src/components/landing/index.js @@ -1,13 +1,13 @@ -import React from 'react'; import { Grid } from '@freecodecamp/react-bootstrap'; -import Helmet from 'react-helmet'; import PropTypes from 'prop-types'; +import React from 'react'; +import Helmet from 'react-helmet'; import { useTranslation } from 'react-i18next'; -import Testimonials from './components/Testimonials'; -import LandingTop from './components/LandingTop'; -import Certifications from './components/Certifications'; import AsSeenIn from './components/AsSeenIn'; +import Certifications from './components/Certifications'; +import LandingTop from './components/LandingTop'; +import Testimonials from './components/Testimonials'; import './landing.css'; diff --git a/client/src/components/layouts/Certification.js b/client/src/components/layouts/Certification.js index cc02f205931..a8350f45278 100644 --- a/client/src/components/layouts/Certification.js +++ b/client/src/components/layouts/Certification.js @@ -1,10 +1,10 @@ -import React, { Component } from 'react'; import PropTypes from 'prop-types'; +import React, { Component } from 'react'; +import Helmet from 'react-helmet'; import { connect } from 'react-redux'; -import { fetchUser, isSignedInSelector, executeGA } from '../../redux'; import { createSelector } from 'reselect'; -import Helmet from 'react-helmet'; +import { fetchUser, isSignedInSelector, executeGA } from '../../redux'; const mapStateToProps = createSelector(isSignedInSelector, isSignedIn => ({ isSignedIn diff --git a/client/src/components/layouts/Default.js b/client/src/components/layouts/Default.js index d0795763bb3..d0fb3363ecb 100644 --- a/client/src/components/layouts/Default.js +++ b/client/src/components/layouts/Default.js @@ -1,12 +1,19 @@ -import React, { Component } from 'react'; +import fontawesome from '@fortawesome/fontawesome'; import PropTypes from 'prop-types'; +import React, { Component } from 'react'; +import Helmet from 'react-helmet'; +import { withTranslation } from 'react-i18next'; import { connect } from 'react-redux'; import { bindActionCreators } from 'redux'; import { createSelector } from 'reselect'; -import Helmet from 'react-helmet'; -import fontawesome from '@fortawesome/fontawesome'; -import { withTranslation } from 'react-i18next'; +import latoBoldURL from '../../../static/fonts/lato/Lato-Bold.woff'; +import latoLightURL from '../../../static/fonts/lato/Lato-Light.woff'; +import latoRegularURL from '../../../static/fonts/lato/Lato-Regular.woff'; +import robotoBoldURL from '../../../static/fonts/roboto-mono/RobotoMono-Bold.woff'; +import robotoItalicURL from '../../../static/fonts/roboto-mono/RobotoMono-Italic.woff'; +import robotoRegularURL from '../../../static/fonts/roboto-mono/RobotoMono-Regular.woff'; +import { isBrowser } from '../../../utils'; import { fetchUser, isSignedInSelector, @@ -17,24 +24,16 @@ import { usernameSelector, executeGA } from '../../redux'; +import Flash from '../Flash'; import { flashMessageSelector, removeFlashMessage } from '../Flash/redux'; -import { isBrowser } from '../../../utils'; - -import OfflineWarning from '../OfflineWarning'; -import Flash from '../Flash'; -import Header from '../Header'; import Footer from '../Footer'; +import Header from '../Header'; +import OfflineWarning from '../OfflineWarning'; // preload common fonts -import latoLightURL from '../../../static/fonts/lato/Lato-Light.woff'; -import latoRegularURL from '../../../static/fonts/lato/Lato-Regular.woff'; -import latoBoldURL from '../../../static/fonts/lato/Lato-Bold.woff'; // eslint-disable-next-line max-len -import robotoRegularURL from '../../../static/fonts/roboto-mono/RobotoMono-Regular.woff'; // eslint-disable-next-line max-len -import robotoBoldURL from '../../../static/fonts/roboto-mono/RobotoMono-Bold.woff'; // eslint-disable-next-line max-len -import robotoItalicURL from '../../../static/fonts/roboto-mono/RobotoMono-Italic.woff'; import './fonts.css'; import './global.css'; diff --git a/client/src/components/layouts/learn.tsx b/client/src/components/layouts/learn.tsx index 4c64dcdc72b..9df35f09a73 100644 --- a/client/src/components/layouts/learn.tsx +++ b/client/src/components/layouts/learn.tsx @@ -1,7 +1,7 @@ import React, { Component } from 'react'; -import { createSelector } from 'reselect'; -import { connect } from 'react-redux'; import { Helmet } from 'react-helmet'; +import { connect } from 'react-redux'; +import { createSelector } from 'reselect'; import { Loader } from '../../components/helpers'; import { userSelector, @@ -9,8 +9,8 @@ import { isSignedInSelector, tryToShowDonationModal } from '../../redux'; -import createRedirect from '../create-redirect'; import DonateModal from '../Donation/DonationModal'; +import createRedirect from '../create-redirect'; import './prism.css'; import './prism-night.css'; diff --git a/client/src/components/profile/Profile.test.tsx b/client/src/components/profile/Profile.test.tsx index 224cfd751f6..2c148bcd794 100644 --- a/client/src/components/profile/Profile.test.tsx +++ b/client/src/components/profile/Profile.test.tsx @@ -1,5 +1,5 @@ -import React from 'react'; import { render, screen } from '@testing-library/react'; +import React from 'react'; import Profile from './Profile'; diff --git a/client/src/components/profile/Profile.tsx b/client/src/components/profile/Profile.tsx index c712d283acd..44aa7bb04b6 100644 --- a/client/src/components/profile/Profile.tsx +++ b/client/src/components/profile/Profile.tsx @@ -1,12 +1,12 @@ -import React from 'react'; import { Grid, Row } from '@freecodecamp/react-bootstrap'; +import React from 'react'; import Helmet from 'react-helmet'; import { TFunction, useTranslation } from 'react-i18next'; import { CurrentChallengeLink, FullWidthRow, Link, Spacer } from '../helpers'; import Camper from './components/Camper'; -import HeatMap from './components/HeatMap'; import Certifications from './components/Certifications'; +import HeatMap from './components/HeatMap'; import Portfolio from './components/Portfolio'; import Timeline from './components/TimeLine'; diff --git a/client/src/components/profile/components/Camper.tsx b/client/src/components/profile/components/Camper.tsx index 131dec45118..ae6f4ae31f5 100644 --- a/client/src/components/profile/components/Camper.tsx +++ b/client/src/components/profile/components/Camper.tsx @@ -1,22 +1,21 @@ -import React from 'react'; -import { Col, Row } from '@freecodecamp/react-bootstrap'; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faAward, faCalendar, faHeart } from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { Col, Row } from '@freecodecamp/react-bootstrap'; +import React from 'react'; import { TFunction, useTranslation } from 'react-i18next'; +import envData from '../../../../../config/env.json'; +import { langCodes } from '../../../../../config/i18n/all-langs'; import { AvatarRenderer } from '../../helpers'; -import SocialIcons from './SocialIcons'; import Link from '../../helpers/link'; +import SocialIcons from './SocialIcons'; import './camper.css'; -import { langCodes } from '../../../../../config/i18n/all-langs'; -import envData from '../../../../../config/env.json'; - const { clientLocale } = envData; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore diff --git a/client/src/components/profile/components/Certifications.tsx b/client/src/components/profile/components/Certifications.tsx index 319ff68a8b6..70ee6a995a2 100644 --- a/client/src/components/profile/components/Certifications.tsx +++ b/client/src/components/profile/components/Certifications.tsx @@ -1,9 +1,9 @@ -import React, { Fragment } from 'react'; -import { curry } from 'lodash-es'; -import { createSelector } from 'reselect'; -import { connect } from 'react-redux'; import { Col, Row } from '@freecodecamp/react-bootstrap'; +import { curry } from 'lodash-es'; +import React, { Fragment } from 'react'; import { useTranslation } from 'react-i18next'; +import { connect } from 'react-redux'; +import { createSelector } from 'reselect'; import { certificatesByNameSelector } from '../../../redux'; import { ButtonSpacer, FullWidthRow, Link, Spacer } from '../../helpers'; diff --git a/client/src/components/profile/components/HeatMap.test.tsx b/client/src/components/profile/components/HeatMap.test.tsx index 61ff1d4649a..625b6de507f 100644 --- a/client/src/components/profile/components/HeatMap.test.tsx +++ b/client/src/components/profile/components/HeatMap.test.tsx @@ -1,5 +1,5 @@ -import React from 'react'; import { render, screen } from '@testing-library/react'; +import React from 'react'; import HeatMap from './HeatMap'; diff --git a/client/src/components/profile/components/HeatMap.tsx b/client/src/components/profile/components/HeatMap.tsx index 1bab5e49362..f04f3b52720 100644 --- a/client/src/components/profile/components/HeatMap.tsx +++ b/client/src/components/profile/components/HeatMap.tsx @@ -1,25 +1,24 @@ -import React, { Component } from 'react'; +import { Row } from '@freecodecamp/react-bootstrap'; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore import CalendarHeatMap from '@freecodecamp/react-calendar-heatmap'; -import { Row } from '@freecodecamp/react-bootstrap'; -import ReactTooltip from 'react-tooltip'; import addDays from 'date-fns/addDays'; import addMonths from 'date-fns/addMonths'; -import startOfDay from 'date-fns/startOfDay'; import isEqual from 'date-fns/isEqual'; +import startOfDay from 'date-fns/startOfDay'; +import React, { Component } from 'react'; import { TFunction, useTranslation } from 'react-i18next'; - -import FullWidthRow from '../../helpers/full-width-row'; -import Spacer from '../../helpers/spacer'; +import ReactTooltip from 'react-tooltip'; import '@freecodecamp/react-calendar-heatmap/dist/styles.css'; import './heatmap.css'; -import { langCodes } from '../../../../../config/i18n/all-langs'; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore import envData from '../../../../../config/env.json'; +import { langCodes } from '../../../../../config/i18n/all-langs'; +import FullWidthRow from '../../helpers/full-width-row'; +import Spacer from '../../helpers/spacer'; // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment const { clientLocale } = envData; diff --git a/client/src/components/profile/components/Portfolio.tsx b/client/src/components/profile/components/Portfolio.tsx index 288d45ba273..304251c81d7 100644 --- a/client/src/components/profile/components/Portfolio.tsx +++ b/client/src/components/profile/components/Portfolio.tsx @@ -1,5 +1,5 @@ -import React from 'react'; import { Media } from '@freecodecamp/react-bootstrap'; +import React from 'react'; import { useTranslation } from 'react-i18next'; import { FullWidthRow } from '../../helpers'; diff --git a/client/src/components/profile/components/SocialIcons.tsx b/client/src/components/profile/components/SocialIcons.tsx index d8cad06034b..781b53afdde 100644 --- a/client/src/components/profile/components/SocialIcons.tsx +++ b/client/src/components/profile/components/SocialIcons.tsx @@ -1,12 +1,12 @@ -import React from 'react'; -import { Row, Col } from '@freecodecamp/react-bootstrap'; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faLinkedin, faGithub, faTwitter } from '@fortawesome/free-brands-svg-icons'; import { faLink } from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { Row, Col } from '@freecodecamp/react-bootstrap'; +import React from 'react'; import { useTranslation } from 'react-i18next'; import './social-icons.css'; diff --git a/client/src/components/profile/components/TimeLine.test.tsx b/client/src/components/profile/components/TimeLine.test.tsx index 966911d5b95..21c9a1782a3 100644 --- a/client/src/components/profile/components/TimeLine.test.tsx +++ b/client/src/components/profile/components/TimeLine.test.tsx @@ -1,9 +1,9 @@ /* eslint-disable @typescript-eslint/ban-ts-comment */ /* eslint-disable @typescript-eslint/no-unsafe-call */ -import React from 'react'; import { render, screen } from '@testing-library/react'; -import TimeLine from './TimeLine'; import { useStaticQuery } from 'gatsby'; +import React from 'react'; +import TimeLine from './TimeLine'; beforeEach(() => { // @ts-ignore diff --git a/client/src/components/profile/components/TimeLine.tsx b/client/src/components/profile/components/TimeLine.tsx index 3d354502f6e..09207815691 100644 --- a/client/src/components/profile/components/TimeLine.tsx +++ b/client/src/components/profile/components/TimeLine.tsx @@ -4,8 +4,6 @@ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ /* eslint-disable @typescript-eslint/restrict-template-expressions */ /* eslint-disable @typescript-eslint/unbound-method */ -import React, { Component, useMemo } from 'react'; -import { reverse, sortBy } from 'lodash-es'; import { Button, Modal, @@ -13,27 +11,25 @@ import { DropdownButton, MenuItem } from '@freecodecamp/react-bootstrap'; +import Loadable from '@loadable/component'; import { useStaticQuery, graphql } from 'gatsby'; +import { reverse, sortBy } from 'lodash-es'; +import React, { Component, useMemo } from 'react'; import { TFunction, withTranslation } from 'react-i18next'; -import './timeline.css'; -import TimelinePagination from './TimelinePagination'; -import { FullWidthRow, Link } from '../../helpers'; -import Loadable from '@loadable/component'; - +import envData from '../../../../../config/env.json'; +import { langCodes } from '../../../../../config/i18n/all-langs'; import { getCertIds, getPathFromID, getTitleFromId } from '../../../../../utils'; - -import { maybeUrlRE } from '../../../utils'; import CertificationIcon from '../../../assets/icons/certification-icon'; +import { maybeUrlRE } from '../../../utils'; +import { FullWidthRow, Link } from '../../helpers'; +import TimelinePagination from './TimelinePagination'; -import { langCodes } from '../../../../../config/i18n/all-langs'; -// eslint-disable-next-line @typescript-eslint/ban-ts-comment -// @ts-ignore -import envData from '../../../../../config/env.json'; +import './timeline.css'; const SolutionViewer = Loadable( () => diff --git a/client/src/components/redirect-home.ts b/client/src/components/redirect-home.ts index 9336e5e53da..29eeb64ae59 100644 --- a/client/src/components/redirect-home.ts +++ b/client/src/components/redirect-home.ts @@ -1,4 +1,4 @@ -import createRedirect from './create-redirect'; import { withPrefix } from 'gatsby'; +import createRedirect from './create-redirect'; export default createRedirect(withPrefix('/')); diff --git a/client/src/components/search/WithInstantSearch.js b/client/src/components/search/WithInstantSearch.js index 619f4712c43..c4c4d6ca20b 100644 --- a/client/src/components/search/WithInstantSearch.js +++ b/client/src/components/search/WithInstantSearch.js @@ -1,12 +1,14 @@ -import React, { Component } from 'react'; import { Location } from '@reach/router'; -import PropTypes from 'prop-types'; -import { connect } from 'react-redux'; -import { InstantSearch, Configure } from 'react-instantsearch-dom'; -import qs from 'query-string'; -import { navigate } from 'gatsby'; -import Media from 'react-responsive'; import algoliasearch from 'algoliasearch/lite'; +import { navigate } from 'gatsby'; +import PropTypes from 'prop-types'; +import qs from 'query-string'; +import React, { Component } from 'react'; +import { InstantSearch, Configure } from 'react-instantsearch-dom'; +import { connect } from 'react-redux'; +import Media from 'react-responsive'; +import { createSelector } from 'reselect'; +import envData from '../../../../config/env.json'; import { newsIndex } from '../../utils/algolia-locale-setup'; import { @@ -15,9 +17,6 @@ import { toggleSearchDropdown, updateSearchQuery } from './redux'; -import envData from '../../../../config/env.json'; - -import { createSelector } from 'reselect'; const { algoliaAppId, algoliaAPIKey } = envData; diff --git a/client/src/components/search/searchBar/search-bar.tsx b/client/src/components/search/searchBar/search-bar.tsx index 1a0341dd4b0..8fea9ce5d9d 100644 --- a/client/src/components/search/searchBar/search-bar.tsx +++ b/client/src/components/search/searchBar/search-bar.tsx @@ -1,16 +1,16 @@ +import { isEqual } from 'lodash-es'; import React, { Component } from 'react'; +import { HotKeys, ObserveKeys } from 'react-hotkeys'; +import { withTranslation } from 'react-i18next'; +import { Hit } from 'react-instantsearch-core'; +import { SearchBox } from 'react-instantsearch-dom'; import { connect } from 'react-redux'; import { AnyAction, bindActionCreators, Dispatch } from 'redux'; import { createSelector } from 'reselect'; -import { SearchBox } from 'react-instantsearch-dom'; -import { HotKeys, ObserveKeys } from 'react-hotkeys'; -import { isEqual } from 'lodash-es'; -import { withTranslation } from 'react-i18next'; import { searchPageUrl } from '../../../utils/algolia-locale-setup'; import WithInstantSearch from '../WithInstantSearch'; -import { Hit } from 'react-instantsearch-core'; import { isSearchDropdownEnabledSelector, isSearchBarFocusedSelector, diff --git a/client/src/components/search/searchBar/search-hits.tsx b/client/src/components/search/searchBar/search-hits.tsx index 5cb6fef4401..d9241487fdc 100644 --- a/client/src/components/search/searchBar/search-hits.tsx +++ b/client/src/components/search/searchBar/search-hits.tsx @@ -1,11 +1,11 @@ -import React, { useEffect } from 'react'; -import { connectStateResults, connectHits } from 'react-instantsearch-dom'; -import { SearchState, Hit } from 'react-instantsearch-core'; import { isEmpty } from 'lodash-es'; +import React, { useEffect } from 'react'; import { useTranslation } from 'react-i18next'; +import { SearchState, Hit } from 'react-instantsearch-core'; +import { connectStateResults, connectHits } from 'react-instantsearch-dom'; import { searchPageUrl } from '../../../utils/algolia-locale-setup'; -import Suggestion from './search-suggestion'; import NoHitsSuggestion from './no-hits-suggestion'; +import Suggestion from './search-suggestion'; const searchUrl = searchPageUrl; interface customHitsPropTypes { diff --git a/client/src/components/search/searchBar/search-suggestion.tsx b/client/src/components/search/searchBar/search-suggestion.tsx index 9fdf8ed7930..b8f16c69c14 100644 --- a/client/src/components/search/searchBar/search-suggestion.tsx +++ b/client/src/components/search/searchBar/search-suggestion.tsx @@ -1,6 +1,6 @@ import React from 'react'; -import { Highlight } from 'react-instantsearch-dom'; import { Hit } from 'react-instantsearch-core'; +import { Highlight } from 'react-instantsearch-dom'; interface suggestionPropTypes { hit: Hit; diff --git a/client/src/components/search/searchPage/search-page-hits.tsx b/client/src/components/search/searchPage/search-page-hits.tsx index 617ce54f37d..2290935013c 100644 --- a/client/src/components/search/searchPage/search-page-hits.tsx +++ b/client/src/components/search/searchPage/search-page-hits.tsx @@ -1,3 +1,4 @@ +import { isEmpty } from 'lodash-es'; import React, { EventHandler, SyntheticEvent } from 'react'; import { AutocompleteExposed, SearchState } from 'react-instantsearch-core'; import { @@ -5,7 +6,6 @@ import { connectStateResults, connectAutoComplete } from 'react-instantsearch-dom'; -import { isEmpty } from 'lodash-es'; import EmptySearch from './empty-search'; import NoResults from './no-results'; diff --git a/client/src/components/settings/Certification.js b/client/src/components/settings/Certification.js index a40ac252f34..f2c38b21cb5 100644 --- a/client/src/components/settings/Certification.js +++ b/client/src/components/settings/Certification.js @@ -1,6 +1,3 @@ -import React, { Component } from 'react'; -import PropTypes from 'prop-types'; -import { find, first } from 'lodash-es'; import { Table, Button, @@ -8,19 +5,22 @@ import { MenuItem } from '@freecodecamp/react-bootstrap'; import { Link, navigate } from 'gatsby'; -import { createSelector } from 'reselect'; +import { find, first } from 'lodash-es'; +import PropTypes from 'prop-types'; +import React, { Component } from 'react'; import { withTranslation } from 'react-i18next'; +import { createSelector } from 'reselect'; import { projectMap, legacyProjectMap } from '../../resources/cert-and-project-map'; -import SectionHeader from './section-header'; +import { maybeUrlRE } from '../../utils'; import ProjectModal from '../SolutionViewer/ProjectModal'; import { FullWidthRow, Spacer } from '../helpers'; -import { maybeUrlRE } from '../../utils'; +import SectionHeader from './section-header'; import './certification.css'; diff --git a/client/src/components/settings/Certification.test.js b/client/src/components/settings/Certification.test.js index bc6ad4d0c82..eb944b36e53 100644 --- a/client/src/components/settings/Certification.test.js +++ b/client/src/components/settings/Certification.test.js @@ -1,5 +1,5 @@ -import React from 'react'; import { render, screen } from '@testing-library/react'; +import React from 'react'; import { Provider } from 'react-redux'; import { createStore } from '../../redux/createStore'; diff --git a/client/src/components/settings/Honesty.test.js b/client/src/components/settings/Honesty.test.js index 7cd60a56e77..5728a206958 100644 --- a/client/src/components/settings/Honesty.test.js +++ b/client/src/components/settings/Honesty.test.js @@ -1,9 +1,9 @@ +import { Button } from '@freecodecamp/react-bootstrap'; import React from 'react'; -import ShallowRenderer from 'react-test-renderer/shallow'; import TestRenderer from 'react-test-renderer'; +import ShallowRenderer from 'react-test-renderer/shallow'; import Honesty from './honesty'; -import { Button } from '@freecodecamp/react-bootstrap'; describe('', () => { const renderer = new ShallowRenderer(); diff --git a/client/src/components/settings/about.tsx b/client/src/components/settings/about.tsx index 8fa41721ce4..d7d3898dd62 100644 --- a/client/src/components/settings/about.tsx +++ b/client/src/components/settings/about.tsx @@ -1,4 +1,3 @@ -import React, { Component } from 'react'; import { FormGroup, ControlLabel, @@ -8,12 +7,13 @@ import { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore } from '@freecodecamp/react-bootstrap'; +import React, { Component } from 'react'; +import { TFunction, withTranslation } from 'react-i18next'; import { FullWidthRow, Spacer } from '../helpers'; +import BlockSaveButton from '../helpers/form/block-save-button'; import ThemeSettings from './theme'; import UsernameSettings from './username'; -import BlockSaveButton from '../helpers/form/block-save-button'; -import { TFunction, withTranslation } from 'react-i18next'; type FormValues = { name: string; diff --git a/client/src/components/settings/danger-zone.tsx b/client/src/components/settings/danger-zone.tsx index 480d1e6f382..00d53102bff 100644 --- a/client/src/components/settings/danger-zone.tsx +++ b/client/src/components/settings/danger-zone.tsx @@ -1,14 +1,14 @@ +import { Button, Panel } from '@freecodecamp/react-bootstrap'; import React, { Component } from 'react'; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore -import { Button, Panel } from '@freecodecamp/react-bootstrap'; +import { TFunction, withTranslation } from 'react-i18next'; import { connect } from 'react-redux'; import { bindActionCreators } from 'redux'; -import { TFunction, withTranslation } from 'react-i18next'; import type { Dispatch } from 'redux'; -import { FullWidthRow, ButtonSpacer, Spacer } from '../helpers'; import { deleteAccount, resetProgress } from '../../redux/settings'; +import { FullWidthRow, ButtonSpacer, Spacer } from '../helpers'; import DeleteModal from './delete-modal'; import ResetModal from './reset-modal'; diff --git a/client/src/components/settings/delete-modal.tsx b/client/src/components/settings/delete-modal.tsx index 6e68a2eba6c..1c27d34aa9e 100644 --- a/client/src/components/settings/delete-modal.tsx +++ b/client/src/components/settings/delete-modal.tsx @@ -1,10 +1,10 @@ +import { Button, Modal } from '@freecodecamp/react-bootstrap'; import React from 'react'; import { Trans, useTranslation } from 'react-i18next'; import { ButtonSpacer } from '../helpers'; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore -import { Button, Modal } from '@freecodecamp/react-bootstrap'; import './danger-zone.css'; diff --git a/client/src/components/settings/email.tsx b/client/src/components/settings/email.tsx index 1f8ce44c0e8..0ce5ee6c1d4 100644 --- a/client/src/components/settings/email.tsx +++ b/client/src/components/settings/email.tsx @@ -1,7 +1,3 @@ -import React, { Component } from 'react'; -import { bindActionCreators } from 'redux'; -import { connect } from 'react-redux'; -import { Link } from 'gatsby'; import { HelpBlock, Alert, @@ -12,17 +8,21 @@ import { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore } from '@freecodecamp/react-bootstrap'; -import isEmail from 'validator/lib/isEmail'; +import { Link } from 'gatsby'; +import React, { Component } from 'react'; import { TFunction, Trans, withTranslation } from 'react-i18next'; +import { connect } from 'react-redux'; +import { bindActionCreators } from 'redux'; import type { Dispatch } from 'redux'; +import isEmail from 'validator/lib/isEmail'; import { updateMyEmail } from '../../redux/settings'; import { maybeEmailRE } from '../../utils'; +import BlockSaveButton from '../helpers/form/block-save-button'; import FullWidthRow from '../helpers/full-width-row'; import Spacer from '../helpers/spacer'; import SectionHeader from './section-header'; -import BlockSaveButton from '../helpers/form/block-save-button'; import ToggleSetting from './toggle-setting'; const mapStateToProps = () => ({}); diff --git a/client/src/components/settings/honesty.tsx b/client/src/components/settings/honesty.tsx index 25f73c157d0..a697284f9ae 100644 --- a/client/src/components/settings/honesty.tsx +++ b/client/src/components/settings/honesty.tsx @@ -1,12 +1,12 @@ +import { Button, Panel } from '@freecodecamp/react-bootstrap'; import React from 'react'; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore -import { Button, Panel } from '@freecodecamp/react-bootstrap'; import { useTranslation } from 'react-i18next'; +import HonestyPolicy from '../../resources/honesty-policy'; import { FullWidthRow } from '../helpers'; import SectionHeader from './section-header'; -import HonestyPolicy from '../../resources/honesty-policy'; import './honesty.css'; diff --git a/client/src/components/settings/internet.tsx b/client/src/components/settings/internet.tsx index edecbf62085..8ff29629be1 100644 --- a/client/src/components/settings/internet.tsx +++ b/client/src/components/settings/internet.tsx @@ -1,6 +1,5 @@ -import React, { Component } from 'react'; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faCheck } from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { HelpBlock, FormControl, @@ -9,14 +8,15 @@ import { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore } from '@freecodecamp/react-bootstrap'; -import isURL from 'validator/lib/isURL'; +import React, { Component } from 'react'; import { TFunction, withTranslation } from 'react-i18next'; +import isURL from 'validator/lib/isURL'; import { maybeUrlRE } from '../../utils'; -import SectionHeader from './section-header'; import { FullWidthRow } from '../helpers'; import BlockSaveButton from '../helpers/form/block-save-button'; +import SectionHeader from './section-header'; interface InternetFormValues { githubProfile: string; diff --git a/client/src/components/settings/portfolio.tsx b/client/src/components/settings/portfolio.tsx index 4e7b1480acc..e7a259422d4 100644 --- a/client/src/components/settings/portfolio.tsx +++ b/client/src/components/settings/portfolio.tsx @@ -1,5 +1,3 @@ -import React, { Component, FormEvent } from 'react'; -import { nanoid } from 'nanoid'; import { Button, FormGroup, @@ -10,14 +8,16 @@ import { // @ts-ignore } from '@freecodecamp/react-bootstrap'; import { findIndex, find, isEqual } from 'lodash-es'; -import isURL from 'validator/lib/isURL'; +import { nanoid } from 'nanoid'; +import React, { Component, FormEvent } from 'react'; import { TFunction, withTranslation } from 'react-i18next'; +import isURL from 'validator/lib/isURL'; import { hasProtocolRE } from '../../utils'; import { FullWidthRow, ButtonSpacer, Spacer } from '../helpers'; -import SectionHeader from './section-header'; import BlockSaveButton from '../helpers/form/block-save-button'; +import SectionHeader from './section-header'; type PortfolioValues = { id: string; diff --git a/client/src/components/settings/privacy.tsx b/client/src/components/settings/privacy.tsx index f29f28e0c93..18b8f232c6c 100644 --- a/client/src/components/settings/privacy.tsx +++ b/client/src/components/settings/privacy.tsx @@ -1,20 +1,20 @@ +import { Button, Form } from '@freecodecamp/react-bootstrap'; import React, { Component } from 'react'; -import { bindActionCreators } from 'redux'; +import { TFunction, withTranslation } from 'react-i18next'; import { connect } from 'react-redux'; +import { bindActionCreators } from 'redux'; +import type { Dispatch } from 'redux'; import { createSelector } from 'reselect'; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore -import { Button, Form } from '@freecodecamp/react-bootstrap'; -import { TFunction, withTranslation } from 'react-i18next'; -import type { Dispatch } from 'redux'; import { userSelector } from '../../redux'; import { submitProfileUI } from '../../redux/settings'; import FullWidthRow from '../helpers/full-width-row'; import Spacer from '../helpers/spacer'; -import ToggleSetting from './toggle-setting'; import SectionHeader from './section-header'; +import ToggleSetting from './toggle-setting'; const mapStateToProps = createSelector(userSelector, user => ({ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment diff --git a/client/src/components/settings/reset-modal.tsx b/client/src/components/settings/reset-modal.tsx index 77d2e58e489..90fc5ce8aba 100644 --- a/client/src/components/settings/reset-modal.tsx +++ b/client/src/components/settings/reset-modal.tsx @@ -1,10 +1,10 @@ +import { Button, Modal } from '@freecodecamp/react-bootstrap'; import React from 'react'; import { useTranslation } from 'react-i18next'; import { ButtonSpacer } from '../helpers'; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore -import { Button, Modal } from '@freecodecamp/react-bootstrap'; type ResetModalProps = { onHide: () => void; diff --git a/client/src/components/settings/theme.tsx b/client/src/components/settings/theme.tsx index aeb13a0fa82..93b4d30afee 100644 --- a/client/src/components/settings/theme.tsx +++ b/client/src/components/settings/theme.tsx @@ -1,7 +1,7 @@ +import { Form } from '@freecodecamp/react-bootstrap'; import React from 'react'; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore -import { Form } from '@freecodecamp/react-bootstrap'; import { useTranslation } from 'react-i18next'; import ToggleSetting from './toggle-setting'; diff --git a/client/src/components/settings/toggle-setting.tsx b/client/src/components/settings/toggle-setting.tsx index c3f74765b5f..ccb7804cde7 100644 --- a/client/src/components/settings/toggle-setting.tsx +++ b/client/src/components/settings/toggle-setting.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { FormGroup, ControlLabel, @@ -6,9 +5,10 @@ import { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore } from '@freecodecamp/react-bootstrap'; +import React from 'react'; -import TB from '../helpers/toggle-button'; import { ButtonSpacer } from '../helpers'; +import TB from '../helpers/toggle-button'; import './toggle-setting.css'; diff --git a/client/src/components/settings/username.tsx b/client/src/components/settings/username.tsx index 0e76a5c9917..461324fedca 100644 --- a/client/src/components/settings/username.tsx +++ b/client/src/components/settings/username.tsx @@ -1,8 +1,4 @@ /* eslint-disable @typescript-eslint/unbound-method */ -import React, { Component } from 'react'; -import { bindActionCreators } from 'redux'; -import { connect } from 'react-redux'; -import { createSelector } from 'reselect'; import { ControlLabel, FormControl, @@ -11,17 +7,21 @@ import { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore } from '@freecodecamp/react-bootstrap'; +import React, { Component } from 'react'; import { TFunction, withTranslation } from 'react-i18next'; +import { connect } from 'react-redux'; +import { bindActionCreators } from 'redux'; import type { Dispatch } from 'redux'; +import { createSelector } from 'reselect'; +import { isValidUsername } from '../../../../utils/validate'; import { validateUsername, usernameValidationSelector, submitNewUsername } from '../../redux/settings'; -import FullWidthRow from '../helpers/full-width-row'; import BlockSaveButton from '../helpers/form/block-save-button'; -import { isValidUsername } from '../../../../utils/validate'; +import FullWidthRow from '../helpers/full-width-row'; type UsernameProps = { isValidUsername: boolean; diff --git a/client/src/pages/404.tsx b/client/src/pages/404.tsx index 95ff28fefef..55e7eced048 100644 --- a/client/src/pages/404.tsx +++ b/client/src/pages/404.tsx @@ -1,10 +1,10 @@ -import React from 'react'; import { Router } from '@reach/router'; import { withPrefix } from 'gatsby'; +import React from 'react'; -import FourOhFour from '../components/FourOhFour'; /* eslint-disable max-len */ import ShowProfileOrFourOhFour from '../client-only-routes/show-profile-or-four-oh-four'; +import FourOhFour from '../components/FourOhFour'; /* eslint-enable max-len */ function FourOhFourPage(): JSX.Element { diff --git a/client/src/pages/certification.tsx b/client/src/pages/certification.tsx index 38f3c48ed16..50660e41c76 100644 --- a/client/src/pages/certification.tsx +++ b/client/src/pages/certification.tsx @@ -1,9 +1,9 @@ -import React from 'react'; import { Router } from '@reach/router'; import { withPrefix } from 'gatsby'; +import React from 'react'; -import RedirectHome from '../components/redirect-home'; import ShowCertification from '../client-only-routes/show-certification'; +import RedirectHome from '../components/redirect-home'; import './certification.css'; diff --git a/client/src/pages/challenges.test.ts b/client/src/pages/challenges.test.ts index 2dc85df4c11..03784f35d80 100644 --- a/client/src/pages/challenges.test.ts +++ b/client/src/pages/challenges.test.ts @@ -6,8 +6,8 @@ * We should either make the expected properties optional, or reevaluate * these tests. */ -import toLearnPath from '../utils/to-learn-path'; import { withPrefix } from 'gatsby'; +import toLearnPath from '../utils/to-learn-path'; describe('toLearnPath', () => { it('should return a string', () => { diff --git a/client/src/pages/challenges.tsx b/client/src/pages/challenges.tsx index b85e576c656..86a5c4e4787 100644 --- a/client/src/pages/challenges.tsx +++ b/client/src/pages/challenges.tsx @@ -1,7 +1,7 @@ // this exists purely to redirect legacy challenge paths to /learn -import React from 'react'; import { Router } from '@reach/router'; import { navigate, withPrefix } from 'gatsby'; +import React from 'react'; import toLearnPath from '../utils/to-learn-path'; diff --git a/client/src/pages/donate.tsx b/client/src/pages/donate.tsx index b2391851dd1..ea0e36467a6 100644 --- a/client/src/pages/donate.tsx +++ b/client/src/pages/donate.tsx @@ -1,13 +1,12 @@ +import { Grid, Row, Col, Alert } from '@freecodecamp/react-bootstrap'; import React, { useEffect } from 'react'; import Helmet from 'react-helmet'; +import { TFunction, withTranslation } from 'react-i18next'; +import { connect } from 'react-redux'; import { bindActionCreators } from 'redux'; import type { Dispatch } from 'redux'; -import { connect } from 'react-redux'; import { createSelector } from 'reselect'; -import { Grid, Row, Col, Alert } from '@freecodecamp/react-bootstrap'; -import { TFunction, withTranslation } from 'react-i18next'; -import { Spacer, Loader } from '../components/helpers'; import DonateForm from '../components/Donation/DonateForm'; import { DonationText, @@ -15,8 +14,9 @@ import { DonationOptionsText, DonationOptionsAlertText } from '../components/Donation/DonationTextComponents'; -import { signInLoadingSelector, userSelector, executeGA } from '../redux'; +import { Spacer, Loader } from '../components/helpers'; import CampersImage from '../components/landing/components/CampersImage'; +import { signInLoadingSelector, userSelector, executeGA } from '../redux'; interface ExecuteGaArg { type: string; diff --git a/client/src/pages/email-sign-up.tsx b/client/src/pages/email-sign-up.tsx index d6f17e015ba..7df6f055e1a 100644 --- a/client/src/pages/email-sign-up.tsx +++ b/client/src/pages/email-sign-up.tsx @@ -1,18 +1,17 @@ +import { Row, Col, Button, Grid } from '@freecodecamp/react-bootstrap'; import React, { useEffect } from 'react'; +import Helmet from 'react-helmet'; +import { TFunction, withTranslation } from 'react-i18next'; +import { connect } from 'react-redux'; import { bindActionCreators } from 'redux'; import type { Dispatch } from 'redux'; -import { connect } from 'react-redux'; -import SectionHeader from '../components/settings/section-header'; -import IntroDescription from '../components/Intro/components/IntroDescription'; -import { TFunction, withTranslation } from 'react-i18next'; - -import { Row, Col, Button, Grid } from '@freecodecamp/react-bootstrap'; -import Helmet from 'react-helmet'; import { createSelector } from 'reselect'; - -import { ButtonSpacer, Spacer } from '../components/helpers'; -import { acceptTerms, userSelector } from '../redux'; +import IntroDescription from '../components/Intro/components/IntroDescription'; import createRedirect from '../components/create-redirect'; +import { ButtonSpacer, Spacer } from '../components/helpers'; +import SectionHeader from '../components/settings/section-header'; + +import { acceptTerms, userSelector } from '../redux'; import './email-sign-up.css'; diff --git a/client/src/pages/learn.tsx b/client/src/pages/learn.tsx index 04a7a83a815..1434a74a9c8 100644 --- a/client/src/pages/learn.tsx +++ b/client/src/pages/learn.tsx @@ -1,15 +1,15 @@ -import React from 'react'; import { Grid, Row, Col } from '@freecodecamp/react-bootstrap'; -import { createSelector } from 'reselect'; import { graphql } from 'gatsby'; +import React from 'react'; import Helmet from 'react-helmet'; -import { connect } from 'react-redux'; import { useTranslation } from 'react-i18next'; +import { connect } from 'react-redux'; +import { createSelector } from 'reselect'; +import Intro from '../components/Intro'; +import Map from '../components/Map'; import { Spacer } from '../components/helpers'; import LearnLayout from '../components/layouts/learn'; -import Map from '../components/Map'; -import Intro from '../components/Intro'; import { userFetchStateSelector, isSignedInSelector, diff --git a/client/src/pages/settings.tsx b/client/src/pages/settings.tsx index ab8eb83d58a..95a19aec6aa 100644 --- a/client/src/pages/settings.tsx +++ b/client/src/pages/settings.tsx @@ -1,9 +1,9 @@ -import React from 'react'; import { Router } from '@reach/router'; import { withPrefix } from 'gatsby'; +import React from 'react'; -import RedirectHome from '../components/redirect-home'; import ShowSettings from '../client-only-routes/show-settings'; +import RedirectHome from '../components/redirect-home'; function Settings(): JSX.Element { return ( diff --git a/client/src/pages/unsubscribed.tsx b/client/src/pages/unsubscribed.tsx index f08f7216b94..55f39702b84 100644 --- a/client/src/pages/unsubscribed.tsx +++ b/client/src/pages/unsubscribed.tsx @@ -1,9 +1,9 @@ -import React from 'react'; import { Router } from '@reach/router'; import { withPrefix } from 'gatsby'; +import React from 'react'; -import RedirectHome from '../components/redirect-home'; import ShowUnsubscribed from '../client-only-routes/show-unsubscribed'; +import RedirectHome from '../components/redirect-home'; function Unsubscribed(): JSX.Element { return ( diff --git a/client/src/pages/update-email.tsx b/client/src/pages/update-email.tsx index 65981674b0d..f98c5d2ca17 100644 --- a/client/src/pages/update-email.tsx +++ b/client/src/pages/update-email.tsx @@ -1,10 +1,3 @@ -import React, { useState } from 'react'; -import type { FormEvent, ChangeEvent } from 'react'; -import { Link } from 'gatsby'; -import { bindActionCreators } from 'redux'; -import type { Dispatch } from 'redux'; -import { connect } from 'react-redux'; -import { createSelector } from 'reselect'; import { Form, FormGroup, @@ -15,10 +8,17 @@ import { Col, Button } from '@freecodecamp/react-bootstrap'; -import Helmet from 'react-helmet'; -import isEmail from 'validator/lib/isEmail'; +import { Link } from 'gatsby'; import { isString } from 'lodash-es'; +import React, { useState } from 'react'; +import type { FormEvent, ChangeEvent } from 'react'; +import Helmet from 'react-helmet'; import { TFunction, withTranslation } from 'react-i18next'; +import { connect } from 'react-redux'; +import { bindActionCreators } from 'redux'; +import type { Dispatch } from 'redux'; +import { createSelector } from 'reselect'; +import isEmail from 'validator/lib/isEmail'; import { Spacer } from '../components/helpers'; import './update-email.css'; diff --git a/client/src/pages/user.tsx b/client/src/pages/user.tsx index 7cac7a5a63f..03559eafa80 100644 --- a/client/src/pages/user.tsx +++ b/client/src/pages/user.tsx @@ -1,9 +1,9 @@ -import React from 'react'; import { Router } from '@reach/router'; import { withPrefix } from 'gatsby'; +import React from 'react'; -import RedirectHome from '../components/redirect-home'; import ShowUser from '../client-only-routes/show-user'; +import RedirectHome from '../components/redirect-home'; function User(): JSX.Element { return ( diff --git a/client/src/redux/accept-terms-saga.js b/client/src/redux/accept-terms-saga.js index b5027e2e3f7..b97bf59a601 100644 --- a/client/src/redux/accept-terms-saga.js +++ b/client/src/redux/accept-terms-saga.js @@ -1,10 +1,10 @@ -import { call, put, takeEvery } from 'redux-saga/effects'; import { navigate } from 'gatsby'; +import { call, put, takeEvery } from 'redux-saga/effects'; -import { acceptTermsComplete, acceptTermsError } from './'; import { createFlashMessage } from '../components/Flash/redux'; import { putUserAcceptsTerms } from '../utils/ajax'; +import { acceptTermsComplete, acceptTermsError } from './'; function* acceptTermsSaga({ payload: quincyEmails }) { try { diff --git a/client/src/redux/action-types.js b/client/src/redux/action-types.js new file mode 100644 index 00000000000..778053c54e5 --- /dev/null +++ b/client/src/redux/action-types.js @@ -0,0 +1,33 @@ +import { createTypes, createAsyncTypes } from '../utils/create-types'; + +export const ns = 'app'; + +export const actionTypes = createTypes( + [ + 'appMount', + 'hardGoTo', + 'allowBlockDonationRequests', + 'closeDonationModal', + 'preventBlockDonationRequests', + 'preventProgressDonationRequests', + 'openDonationModal', + 'onlineStatusChange', + 'resetUserData', + 'tryToShowDonationModal', + 'executeGA', + 'submitComplete', + 'updateComplete', + 'updateCurrentChallengeId', + 'updateFailed', + 'updateDonationFormState', + ...createAsyncTypes('fetchUser'), + ...createAsyncTypes('addDonation'), + ...createAsyncTypes('createStripeSession'), + ...createAsyncTypes('postChargeStripe'), + ...createAsyncTypes('fetchProfileForUser'), + ...createAsyncTypes('acceptTerms'), + ...createAsyncTypes('showCert'), + ...createAsyncTypes('reportUser') + ], + ns +); diff --git a/client/src/redux/app-mount-saga.js b/client/src/redux/app-mount-saga.js index d5f2774f18b..6f9e68ca9b6 100644 --- a/client/src/redux/app-mount-saga.js +++ b/client/src/redux/app-mount-saga.js @@ -1,5 +1,5 @@ -import { put, takeEvery } from 'redux-saga/effects'; import qs from 'query-string'; +import { put, takeEvery } from 'redux-saga/effects'; import { createFlashMessage } from '../components/Flash/redux'; function* parseMessagesSaga() { diff --git a/client/src/redux/createStore.js b/client/src/redux/createStore.js index 7582e49acda..edab62b6184 100644 --- a/client/src/redux/createStore.js +++ b/client/src/redux/createStore.js @@ -1,15 +1,14 @@ /* eslint-disable-next-line max-len */ -import { composeWithDevTools } from 'redux-devtools-extension/logOnlyInProduction'; import { createStore as reduxCreateStore, applyMiddleware } from 'redux'; -import createSagaMiddleware from 'redux-saga'; +import { composeWithDevTools } from 'redux-devtools-extension/logOnlyInProduction'; import { createEpicMiddleware } from 'redux-observable'; +import createSagaMiddleware from 'redux-saga'; +import envData from '../../../config/env.json'; +import { isBrowser } from '../../utils'; import rootEpic from './rootEpic'; import rootReducer from './rootReducer'; import rootSaga from './rootSaga'; -import { isBrowser } from '../../utils'; - -import envData from '../../../config/env.json'; const { environment } = envData; diff --git a/client/src/redux/donation-saga.js b/client/src/redux/donation-saga.js index ed4594fc298..40e9490a8b4 100644 --- a/client/src/redux/donation-saga.js +++ b/client/src/redux/donation-saga.js @@ -1,4 +1,6 @@ import { put, select, takeEvery, delay, call, take } from 'redux-saga/effects'; +import { addDonation } from '../utils/ajax'; +import { actionTypes as appTypes } from './action-types'; import { openDonationModal, @@ -7,12 +9,9 @@ import { preventProgressDonationRequests, recentlyClaimedBlockSelector, addDonationComplete, - addDonationError, - types as appTypes + addDonationError } from './'; -import { addDonation } from '../utils/ajax'; - const defaultDonationError = `Something is not right. Please contact donors@freecodecamp.org`; function* showDonateModalSaga() { diff --git a/client/src/redux/error-saga.js b/client/src/redux/error-saga.js index fa3d81ffe56..b419164e550 100644 --- a/client/src/redux/error-saga.js +++ b/client/src/redux/error-saga.js @@ -1,10 +1,10 @@ import { navigate } from 'gatsby'; -import { takeEvery, put } from 'redux-saga/effects'; import { isError } from 'lodash-es'; +import { takeEvery, put } from 'redux-saga/effects'; +import { createFlashMessage } from '../components/Flash/redux'; import { isHandledError, unwrapHandledError } from '../utils/handled-error'; import { reportClientSideError } from '../utils/report-error'; -import { createFlashMessage } from '../components/Flash/redux'; import reportedErrorMessage from '../utils/reported-error-message'; const errorActionSelector = action => isError(action.payload); diff --git a/client/src/redux/failed-updates-epic.js b/client/src/redux/failed-updates-epic.js index 6c057e9a7a6..1c96b121b1c 100644 --- a/client/src/redux/failed-updates-epic.js +++ b/client/src/redux/failed-updates-epic.js @@ -1,3 +1,4 @@ +import { ofType } from 'redux-observable'; import { merge, empty } from 'rxjs'; import { tap, @@ -7,19 +8,14 @@ import { switchMap, catchError } from 'rxjs/operators'; -import { ofType } from 'redux-observable'; import store from 'store'; import { v4 as uuid } from 'uuid'; -import { - types, - onlineStatusChange, - isOnlineSelector, - isSignedInSelector -} from './'; -import postUpdate$ from '../templates/Challenges/utils/postUpdate$'; -import { isGoodXHRStatus } from '../templates/Challenges/utils'; import { backEndProject } from '../../utils/challengeTypes'; +import { isGoodXHRStatus } from '../templates/Challenges/utils'; +import postUpdate$ from '../templates/Challenges/utils/postUpdate$'; +import { actionTypes } from './action-types'; +import { onlineStatusChange, isOnlineSelector, isSignedInSelector } from './'; const key = 'fcc-failed-updates'; @@ -33,7 +29,7 @@ const isSubmitable = failure => function failedUpdateEpic(action$, state$) { const storeUpdates = action$.pipe( - ofType(types.updateFailed), + ofType(actionTypes.updateFailed), tap(({ payload = {} }) => { if ('endpoint' in payload && 'payload' in payload) { const failures = store.get(key) || []; @@ -45,7 +41,7 @@ function failedUpdateEpic(action$, state$) { ); const flushUpdates = action$.pipe( - ofType(types.fetchUserComplete, types.updateComplete), + ofType(actionTypes.fetchUserComplete, actionTypes.updateComplete), filter(() => isSignedInSelector(state$.value)), filter(() => store.get(key)), filter(() => isOnlineSelector(state$.value)), diff --git a/client/src/redux/failed-updates-epic.test.js b/client/src/redux/failed-updates-epic.test.js index 7f3e66eb0e7..f344e74619d 100644 --- a/client/src/redux/failed-updates-epic.test.js +++ b/client/src/redux/failed-updates-epic.test.js @@ -1,8 +1,8 @@ -import { Subject } from 'rxjs'; import { ActionsObservable, StateObservable } from 'redux-observable'; -import failedUpdatesEpic from './failed-updates-epic'; -import { types } from './'; +import { Subject } from 'rxjs'; import store from 'store'; +import { actionTypes } from './action-types'; +import failedUpdatesEpic from './failed-updates-epic'; jest.mock('../analytics'); @@ -13,7 +13,7 @@ describe('failed-updates-epic', () => { store.set(key, failedSubmissions); const action$ = ActionsObservable.of({ - type: types.updateComplete + type: actionTypes.updateComplete }); const state$ = new StateObservable(new Subject(), initialState); const epic$ = failedUpdatesEpic(action$, state$); diff --git a/client/src/redux/fetch-user-saga.js b/client/src/redux/fetch-user-saga.js index e2147413b47..5d60b990b8b 100644 --- a/client/src/redux/fetch-user-saga.js +++ b/client/src/redux/fetch-user-saga.js @@ -1,13 +1,13 @@ import { call, put, takeEvery } from 'redux-saga/effects'; +import { getSessionUser, getUserProfile } from '../utils/ajax'; +import { jwt } from './cookieValues'; import { fetchUserComplete, fetchUserError, fetchProfileForUserError, fetchProfileForUserComplete } from './'; -import { getSessionUser, getUserProfile } from '../utils/ajax'; -import { jwt } from './cookieValues'; function* fetchSessionUser() { if (!jwt) { diff --git a/client/src/redux/ga-saga.test.js b/client/src/redux/ga-saga.test.js index bb6a8bf06fa..582b87035e3 100644 --- a/client/src/redux/ga-saga.test.js +++ b/client/src/redux/ga-saga.test.js @@ -1,7 +1,7 @@ -import { types } from '.'; -import { createGaSaga } from './ga-saga'; -import ga from '../analytics'; import { expectSaga } from 'redux-saga-test-plan'; +import ga from '../analytics'; +import { actionTypes } from './action-types'; +import { createGaSaga } from './ga-saga'; jest.mock('../analytics'); @@ -16,12 +16,12 @@ describe('ga-saga', () => { } }; return ( - expectSaga(createGaSaga, types) + expectSaga(createGaSaga, actionTypes) // Assert that the `call` with expected pramater will eventually happen. .call(GaTypes.event, mockEventPayload.data) // Dispatch any actions that the saga will `take`. - .dispatch({ type: types.executeGA, payload: mockEventPayload }) + .dispatch({ type: actionTypes.executeGA, payload: mockEventPayload }) // Start the test. .run() diff --git a/client/src/redux/hard-go-to-epic.js b/client/src/redux/hard-go-to-epic.js index 300f4e31c69..53a4cb302a5 100644 --- a/client/src/redux/hard-go-to-epic.js +++ b/client/src/redux/hard-go-to-epic.js @@ -1,11 +1,11 @@ import { ofType } from 'redux-observable'; import { tap, ignoreElements } from 'rxjs/operators'; -import { types } from './'; +import { actionTypes } from './action-types'; export default function hardGoToEpic(action$, _, { location }) { return action$.pipe( - ofType(types.hardGoTo), + ofType(actionTypes.hardGoTo), tap(({ payload }) => { location.href = payload; }), diff --git a/client/src/redux/index.js b/client/src/redux/index.js index d00dbe3b53a..33eb196d811 100644 --- a/client/src/redux/index.js +++ b/client/src/redux/index.js @@ -1,27 +1,26 @@ -import { createAction, handleActions } from 'redux-actions'; import { uniqBy } from 'lodash-es'; +import { createAction, handleActions } from 'redux-actions'; import store from 'store'; -import { createTypes, createAsyncTypes } from '../utils/create-types'; -import { createFetchUserSaga } from './fetch-user-saga'; +import { actionTypes as challengeTypes } from '../templates/Challenges/redux/action-types'; +import { CURRENT_CHALLENGE_KEY } from '../templates/Challenges/redux/current-challenge-saga'; import { createAcceptTermsSaga } from './accept-terms-saga'; +import { actionTypes, ns } from './action-types'; import { createAppMountSaga } from './app-mount-saga'; -import { createReportUserSaga } from './report-user-saga'; -import { createShowCertSaga } from './show-cert-saga'; -import { createNightModeSaga } from './night-mode-saga'; import { createDonationSaga } from './donation-saga'; +import failedUpdatesEpic from './failed-updates-epic'; +import { createFetchUserSaga } from './fetch-user-saga'; import { createGaSaga } from './ga-saga'; import hardGoToEpic from './hard-go-to-epic'; -import failedUpdatesEpic from './failed-updates-epic'; +import { createNightModeSaga } from './night-mode-saga'; +import { createReportUserSaga } from './report-user-saga'; + +import { actionTypes as settingsTypes } from './settings/action-types'; +import { createShowCertSaga } from './show-cert-saga'; import updateCompleteEpic from './update-complete-epic'; -import { types as settingsTypes } from './settings'; -import { types as challengeTypes } from '../templates/Challenges/redux/'; -// eslint-disable-next-line max-len -import { CURRENT_CHALLENGE_KEY } from '../templates/Challenges/redux/current-challenge-saga'; - -export const ns = 'app'; +export { ns }; export const defaultFetchState = { pending: true, @@ -62,114 +61,92 @@ const initialState = { } }; -export const types = createTypes( - [ - 'appMount', - 'hardGoTo', - 'allowBlockDonationRequests', - 'closeDonationModal', - 'preventBlockDonationRequests', - 'preventProgressDonationRequests', - 'openDonationModal', - 'onlineStatusChange', - 'resetUserData', - 'tryToShowDonationModal', - 'executeGA', - 'submitComplete', - 'updateComplete', - 'updateCurrentChallengeId', - 'updateFailed', - 'updateDonationFormState', - ...createAsyncTypes('fetchUser'), - ...createAsyncTypes('addDonation'), - ...createAsyncTypes('fetchProfileForUser'), - ...createAsyncTypes('acceptTerms'), - ...createAsyncTypes('showCert'), - ...createAsyncTypes('reportUser') - ], - ns -); - export const epics = [hardGoToEpic, failedUpdatesEpic, updateCompleteEpic]; export const sagas = [ - ...createAcceptTermsSaga(types), - ...createAppMountSaga(types), - ...createDonationSaga(types), - ...createGaSaga(types), - ...createFetchUserSaga(types), - ...createShowCertSaga(types), - ...createReportUserSaga(types), - ...createNightModeSaga({ ...types, ...settingsTypes }) + ...createAcceptTermsSaga(actionTypes), + ...createAppMountSaga(actionTypes), + ...createDonationSaga(actionTypes), + ...createGaSaga(actionTypes), + ...createFetchUserSaga(actionTypes), + ...createShowCertSaga(actionTypes), + ...createReportUserSaga(actionTypes), + ...createNightModeSaga({ ...actionTypes, ...settingsTypes }) ]; -export const appMount = createAction(types.appMount); +export const appMount = createAction(actionTypes.appMount); export const tryToShowDonationModal = createAction( - types.tryToShowDonationModal + actionTypes.tryToShowDonationModal ); -export const executeGA = createAction(types.executeGA); +export const executeGA = createAction(actionTypes.executeGA); export const allowBlockDonationRequests = createAction( - types.allowBlockDonationRequests + actionTypes.allowBlockDonationRequests ); -export const closeDonationModal = createAction(types.closeDonationModal); -export const openDonationModal = createAction(types.openDonationModal); +export const closeDonationModal = createAction(actionTypes.closeDonationModal); +export const openDonationModal = createAction(actionTypes.openDonationModal); export const preventBlockDonationRequests = createAction( - types.preventBlockDonationRequests + actionTypes.preventBlockDonationRequests ); export const preventProgressDonationRequests = createAction( - types.preventProgressDonationRequests + actionTypes.preventProgressDonationRequests ); export const updateDonationFormState = createAction( - types.updateDonationFormState + actionTypes.updateDonationFormState ); -export const onlineStatusChange = createAction(types.onlineStatusChange); +export const onlineStatusChange = createAction(actionTypes.onlineStatusChange); // TODO: re-evaluate this since /internal is no longer used. // `hardGoTo` is used to hit the API server directly // without going through /internal // used for things like /signin and /signout -export const hardGoTo = createAction(types.hardGoTo); +export const hardGoTo = createAction(actionTypes.hardGoTo); -export const submitComplete = createAction(types.submitComplete); -export const updateComplete = createAction(types.updateComplete); -export const updateFailed = createAction(types.updateFailed); +export const submitComplete = createAction(actionTypes.submitComplete); +export const updateComplete = createAction(actionTypes.updateComplete); +export const updateFailed = createAction(actionTypes.updateFailed); -export const acceptTerms = createAction(types.acceptTerms); -export const acceptTermsComplete = createAction(types.acceptTermsComplete); -export const acceptTermsError = createAction(types.acceptTermsError); +export const acceptTerms = createAction(actionTypes.acceptTerms); +export const acceptTermsComplete = createAction( + actionTypes.acceptTermsComplete +); +export const acceptTermsError = createAction(actionTypes.acceptTermsError); -export const fetchUser = createAction(types.fetchUser); -export const fetchUserComplete = createAction(types.fetchUserComplete); -export const fetchUserError = createAction(types.fetchUserError); +export const fetchUser = createAction(actionTypes.fetchUser); +export const fetchUserComplete = createAction(actionTypes.fetchUserComplete); +export const fetchUserError = createAction(actionTypes.fetchUserError); -export const addDonation = createAction(types.addDonation); -export const addDonationComplete = createAction(types.addDonationComplete); -export const addDonationError = createAction(types.addDonationError); +export const addDonation = createAction(actionTypes.addDonation); +export const addDonationComplete = createAction( + actionTypes.addDonationComplete +); +export const addDonationError = createAction(actionTypes.addDonationError); -export const fetchProfileForUser = createAction(types.fetchProfileForUser); +export const fetchProfileForUser = createAction( + actionTypes.fetchProfileForUser +); export const fetchProfileForUserComplete = createAction( - types.fetchProfileForUserComplete + actionTypes.fetchProfileForUserComplete ); export const fetchProfileForUserError = createAction( - types.fetchProfileForUserError + actionTypes.fetchProfileForUserError ); -export const reportUser = createAction(types.reportUser); -export const reportUserComplete = createAction(types.reportUserComplete); -export const reportUserError = createAction(types.reportUserError); +export const reportUser = createAction(actionTypes.reportUser); +export const reportUserComplete = createAction(actionTypes.reportUserComplete); +export const reportUserError = createAction(actionTypes.reportUserError); -export const resetUserData = createAction(types.resetUserData); +export const resetUserData = createAction(actionTypes.resetUserData); -export const showCert = createAction(types.showCert); -export const showCertComplete = createAction(types.showCertComplete); -export const showCertError = createAction(types.showCertError); +export const showCert = createAction(actionTypes.showCert); +export const showCertComplete = createAction(actionTypes.showCertComplete); +export const showCertError = createAction(actionTypes.showCertError); export const updateCurrentChallengeId = createAction( - types.updateCurrentChallengeId + actionTypes.updateCurrentChallengeId ); export const completedChallengesSelector = state => @@ -384,7 +361,7 @@ function spreadThePayloadOnUser(state, payload) { export const reducer = handleActions( { - [types.acceptTermsComplete]: (state, { payload }) => { + [actionTypes.acceptTermsComplete]: (state, { payload }) => { const { appUsername } = state; return { ...state, @@ -405,21 +382,21 @@ export const reducer = handleActions( } }; }, - [types.allowBlockDonationRequests]: (state, { payload }) => { + [actionTypes.allowBlockDonationRequests]: (state, { payload }) => { return { ...state, recentlyClaimedBlock: payload }; }, - [types.updateDonationFormState]: (state, { payload }) => ({ + [actionTypes.updateDonationFormState]: (state, { payload }) => ({ ...state, donationFormState: { ...state.donationFormState, ...payload } }), - [types.addDonation]: state => ({ + [actionTypes.addDonation]: state => ({ ...state, donationFormState: { ...defaultDonationFormState, processing: true } }), - [types.addDonationComplete]: state => { + [actionTypes.addDonationComplete]: state => { const { appUsername } = state; return { ...state, @@ -434,19 +411,19 @@ export const reducer = handleActions( donationFormState: { ...defaultDonationFormState, success: true } }; }, - [types.addDonationError]: (state, { payload }) => ({ + [actionTypes.addDonationError]: (state, { payload }) => ({ ...state, donationFormState: { ...defaultDonationFormState, error: payload } }), - [types.fetchUser]: state => ({ + [actionTypes.fetchUser]: state => ({ ...state, userFetchState: { ...defaultFetchState } }), - [types.fetchProfileForUser]: state => ({ + [actionTypes.fetchProfileForUser]: state => ({ ...state, userProfileFetchState: { ...defaultFetchState } }), - [types.fetchUserComplete]: ( + [actionTypes.fetchUserComplete]: ( state, { payload: { user, username, sessionMeta } } ) => ({ @@ -468,7 +445,7 @@ export const reducer = handleActions( ...sessionMeta } }), - [types.fetchUserError]: (state, { payload }) => ({ + [actionTypes.fetchUserError]: (state, { payload }) => ({ ...state, userFetchState: { pending: false, @@ -477,7 +454,7 @@ export const reducer = handleActions( error: payload } }), - [types.fetchProfileForUserComplete]: ( + [actionTypes.fetchProfileForUserComplete]: ( state, { payload: { user, username } } ) => { @@ -496,7 +473,7 @@ export const reducer = handleActions( } }; }, - [types.fetchProfileForUserError]: (state, { payload }) => ({ + [actionTypes.fetchProfileForUserError]: (state, { payload }) => ({ ...state, userProfileFetchState: { pending: false, @@ -505,37 +482,37 @@ export const reducer = handleActions( error: payload } }), - [types.onlineStatusChange]: (state, { payload: isOnline }) => ({ + [actionTypes.onlineStatusChange]: (state, { payload: isOnline }) => ({ ...state, isOnline }), - [types.closeDonationModal]: state => ({ + [actionTypes.closeDonationModal]: state => ({ ...state, showDonationModal: false }), - [types.openDonationModal]: state => ({ + [actionTypes.openDonationModal]: state => ({ ...state, showDonationModal: true }), - [types.preventBlockDonationRequests]: state => ({ + [actionTypes.preventBlockDonationRequests]: state => ({ ...state, recentlyClaimedBlock: null }), - [types.preventProgressDonationRequests]: state => ({ + [actionTypes.preventProgressDonationRequests]: state => ({ ...state, canRequestProgressDonation: false }), - [types.resetUserData]: state => ({ + [actionTypes.resetUserData]: state => ({ ...state, appUsername: '', user: {} }), - [types.showCert]: state => ({ + [actionTypes.showCert]: state => ({ ...state, showCert: {}, showCertFetchState: { ...defaultFetchState } }), - [types.showCertComplete]: (state, { payload }) => ({ + [actionTypes.showCertComplete]: (state, { payload }) => ({ ...state, showCert: payload, showCertFetchState: { @@ -544,7 +521,7 @@ export const reducer = handleActions( complete: true } }), - [types.showCertError]: (state, { payload }) => ({ + [actionTypes.showCertError]: (state, { payload }) => ({ ...state, showCert: {}, showCertFetchState: { @@ -554,7 +531,7 @@ export const reducer = handleActions( error: payload } }), - [types.submitComplete]: (state, { payload }) => { + [actionTypes.submitComplete]: (state, { payload }) => { let submittedchallenges = [{ ...payload, completedDate: Date.now() }]; if (payload.challArray) { submittedchallenges = payload.challArray; diff --git a/client/src/redux/report-user-saga.js b/client/src/redux/report-user-saga.js index 75243fba68c..34906e11151 100644 --- a/client/src/redux/report-user-saga.js +++ b/client/src/redux/report-user-saga.js @@ -1,10 +1,10 @@ -import { call, put, takeEvery } from 'redux-saga/effects'; import { navigate } from 'gatsby'; +import { call, put, takeEvery } from 'redux-saga/effects'; -import { reportUserComplete, reportUserError } from './'; import { createFlashMessage } from '../components/Flash/redux'; import { postReportUser } from '../utils/ajax'; +import { reportUserComplete, reportUserError } from './'; function* reportUserSaga({ payload }) { try { diff --git a/client/src/redux/rootEpic.js b/client/src/redux/rootEpic.js index 25ed10dfd2b..dd956348596 100644 --- a/client/src/redux/rootEpic.js +++ b/client/src/redux/rootEpic.js @@ -1,7 +1,7 @@ import { combineEpics } from 'redux-observable'; -import { epics as appEpics } from './'; import { epics as challengeEpics } from '../templates/Challenges/redux'; +import { epics as appEpics } from './'; const rootEpic = combineEpics(...appEpics, ...challengeEpics); diff --git a/client/src/redux/rootReducer.js b/client/src/redux/rootReducer.js index 88294fe6aea..587b52e66ba 100644 --- a/client/src/redux/rootReducer.js +++ b/client/src/redux/rootReducer.js @@ -1,23 +1,23 @@ import { combineReducers } from 'redux'; -import { reducer as app, ns as appNameSpace } from './'; import { reducer as flash, ns as flashNameSpace } from '../components/Flash/redux'; -import { reducer as settings, ns as settingsNameSpace } from './settings'; import { - reducer as curriculumMap, - ns as curriculumMapNameSpace -} from '../templates/Introduction/redux'; + reducer as search, + ns as searchNameSpace +} from '../components/search/redux'; import { reducer as challenge, ns as challengeNameSpace } from '../templates/Challenges/redux'; import { - reducer as search, - ns as searchNameSpace -} from '../components/search/redux'; + reducer as curriculumMap, + ns as curriculumMapNameSpace +} from '../templates/Introduction/redux'; +import { reducer as settings, ns as settingsNameSpace } from './settings'; +import { reducer as app, ns as appNameSpace } from './'; export default combineReducers({ [appNameSpace]: app, diff --git a/client/src/redux/rootSaga.js b/client/src/redux/rootSaga.js index ccc836cf66b..ec83d4a5b6e 100644 --- a/client/src/redux/rootSaga.js +++ b/client/src/redux/rootSaga.js @@ -1,9 +1,9 @@ import { all } from 'redux-saga/effects'; -import errorSagas from './error-saga'; -import { sagas as appSagas } from './'; import { sagas as challengeSagas } from '../templates/Challenges/redux'; +import errorSagas from './error-saga'; import { sagas as settingsSagas } from './settings'; +import { sagas as appSagas } from './'; export default function* rootSaga() { yield all([...errorSagas, ...appSagas, ...challengeSagas, ...settingsSagas]); diff --git a/client/src/redux/settings/action-types.js b/client/src/redux/settings/action-types.js new file mode 100644 index 00000000000..a153c5568d3 --- /dev/null +++ b/client/src/redux/settings/action-types.js @@ -0,0 +1,19 @@ +import { createTypes, createAsyncTypes } from '../../utils/create-types'; + +export const ns = 'settings'; + +export const actionTypes = createTypes( + [ + ...createAsyncTypes('validateUsername'), + ...createAsyncTypes('submitNewAbout'), + ...createAsyncTypes('submitNewUsername'), + ...createAsyncTypes('updateMyEmail'), + ...createAsyncTypes('updateLegacyCert'), + ...createAsyncTypes('updateUserFlag'), + ...createAsyncTypes('submitProfileUI'), + ...createAsyncTypes('verifyCert'), + ...createAsyncTypes('resetProgress'), + ...createAsyncTypes('deleteAccount') + ], + ns +); diff --git a/client/src/redux/settings/danger-zone-saga.js b/client/src/redux/settings/danger-zone-saga.js index e8ebc6e3724..1e1f03bc4f9 100644 --- a/client/src/redux/settings/danger-zone-saga.js +++ b/client/src/redux/settings/danger-zone-saga.js @@ -1,10 +1,11 @@ import { navigate } from 'gatsby'; import { call, put, takeEvery, take } from 'redux-saga/effects'; -import { deleteAccountError, resetProgressError } from './'; -import { resetUserData, fetchUser, types as appTypes } from '../'; -import { postResetProgress, postDeleteAccount } from '../../utils/ajax'; +import { resetUserData, fetchUser } from '../'; import { createFlashMessage } from '../../components/Flash/redux'; +import { postResetProgress, postDeleteAccount } from '../../utils/ajax'; +import { actionTypes as appTypes } from '../action-types'; +import { deleteAccountError, resetProgressError } from './'; function* deleteAccountSaga() { try { diff --git a/client/src/redux/settings/index.js b/client/src/redux/settings/index.js index 9609c90c8af..be08635a29c 100644 --- a/client/src/redux/settings/index.js +++ b/client/src/redux/settings/index.js @@ -1,11 +1,10 @@ import { createAction, handleActions } from 'redux-actions'; - -import { createTypes, createAsyncTypes } from '../../utils/create-types'; +import { actionTypes as types, ns } from './action-types'; import { createDangerZoneSaga } from './danger-zone-saga'; import { createSettingsSagas } from './settings-sagas'; import { createUpdateMyEmailSaga } from './update-email-saga'; -export const ns = 'settings'; +export { ns }; const defaultFetchState = { pending: false, @@ -21,21 +20,6 @@ const initialState = { } }; -export const types = createTypes( - [ - ...createAsyncTypes('validateUsername'), - ...createAsyncTypes('submitNewAbout'), - ...createAsyncTypes('submitNewUsername'), - ...createAsyncTypes('updateMyEmail'), - ...createAsyncTypes('updateUserFlag'), - ...createAsyncTypes('submitProfileUI'), - ...createAsyncTypes('verifyCert'), - ...createAsyncTypes('resetProgress'), - ...createAsyncTypes('deleteAccount') - ], - ns -); - export const sagas = [ ...createSettingsSagas(types), ...createUpdateMyEmailSaga(types), diff --git a/client/src/redux/settings/settings-sagas.js b/client/src/redux/settings/settings-sagas.js index 1472f4ec1c5..1e242918481 100644 --- a/client/src/redux/settings/settings-sagas.js +++ b/client/src/redux/settings/settings-sagas.js @@ -1,5 +1,14 @@ import { call, delay, put, takeLatest, takeEvery } from 'redux-saga/effects'; +import { createFlashMessage } from '../../components/Flash/redux'; +import { + getUsernameExists, + putUpdateMyAbout, + putUpdateMyProfileUI, + putUpdateMyUsername, + putUpdateUserFlag, + putVerifyCert +} from '../../utils/ajax'; import { updateUserFlagComplete, updateUserFlagError, @@ -14,15 +23,6 @@ import { verifyCertComplete, verifyCertError } from './'; -import { - getUsernameExists, - putUpdateMyAbout, - putUpdateMyProfileUI, - putUpdateMyUsername, - putUpdateUserFlag, - putVerifyCert -} from '../../utils/ajax'; -import { createFlashMessage } from '../../components/Flash/redux'; function* submitNewAboutSaga({ payload }) { try { diff --git a/client/src/redux/settings/update-email-saga.js b/client/src/redux/settings/update-email-saga.js index b3809fde346..a1dce59b0ca 100644 --- a/client/src/redux/settings/update-email-saga.js +++ b/client/src/redux/settings/update-email-saga.js @@ -1,11 +1,11 @@ import { call, put, takeEvery } from 'redux-saga/effects'; import isEmail from 'validator/lib/isEmail'; -import { updateMyEmailComplete, updateMyEmailError } from './'; import { createFlashMessage } from '../../components/Flash/redux'; import { putUserUpdateEmail } from '../../utils/ajax'; import reallyWeirdErrorMessage from '../../utils/really-weird-error-message'; +import { updateMyEmailComplete, updateMyEmailError } from './'; function* updateMyEmailSaga({ payload: email = '' }) { if (!email || !isEmail(email)) { diff --git a/client/src/redux/show-cert-saga.js b/client/src/redux/show-cert-saga.js index e352fab7782..682aafe20d2 100644 --- a/client/src/redux/show-cert-saga.js +++ b/client/src/redux/show-cert-saga.js @@ -1,5 +1,5 @@ -import { put, takeEvery, call } from 'redux-saga/effects'; import { navigate } from 'gatsby'; +import { put, takeEvery, call } from 'redux-saga/effects'; import { createFlashMessage } from '../components/Flash/redux'; import { getShowCert } from '../utils/ajax'; diff --git a/client/src/redux/update-complete-epic.js b/client/src/redux/update-complete-epic.js index 792a68855f9..bde70298164 100644 --- a/client/src/redux/update-complete-epic.js +++ b/client/src/redux/update-complete-epic.js @@ -1,7 +1,8 @@ import { ofType } from 'redux-observable'; import { mapTo, filter } from 'rxjs/operators'; -import { types, onlineStatusChange, isOnlineSelector } from './'; +import { actionTypes as types } from './action-types'; +import { onlineStatusChange, isOnlineSelector } from './'; export default function updateCompleteEpic(action$, state$) { return action$.pipe( diff --git a/client/src/templates/Challenges/classic/ActionRow.js b/client/src/templates/Challenges/classic/ActionRow.js index 841de847514..bafbe970948 100644 --- a/client/src/templates/Challenges/classic/ActionRow.js +++ b/client/src/templates/Challenges/classic/ActionRow.js @@ -1,7 +1,7 @@ -import React from 'react'; import PropTypes from 'prop-types'; -import EditorTabs from './EditorTabs'; +import React from 'react'; import BreadCrumb from '../components/bread-crumb'; +import EditorTabs from './EditorTabs'; const propTypes = { block: PropTypes.string, diff --git a/client/src/templates/Challenges/classic/DesktopLayout.js b/client/src/templates/Challenges/classic/DesktopLayout.js index 3fa3bf0509b..cdf7bf22320 100644 --- a/client/src/templates/Challenges/classic/DesktopLayout.js +++ b/client/src/templates/Challenges/classic/DesktopLayout.js @@ -1,10 +1,10 @@ +import { first } from 'lodash-es'; +import PropTypes from 'prop-types'; import React, { Component } from 'react'; import { ReflexContainer, ReflexSplitter, ReflexElement } from 'react-reflex'; -import PropTypes from 'prop-types'; -import { first } from 'lodash-es'; -import EditorTabs from './EditorTabs'; -import ActionRow from './ActionRow'; import envData from '../../../../../config/env.json'; +import ActionRow from './ActionRow'; +import EditorTabs from './EditorTabs'; const { showUpcomingChanges } = envData; diff --git a/client/src/templates/Challenges/classic/EditorTabs.js b/client/src/templates/Challenges/classic/EditorTabs.js index 112b4bb6e2a..81dbedb5678 100644 --- a/client/src/templates/Challenges/classic/EditorTabs.js +++ b/client/src/templates/Challenges/classic/EditorTabs.js @@ -1,6 +1,6 @@ +import PropTypes from 'prop-types'; import React, { Component } from 'react'; import { connect } from 'react-redux'; -import PropTypes from 'prop-types'; import { createSelector } from 'reselect'; import { diff --git a/client/src/templates/Challenges/classic/MobileLayout.js b/client/src/templates/Challenges/classic/MobileLayout.js index dd8d9af2d3e..476020e54e6 100644 --- a/client/src/templates/Challenges/classic/MobileLayout.js +++ b/client/src/templates/Challenges/classic/MobileLayout.js @@ -1,15 +1,15 @@ -import React, { Component } from 'react'; -import PropTypes from 'prop-types'; import { TabPane, Tabs } from '@freecodecamp/react-bootstrap'; +import i18next from 'i18next'; +import PropTypes from 'prop-types'; +import React, { Component } from 'react'; import { connect } from 'react-redux'; -import ToolPanel from '../components/Tool-Panel'; -import { createStructuredSelector } from 'reselect'; -import { currentTabSelector, moveToTab } from '../redux'; import { bindActionCreators } from 'redux'; -import EditorTabs from './EditorTabs'; +import { createStructuredSelector } from 'reselect'; import envData from '../../../../../config/env.json'; -import i18next from 'i18next'; +import ToolPanel from '../components/Tool-Panel'; +import { currentTabSelector, moveToTab } from '../redux'; +import EditorTabs from './EditorTabs'; const { showUpcomingChanges } = envData; diff --git a/client/src/templates/Challenges/classic/MultifileEditor.js b/client/src/templates/Challenges/classic/MultifileEditor.js index 694fc373b4e..101c2c1630c 100644 --- a/client/src/templates/Challenges/classic/MultifileEditor.js +++ b/client/src/templates/Challenges/classic/MultifileEditor.js @@ -3,7 +3,6 @@ import React, { Component } from 'react'; import { connect } from 'react-redux'; import { ReflexContainer, ReflexElement, ReflexSplitter } from 'react-reflex'; import { createSelector } from 'reselect'; -import { getTargetEditor } from '../utils/getTargetEditor'; import { isDonationModalOpenSelector, userSelector } from '../../../redux'; import { canFocusEditorSelector, @@ -16,6 +15,7 @@ import { visibleEditorsSelector, updateFile } from '../redux'; +import { getTargetEditor } from '../utils/getTargetEditor'; import './editor.css'; import Editor from './editor'; diff --git a/client/src/templates/Challenges/classic/Show.tsx b/client/src/templates/Challenges/classic/Show.tsx index adbeb577514..f709ed52ff2 100644 --- a/client/src/templates/Challenges/classic/Show.tsx +++ b/client/src/templates/Challenges/classic/Show.tsx @@ -2,32 +2,19 @@ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ // Package Utilities +import { graphql } from 'gatsby'; import React, { Component } from 'react'; +import Helmet from 'react-helmet'; +import { TFunction, withTranslation } from 'react-i18next'; +import { connect } from 'react-redux'; +import Media from 'react-responsive'; import { bindActionCreators, Dispatch } from 'redux'; import { createStructuredSelector } from 'reselect'; -import { connect } from 'react-redux'; -import Helmet from 'react-helmet'; -import { graphql } from 'gatsby'; -import Media from 'react-responsive'; -import { TFunction, withTranslation } from 'react-i18next'; // Local Utilities -import LearnLayout from '../../../components/layouts/learn'; -import MultifileEditor from './MultifileEditor'; -import Preview from '../components/Preview'; -import SidePanel from '../components/Side-Panel'; -import Output from '../components/output'; -import CompletionModal from '../components/completion-modal'; -import HelpModal from '../components/HelpModal'; -import VideoModal from '../components/VideoModal'; -import ResetModal from '../components/ResetModal'; -import MobileLayout from './MobileLayout'; -import DesktopLayout from './DesktopLayout'; -import Hotkeys from '../components/Hotkeys'; -import { getGuideUrl } from '../utils'; import store from 'store'; import { challengeTypes } from '../../../../utils/challengeTypes'; -import { isContained } from '../../../utils/is-contained'; +import LearnLayout from '../../../components/layouts/learn'; import { ChallengeNodeType, ChallengeFileType, @@ -35,6 +22,17 @@ import { TestType, ResizePropsType } from '../../../redux/prop-types'; +import { isContained } from '../../../utils/is-contained'; +import ChallengeDescription from '../components/Challenge-Description'; +import HelpModal from '../components/HelpModal'; +import Hotkeys from '../components/Hotkeys'; +import Preview from '../components/Preview'; +import ResetModal from '../components/ResetModal'; +import SidePanel from '../components/Side-Panel'; +import VideoModal from '../components/VideoModal'; +import ChallengeTitle from '../components/challenge-title'; +import CompletionModal from '../components/completion-modal'; +import Output from '../components/output'; import { createFiles, challengeFilesSelector, @@ -45,8 +43,13 @@ import { challengeMounted, consoleOutputSelector, executeChallenge, - cancelTests + cancelTests, + isChallengeCompletedSelector } from '../redux'; +import { getGuideUrl } from '../utils'; +import DesktopLayout from './DesktopLayout'; +import MobileLayout from './MobileLayout'; +import MultifileEditor from './MultifileEditor'; // Styles import './classic.css'; @@ -56,7 +59,8 @@ import '../components/test-frame.css'; const mapStateToProps = createStructuredSelector({ files: challengeFilesSelector, tests: challengeTestsSelector, - output: consoleOutputSelector + output: consoleOutputSelector, + isChallengeCompleted: isChallengeCompletedSelector }); const mapDispatchToProps = (dispatch: Dispatch) => @@ -83,6 +87,7 @@ interface ShowClassicProps { files: ChallengeFileType; initConsole: (arg0: string) => void; initTests: (tests: TestType[]) => void; + isChallengeCompleted: boolean; output: string[]; pageContext: { challengeMeta: ChallengeMetaType; @@ -287,15 +292,27 @@ class ShowClassic extends Component { return ( + } + challengeTitle={ + + {title} + + } className='full-height' - description={description} guideUrl={getGuideUrl({ forumTopicId, title })} - instructions={instructions} instructionsPanelRef={this.instructionsPanelRef} showToolPanel={showToolPanel} - superBlock={superBlock} - title={title} - translationPending={translationPending} videoUrl={this.getVideoUrl()} /> ); diff --git a/client/src/templates/Challenges/classic/editor.tsx b/client/src/templates/Challenges/classic/editor.tsx index 2003faf70b8..b797bcd65e7 100644 --- a/client/src/templates/Challenges/classic/editor.tsx +++ b/client/src/templates/Challenges/classic/editor.tsx @@ -1,3 +1,12 @@ +import Loadable from '@loadable/component'; +// eslint-disable-next-line import/no-duplicates +import type * as monacoEditor from 'monaco-editor/esm/vs/editor/editor.api'; +import type { + IRange, + editor, + Range as RangeType + // eslint-disable-next-line import/no-duplicates +} from 'monaco-editor/esm/vs/editor/editor.api'; import React, { useEffect, Suspense, @@ -7,8 +16,17 @@ import React, { } from 'react'; import { connect } from 'react-redux'; import { createSelector } from 'reselect'; -import Loadable from '@loadable/component'; +import { Loader } from '../../../components/helpers'; +import { userSelector, isDonationModalOpenSelector } from '../../../redux'; +import { + ChallengeFileType, + DimensionsType, + ExtTypes, + FileKeyTypes, + ResizePropsType, + TestType +} from '../../../redux/prop-types'; import { canFocusEditorSelector, consoleOutputSelector, @@ -21,25 +39,6 @@ import { challengeTestsSelector, submitChallenge } from '../redux'; -import { userSelector, isDonationModalOpenSelector } from '../../../redux'; -import { Loader } from '../../../components/helpers'; -import { - ChallengeFileType, - DimensionsType, - ExtTypes, - FileKeyTypes, - ResizePropsType, - TestType -} from '../../../redux/prop-types'; - -// eslint-disable-next-line import/no-duplicates -import type * as monacoEditor from 'monaco-editor/esm/vs/editor/editor.api'; -import type { - IRange, - editor, - Range as RangeType - // eslint-disable-next-line import/no-duplicates -} from 'monaco-editor/esm/vs/editor/editor.api'; import './editor.css'; diff --git a/client/src/templates/Challenges/codeally/show.tsx b/client/src/templates/Challenges/codeally/show.tsx index a0a38d25f34..70de9bbd592 100644 --- a/client/src/templates/Challenges/codeally/show.tsx +++ b/client/src/templates/Challenges/codeally/show.tsx @@ -1,11 +1,11 @@ /* eslint-disable max-len */ // Package Utilities -import React, { Component } from 'react'; -import { bindActionCreators } from 'redux'; -import { connect } from 'react-redux'; -import Helmet from 'react-helmet'; import { graphql } from 'gatsby'; +import React, { Component } from 'react'; +import Helmet from 'react-helmet'; +import { connect } from 'react-redux'; +import { bindActionCreators } from 'redux'; import type { Dispatch } from 'redux'; // Local Utilities diff --git a/client/src/templates/Challenges/components/HelpModal.js b/client/src/templates/Challenges/components/HelpModal.js index 1fc9435708d..1e84b29fd02 100644 --- a/client/src/templates/Challenges/components/HelpModal.js +++ b/client/src/templates/Challenges/components/HelpModal.js @@ -1,13 +1,13 @@ -import React, { Component } from 'react'; -import PropTypes from 'prop-types'; -import { bindActionCreators } from 'redux'; -import { connect } from 'react-redux'; import { Button, Modal } from '@freecodecamp/react-bootstrap'; +import PropTypes from 'prop-types'; +import React, { Component } from 'react'; import { Trans, withTranslation } from 'react-i18next'; +import { connect } from 'react-redux'; +import { bindActionCreators } from 'redux'; -import { createQuestion, closeModal, isHelpModalOpenSelector } from '../redux'; -import { executeGA } from '../../../redux'; import envData from '../../../../../config/env.json'; +import { executeGA } from '../../../redux'; +import { createQuestion, closeModal, isHelpModalOpenSelector } from '../redux'; import './help-modal.css'; diff --git a/client/src/templates/Challenges/components/Hotkeys.tsx b/client/src/templates/Challenges/components/Hotkeys.tsx index 5debfd2f256..0d2a2a94d64 100644 --- a/client/src/templates/Challenges/components/Hotkeys.tsx +++ b/client/src/templates/Challenges/components/Hotkeys.tsx @@ -1,8 +1,8 @@ /* eslint-disable @typescript-eslint/no-unsafe-call */ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ +import { navigate } from 'gatsby'; import React from 'react'; import { HotKeys, GlobalHotKeys } from 'react-hotkeys'; -import { navigate } from 'gatsby'; import { connect } from 'react-redux'; import { createSelector } from 'reselect'; diff --git a/client/src/templates/Challenges/components/Preview.js b/client/src/templates/Challenges/components/Preview.js index 869e4aa0bca..87f476e764d 100644 --- a/client/src/templates/Challenges/components/Preview.js +++ b/client/src/templates/Challenges/components/Preview.js @@ -1,8 +1,8 @@ -import React, { Component } from 'react'; -import { bindActionCreators } from 'redux'; -import { connect } from 'react-redux'; import PropTypes from 'prop-types'; +import React, { Component } from 'react'; import { withTranslation } from 'react-i18next'; +import { connect } from 'react-redux'; +import { bindActionCreators } from 'redux'; import { previewMounted } from '../redux'; diff --git a/client/src/templates/Challenges/components/ResetModal.tsx b/client/src/templates/Challenges/components/ResetModal.tsx index 64071b45415..c97313c9686 100644 --- a/client/src/templates/Challenges/components/ResetModal.tsx +++ b/client/src/templates/Challenges/components/ResetModal.tsx @@ -1,14 +1,14 @@ // Package Utilities -import React from 'react'; -import { bindActionCreators, Dispatch } from 'redux'; -import { connect } from 'react-redux'; -import { createSelector } from 'reselect'; import { Button, Modal } from '@freecodecamp/react-bootstrap'; +import React from 'react'; import { useTranslation } from 'react-i18next'; +import { connect } from 'react-redux'; +import { bindActionCreators, Dispatch } from 'redux'; +import { createSelector } from 'reselect'; // Local Utilities -import { isResetModalOpenSelector, closeModal, resetChallenge } from '../redux'; import { executeGA } from '../../../redux'; +import { isResetModalOpenSelector, closeModal, resetChallenge } from '../redux'; // Styles import './reset-modal.css'; diff --git a/client/src/templates/Challenges/components/Side-Panel.js b/client/src/templates/Challenges/components/Side-Panel.js index bba4137a104..f54b4e775bf 100644 --- a/client/src/templates/Challenges/components/Side-Panel.js +++ b/client/src/templates/Challenges/components/Side-Panel.js @@ -1,38 +1,27 @@ -import React, { Component } from 'react'; import PropTypes from 'prop-types'; +import React, { Component } from 'react'; import { connect } from 'react-redux'; -import ChallengeTitle from './challenge-title'; -import ChallengeDescription from './Challenge-Description'; -import ToolPanel from './Tool-Panel'; -import TestSuite from './Test-Suite'; - -import { challengeTestsSelector, isChallengeCompletedSelector } from '../redux'; import { createSelector } from 'reselect'; -import './side-panel.css'; import { mathJaxScriptLoader } from '../../../utils/script-loaders'; +import { challengeTestsSelector } from '../redux'; +import TestSuite from './Test-Suite'; +import ToolPanel from './Tool-Panel'; -const mapStateToProps = createSelector( - isChallengeCompletedSelector, - challengeTestsSelector, - (isChallengeCompleted, tests) => ({ - isChallengeCompleted, - tests - }) -); +import './side-panel.css'; + +const mapStateToProps = createSelector(challengeTestsSelector, tests => ({ + tests +})); const propTypes = { block: PropTypes.string, - description: PropTypes.string, + challengeDescription: PropTypes.element.isRequired, + challengeTitle: PropTypes.element.isRequired, guideUrl: PropTypes.string, - instructions: PropTypes.string, instructionsPanelRef: PropTypes.any.isRequired, - isChallengeCompleted: PropTypes.bool, showToolPanel: PropTypes.bool, - superBlock: PropTypes.string, tests: PropTypes.arrayOf(PropTypes.object), - title: PropTypes.string, - translationPending: PropTypes.bool.isRequired, videoUrl: PropTypes.string }; @@ -68,20 +57,8 @@ export class SidePanel extends Component { } render() { - const { - block, - title, - description, - instructions, - instructionsPanelRef, - isChallengeCompleted, - guideUrl, - tests, - showToolPanel, - superBlock, - translationPending, - videoUrl - } = this.props; + const { instructionsPanelRef, guideUrl, tests, showToolPanel, videoUrl } = + this.props; return (
-
- - {title} - - -
+ {this.props.challengeTitle} + {this.props.challengeDescription} {showToolPanel && }
diff --git a/client/src/templates/Challenges/components/Test-Suite.js b/client/src/templates/Challenges/components/Test-Suite.js index 903d2c64ab8..74134981e5e 100644 --- a/client/src/templates/Challenges/components/Test-Suite.js +++ b/client/src/templates/Challenges/components/Test-Suite.js @@ -1,8 +1,8 @@ -import React from 'react'; import PropTypes from 'prop-types'; +import React from 'react'; -import GreenPass from '../../../assets/icons/green-pass'; import Fail from '../../../assets/icons/fail'; +import GreenPass from '../../../assets/icons/green-pass'; import Initial from '../../../assets/icons/initial'; import './test-suite.css'; diff --git a/client/src/templates/Challenges/components/Tool-Panel.js b/client/src/templates/Challenges/components/Tool-Panel.js index 23afc5e5e7a..4c20bac2079 100644 --- a/client/src/templates/Challenges/components/Tool-Panel.js +++ b/client/src/templates/Challenges/components/Tool-Panel.js @@ -1,14 +1,13 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import { bindActionCreators } from 'redux'; -import { connect } from 'react-redux'; -import { useTranslation } from 'react-i18next'; - import { Button, DropdownButton, MenuItem } from '@freecodecamp/react-bootstrap'; +import PropTypes from 'prop-types'; +import React from 'react'; +import { useTranslation } from 'react-i18next'; +import { connect } from 'react-redux'; +import { bindActionCreators } from 'redux'; import './tool-panel.css'; import { openModal, executeChallenge } from '../redux'; diff --git a/client/src/templates/Challenges/components/VideoModal.js b/client/src/templates/Challenges/components/VideoModal.js index e67cc44e958..791b285c9d3 100644 --- a/client/src/templates/Challenges/components/VideoModal.js +++ b/client/src/templates/Challenges/components/VideoModal.js @@ -1,12 +1,12 @@ -import React, { Component } from 'react'; -import PropTypes from 'prop-types'; -import { bindActionCreators } from 'redux'; -import { connect } from 'react-redux'; import { Modal } from '@freecodecamp/react-bootstrap'; +import PropTypes from 'prop-types'; +import React, { Component } from 'react'; import { withTranslation } from 'react-i18next'; +import { connect } from 'react-redux'; +import { bindActionCreators } from 'redux'; -import { closeModal, isVideoModalOpenSelector } from '../redux'; import { executeGA } from '../../../redux'; +import { closeModal, isVideoModalOpenSelector } from '../redux'; import './video-modal.css'; diff --git a/client/src/templates/Challenges/components/bread-crumb.tsx b/client/src/templates/Challenges/components/bread-crumb.tsx index d21dd8dfe08..2555c15f725 100644 --- a/client/src/templates/Challenges/components/bread-crumb.tsx +++ b/client/src/templates/Challenges/components/bread-crumb.tsx @@ -1,8 +1,8 @@ +import i18next from 'i18next'; import React from 'react'; import { Link } from '../../../components/helpers/index'; import './challenge-title.css'; -import i18next from 'i18next'; interface BreadCrumbProps { block: string; diff --git a/client/src/templates/Challenges/components/challenge-title.tsx b/client/src/templates/Challenges/components/challenge-title.tsx index a2631020932..791e04ec891 100644 --- a/client/src/templates/Challenges/components/challenge-title.tsx +++ b/client/src/templates/Challenges/components/challenge-title.tsx @@ -1,12 +1,11 @@ -import React from 'react'; -import { Link } from '../../../components/helpers/index'; import i18next from 'i18next'; +import React from 'react'; +import GreenPass from '../../../assets/icons/green-pass'; +import { Link } from '../../../components/helpers/index'; +import BreadCrumb from './bread-crumb'; import './challenge-title.css'; -import GreenPass from '../../../assets/icons/green-pass'; -import BreadCrumb from './bread-crumb'; - interface ChallengeTitleProps { block: string; children: string; diff --git a/client/src/templates/Challenges/components/completion-modal-body.test.tsx b/client/src/templates/Challenges/components/completion-modal-body.test.tsx index 4744c9c8010..af1d8fd617b 100644 --- a/client/src/templates/Challenges/components/completion-modal-body.test.tsx +++ b/client/src/templates/Challenges/components/completion-modal-body.test.tsx @@ -1,5 +1,5 @@ -import React from 'react'; import { render, fireEvent, screen } from '@testing-library/react'; +import React from 'react'; import CompletionModalBody from './completion-modal-body'; diff --git a/client/src/templates/Challenges/components/completion-modal-body.tsx b/client/src/templates/Challenges/components/completion-modal-body.tsx index a1b41969590..73522636090 100644 --- a/client/src/templates/Challenges/components/completion-modal-body.tsx +++ b/client/src/templates/Challenges/components/completion-modal-body.tsx @@ -1,7 +1,7 @@ -import React, { PureComponent } from 'react'; import BezierEasing from 'bezier-easing'; -import GreenPass from '../../../assets/icons/green-pass'; +import React, { PureComponent } from 'react'; import { TFunction, withTranslation } from 'react-i18next'; +import GreenPass from '../../../assets/icons/green-pass'; interface CompletionModalBodyProps { block: string; diff --git a/client/src/templates/Challenges/components/completion-modal.tsx b/client/src/templates/Challenges/components/completion-modal.tsx index 40fe2d9c2dc..e0339c186a0 100644 --- a/client/src/templates/Challenges/components/completion-modal.tsx +++ b/client/src/templates/Challenges/components/completion-modal.tsx @@ -1,21 +1,23 @@ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/restrict-template-expressions */ -import React, { Component } from 'react'; -import { noop } from 'lodash-es'; -import { connect } from 'react-redux'; -import { createSelector } from 'reselect'; import { Button, Modal } from '@freecodecamp/react-bootstrap'; import { useStaticQuery, graphql } from 'gatsby'; +import { noop } from 'lodash-es'; +import React, { Component } from 'react'; import { TFunction, withTranslation } from 'react-i18next'; +import { connect } from 'react-redux'; import { Dispatch } from 'redux'; +import { createSelector } from 'reselect'; -import Login from '../../../components/Header/components/Login'; -import CompletionModalBody from './completion-modal-body'; import { dasherize } from '../../../../../utils/slugs'; +import Login from '../../../components/Header/components/Login'; +import { + isSignedInSelector, + executeGA, + allowBlockDonationRequests +} from '../../../redux'; import { AllChallengeNodeType } from '../../../redux/prop-types'; -import './completion-modal.css'; - import { closeModal, submitChallenge, @@ -25,12 +27,9 @@ import { challengeFilesSelector, challengeMetaSelector } from '../redux'; +import CompletionModalBody from './completion-modal-body'; -import { - isSignedInSelector, - executeGA, - allowBlockDonationRequests -} from '../../../redux'; +import './completion-modal.css'; const mapStateToProps = createSelector( challengeFilesSelector, diff --git a/client/src/templates/Challenges/components/output.tsx b/client/src/templates/Challenges/components/output.tsx index 10af12bf36b..7c499388178 100644 --- a/client/src/templates/Challenges/components/output.tsx +++ b/client/src/templates/Challenges/components/output.tsx @@ -1,8 +1,8 @@ +import { isEmpty } from 'lodash-es'; import React, { Component } from 'react'; import sanitizeHtml from 'sanitize-html'; import './output.css'; -import { isEmpty } from 'lodash-es'; interface OutputProps { defaultOutput: string; diff --git a/client/src/templates/Challenges/components/prism-formatted.tsx b/client/src/templates/Challenges/components/prism-formatted.tsx index d9026c2a34e..89a117eebc2 100644 --- a/client/src/templates/Challenges/components/prism-formatted.tsx +++ b/client/src/templates/Challenges/components/prism-formatted.tsx @@ -1,5 +1,5 @@ -import React, { Component } from 'react'; import Prism from 'prismjs'; +import React, { Component } from 'react'; interface PrismFormattedProps { className?: string; diff --git a/client/src/templates/Challenges/projects/backend/Show.tsx b/client/src/templates/Challenges/projects/backend/Show.tsx index b67d49557a6..9df8b2e481c 100644 --- a/client/src/templates/Challenges/projects/backend/Show.tsx +++ b/client/src/templates/Challenges/projects/backend/Show.tsx @@ -2,15 +2,30 @@ /* eslint-disable @typescript-eslint/no-unsafe-call */ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ // Package Utilities -import React, { Component } from 'react'; import { Grid, Col, Row } from '@freecodecamp/react-bootstrap'; -import { createSelector } from 'reselect'; -import { connect } from 'react-redux'; import { graphql } from 'gatsby'; +import React, { Component } from 'react'; import Helmet from 'react-helmet'; import { TFunction, withTranslation } from 'react-i18next'; +import { connect } from 'react-redux'; +import { createSelector } from 'reselect'; // Local Utilities +import Spacer from '../../../../components/helpers/spacer'; +import LearnLayout from '../../../../components/layouts/learn'; +import { isSignedInSelector } from '../../../../redux'; +import { + ChallengeNodeType, + ChallengeMetaType, + TestType +} from '../../../../redux/prop-types'; +import ChallengeDescription from '../../components/Challenge-Description'; +import HelpModal from '../../components/HelpModal'; +import Hotkeys from '../../components/Hotkeys'; +import TestSuite from '../../components/Test-Suite'; +import ChallengeTitle from '../../components/challenge-title'; +import CompletionModal from '../../components/completion-modal'; +import Output from '../../components/output'; import { executeChallenge, challengeMounted, @@ -23,23 +38,8 @@ import { updateSolutionFormValues } from '../../redux'; import { getGuideUrl } from '../../utils'; -import LearnLayout from '../../../../components/layouts/learn'; -import ChallengeTitle from '../../components/challenge-title'; -import ChallengeDescription from '../../components/Challenge-Description'; -import TestSuite from '../../components/Test-Suite'; -import Output from '../../components/output'; -import CompletionModal from '../../components/completion-modal'; -import HelpModal from '../../components/HelpModal'; -import ProjectToolPanel from '../tool-panel'; import SolutionForm from '../solution-form'; -import Spacer from '../../../../components/helpers/spacer'; -import { - ChallengeNodeType, - ChallengeMetaType, - TestType -} from '../../../../redux/prop-types'; -import { isSignedInSelector } from '../../../../redux'; -import Hotkeys from '../../components/Hotkeys'; +import ProjectToolPanel from '../tool-panel'; // Styles import '../../components/test-frame.css'; diff --git a/client/src/templates/Challenges/projects/frontend/Show.tsx b/client/src/templates/Challenges/projects/frontend/Show.tsx index 88b44f6e9f2..9b8d912a429 100644 --- a/client/src/templates/Challenges/projects/frontend/Show.tsx +++ b/client/src/templates/Challenges/projects/frontend/Show.tsx @@ -1,21 +1,28 @@ /* eslint-disable @typescript-eslint/no-unsafe-call */ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ // Package Utilities -import React, { Component } from 'react'; import { Grid, Col, Row } from '@freecodecamp/react-bootstrap'; -import { connect } from 'react-redux'; -import { bindActionCreators } from 'redux'; import { graphql } from 'gatsby'; +import React, { Component } from 'react'; import Helmet from 'react-helmet'; import { TFunction, withTranslation } from 'react-i18next'; -import { createSelector } from 'reselect'; +import { connect } from 'react-redux'; +import { bindActionCreators } from 'redux'; import type { Dispatch } from 'redux'; +import { createSelector } from 'reselect'; // Local Utilities +import Spacer from '../../../../components/helpers/spacer'; +import LearnLayout from '../../../../components/layouts/learn'; import { ChallengeNodeType, ChallengeMetaType } from '../../../../redux/prop-types'; +import ChallengeDescription from '../../components/Challenge-Description'; +import HelpModal from '../../components/HelpModal'; +import Hotkeys from '../../components/Hotkeys'; +import ChallengeTitle from '../../components/challenge-title'; +import CompletionModal from '../../components/completion-modal'; import { challengeMounted, isChallengeCompletedSelector, @@ -24,15 +31,8 @@ import { updateSolutionFormValues } from '../../redux'; import { getGuideUrl } from '../../utils'; -import LearnLayout from '../../../../components/layouts/learn'; -import ChallengeTitle from '../../components/challenge-title'; -import ChallengeDescription from '../../components/Challenge-Description'; -import Spacer from '../../../../components/helpers/spacer'; import SolutionForm from '../solution-form'; import ProjectToolPanel from '../tool-panel'; -import CompletionModal from '../../components/completion-modal'; -import HelpModal from '../../components/HelpModal'; -import Hotkeys from '../../components/Hotkeys'; // Redux Setup const mapStateToProps = createSelector( diff --git a/client/src/templates/Challenges/projects/solution-form.tsx b/client/src/templates/Challenges/projects/solution-form.tsx index 0de27a09b0c..f3cfe8f06e3 100644 --- a/client/src/templates/Challenges/projects/solution-form.tsx +++ b/client/src/templates/Challenges/projects/solution-form.tsx @@ -2,13 +2,13 @@ import React, { Component } from 'react'; import { withTranslation } from 'react-i18next'; import type { WithTranslation } from 'react-i18next'; -import { Form } from '../../../components/formHelpers'; import { backend, backEndProject, frontEndProject, pythonProject } from '../../../../utils/challengeTypes'; +import { Form } from '../../../components/formHelpers'; interface SubmitProps { isShouldCompletionModalOpen: boolean; diff --git a/client/src/templates/Challenges/projects/tool-panel.tsx b/client/src/templates/Challenges/projects/tool-panel.tsx index 17ed31727aa..b058ef5032a 100644 --- a/client/src/templates/Challenges/projects/tool-panel.tsx +++ b/client/src/templates/Challenges/projects/tool-panel.tsx @@ -1,8 +1,8 @@ -import React, { Component } from 'react'; -import { bindActionCreators, Dispatch } from 'redux'; -import { connect } from 'react-redux'; import { Button } from '@freecodecamp/react-bootstrap'; +import React, { Component } from 'react'; import { TFunction, withTranslation } from 'react-i18next'; +import { connect } from 'react-redux'; +import { bindActionCreators, Dispatch } from 'redux'; import { openModal } from '../redux'; diff --git a/client/src/templates/Challenges/rechallenge/transformers.js b/client/src/templates/Challenges/rechallenge/transformers.js index a3926f9b8ac..ba1a5d2cdbd 100644 --- a/client/src/templates/Challenges/rechallenge/transformers.js +++ b/client/src/templates/Challenges/rechallenge/transformers.js @@ -1,3 +1,4 @@ +import protect from '@freecodecamp/loop-protect'; import { attempt, cond, @@ -10,8 +11,9 @@ import { stubTrue } from 'lodash-es'; -import protect from '@freecodecamp/loop-protect'; - +// the config files are created during the build, but not before linting +// eslint-disable-next-line import/no-unresolved +import sassData from '../../../../../config/client/sass-compile.json'; import { transformContents, transformHeadTailAndContents, @@ -21,10 +23,6 @@ import { } from '../../../../../utils/polyvinyl'; import createWorker from '../utils/worker-executor'; -// the config files are created during the build, but not before linting -// eslint-disable-next-line import/no-unresolved -import sassData from '../../../../../config/client/sass-compile.json'; - const { filename: sassCompile } = sassData; const protectTimeout = 100; diff --git a/client/src/templates/Challenges/redux/action-types.js b/client/src/templates/Challenges/redux/action-types.js new file mode 100644 index 00000000000..156b9e40db6 --- /dev/null +++ b/client/src/templates/Challenges/redux/action-types.js @@ -0,0 +1,48 @@ +import { createTypes } from '../../../utils/create-types'; + +export const ns = 'challenge'; + +export const actionTypes = createTypes( + [ + 'createFiles', + 'createQuestion', + 'initTests', + 'initConsole', + 'initLogs', + 'updateConsole', + 'updateChallengeMeta', + 'updateFile', + 'updateJSEnabled', + 'updateSolutionFormValues', + 'updateSuccessMessage', + 'updateTests', + 'updateLogs', + 'cancelTests', + + 'logsToConsole', + + 'lockCode', + 'unlockCode', + 'disableBuildOnError', + 'storedCodeFound', + 'noStoredCodeFound', + 'saveEditorContent', + + 'closeModal', + 'openModal', + + 'previewMounted', + 'challengeMounted', + 'checkChallenge', + 'executeChallenge', + 'resetChallenge', + 'submitChallenge', + + 'moveToTab', + + 'setEditorFocusability', + 'toggleVisibleEditor', + 'setAccessibilityMode' + ], + ns +); diff --git a/client/src/templates/Challenges/redux/code-lock-epic.js b/client/src/templates/Challenges/redux/code-lock-epic.js index e9a2e4b3622..5ae23720182 100644 --- a/client/src/templates/Challenges/redux/code-lock-epic.js +++ b/client/src/templates/Challenges/redux/code-lock-epic.js @@ -1,9 +1,10 @@ -import { map } from 'rxjs/operators'; import { ofType } from 'redux-observable'; -import { types, unlockCode } from './'; +import { map } from 'rxjs/operators'; +import { actionTypes } from './action-types'; +import { unlockCode } from './'; function codeLockEpic(action$) { - return action$.pipe(ofType(types.updateFile), map(unlockCode)); + return action$.pipe(ofType(actionTypes.updateFile), map(unlockCode)); } export default codeLockEpic; diff --git a/client/src/templates/Challenges/redux/code-storage-epic.js b/client/src/templates/Challenges/redux/code-storage-epic.js index 0cd2163f98d..e5c307ce11f 100644 --- a/client/src/templates/Challenges/redux/code-storage-epic.js +++ b/client/src/templates/Challenges/redux/code-storage-epic.js @@ -1,10 +1,14 @@ +import { combineEpics, ofType } from 'redux-observable'; import { of } from 'rxjs'; import { filter, switchMap, map, tap, ignoreElements } from 'rxjs/operators'; -import { combineEpics, ofType } from 'redux-observable'; import store from 'store'; +import { setContent, isPoly } from '../../../../../utils/polyvinyl'; +import { createFlashMessage } from '../../../components/Flash/redux'; +import { actionTypes as appTypes } from '../../../redux/action-types'; + +import { actionTypes } from './action-types'; import { - types, storedCodeFound, noStoredCodeFound, isCodeLockedSelector, @@ -12,12 +16,6 @@ import { challengeMetaSelector } from './'; -import { types as appTypes } from '../../../redux'; - -import { setContent, isPoly } from '../../../../../utils/polyvinyl'; - -import { createFlashMessage } from '../../../components/Flash/redux'; - const legacyPrefixes = [ 'Bonfire: ', 'Waypoint: ', @@ -64,7 +62,7 @@ function isFilesAllPoly(files) { function clearCodeEpic(action$, state$) { return action$.pipe( - ofType(appTypes.submitComplete, types.resetChallenge), + ofType(appTypes.submitComplete, actionTypes.resetChallenge), tap(() => { const { id } = challengeMetaSelector(state$.value); store.remove(id); @@ -75,7 +73,7 @@ function clearCodeEpic(action$, state$) { function saveCodeEpic(action$, state$) { return action$.pipe( - ofType(types.executeChallenge, types.saveEditorContent), + ofType(actionTypes.executeChallenge, actionTypes.saveEditorContent), // do not save challenge if code is locked filter(() => !isCodeLockedSelector(state$.value)), map(action => { @@ -95,7 +93,7 @@ function saveCodeEpic(action$, state$) { return { ...action, error: true }; } }), - ofType(types.saveEditorContent), + ofType(actionTypes.saveEditorContent), switchMap(({ error }) => of( createFlashMessage({ @@ -112,7 +110,7 @@ function saveCodeEpic(action$, state$) { function loadCodeEpic(action$, state$) { return action$.pipe( - ofType(types.challengeMounted), + ofType(actionTypes.challengeMounted), filter(() => { const files = challengeFilesSelector(state$.value); return Object.keys(files).length > 0; diff --git a/client/src/templates/Challenges/redux/completion-epic.js b/client/src/templates/Challenges/redux/completion-epic.js index 699d353fc65..0ba44814f29 100644 --- a/client/src/templates/Challenges/redux/completion-epic.js +++ b/client/src/templates/Challenges/redux/completion-epic.js @@ -1,3 +1,5 @@ +import { navigate } from 'gatsby'; +import { ofType } from 'redux-observable'; import { of, empty } from 'rxjs'; import { switchMap, @@ -7,18 +9,8 @@ import { filter, finalize } from 'rxjs/operators'; -import { ofType } from 'redux-observable'; -import { navigate } from 'gatsby'; -import { - projectFormValuesSelector, - types, - challengeMetaSelector, - challengeTestsSelector, - closeModal, - challengeFilesSelector, - updateSolutionFormValues -} from './'; +import { challengeTypes, submitTypes } from '../../../../utils/challengeTypes'; import { userSelector, isSignedInSelector, @@ -28,9 +20,17 @@ import { usernameSelector } from '../../../redux'; -import postUpdate$ from '../utils/postUpdate$'; -import { challengeTypes, submitTypes } from '../../../../utils/challengeTypes'; import { getVerifyCanClaimCert } from '../../../utils/ajax'; +import postUpdate$ from '../utils/postUpdate$'; +import { actionTypes } from './action-types'; +import { + projectFormValuesSelector, + challengeMetaSelector, + challengeTestsSelector, + closeModal, + challengeFilesSelector, + updateSolutionFormValues +} from './'; function postChallenge(update, username) { const saveChallenge = postUpdate$(update).pipe( @@ -57,11 +57,11 @@ function submitModern(type, state) { challengeType === 11 || (tests.length > 0 && tests.every(test => test.pass && !test.err)) ) { - if (type === types.checkChallenge) { + if (type === actionTypes.checkChallenge) { return of({ type: 'this was a check challenge' }); } - if (type === types.submitChallenge) { + if (type === actionTypes.submitChallenge) { const { id } = challengeMetaSelector(state); const files = challengeFilesSelector(state); const { username } = userSelector(state); @@ -80,7 +80,7 @@ function submitModern(type, state) { } function submitProject(type, state) { - if (type === types.checkChallenge) { + if (type === actionTypes.checkChallenge) { return empty(); } @@ -104,7 +104,7 @@ function submitProject(type, state) { function submitBackendChallenge(type, state) { const tests = challengeTestsSelector(state); if (tests.length > 0 && tests.every(test => test.pass && !test.err)) { - if (type === types.submitChallenge) { + if (type === actionTypes.submitChallenge) { const { id } = challengeMetaSelector(state); const { username } = userSelector(state); const { @@ -131,7 +131,7 @@ const submitters = { export default function completionEpic(action$, state$) { return action$.pipe( - ofType(types.submitChallenge), + ofType(actionTypes.submitChallenge), switchMap(({ type }) => { const state = state$.value; const meta = challengeMetaSelector(state); diff --git a/client/src/templates/Challenges/redux/create-question-epic.js b/client/src/templates/Challenges/redux/create-question-epic.js index c5c230fdb5f..143c7fc6acc 100644 --- a/client/src/templates/Challenges/redux/create-question-epic.js +++ b/client/src/templates/Challenges/redux/create-question-epic.js @@ -1,16 +1,16 @@ import dedent from 'dedent'; +import i18next from 'i18next'; import { ofType } from 'redux-observable'; +import { tap, mapTo } from 'rxjs/operators'; +import envData from '../../../../../config/env.json'; import { - types, closeModal, challengeFilesSelector, challengeMetaSelector, projectFormValuesSelector } from '../redux'; -import { tap, mapTo } from 'rxjs/operators'; import { transformEditorLink } from '../utils'; -import envData from '../../../../../config/env.json'; -import i18next from 'i18next'; +import { actionTypes } from './action-types'; const { forumLocation } = envData; @@ -29,7 +29,7 @@ function filesToMarkdown(files = {}) { function createQuestionEpic(action$, state$, { window }) { return action$.pipe( - ofType(types.createQuestion), + ofType(actionTypes.createQuestion), tap(() => { const state = state$.value; const files = challengeFilesSelector(state); diff --git a/client/src/templates/Challenges/redux/execute-challenge-saga.js b/client/src/templates/Challenges/redux/execute-challenge-saga.js index 0c4e643cefb..a9aae70d5a0 100644 --- a/client/src/templates/Challenges/redux/execute-challenge-saga.js +++ b/client/src/templates/Challenges/redux/execute-challenge-saga.js @@ -1,3 +1,6 @@ +import i18next from 'i18next'; +import { escape } from 'lodash-es'; +import { channel } from 'redux-saga'; import { delay, put, @@ -10,10 +13,17 @@ import { take, cancel } from 'redux-saga/effects'; -import { channel } from 'redux-saga'; -import { escape } from 'lodash-es'; -import i18next from 'i18next'; +import { + buildChallenge, + canBuildChallenge, + getTestRunner, + challengeHasPreview, + updatePreview, + isJavaScriptChallenge, + isLoopProtected +} from '../utils/build'; +import { actionTypes } from './action-types'; import { challengeDataSelector, challengeMetaSelector, @@ -26,20 +36,9 @@ import { updateTests, openModal, isBuildEnabledSelector, - disableBuildOnError, - types + disableBuildOnError } from './'; -import { - buildChallenge, - canBuildChallenge, - getTestRunner, - challengeHasPreview, - updatePreview, - isJavaScriptChallenge, - isLoopProtected -} from '../utils/build'; - // How long before bailing out of a preview. const previewTimeout = 2500; let previewTask; @@ -52,7 +51,7 @@ export function* executeCancellableChallengeSaga(payload) { const task = yield fork(executeChallengeSaga, payload); previewTask = yield fork(previewChallengeSaga, { flushLogs: false }); - yield take(types.cancelTests); + yield take(actionTypes.cancelTests); yield cancel(task); } diff --git a/client/src/templates/Challenges/redux/index.js b/client/src/templates/Challenges/redux/index.js index b63d31af360..351c60e0529 100644 --- a/client/src/templates/Challenges/redux/index.js +++ b/client/src/templates/Challenges/redux/index.js @@ -1,22 +1,20 @@ -import { createAction, handleActions } from 'redux-actions'; import { isEmpty } from 'lodash-es'; +import { createAction, handleActions } from 'redux-actions'; -import { createTypes } from '../../../utils/create-types'; -import { createPoly } from '../../../../../utils/polyvinyl'; import { getLines } from '../../../../../utils/get-lines'; -import completionEpic from './completion-epic'; -import codeLockEpic from './code-lock-epic'; -import createQuestionEpic from './create-question-epic'; -import codeStorageEpic from './code-storage-epic'; - -import { createExecuteChallengeSaga } from './execute-challenge-saga'; -import { createCurrentChallengeSaga } from './current-challenge-saga'; +import { createPoly } from '../../../../../utils/polyvinyl'; import { challengeTypes } from '../../../../utils/challengeTypes'; -import { getTargetEditor } from '../utils/getTargetEditor'; import { completedChallengesSelector } from '../../../redux'; +import { getTargetEditor } from '../utils/getTargetEditor'; +import { actionTypes, ns } from './action-types'; +import codeLockEpic from './code-lock-epic'; +import codeStorageEpic from './code-storage-epic'; +import completionEpic from './completion-epic'; +import createQuestionEpic from './create-question-epic'; +import { createCurrentChallengeSaga } from './current-challenge-saga'; +import { createExecuteChallengeSaga } from './execute-challenge-saga'; -export const ns = 'challenge'; -export const backendNS = 'backendChallenge'; +export { ns }; const initialState = { canFocusEditor: true, @@ -47,51 +45,6 @@ const initialState = { successMessage: 'Happy Coding!' }; -export const types = createTypes( - [ - 'createFiles', - 'createQuestion', - 'initTests', - 'initConsole', - 'initLogs', - 'updateConsole', - 'updateChallengeMeta', - 'updateFile', - 'updateJSEnabled', - 'updateSolutionFormValues', - 'updateSuccessMessage', - 'updateTests', - 'updateLogs', - 'cancelTests', - - 'logsToConsole', - - 'lockCode', - 'unlockCode', - 'disableBuildOnError', - 'storedCodeFound', - 'noStoredCodeFound', - 'saveEditorContent', - - 'closeModal', - 'openModal', - - 'previewMounted', - 'challengeMounted', - 'checkChallenge', - 'executeChallenge', - 'resetChallenge', - 'submitChallenge', - - 'moveToTab', - - 'setEditorFocusability', - 'toggleVisibleEditor', - 'setAccessibilityMode' - ], - ns -); - export const epics = [ codeLockEpic, completionEpic, @@ -100,73 +53,87 @@ export const epics = [ ]; export const sagas = [ - ...createExecuteChallengeSaga(types), - ...createCurrentChallengeSaga(types) + ...createExecuteChallengeSaga(actionTypes), + ...createCurrentChallengeSaga(actionTypes) ]; // TODO: can createPoly handle editable region, rather than separating it? -export const createFiles = createAction(types.createFiles, challengeFiles => - Object.keys(challengeFiles) - .filter(key => challengeFiles[key]) - .map(key => challengeFiles[key]) - .reduce( - (challengeFiles, file) => ({ - ...challengeFiles, - [file.key]: { - ...createPoly(file), - seed: file.contents.slice(), - editableContents: getLines( - file.contents, - file.editableRegionBoundaries - ), - seedEditableRegionBoundaries: file.editableRegionBoundaries.slice() - } - }), - {} - ) +export const createFiles = createAction( + actionTypes.createFiles, + challengeFiles => + Object.keys(challengeFiles) + .filter(key => challengeFiles[key]) + .map(key => challengeFiles[key]) + .reduce( + (challengeFiles, file) => ({ + ...challengeFiles, + [file.key]: { + ...createPoly(file), + seed: file.contents.slice(), + editableContents: getLines( + file.contents, + file.editableRegionBoundaries + ), + seedEditableRegionBoundaries: file.editableRegionBoundaries.slice() + } + }), + {} + ) ); -export const createQuestion = createAction(types.createQuestion); -export const initTests = createAction(types.initTests); -export const updateTests = createAction(types.updateTests); -export const cancelTests = createAction(types.cancelTests); +export const createQuestion = createAction(actionTypes.createQuestion); +export const initTests = createAction(actionTypes.initTests); +export const updateTests = createAction(actionTypes.updateTests); +export const cancelTests = createAction(actionTypes.cancelTests); -export const initConsole = createAction(types.initConsole); -export const initLogs = createAction(types.initLogs); -export const updateChallengeMeta = createAction(types.updateChallengeMeta); -export const updateFile = createAction(types.updateFile); -export const updateConsole = createAction(types.updateConsole); -export const updateLogs = createAction(types.updateLogs); -export const updateJSEnabled = createAction(types.updateJSEnabled); +export const initConsole = createAction(actionTypes.initConsole); +export const initLogs = createAction(actionTypes.initLogs); +export const updateChallengeMeta = createAction( + actionTypes.updateChallengeMeta +); +export const updateFile = createAction(actionTypes.updateFile); +export const updateConsole = createAction(actionTypes.updateConsole); +export const updateLogs = createAction(actionTypes.updateLogs); +export const updateJSEnabled = createAction(actionTypes.updateJSEnabled); export const updateSolutionFormValues = createAction( - types.updateSolutionFormValues + actionTypes.updateSolutionFormValues +); +export const updateSuccessMessage = createAction( + actionTypes.updateSuccessMessage ); -export const updateSuccessMessage = createAction(types.updateSuccessMessage); -export const logsToConsole = createAction(types.logsToConsole); +export const logsToConsole = createAction(actionTypes.logsToConsole); -export const lockCode = createAction(types.lockCode); -export const unlockCode = createAction(types.unlockCode); -export const disableBuildOnError = createAction(types.disableBuildOnError); -export const storedCodeFound = createAction(types.storedCodeFound); -export const noStoredCodeFound = createAction(types.noStoredCodeFound); -export const saveEditorContent = createAction(types.saveEditorContent); +export const lockCode = createAction(actionTypes.lockCode); +export const unlockCode = createAction(actionTypes.unlockCode); +export const disableBuildOnError = createAction( + actionTypes.disableBuildOnError +); +export const storedCodeFound = createAction(actionTypes.storedCodeFound); +export const noStoredCodeFound = createAction(actionTypes.noStoredCodeFound); +export const saveEditorContent = createAction(actionTypes.saveEditorContent); -export const closeModal = createAction(types.closeModal); -export const openModal = createAction(types.openModal); +export const closeModal = createAction(actionTypes.closeModal); +export const openModal = createAction(actionTypes.openModal); -export const previewMounted = createAction(types.previewMounted); -export const challengeMounted = createAction(types.challengeMounted); -export const checkChallenge = createAction(types.checkChallenge); -export const executeChallenge = createAction(types.executeChallenge); -export const resetChallenge = createAction(types.resetChallenge); -export const submitChallenge = createAction(types.submitChallenge); +export const previewMounted = createAction(actionTypes.previewMounted); +export const challengeMounted = createAction(actionTypes.challengeMounted); +export const checkChallenge = createAction(actionTypes.checkChallenge); +export const executeChallenge = createAction(actionTypes.executeChallenge); +export const resetChallenge = createAction(actionTypes.resetChallenge); +export const submitChallenge = createAction(actionTypes.submitChallenge); -export const moveToTab = createAction(types.moveToTab); +export const moveToTab = createAction(actionTypes.moveToTab); -export const setEditorFocusability = createAction(types.setEditorFocusability); -export const toggleVisibleEditor = createAction(types.toggleVisibleEditor); -export const setAccessibilityMode = createAction(types.setAccessibilityMode); +export const setEditorFocusability = createAction( + actionTypes.setEditorFocusability +); +export const toggleVisibleEditor = createAction( + actionTypes.toggleVisibleEditor +); +export const setAccessibilityMode = createAction( + actionTypes.setAccessibilityMode +); export const currentTabSelector = state => state[ns].currentTab; export const challengeFilesSelector = state => state[ns].challengeFiles; @@ -249,12 +216,12 @@ export const inAccessibilityModeSelector = state => export const reducer = handleActions( { - [types.createFiles]: (state, { payload }) => ({ + [actionTypes.createFiles]: (state, { payload }) => ({ ...state, challengeFiles: payload, visibleEditors: { [getTargetEditor(payload)]: true } }), - [types.updateFile]: ( + [actionTypes.updateFile]: ( state, { payload: { key, editorValue, editableRegionBoundaries } } ) => ({ @@ -269,47 +236,47 @@ export const reducer = handleActions( } } }), - [types.storedCodeFound]: (state, { payload }) => ({ + [actionTypes.storedCodeFound]: (state, { payload }) => ({ ...state, challengeFiles: payload }), - [types.initTests]: (state, { payload }) => ({ + [actionTypes.initTests]: (state, { payload }) => ({ ...state, challengeTests: payload }), - [types.updateTests]: (state, { payload }) => ({ + [actionTypes.updateTests]: (state, { payload }) => ({ ...state, challengeTests: payload }), - [types.initConsole]: (state, { payload }) => ({ + [actionTypes.initConsole]: (state, { payload }) => ({ ...state, consoleOut: payload ? [payload] : [] }), - [types.updateConsole]: (state, { payload }) => ({ + [actionTypes.updateConsole]: (state, { payload }) => ({ ...state, consoleOut: state.consoleOut.concat(payload) }), - [types.initLogs]: state => ({ + [actionTypes.initLogs]: state => ({ ...state, logsOut: [] }), - [types.updateLogs]: (state, { payload }) => ({ + [actionTypes.updateLogs]: (state, { payload }) => ({ ...state, logsOut: state.logsOut.concat(payload) }), - [types.logsToConsole]: (state, { payload }) => ({ + [actionTypes.logsToConsole]: (state, { payload }) => ({ ...state, consoleOut: isEmpty(state.logsOut) ? state.consoleOut : state.consoleOut.concat(payload, state.logsOut) }), - [types.updateChallengeMeta]: (state, { payload }) => ({ + [actionTypes.updateChallengeMeta]: (state, { payload }) => ({ ...state, challengeMeta: { ...payload } }), - [types.resetChallenge]: state => ({ + [actionTypes.resetChallenge]: state => ({ ...state, currentTab: 2, challengeFiles: { @@ -337,56 +304,56 @@ export const reducer = handleActions( })), consoleOut: [] }), - [types.updateSolutionFormValues]: (state, { payload }) => ({ + [actionTypes.updateSolutionFormValues]: (state, { payload }) => ({ ...state, projectFormValues: payload }), - [types.lockCode]: state => ({ + [actionTypes.lockCode]: state => ({ ...state, isCodeLocked: true }), - [types.unlockCode]: state => ({ + [actionTypes.unlockCode]: state => ({ ...state, isBuildEnabled: true, isCodeLocked: false }), - [types.disableBuildOnError]: state => ({ + [actionTypes.disableBuildOnError]: state => ({ ...state, isBuildEnabled: false }), - [types.updateSuccessMessage]: (state, { payload }) => ({ + [actionTypes.updateSuccessMessage]: (state, { payload }) => ({ ...state, successMessage: payload }), - [types.closeModal]: (state, { payload }) => ({ + [actionTypes.closeModal]: (state, { payload }) => ({ ...state, modal: { ...state.modal, [payload]: false } }), - [types.openModal]: (state, { payload }) => ({ + [actionTypes.openModal]: (state, { payload }) => ({ ...state, modal: { ...state.modal, [payload]: true } }), - [types.moveToTab]: (state, { payload }) => ({ + [actionTypes.moveToTab]: (state, { payload }) => ({ ...state, currentTab: payload }), - [types.executeChallenge]: state => ({ + [actionTypes.executeChallenge]: state => ({ ...state, currentTab: 3 }), - [types.setEditorFocusability]: (state, { payload }) => ({ + [actionTypes.setEditorFocusability]: (state, { payload }) => ({ ...state, canFocusEditor: payload }), - [types.toggleVisibleEditor]: (state, { payload }) => { + [actionTypes.toggleVisibleEditor]: (state, { payload }) => { return { ...state, visibleEditors: { @@ -395,7 +362,7 @@ export const reducer = handleActions( } }; }, - [types.setAccessibilityMode]: (state, { payload }) => ({ + [actionTypes.setAccessibilityMode]: (state, { payload }) => ({ ...state, inAccessibilityMode: payload }) diff --git a/client/src/templates/Challenges/utils/build.js b/client/src/templates/Challenges/utils/build.js index 9cc86327377..b7c307bb36e 100644 --- a/client/src/templates/Challenges/utils/build.js +++ b/client/src/templates/Challenges/utils/build.js @@ -1,18 +1,17 @@ -import { getTransformers } from '../rechallenge/transformers'; -import { cssToHtml, jsToHtml, concatHtml } from '../rechallenge/builders.js'; -import { challengeTypes } from '../../../../utils/challengeTypes'; -import createWorker from './worker-executor'; -import { - createTestFramer, - runTestInTestFrame, - createMainFramer -} from './frame'; - // the config files are created during the build, but not before linting // eslint-disable-next-line import/no-unresolved import frameRunnerData from '../../../../../config/client/frame-runner.json'; // eslint-disable-next-line import/no-unresolved import testEvaluatorData from '../../../../../config/client/test-evaluator.json'; +import { challengeTypes } from '../../../../utils/challengeTypes'; +import { cssToHtml, jsToHtml, concatHtml } from '../rechallenge/builders.js'; +import { getTransformers } from '../rechallenge/transformers'; +import { + createTestFramer, + runTestInTestFrame, + createMainFramer +} from './frame'; +import createWorker from './worker-executor'; const { filename: runner } = frameRunnerData; const { filename: testEvaluator } = testEvaluatorData; diff --git a/client/src/templates/Challenges/utils/getTargetEditor.js b/client/src/templates/Challenges/utils/getTargetEditor.js index 9c9972ddb70..e52a18015c7 100644 --- a/client/src/templates/Challenges/utils/getTargetEditor.js +++ b/client/src/templates/Challenges/utils/getTargetEditor.js @@ -1,5 +1,5 @@ -import { toSortedArray } from '../../../../../utils/sort-files'; import { isEmpty } from 'lodash-es'; +import { toSortedArray } from '../../../../../utils/sort-files'; export function getTargetEditor(challengeFiles) { if (isEmpty(challengeFiles)) return null; diff --git a/client/src/templates/Challenges/video/Show.tsx b/client/src/templates/Challenges/video/Show.tsx index 9788d609a65..340fe88d896 100644 --- a/client/src/templates/Challenges/video/Show.tsx +++ b/client/src/templates/Challenges/video/Show.tsx @@ -1,29 +1,29 @@ // Package Utilities -import React, { Component } from 'react'; import { Button, Grid, Col, Row } from '@freecodecamp/react-bootstrap'; -import { connect } from 'react-redux'; -import { bindActionCreators } from 'redux'; import { graphql } from 'gatsby'; +import React, { Component } from 'react'; import Helmet from 'react-helmet'; -import YouTube from 'react-youtube'; -import { createSelector } from 'reselect'; import { ObserveKeys } from 'react-hotkeys'; import { TFunction, withTranslation } from 'react-i18next'; +import { connect } from 'react-redux'; +import YouTube from 'react-youtube'; +import { bindActionCreators } from 'redux'; import type { Dispatch } from 'redux'; +import { createSelector } from 'reselect'; // Local Utilities -import PrismFormatted from '../components/prism-formatted'; +import Loader from '../../../components/helpers/loader'; +import Spacer from '../../../components/helpers/spacer'; +import LearnLayout from '../../../components/layouts/learn'; import { ChallengeNodeType, ChallengeMetaType } from '../../../redux/prop-types'; -import LearnLayout from '../../../components/layouts/learn'; -import ChallengeTitle from '../components/challenge-title'; import ChallengeDescription from '../components/Challenge-Description'; -import Spacer from '../../../components/helpers/spacer'; -import CompletionModal from '../components/completion-modal'; import Hotkeys from '../components/Hotkeys'; -import Loader from '../../../components/helpers/loader'; +import ChallengeTitle from '../components/challenge-title'; +import CompletionModal from '../components/completion-modal'; +import PrismFormatted from '../components/prism-formatted'; import { isChallengeCompletedSelector, challengeMounted, diff --git a/client/src/templates/Introduction/Intro.js b/client/src/templates/Introduction/Intro.js index 1090077bde3..6c64051a9f0 100644 --- a/client/src/templates/Introduction/Intro.js +++ b/client/src/templates/Introduction/Intro.js @@ -1,13 +1,13 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import { Link, graphql } from 'gatsby'; -import Helmet from 'react-helmet'; import { Grid, ListGroup, ListGroupItem } from '@freecodecamp/react-bootstrap'; +import { Link, graphql } from 'gatsby'; +import PropTypes from 'prop-types'; +import React from 'react'; +import Helmet from 'react-helmet'; import { useTranslation } from 'react-i18next'; -import LearnLayout from '../../components/layouts/learn'; -import FullWidthRow from '../../components/helpers/full-width-row'; import ButtonSpacer from '../../components/helpers/button-spacer'; +import FullWidthRow from '../../components/helpers/full-width-row'; +import LearnLayout from '../../components/layouts/learn'; import { MarkdownRemark, AllChallengeNode } from '../../redux/prop-types'; import './intro.css'; diff --git a/client/src/templates/Introduction/SuperBlockIntro.js b/client/src/templates/Introduction/SuperBlockIntro.js index cd66cb9caa7..32225f6fdd5 100644 --- a/client/src/templates/Introduction/SuperBlockIntro.js +++ b/client/src/templates/Introduction/SuperBlockIntro.js @@ -1,21 +1,18 @@ -import React, { Fragment, useEffect, memo } from 'react'; -import PropTypes from 'prop-types'; -import Helmet from 'react-helmet'; +import { Grid, Row, Col } from '@freecodecamp/react-bootstrap'; import { graphql } from 'gatsby'; import { uniq } from 'lodash-es'; -import { connect } from 'react-redux'; -import { createSelector } from 'reselect'; -import { bindActionCreators } from 'redux'; +import PropTypes from 'prop-types'; +import React, { Fragment, useEffect, memo } from 'react'; +import Helmet from 'react-helmet'; import { withTranslation } from 'react-i18next'; -import { Grid, Row, Col } from '@freecodecamp/react-bootstrap'; +import { connect } from 'react-redux'; import { configureAnchors } from 'react-scrollable-anchor'; +import { bindActionCreators } from 'redux'; +import { createSelector } from 'reselect'; +import DonateModal from '../../../../client/src/components/Donation/DonationModal'; import Login from '../../components/Header/components/Login'; import Map from '../../components/Map'; -import CertChallenge from './components/CertChallenge'; -import SuperBlockIntro from './components/SuperBlockIntro'; -import Block from './components/Block'; -import DonateModal from '../../../../client/src/components/Donation/DonationModal'; import { Spacer } from '../../components/helpers'; import { currentChallengeIdSelector, @@ -24,8 +21,11 @@ import { tryToShowDonationModal, userSelector } from '../../redux'; -import { resetExpansion, toggleBlock } from './redux'; import { MarkdownRemark, AllChallengeNode, User } from '../../redux/prop-types'; +import Block from './components/Block'; +import CertChallenge from './components/CertChallenge'; +import SuperBlockIntro from './components/SuperBlockIntro'; +import { resetExpansion, toggleBlock } from './redux'; import './intro.css'; diff --git a/client/src/templates/Introduction/components/Block.js b/client/src/templates/Introduction/components/Block.js index b55df9a13f4..25eaf6a180a 100644 --- a/client/src/templates/Introduction/components/Block.js +++ b/client/src/templates/Introduction/components/Block.js @@ -1,20 +1,20 @@ -import React, { Component } from 'react'; import PropTypes from 'prop-types'; -import { bindActionCreators } from 'redux'; -import { connect } from 'react-redux'; -import { createSelector } from 'reselect'; +import React, { Component } from 'react'; import { withTranslation } from 'react-i18next'; +import { connect } from 'react-redux'; import ScrollableAnchor from 'react-scrollable-anchor'; +import { bindActionCreators } from 'redux'; +import { createSelector } from 'reselect'; -import { makeExpandedBlockSelector, toggleBlock } from '../redux'; -import { completedChallengesSelector, executeGA } from '../../../redux'; -import Challenges from './Challenges'; -import Caret from '../../../assets/icons/caret'; -import GreenPass from '../../../assets/icons/green-pass'; -import GreenNotCompleted from '../../../assets/icons/green-not-completed'; -import { isAuditedCert } from '../../../../../utils/is-audited'; import envData from '../../../../../config/env.json'; +import { isAuditedCert } from '../../../../../utils/is-audited'; +import Caret from '../../../assets/icons/caret'; +import GreenNotCompleted from '../../../assets/icons/green-not-completed'; +import GreenPass from '../../../assets/icons/green-pass'; import { Link } from '../../../components/helpers/'; +import { completedChallengesSelector, executeGA } from '../../../redux'; +import { makeExpandedBlockSelector, toggleBlock } from '../redux'; +import Challenges from './Challenges'; const { curriculumLocale } = envData; diff --git a/client/src/templates/Introduction/components/CertChallenge.js b/client/src/templates/Introduction/components/CertChallenge.js index 762c270fbe6..e1c5df7c4e8 100644 --- a/client/src/templates/Introduction/components/CertChallenge.js +++ b/client/src/templates/Introduction/components/CertChallenge.js @@ -1,24 +1,24 @@ -import React, { useState, useEffect } from 'react'; +import { Button } from '@freecodecamp/react-bootstrap'; +import { navigate } from 'gatsby-link'; import PropTypes from 'prop-types'; +import React, { useState, useEffect } from 'react'; +import { withTranslation } from 'react-i18next'; import { connect } from 'react-redux'; import { createSelector } from 'reselect'; -import { withTranslation } from 'react-i18next'; -import { Button } from '@freecodecamp/react-bootstrap'; -import CertificationCard from './CertificationCard'; - -import { stepsToClaimSelector } from '../../../redux'; -import { verifyCert } from '../../../redux/settings'; -import { createFlashMessage } from '../../../components/Flash/redux'; -import { StepsType, User } from '../../../redux/prop-types'; - -import { certMap } from '../../../resources/cert-and-project-map'; import { certSlugTypeMap, superBlockCertTypeMap } from '../../../../../config/certification-settings'; +import { createFlashMessage } from '../../../components/Flash/redux'; +import { stepsToClaimSelector } from '../../../redux'; + +import { StepsType, User } from '../../../redux/prop-types'; +import { verifyCert } from '../../../redux/settings'; + +import { certMap } from '../../../resources/cert-and-project-map'; import { getVerifyCanClaimCert } from '../../../utils/ajax'; -import { navigate } from 'gatsby-link'; +import CertificationCard from './CertificationCard'; const propTypes = { createFlashMessage: PropTypes.func.isRequired, diff --git a/client/src/templates/Introduction/components/CertificationCard.js b/client/src/templates/Introduction/components/CertificationCard.js index 8660c66ef0f..c5982e7ce61 100644 --- a/client/src/templates/Introduction/components/CertificationCard.js +++ b/client/src/templates/Introduction/components/CertificationCard.js @@ -1,14 +1,14 @@ -import React, { useState } from 'react'; import PropTypes from 'prop-types'; +import React, { useState } from 'react'; -import GreenNotCompleted from '../../../assets/icons/green-not-completed'; -import ScrollableAnchor from 'react-scrollable-anchor'; -// import { navigate } from 'gatsby'; import { useTranslation } from 'react-i18next'; -import ClaimCertSteps from './ClaimCertSteps'; +import ScrollableAnchor from 'react-scrollable-anchor'; +import Caret from '../../../assets/icons/caret'; +import GreenNotCompleted from '../../../assets/icons/green-not-completed'; +// import { navigate } from 'gatsby'; import GreenPass from '../../../assets/icons/green-pass'; import { StepsType } from '../../../redux/prop-types'; -import Caret from '../../../assets/icons/caret'; +import ClaimCertSteps from './ClaimCertSteps'; const propTypes = { i18nCertText: PropTypes.string, diff --git a/client/src/templates/Introduction/components/Challenges.js b/client/src/templates/Introduction/components/Challenges.js index 5f5ac316163..532ac0f6c91 100644 --- a/client/src/templates/Introduction/components/Challenges.js +++ b/client/src/templates/Introduction/components/Challenges.js @@ -1,14 +1,14 @@ -import React, { Component } from 'react'; -import PropTypes from 'prop-types'; -import { bindActionCreators } from 'redux'; -import { connect } from 'react-redux'; -import { createSelector } from 'reselect'; import { Link } from 'gatsby'; +import PropTypes from 'prop-types'; +import React, { Component } from 'react'; import { withTranslation } from 'react-i18next'; +import { connect } from 'react-redux'; +import { bindActionCreators } from 'redux'; +import { createSelector } from 'reselect'; -import { completedChallengesSelector, executeGA } from '../../../redux'; -import GreenPass from '../../../assets/icons/green-pass'; import GreenNotCompleted from '../../../assets/icons/green-not-completed'; +import GreenPass from '../../../assets/icons/green-pass'; +import { completedChallengesSelector, executeGA } from '../../../redux'; const mapStateToProps = state => { return createSelector(completedChallengesSelector, completedChallenges => ({ diff --git a/client/src/templates/Introduction/components/ClaimCertSteps.js b/client/src/templates/Introduction/components/ClaimCertSteps.js index f5ac8be78d1..f02a09f9f88 100644 --- a/client/src/templates/Introduction/components/ClaimCertSteps.js +++ b/client/src/templates/Introduction/components/ClaimCertSteps.js @@ -1,11 +1,11 @@ -import React from 'react'; -import PropTypes from 'prop-types'; import { Link } from 'gatsby'; +import PropTypes from 'prop-types'; +import React from 'react'; import { withTranslation, useTranslation } from 'react-i18next'; -import { StepsType } from '../../../redux/prop-types'; -import GreenPass from '../../../assets/icons/green-pass'; import GreenNotCompleted from '../../../assets/icons/green-not-completed'; +import GreenPass from '../../../assets/icons/green-pass'; +import { StepsType } from '../../../redux/prop-types'; const mapIconStyle = { height: '15px', marginRight: '10px', width: '15px' }; diff --git a/client/src/templates/Introduction/components/SuperBlockIntro.js b/client/src/templates/Introduction/components/SuperBlockIntro.js index ca69450e384..848bba39952 100644 --- a/client/src/templates/Introduction/components/SuperBlockIntro.js +++ b/client/src/templates/Introduction/components/SuperBlockIntro.js @@ -1,9 +1,9 @@ -import React from 'react'; import PropTypes from 'prop-types'; +import React from 'react'; import { useTranslation } from 'react-i18next'; -import { Spacer } from '../../../components/helpers'; import { generateIconComponent } from '../../../assets/icons'; +import { Spacer } from '../../../components/helpers'; const propTypes = { superBlock: PropTypes.string diff --git a/client/src/utils/ajax.ts b/client/src/utils/ajax.ts index 1f15f6fa398..d13b58ceeb0 100644 --- a/client/src/utils/ajax.ts +++ b/client/src/utils/ajax.ts @@ -1,5 +1,5 @@ -import envData from '../../../config/env.json'; import cookies from 'browser-cookies'; +import envData from '../../../config/env.json'; import type { UserType } from '../redux/prop-types'; diff --git a/client/src/utils/curriculum-helpers.test.ts b/client/src/utils/curriculum-helpers.test.ts index a61f2c61652..708ce3c6fc2 100644 --- a/client/src/utils/curriculum-helpers.test.ts +++ b/client/src/utils/curriculum-helpers.test.ts @@ -1,8 +1,8 @@ -import __testHelpers, { removeJSComments } from './curriculum-helpers'; -import jsTestValues from './__fixtures/curriculum-helpers-javascript'; import cssTestValues from './__fixtures/curriculum-helpers-css'; import htmlTestValues from './__fixtures/curriculum-helpers-html'; +import jsTestValues from './__fixtures/curriculum-helpers-javascript'; import whiteSpaceTestValues from './__fixtures/curriculum-helpers-remove-white-space'; +import __testHelpers, { removeJSComments } from './curriculum-helpers'; const { stringWithWhiteSpaceChars, stringWithWhiteSpaceCharsRemoved } = whiteSpaceTestValues; diff --git a/client/src/utils/curriculum-helpers.ts b/client/src/utils/curriculum-helpers.ts index a5d7b12ed5d..33818215d49 100644 --- a/client/src/utils/curriculum-helpers.ts +++ b/client/src/utils/curriculum-helpers.ts @@ -1,5 +1,5 @@ -import CSSHelp from './css-help'; import strip from '@freecodecamp/strip-comments'; +import CSSHelp from './css-help'; const removeHtmlComments = (str: string): string => str.replace(/|$)/g, ''); diff --git a/client/src/utils/handled-error.test.ts b/client/src/utils/handled-error.test.ts index 42e59cb839d..dd96a9783b6 100644 --- a/client/src/utils/handled-error.test.ts +++ b/client/src/utils/handled-error.test.ts @@ -1,5 +1,5 @@ -import { isObject } from 'lodash-es'; import type { AxiosError } from 'axios'; +import { isObject } from 'lodash-es'; import { isHandledError, diff --git a/client/src/utils/handled-error.ts b/client/src/utils/handled-error.ts index 178074b5e6b..c1068ca3638 100644 --- a/client/src/utils/handled-error.ts +++ b/client/src/utils/handled-error.ts @@ -1,10 +1,9 @@ -import { has } from 'lodash-es'; import type { AxiosError, AxiosResponse } from 'axios'; - -import standardErrorMessage from './standard-error-message'; -import reportedErrorMessage from './reported-error-message'; +import { has } from 'lodash-es'; import { reportClientSideError } from './report-error'; +import reportedErrorMessage from './reported-error-message'; +import standardErrorMessage from './standard-error-message'; interface ErrorData { type?: string; diff --git a/client/utils/buildChallenges.js b/client/utils/buildChallenges.js index b16d4459145..c64bd1c0292 100644 --- a/client/utils/buildChallenges.js +++ b/client/utils/buildChallenges.js @@ -1,13 +1,13 @@ -const _ = require('lodash'); const path = require('path'); +const _ = require('lodash'); +const envData = require('../../config/env.json'); const { getChallengesForLang, createChallenge, challengesDir, getChallengesDirForLang } = require('../../curriculum/getChallenges'); -const envData = require('../../config/env.json'); const { curriculumLocale } = envData; diff --git a/client/utils/gatsby/layoutSelector.test.js b/client/utils/gatsby/layoutSelector.test.js index e4da7366d56..64f515a49b4 100644 --- a/client/utils/gatsby/layoutSelector.test.js +++ b/client/utils/gatsby/layoutSelector.test.js @@ -2,11 +2,11 @@ import React from 'react'; import { Provider } from 'react-redux'; import ShallowRenderer from 'react-test-renderer/shallow'; -import layoutSelector from './layout-selector'; -import { createStore } from '../../src/redux/createStore'; import FourOhFourPage from '../../src/pages/404'; -import Learn from '../../src/pages/learn'; import Certification from '../../src/pages/certification'; +import Learn from '../../src/pages/learn'; +import { createStore } from '../../src/redux/createStore'; +import layoutSelector from './layout-selector'; jest.mock('../../src/analytics'); diff --git a/client/utils/tags.js b/client/utils/tags.js index 7c69fcc21d2..dd1c1e57380 100644 --- a/client/utils/tags.js +++ b/client/utils/tags.js @@ -1,7 +1,7 @@ -import React from 'react'; import { withPrefix } from 'gatsby'; import i18next from 'i18next'; import psl from 'psl'; +import React from 'react'; import env from '../../config/env.json'; const { homeLocation } = env; diff --git a/client/webpack-workers.js b/client/webpack-workers.js index 6dbd8b585d2..a4e7f70792a 100644 --- a/client/webpack-workers.js +++ b/client/webpack-workers.js @@ -1,7 +1,7 @@ -const path = require('path'); -const webpack = require('webpack'); -const CopyWebpackPlugin = require('copy-webpack-plugin'); const { writeFileSync } = require('fs'); +const path = require('path'); +const CopyWebpackPlugin = require('copy-webpack-plugin'); +const webpack = require('webpack'); module.exports = (env = {}) => { const __DEV__ = env.production !== true; diff --git a/curriculum/getChallenges.js b/curriculum/getChallenges.js index 3980b90380a..8db7f862261 100644 --- a/curriculum/getChallenges.js +++ b/curriculum/getChallenges.js @@ -1,10 +1,14 @@ +const fs = require('fs'); const path = require('path'); +const util = require('util'); +const yaml = require('js-yaml'); const { findIndex, reduce, toString } = require('lodash'); const readDirP = require('readdirp'); -const yaml = require('js-yaml'); +const { helpCategoryMap } = require('../client/utils/challengeTypes'); +const { showUpcomingChanges } = require('../config/env.json'); +const { curriculum: curriculumLangs } = + require('../config/i18n/all-langs').availableLangs; const { parseMD } = require('../tools/challenge-parser/parser'); -const fs = require('fs'); -const util = require('util'); /* eslint-disable max-len */ const { translateCommentsInChallenge @@ -12,13 +16,8 @@ const { /* eslint-enable max-len*/ const { isAuditedCert } = require('../utils/is-audited'); -const { dasherize } = require('../utils/slugs'); const { createPoly } = require('../utils/polyvinyl'); -const { helpCategoryMap } = require('../client/utils/challengeTypes'); -const { curriculum: curriculumLangs } = - require('../config/i18n/all-langs').availableLangs; - -const { showUpcomingChanges } = require('../config/env.json'); +const { dasherize } = require('../utils/slugs'); const access = util.promisify(fs.access); diff --git a/curriculum/gulpfile.js b/curriculum/gulpfile.js index 32246060203..2128d2b14e0 100644 --- a/curriculum/gulpfile.js +++ b/curriculum/gulpfile.js @@ -1,8 +1,8 @@ const gulp = require('gulp'); const through2 = require('through2'); -const { testedLang } = require('./utils'); const lintMarkdown = require('../tools/scripts/lint'); +const { testedLang } = require('./utils'); /** * Tasks diff --git a/curriculum/test/test-challenges.js b/curriculum/test/test-challenges.js index 2ca81404b34..9c3239a73f0 100644 --- a/curriculum/test/test-challenges.js +++ b/curriculum/test/test-challenges.js @@ -1,10 +1,20 @@ /* eslint-disable no-loop-func */ const path = require('path'); +const { inspect } = require('util'); +const vm = require('vm'); +const { assert, AssertionError } = require('chai'); +const jsdom = require('jsdom'); const liveServer = require('live-server'); -const stringSimilarity = require('string-similarity'); -const { isAuditedCert } = require('../../utils/is-audited'); - +const lodash = require('lodash'); +const Mocha = require('mocha'); +const mockRequire = require('mock-require'); const spinner = require('ora')(); +const puppeteer = require('puppeteer'); +const stringSimilarity = require('string-similarity'); + +// lodash-es can't easily be used in node environments, so we just mock it out +// for the original lodash in testing. +mockRequire('lodash-es', lodash); const clientPath = path.resolve(__dirname, '../../client'); require('@babel/polyfill'); @@ -16,50 +26,34 @@ require('@babel/register')({ ignore: [/node_modules/], only: [clientPath] }); - -const mockRequire = require('mock-require'); -const lodash = require('lodash'); - -// lodash-es can't easily be used in node environments, so we just mock it out -// for the original lodash in testing. -mockRequire('lodash-es', lodash); - -const createPseudoWorker = require('./utils/pseudo-worker'); +const { + buildDOMChallenge, + buildJSChallenge +} = require('../../client/src/templates/Challenges/utils/build'); const { default: createWorker } = require('../../client/src/templates/Challenges/utils/worker-executor'); +const { challengeTypes } = require('../../client/utils/challengeTypes'); +// the config files are created during the build, but not before linting +/* eslint-disable import/no-unresolved */ +const testEvaluator = + require('../../config/client/test-evaluator.json').filename; +/* eslint-enable import/no-unresolved */ -const { assert, AssertionError } = require('chai'); -const Mocha = require('mocha'); - -const { flatten, isEmpty, cloneDeep, isEqual } = lodash; const { getLines } = require('../../utils/get-lines'); +const { isAuditedCert } = require('../../utils/is-audited'); -const jsdom = require('jsdom'); - -const vm = require('vm'); - -const puppeteer = require('puppeteer'); - +const { toSortedArray } = require('../../utils/sort-files'); const { getChallengesForLang, getMetaForBlock, getTranslatableComments } = require('../getChallenges'); - -const MongoIds = require('./utils/mongoIds'); -const ChallengeTitles = require('./utils/challengeTitles'); const { challengeSchemaValidator } = require('../schema/challengeSchema'); -const { challengeTypes } = require('../../client/utils/challengeTypes'); - -const { toSortedArray } = require('../../utils/sort-files'); - const { testedLang } = require('../utils'); - -const { - buildDOMChallenge, - buildJSChallenge -} = require('../../client/src/templates/Challenges/utils/build'); +const ChallengeTitles = require('./utils/challengeTitles'); +const MongoIds = require('./utils/mongoIds'); +const createPseudoWorker = require('./utils/pseudo-worker'); const { sortChallenges } = require('./utils/sort-challenges'); @@ -67,13 +61,6 @@ const TRANSLATABLE_COMMENTS = getTranslatableComments( path.resolve(__dirname, '..', 'dictionaries') ); -// the config files are created during the build, but not before linting -/* eslint-disable import/no-unresolved */ -const testEvaluator = - require('../../config/client/test-evaluator.json').filename; -/* eslint-enable import/no-unresolved */ -const { inspect } = require('util'); - const commentExtractors = { html: require('./utils/extract-html-comments'), js: require('./utils/extract-js-comments'), @@ -82,6 +69,8 @@ const commentExtractors = { scriptJs: require('./utils/extract-script-js-comments') }; +const { flatten, isEmpty, cloneDeep, isEqual } = lodash; + // rethrow unhandled rejections to make sure the tests exit with -1 process.on('unhandledRejection', err => handleRejection(err)); diff --git a/curriculum/test/utils/mongoIds.js b/curriculum/test/utils/mongoIds.js index 3148581acd3..efa01ff36b5 100644 --- a/curriculum/test/utils/mongoIds.js +++ b/curriculum/test/utils/mongoIds.js @@ -1,5 +1,5 @@ -const findIndex = require('lodash/findIndex'); const Joi = require('joi'); +const findIndex = require('lodash/findIndex'); Joi.objectId = require('joi-objectid')(Joi); const schema = Joi.objectId(); diff --git a/curriculum/test/utils/plugins/get-css-comments.js b/curriculum/test/utils/plugins/get-css-comments.js index 355faf9a3c0..212d141c698 100644 --- a/curriculum/test/utils/plugins/get-css-comments.js +++ b/curriculum/test/utils/plugins/get-css-comments.js @@ -1,6 +1,6 @@ +var css = require('css'); const { isEmpty } = require('lodash'); const visit = require('unist-util-visit'); -var css = require('css'); const { commentToData } = require('../comment-to-data'); function visitComments(node, cb) { diff --git a/curriculum/test/utils/plugins/get-script-js-comments.js b/curriculum/test/utils/plugins/get-script-js-comments.js index d50edaf87e9..5cb45471f5c 100644 --- a/curriculum/test/utils/plugins/get-script-js-comments.js +++ b/curriculum/test/utils/plugins/get-script-js-comments.js @@ -1,6 +1,6 @@ +const acorn = require('acorn'); const { isEmpty } = require('lodash'); const visit = require('unist-util-visit'); -const acorn = require('acorn'); const { commentToData } = require('../comment-to-data'); const parser = acorn.Parser; diff --git a/tools/challenge-helper-scripts/create-next-step.js b/tools/challenge-helper-scripts/create-next-step.js index 4483f550027..b25b940a60c 100644 --- a/tools/challenge-helper-scripts/create-next-step.js +++ b/tools/challenge-helper-scripts/create-next-step.js @@ -1,7 +1,7 @@ -const { getProjectPath } = require('./helpers/get-project-path'); const { getLastStepFileContent } = require('./helpers/get-last-step-file-content'); +const { getProjectPath } = require('./helpers/get-project-path'); const { reorderSteps, createStepFile } = require('./utils'); const projectPath = getProjectPath(); diff --git a/tools/challenge-helper-scripts/create-project.ts b/tools/challenge-helper-scripts/create-project.ts index a8e01c73f5c..58fc3ba39bd 100644 --- a/tools/challenge-helper-scripts/create-project.ts +++ b/tools/challenge-helper-scripts/create-project.ts @@ -1,11 +1,11 @@ -import fs from 'fs/promises'; import { existsSync } from 'fs'; +import fs from 'fs/promises'; import path from 'path'; -import { format } from 'prettier'; import { prompt } from 'inquirer'; +import { format } from 'prettier'; -import { createStepFile } from './utils.js'; import { blockNameify } from '../../utils/block-nameify'; +import { createStepFile } from './utils.js'; const superBlocks = [ 'responsive-web-design', diff --git a/tools/challenge-helper-scripts/utils.js b/tools/challenge-helper-scripts/utils.js index b6cdc68df10..ecf8677d9dd 100644 --- a/tools/challenge-helper-scripts/utils.js +++ b/tools/challenge-helper-scripts/utils.js @@ -1,14 +1,14 @@ const fs = require('fs'); const path = require('path'); -const matter = require('gray-matter'); const ObjectID = require('bson-objectid'); -const { parseMDSync } = require('../challenge-parser/parser'); +const matter = require('gray-matter'); const { getMetaData } = require('../challenge-helper-scripts/helpers/get-project-path-metadata'); -const { getStepTemplate } = require('./helpers/get-step-template'); +const { parseMDSync } = require('../challenge-parser/parser'); const { getProjectMetaPath } = require('./helpers/get-project-meta-path'); const { getProjectPath } = require('./helpers/get-project-path'); +const { getStepTemplate } = require('./helpers/get-step-template'); const { padWithLeadingZeros } = require('./helpers/pad-with-leading-zeros'); const createStepFile = ({ diff --git a/tools/challenge-helper-scripts/utils.test.js b/tools/challenge-helper-scripts/utils.test.js index c49797785e2..489a80c8840 100644 --- a/tools/challenge-helper-scripts/utils.test.js +++ b/tools/challenge-helper-scripts/utils.test.js @@ -1,6 +1,7 @@ const fs = require('fs'); -const mock = require('mock-fs'); +const ObjectID = require('bson-objectid'); const glob = require('glob'); +const mock = require('mock-fs'); // NOTE: // Use `console.log()` before mocking the filesystem or use @@ -48,7 +49,6 @@ jest.mock( ); const mockChallengeId = '60d35cf3fe32df2ce8e31b03'; -const ObjectID = require('bson-objectid'); const { getStepTemplate } = require('./helpers/get-step-template'); const { createStepFile, reorderSteps } = require('./utils'); diff --git a/tools/challenge-parser/parser/index.js b/tools/challenge-parser/parser/index.js index 60ad65fbcbb..17fa9e6d78a 100644 --- a/tools/challenge-parser/parser/index.js +++ b/tools/challenge-parser/parser/index.js @@ -1,17 +1,17 @@ -const { readSync } = require('to-vfile'); -const remark = require('remark-parse'); const directive = require('remark-directive'); const frontmatter = require('remark-frontmatter'); -const addTests = require('./plugins/add-tests'); -const restoreDirectives = require('./plugins/restore-directives'); -const replaceImports = require('./plugins/replace-imports'); +const remark = require('remark-parse'); +const { readSync } = require('to-vfile'); +const unified = require('unified'); const addFrontmatter = require('./plugins/add-frontmatter'); -const addText = require('./plugins/add-text'); -const addVideoQuestion = require('./plugins/add-video-question'); const addSeed = require('./plugins/add-seed'); const addSolution = require('./plugins/add-solution'); +const addTests = require('./plugins/add-tests'); +const addText = require('./plugins/add-text'); +const addVideoQuestion = require('./plugins/add-video-question'); +const replaceImports = require('./plugins/replace-imports'); +const restoreDirectives = require('./plugins/restore-directives'); const tableAndStrikeThrough = require('./plugins/table-and-strikethrough'); -const unified = require('unified'); // by convention, anything that adds to file.data has the name add. const processor = unified() diff --git a/tools/challenge-parser/parser/plugins/add-frontmatter.js b/tools/challenge-parser/parser/plugins/add-frontmatter.js index 5a23cc12a00..fac8d4b2ece 100644 --- a/tools/challenge-parser/parser/plugins/add-frontmatter.js +++ b/tools/challenge-parser/parser/plugins/add-frontmatter.js @@ -1,5 +1,5 @@ -const visit = require('unist-util-visit'); const YAML = require('js-yaml'); +const visit = require('unist-util-visit'); function plugin() { return transformer; diff --git a/tools/challenge-parser/parser/plugins/add-seed.js b/tools/challenge-parser/parser/plugins/add-seed.js index 337d58c6215..e4f8900083b 100644 --- a/tools/challenge-parser/parser/plugins/add-seed.js +++ b/tools/challenge-parser/parser/plugins/add-seed.js @@ -1,9 +1,9 @@ +const { isEmpty } = require('lodash'); +const { root } = require('mdast-builder'); +const visitChildren = require('unist-util-visit-children'); const getAllBetween = require('./utils/between-headings'); // const visit = require('unist-util-visit'); -const visitChildren = require('unist-util-visit-children'); -const { root } = require('mdast-builder'); const { getFileVisitor } = require('./utils/get-file-visitor'); -const { isEmpty } = require('lodash'); const editableRegionMarker = '--fcc-editable-region--'; diff --git a/tools/challenge-parser/parser/plugins/add-seed.test.js b/tools/challenge-parser/parser/plugins/add-seed.test.js index 64898567297..a448ef86795 100644 --- a/tools/challenge-parser/parser/plugins/add-seed.test.js +++ b/tools/challenge-parser/parser/plugins/add-seed.test.js @@ -1,24 +1,24 @@ +const { isObject } = require('lodash'); const isArray = require('lodash/isArray'); -const simpleAST = require('../__fixtures__/ast-simple.json'); -const withEditableAST = require('../__fixtures__/ast-with-markers.json'); -const withSeedKeysAST = require('../__fixtures__/ast-seed-keys.json'); -const withExtraLinesAST = require('../__fixtures__/ast-with-extra-lines.json'); -const orphanKeyAST = require('../__fixtures__/ast-orphan-key.json'); const adjacentKeysAST = require('../__fixtures__/ast-adjacent-keys.json'); const withBeforeAfterAST = require('../__fixtures__/ast-before-after.json'); -const emptyBeforeAST = require('../__fixtures__/ast-empty-before.json'); +const cCodeAST = require('../__fixtures__/ast-c-code.json'); +const doubleMarkerAST = require('../__fixtures__/ast-double-marker.json'); const emptyAfterAST = require('../__fixtures__/ast-empty-after.json'); +const emptyBeforeAST = require('../__fixtures__/ast-empty-before.json'); +const emptyContentAST = require('../__fixtures__/ast-empty-contents.json'); const emptyCSSAST = require('../__fixtures__/ast-empty-css.json'); const emptyHTMLAST = require('../__fixtures__/ast-empty-html.json'); -const doubleMarkerAST = require('../__fixtures__/ast-double-marker.json'); -const jsxSeedAST = require('../__fixtures__/ast-jsx-seed.json'); -const cCodeAST = require('../__fixtures__/ast-c-code.json'); const explodedMarkerAST = require('../__fixtures__/ast-exploded-marker.json'); -const emptyContentAST = require('../__fixtures__/ast-empty-contents.json'); +const jsxSeedAST = require('../__fixtures__/ast-jsx-seed.json'); +const orphanKeyAST = require('../__fixtures__/ast-orphan-key.json'); +const withSeedKeysAST = require('../__fixtures__/ast-seed-keys.json'); +const simpleAST = require('../__fixtures__/ast-simple.json'); +const withExtraLinesAST = require('../__fixtures__/ast-with-extra-lines.json'); +const withEditableAST = require('../__fixtures__/ast-with-markers.json'); const addSeed = require('./add-seed'); -const { isObject } = require('lodash'); describe('add-seed plugin', () => { const plugin = addSeed(); diff --git a/tools/challenge-parser/parser/plugins/add-solution.js b/tools/challenge-parser/parser/plugins/add-solution.js index f4540a57952..6a373f3a678 100644 --- a/tools/challenge-parser/parser/plugins/add-solution.js +++ b/tools/challenge-parser/parser/plugins/add-solution.js @@ -1,10 +1,10 @@ -const visitChildren = require('unist-util-visit-children'); const { root } = require('mdast-builder'); +const visitChildren = require('unist-util-visit-children'); +const { editableRegionMarker } = require('./add-seed'); +const getAllBetween = require('./utils/between-headings'); const { getFileVisitor } = require('./utils/get-file-visitor'); const { splitOnThematicBreak } = require('./utils/split-on-thematic-break'); -const getAllBetween = require('./utils/between-headings'); -const { editableRegionMarker } = require('./add-seed'); function validateMarkers({ value }) { const lines = value.split('\n'); diff --git a/tools/challenge-parser/parser/plugins/add-solution.test.js b/tools/challenge-parser/parser/plugins/add-solution.test.js index 46187980244..281b3139917 100644 --- a/tools/challenge-parser/parser/plugins/add-solution.test.js +++ b/tools/challenge-parser/parser/plugins/add-solution.test.js @@ -1,9 +1,9 @@ -const mockAST = require('../__fixtures__/ast-simple.json'); +const { isObject } = require('lodash'); const editableSolutionAST = require('../__fixtures__/ast-erm-in-solution.json'); const multiSolnsAST = require('../__fixtures__/ast-multiple-solutions.json'); +const mockAST = require('../__fixtures__/ast-simple.json'); const addSolution = require('./add-solution'); -const { isObject } = require('lodash'); describe('add solution plugin', () => { const plugin = addSolution(); diff --git a/tools/challenge-parser/parser/plugins/add-tests.test.js b/tools/challenge-parser/parser/plugins/add-tests.test.js index cdb7d1cc6a6..c5abae0aed3 100644 --- a/tools/challenge-parser/parser/plugins/add-tests.test.js +++ b/tools/challenge-parser/parser/plugins/add-tests.test.js @@ -1,5 +1,5 @@ -const simpleAST = require('../__fixtures__/ast-simple.json'); const brokenHintsAST = require('../__fixtures__/ast-broken-hints.json'); +const simpleAST = require('../__fixtures__/ast-simple.json'); const addTests = require('./add-tests'); describe('add-tests plugin', () => { diff --git a/tools/challenge-parser/parser/plugins/add-text.test.js b/tools/challenge-parser/parser/plugins/add-text.test.js index d020a954d2d..45752e24c4b 100644 --- a/tools/challenge-parser/parser/plugins/add-text.test.js +++ b/tools/challenge-parser/parser/plugins/add-text.test.js @@ -1,7 +1,7 @@ -const mockAST = require('../__fixtures__/ast-simple.json'); // eslint-disable-next-line max-len const incorrectMarkersAST = require('../__fixtures__/ast-incorrect-markers.json'); const realisticAST = require('../__fixtures__/ast-realistic.json'); +const mockAST = require('../__fixtures__/ast-simple.json'); const addText = require('./add-text'); describe('add-text', () => { diff --git a/tools/challenge-parser/parser/plugins/replace-imports.js b/tools/challenge-parser/parser/plugins/replace-imports.js index 1925672e8a5..0c855c5afb5 100644 --- a/tools/challenge-parser/parser/plugins/replace-imports.js +++ b/tools/challenge-parser/parser/plugins/replace-imports.js @@ -1,11 +1,11 @@ const path = require('path'); +const { isEmpty } = require('lodash'); +const remark = require('remark'); const { read } = require('to-vfile'); const modifyChildren = require('unist-util-modify-children'); -const remark = require('remark'); const remove = require('unist-util-remove'); -const visit = require('unist-util-visit'); const { selectAll } = require('unist-util-select'); -const { isEmpty } = require('lodash'); +const visit = require('unist-util-visit'); const { editableRegionMarker } = require('./add-seed'); const tableAndStrikeThrough = require('./table-and-strikethrough'); diff --git a/tools/challenge-parser/parser/plugins/replace-imports.test.js b/tools/challenge-parser/parser/plugins/replace-imports.test.js index 6d638e577b0..b3baf78f46e 100644 --- a/tools/challenge-parser/parser/plugins/replace-imports.test.js +++ b/tools/challenge-parser/parser/plugins/replace-imports.test.js @@ -3,12 +3,12 @@ const cloneDeep = require('lodash/cloneDeep'); const toVfile = require('to-vfile'); const selectAll = require('unist-util-select').selectAll; -const addImports = require('./replace-imports'); -const originalImportsAST = require('../__fixtures__/ast-imports.json'); -const originalImportsTwoAST = require('../__fixtures__/ast-imports-two.json'); const originalImportsExtraAST = require('../__fixtures__/ast-imports-extra.json'); -const originalSimpleAST = require('../__fixtures__/ast-simple.json'); +const originalImportsTwoAST = require('../__fixtures__/ast-imports-two.json'); +const originalImportsAST = require('../__fixtures__/ast-imports.json'); const originalMarkerAST = require('../__fixtures__/ast-marker-imports.json'); +const originalSimpleAST = require('../__fixtures__/ast-simple.json'); +const addImports = require('./replace-imports'); describe('replace-imports', () => { let importsAST; diff --git a/tools/challenge-parser/parser/plugins/restore-directives.js b/tools/challenge-parser/parser/plugins/restore-directives.js index 1771c972051..0b4d33d1226 100644 --- a/tools/challenge-parser/parser/plugins/restore-directives.js +++ b/tools/challenge-parser/parser/plugins/restore-directives.js @@ -1,7 +1,7 @@ -const visit = require('unist-util-visit'); -const { matches } = require('unist-util-select'); const directive = require('mdast-util-directive'); var toMarkdown = require('mdast-util-to-markdown'); +const { matches } = require('unist-util-select'); +const visit = require('unist-util-visit'); function plugin() { return transformer; diff --git a/tools/challenge-parser/parser/plugins/restore-directives.test.js b/tools/challenge-parser/parser/plugins/restore-directives.test.js index f65dbed02f9..c2ee139f5ee 100644 --- a/tools/challenge-parser/parser/plugins/restore-directives.test.js +++ b/tools/challenge-parser/parser/plugins/restore-directives.test.js @@ -1,9 +1,9 @@ const cloneDeep = require('lodash/cloneDeep'); -const { selectAll } = require('unist-util-select'); const find = require('unist-util-find'); +const { selectAll } = require('unist-util-select'); -const restoreDirectives = require('./restore-directives'); const directivesOriginalAST = require('../__fixtures__/ast-directives.json'); +const restoreDirectives = require('./restore-directives'); describe('restore-directives', () => { let directivesAST; diff --git a/tools/challenge-parser/parser/plugins/table-and-strikethrough.js b/tools/challenge-parser/parser/plugins/table-and-strikethrough.js index 1911163004f..e1a1472f1ec 100644 --- a/tools/challenge-parser/parser/plugins/table-and-strikethrough.js +++ b/tools/challenge-parser/parser/plugins/table-and-strikethrough.js @@ -1,8 +1,8 @@ 'use strict'; +var fromMarkdown = require('mdast-util-gfm/from-markdown'); var strikethrough = require('micromark-extension-gfm-strikethrough'); var table = require('micromark-extension-gfm-table'); -var fromMarkdown = require('mdast-util-gfm/from-markdown'); module.exports = tableAndStrikethrough; diff --git a/tools/challenge-parser/parser/plugins/utils/between-headings.js b/tools/challenge-parser/parser/plugins/utils/between-headings.js index a8c920db783..ecea2493faa 100644 --- a/tools/challenge-parser/parser/plugins/utils/between-headings.js +++ b/tools/challenge-parser/parser/plugins/utils/between-headings.js @@ -1,7 +1,7 @@ -const between = require('unist-util-find-all-between'); const find = require('unist-util-find'); const findAfter = require('unist-util-find-after'); const findAllAfter = require('unist-util-find-all-after'); +const between = require('unist-util-find-all-between'); function getAllBetween(tree, marker) { const start = find(tree, { diff --git a/tools/challenge-parser/parser/plugins/utils/between-headings.test.js b/tools/challenge-parser/parser/plugins/utils/between-headings.test.js index 164c401e61c..07fe93c1985 100644 --- a/tools/challenge-parser/parser/plugins/utils/between-headings.test.js +++ b/tools/challenge-parser/parser/plugins/utils/between-headings.test.js @@ -1,10 +1,10 @@ const isArray = require('lodash/isArray'); -const find = require('unist-util-find'); const { root } = require('mdast-builder'); +const find = require('unist-util-find'); -const getAllBetween = require('./between-headings'); -const simpleAst = require('../../__fixtures__/ast-simple.json'); const extraHeadingAst = require('../../__fixtures__/ast-extra-heading.json'); +const simpleAst = require('../../__fixtures__/ast-simple.json'); +const getAllBetween = require('./between-headings'); describe('between-headings', () => { it('should return an array', () => { diff --git a/tools/challenge-parser/parser/plugins/utils/get-file-visitor.js b/tools/challenge-parser/parser/plugins/utils/get-file-visitor.js index ac8ed23f7fd..4f263a55e2a 100644 --- a/tools/challenge-parser/parser/plugins/utils/get-file-visitor.js +++ b/tools/challenge-parser/parser/plugins/utils/get-file-visitor.js @@ -1,6 +1,6 @@ +const { isEmpty } = require('lodash'); const is = require('unist-util-is'); const position = require('unist-util-position'); -const { isEmpty } = require('lodash'); const getId = require('./get-id'); diff --git a/tools/challenge-parser/parser/plugins/utils/get-id.test.js b/tools/challenge-parser/parser/plugins/utils/get-id.test.js index affbbc8f8c8..26c7647e843 100644 --- a/tools/challenge-parser/parser/plugins/utils/get-id.test.js +++ b/tools/challenge-parser/parser/plugins/utils/get-id.test.js @@ -1,8 +1,8 @@ -const getId = require('./get-id'); const idNode = require('./__fixtures__/id-node.json'); const imageNode = require('./__fixtures__/image-node.json'); const multipleChildrenNode = require('./__fixtures__/multiple-children.json'); const nonIdNode = require('./__fixtures__/non-id-node.json'); +const getId = require('./get-id'); describe('get-id', () => { it('should return a string', () => { diff --git a/tools/challenge-parser/parser/plugins/utils/mdast-to-html.js b/tools/challenge-parser/parser/plugins/utils/mdast-to-html.js index 5fee1f1817d..a4034d43f4f 100644 --- a/tools/challenge-parser/parser/plugins/utils/mdast-to-html.js +++ b/tools/challenge-parser/parser/plugins/utils/mdast-to-html.js @@ -1,6 +1,6 @@ const hastToHTML = require('hast-util-to-html'); -const mdastToHast = require('mdast-util-to-hast'); const { root } = require('mdast-builder'); +const mdastToHast = require('mdast-util-to-hast'); function mdastToHTML(nodes) { if (!Array.isArray(nodes)) diff --git a/tools/challenge-parser/parser/plugins/utils/mdast-to-html.test.js b/tools/challenge-parser/parser/plugins/utils/mdast-to-html.test.js index 3177adea29a..c7b3d1e61bb 100644 --- a/tools/challenge-parser/parser/plugins/utils/mdast-to-html.test.js +++ b/tools/challenge-parser/parser/plugins/utils/mdast-to-html.test.js @@ -1,8 +1,8 @@ -const mdastToHTML = require('./mdast-to-html'); +const leadingInlineHTMLNode = require('./__fixtures__/leading-html-node.json'); const mdastMixedNodes = require('./__fixtures__/mdast-mixed-nodes.json'); const mdastWithEmNode = require('./__fixtures__/mdast-with-em.json'); const singleNode = require('./__fixtures__/non-id-node.json'); -const leadingInlineHTMLNode = require('./__fixtures__/leading-html-node.json'); +const mdastToHTML = require('./mdast-to-html'); describe('mdast-to-html', () => { it('should return a string', () => { diff --git a/tools/challenge-parser/parser/tools/full-parse.js b/tools/challenge-parser/parser/tools/full-parse.js index 06bdbb5e475..6e562f96814 100644 --- a/tools/challenge-parser/parser/tools/full-parse.js +++ b/tools/challenge-parser/parser/tools/full-parse.js @@ -1,5 +1,5 @@ -const { inspect } = require('util'); const path = require('path'); +const { inspect } = require('util'); const { parseMD } = require('../index'); diff --git a/tools/challenge-parser/parser/tools/generate-ast.js b/tools/challenge-parser/parser/tools/generate-ast.js index da91fe052ff..c777aed35a1 100644 --- a/tools/challenge-parser/parser/tools/generate-ast.js +++ b/tools/challenge-parser/parser/tools/generate-ast.js @@ -1,7 +1,7 @@ -const { read } = require('to-vfile'); const remark = require('remark'); const directive = require('remark-directive'); const frontmatter = require('remark-frontmatter'); +const { read } = require('to-vfile'); (async () => { const path = './example.md'; diff --git a/tools/challenge-parser/parser/tools/inspect-ast.js b/tools/challenge-parser/parser/tools/inspect-ast.js index 6024dbff04c..6a87201e84e 100644 --- a/tools/challenge-parser/parser/tools/inspect-ast.js +++ b/tools/challenge-parser/parser/tools/inspect-ast.js @@ -1,7 +1,7 @@ -const { read } = require('to-vfile'); +const { inspect } = require('util'); const remark = require('remark'); const html = require('remark-html'); -const { inspect } = require('util'); +const { read } = require('to-vfile'); (async () => { const path = './example.md'; diff --git a/tools/challenge-parser/parser/tools/parse-md.js b/tools/challenge-parser/parser/tools/parse-md.js index b656434d0ec..43d9b7b1343 100644 --- a/tools/challenge-parser/parser/tools/parse-md.js +++ b/tools/challenge-parser/parser/tools/parse-md.js @@ -1,7 +1,7 @@ -const { read } = require('to-vfile'); const remark = require('remark'); const directives = require('remark-directive'); const stringify = require('remark-stringify'); +const { read } = require('to-vfile'); (async () => { const path = './example.md'; diff --git a/tools/challenge-parser/translation-parser/index.test.js b/tools/challenge-parser/translation-parser/index.test.js index 98f097fbc83..74904d322ff 100644 --- a/tools/challenge-parser/translation-parser/index.test.js +++ b/tools/challenge-parser/translation-parser/index.test.js @@ -1,12 +1,12 @@ +const { + ENGLISH_CHALLENGE_NO_FILES +} = require('./__fixtures__/challenge-objects'); +const { SIMPLE_TRANSLATION } = require('./__mocks__/mock-comments'); const { translateComments, translateCommentsInChallenge, translateGeneric } = require('.'); -const { - ENGLISH_CHALLENGE_NO_FILES -} = require('./__fixtures__/challenge-objects'); -const { SIMPLE_TRANSLATION } = require('./__mocks__/mock-comments'); let logSpy; diff --git a/tools/crowdin/actions/convert-chinese/index.js b/tools/crowdin/actions/convert-chinese/index.js index 1fb7f497644..97040135075 100644 --- a/tools/crowdin/actions/convert-chinese/index.js +++ b/tools/crowdin/actions/convert-chinese/index.js @@ -1,6 +1,6 @@ /* eslint-disable import/no-unresolved */ -const fs = require('fs-extra'); const path = require('path'); +const fs = require('fs-extra'); const opencc = require('node-opencc'); const getFiles = async (directory, fileList = []) => { diff --git a/tools/crowdin/actions/hide-specific-string/index.js b/tools/crowdin/actions/hide-specific-string/index.js index 1eccdfd103e..a3faed2015a 100644 --- a/tools/crowdin/actions/hide-specific-string/index.js +++ b/tools/crowdin/actions/hide-specific-string/index.js @@ -1,8 +1,8 @@ require('dotenv').config({ path: `${__dirname}/../../.env` }); +const core = require('@actions/core'); const { getFiles } = require('../../utils/files'); const { getStrings, changeHiddenStatus } = require('../../utils/strings'); // eslint-disable-next-line import/no-unresolved -const core = require('@actions/core'); const filename = core.getInput('filename'); const stringContent = core.getInput('string-content'); diff --git a/tools/crowdin/utils/dirs.js b/tools/crowdin/utils/dirs.js index e853b7a0533..e7138555e19 100644 --- a/tools/crowdin/utils/dirs.js +++ b/tools/crowdin/utils/dirs.js @@ -1,6 +1,6 @@ -const makeRequest = require('./make-request'); -const delay = require('./delay'); const authHeader = require('./auth-header'); +const delay = require('./delay'); +const makeRequest = require('./make-request'); const getDirs = async projectId => { let headers = { ...authHeader }; diff --git a/tools/crowdin/utils/files.js b/tools/crowdin/utils/files.js index a3800790289..740fd0771c9 100644 --- a/tools/crowdin/utils/files.js +++ b/tools/crowdin/utils/files.js @@ -1,5 +1,5 @@ -const makeRequest = require('./make-request'); const authHeader = require('./auth-header'); +const makeRequest = require('./make-request'); const addFile = async (projectId, filename, fileContent, directoryId) => { let headers = { ...authHeader }; diff --git a/tools/scripts/build/build-curriculum.js b/tools/scripts/build/build-curriculum.js index ecba913b2ed..7a1c18be941 100644 --- a/tools/scripts/build/build-curriculum.js +++ b/tools/scripts/build/build-curriculum.js @@ -1,5 +1,5 @@ -const path = require('path'); const fs = require('fs'); +const path = require('path'); const { getChallengesForLang } = require('../../../curriculum/getChallenges'); diff --git a/tools/scripts/build/ensure-env.js b/tools/scripts/build/ensure-env.js index f006f01fd36..9704aa5ffde 100644 --- a/tools/scripts/build/ensure-env.js +++ b/tools/scripts/build/ensure-env.js @@ -1,8 +1,8 @@ const fs = require('fs'); const path = require('path'); -const env = require('../../../config/read-env'); const { availableLangs } = require('../../../config/i18n/all-langs'); +const env = require('../../../config/read-env'); const globalConfigPath = path.resolve(__dirname, '../../../config'); diff --git a/tools/scripts/lint/index.js b/tools/scripts/lint/index.js index b29e0821189..ebddce83613 100644 --- a/tools/scripts/lint/index.js +++ b/tools/scripts/lint/index.js @@ -1,6 +1,6 @@ -const YAML = require('js-yaml'); const fs = require('fs'); const path = require('path'); +const YAML = require('js-yaml'); const argv = require('yargs').argv; const linter = require('./linter'); diff --git a/tools/scripts/seed/seedAuthUser.js b/tools/scripts/seed/seedAuthUser.js index 4052e61a826..5f9c5fa87b5 100644 --- a/tools/scripts/seed/seedAuthUser.js +++ b/tools/scripts/seed/seedAuthUser.js @@ -1,18 +1,15 @@ -const fullyCertifiedUser = require('./certifiedUserData'); - const path = require('path'); -require('dotenv').config({ path: path.resolve(__dirname, '../../../.env') }); -const MongoClient = require('mongodb').MongoClient; -const ObjectId = require('mongodb').ObjectID; const debug = require('debug'); +require('dotenv').config({ path: path.resolve(__dirname, '../../../.env') }); +const { MongoClient, ObjectId } = require('mongodb'); +const defaultUserImage = require('../../../config/misc').defaultUserImage; +const fullyCertifiedUser = require('./certifiedUserData'); const envVariables = process.argv; const log = debug('fcc:tools:seedLocalAuthUser'); const { MONGOHQ_URL } = process.env; -const defaultUserImage = require('../../../config/misc').defaultUserImage; - function handleError(err, client) { if (err) { console.error('Oh noes!! Error seeding local auth user.'); diff --git a/tools/ui-components/rollup.config.js b/tools/ui-components/rollup.config.js index b35ce13170e..da488ac6bf7 100644 --- a/tools/ui-components/rollup.config.js +++ b/tools/ui-components/rollup.config.js @@ -1,7 +1,7 @@ -import { nodeResolve } from '@rollup/plugin-node-resolve'; import babel from '@rollup/plugin-babel'; -import postcss from 'rollup-plugin-postcss'; import commonjs from '@rollup/plugin-commonjs'; +import { nodeResolve } from '@rollup/plugin-node-resolve'; +import postcss from 'rollup-plugin-postcss'; import { terser } from 'rollup-plugin-terser'; const production = process.env.NODE_ENV !== 'development'; diff --git a/tools/ui-components/src/button.js b/tools/ui-components/src/button.js index 7a7b95c32e3..a7081873381 100644 --- a/tools/ui-components/src/button.js +++ b/tools/ui-components/src/button.js @@ -1,5 +1,5 @@ -import React from 'react'; import PropTypes from 'prop-types'; +import React from 'react'; import './button.css'; diff --git a/tools/ui-components/src/button.test.js b/tools/ui-components/src/button.test.js index 31f57bb2a06..6c222b4d013 100644 --- a/tools/ui-components/src/button.test.js +++ b/tools/ui-components/src/button.test.js @@ -1,6 +1,6 @@ -import React from 'react'; import { render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; +import React from 'react'; import { Button } from './button'; diff --git a/tools/ui-components/src/color-system.js b/tools/ui-components/src/color-system.js index 28f906499cb..f4540aaa5c4 100644 --- a/tools/ui-components/src/color-system.js +++ b/tools/ui-components/src/color-system.js @@ -1,5 +1,5 @@ -import React from 'react'; import PropTypes from 'prop-types'; +import React from 'react'; import colorList from './colors.css'; diff --git a/utils/sort-files.test.js b/utils/sort-files.test.js index 19955ab04de..234aff69793 100644 --- a/utils/sort-files.test.js +++ b/utils/sort-files.test.js @@ -1,5 +1,5 @@ -const { toSortedArray } = require('./sort-files'); const { challengeFiles } = require('./__fixtures__/challenges'); +const { toSortedArray } = require('./sort-files'); describe('sort-files', () => { describe('toSortedArray', () => {