diff --git a/.eslintrc-base.json b/.eslintrc-base.json index fb9225b7ff..6941a96a20 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 8a6d44af60..1e5688d5e0 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 67e2718ea8..8905c2edb6 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 90ce86ab13..38da2a3e3b 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 dbae1cd766..1110b7196f 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 6d05d65c1a..ac389b2635 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 45fc4f29f7..a662fe4d1d 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 74fa545d86..e5c5fcb371 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 98c3a0f64c..dd9b771db5 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 099908de47..4bdd7802b9 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 d3d02d6c59..26de9e4050 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 1caec372ff..24ae6213bc 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 568387d638..e8d9d087b5 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 7d56e11474..8d04743831 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 2daef38919..a26a2f71eb 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 0bb4e1fa42..d58b8df13a 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 18e0f88289..8d5970e7bb 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 8bd139000d..593d5930ed 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 cc488cd790..219ed97724 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 0cf543c0b2..ae9bd7f608 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 092e8ef323..e6938162c4 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 1112970ba4..c6f59b74fe 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 8dc43098ee..b30f8f5f44 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 a7ffe8bfa9..bf19cddedf 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 477948eb9a..768d0ea0d0 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 6c1282bedf..e73e1be05d 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 de441ee625..326d9c1c45 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 331a18f728..de1cd7d40b 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 9e154af5a6..95203071b9 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 321622509f..5b66caa26f 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 0a4074c55d..e2292ec15c 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 86e3ad012d..4d4fa4d406 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 b488ead6ab..c0c0fd3cca 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 f7e77a3956..d6efa04f84 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 f2e9bbdb03..264c0c1601 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 670e447239..7979177022 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 3fe4a33b3d..5802bb0430 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 88148056d1..f254ef7160 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 72c910305c..3a4b16963b 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 838290f56e..a8cf25b2c5 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 8d345e239e..29ca8ffdef 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 b40ce6a3af..76933b23b9 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 4b22879012..0ddd3c0248 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 dd40a0c878..ec3bc6b798 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 13adf0cb60..bc1189cbe7 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 1745109a4b..892b47c82c 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 295bff1365..61ab4cf107 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 12bbbbfd1b..558a84e1cf 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 45a033fa99..ac73a54a68 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 c2b15ca9ff..1aacb89bcd 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 01f7423541..01f649cdbe 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 e3c2f2fcf0..46059692a8 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 dbda4bb868..34a8abc9a1 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 1e793aefbf..748af6494e 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 8b166d7c6d..2bf96c08e2 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 b228a3806a..22334f5184 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 d6c99a83c3..c7281d41b3 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 701fda03fc..9da7a223f1 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 72981789d0..54e6d3339a 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 e638b653b8..e332aaaa3e 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 04af9bb4c7..0e7586d52a 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 3e02b7ae7d..f5ffb701d6 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 37e5c5bc33..947ecde5bd 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 cfdf208240..6b7b761ffd 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 77836f9423..791b61d8a1 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 0e3ce7955d..c380cde3c6 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 240a42dd71..d0a43f2f27 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 f3d6830fec..1b15347703 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 e0115dba1b..4910875baa 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 d61660efee..d091d70c5e 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 1864462d12..4a4ef0921a 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 7324bc006c..e2193d5b50 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 86a2c622cc..1a57838e3c 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 93cd59dce5..25e9acff3b 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 fb847c83f9..362390d3fd 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 186d0dfbcc..fc26e84fbd 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 dfb3d4de31..798ced0a87 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 ebb39fa196..bc9dd2d672 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 78425d80a6..8708115747 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 983b6fe10c..dc8ceb67ef 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 7657175490..89e1892f2b 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 9e4e5a26b1..c34a120c8a 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 3461b5ac49..9d1d93599b 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 62dff19f1e..252953cab8 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 20017619dc..cda1a77ef1 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 103a3e9aa1..d1af6cb536 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 9e94d40b1a..a7be1cab31 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 a4fc310de5..ff6e0fec5f 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 e0a6c6f015..aff37de6ae 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 cc02f20593..a8350f4527 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 d0795763bb..d0fb3363ec 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 4c64dcdc72..9df35f09a7 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 224cfd751f..2c148bcd79 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 c712d283ac..44aa7bb04b 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 131dec4511..ae6f4ae31f 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 319ff68a8b..70ee6a995a 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 61ff1d4649..625b6de507 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 1bab5e4936..f04f3b5272 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 288d45ba27..304251c81d 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 d8cad06034..781b53afdd 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 966911d5b9..21c9a1782a 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 3d354502f6..0920781569 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 9336e5e53d..29eeb64ae5 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 619f4712c4..c4c4d6ca20 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 1a0341dd4b..8fea9ce5d9 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 5cb6fef440..d9241487fd 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 9fdf8ed793..b8f16c69c1 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 617ce54f37..2290935013 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 a40ac252f3..f2c38b21cb 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 bc6ad4d0c8..eb944b36e5 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 7cd60a56e7..5728a20695 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 8fa41721ce..d7d3898dd6 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 480d1e6f38..00d53102bf 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 6e68a2eba6..1c27d34aa9 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 1f8ce44c0e..0ce5ee6c1d 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 25f73c157d..a697284f9a 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 edecbf6208..8ff29629be 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 4e7b1480ac..e7a259422d 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 f29f28e0c9..18b8f232c6 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 77d2e58e48..90fc5ce8ab 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 aeb13a0fa8..93b4d30afe 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 c3f74765b5..ccb7804cde 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 0e76a5c991..461324fedc 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 95ff28fefe..55e7eced04 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 38f3c48ed1..50660e41c7 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 2dc85df4c1..03784f35d8 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 b85e576c65..86a5c4e478 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 b2391851dd..ea0e36467a 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 d6f17e015b..7df6f055e1 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 04a7a83a81..1434a74a9c 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 ab8eb83d58..95a19aec6a 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 f08f7216b9..55f39702b8 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 65981674b0..f98c5d2ca1 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 7cac7a5a63..03559eafa8 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 b5027e2e3f..b97bf59a60 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 0000000000..778053c54e --- /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 d5f2774f18..6f9e68ca9b 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 7582e49acd..edab62b618 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 ed4594fc29..40e9490a8b 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 fa3d81ffe5..b419164e55 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 6c057e9a7a..1c96b121b1 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 7f3e66eb0e..f344e74619 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 e2147413b4..5d60b990b8 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 bb6a8bf06f..582b87035e 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 300f4e31c6..53a4cb302a 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 d00dbe3b53..33eb196d81 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 75243fba68..34906e1115 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 25ed10dfd2..dd95634859 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 88294fe6ae..587b52e66b 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 ccc836cf66..ec83d4a5b6 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 0000000000..a153c5568d --- /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 e8ebc6e372..1e1f03bc4f 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 9609c90c8a..be08635a29 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 1472f4ec1c..1e24291848 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 b3809fde34..a1dce59b0c 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 e352fab778..682aafe20d 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 792a68855f..bde7029816 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 841de84751..bafbe97094 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 3fa3bf0509..cdf7bf2232 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 112b4bb6e2..81dbedb567 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 dd8d9af2d3..476020e54e 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 694fc373b4..101c2c1630 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 adbeb57751..f709ed52ff 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 2003faf70b..b797bcd65e 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 a0a38d25f3..70de9bbd59 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 1fc9435708..1e84b29fd0 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 5debfd2f25..0d2a2a94d6 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 869e4aa0bc..87f476e764 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 64071b4541..c97313c968 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 bba4137a10..f54b4e775b 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 903d2c64ab..74134981e5 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 23afc5e5e7..4c20bac207 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 e67cc44e95..791b285c9d 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 d21dd8dfe0..2555c15f72 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 a263102093..791e04ec89 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 4744c9c801..af1d8fd617 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 a1b4196959..7352263609 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 40fe2d9c2d..e0339c186a 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 10af12bf36..7c49938817 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 d9026c2a34..89a117eebc 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 b67d49557a..9df8b2e481 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 88b44f6e9f..9b8d912a42 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 0de27a09b0..f3cfe8f06e 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 17ed31727a..b058ef5032 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 a3926f9b8a..ba1a5d2cdb 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 0000000000..156b9e40db --- /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 e9a2e4b362..5ae2372018 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 0cd2163f98..e5c307ce11 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 699d353fc6..0ba44814f2 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 c5c230fdb5..143c7fc6ac 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 0c4e643cef..a9aae70d5a 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 b63d31af36..351c60e052 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 9cc8632737..b7c307bb36 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 9c9972ddb7..e52a18015c 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 9788d609a6..340fe88d89 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 1090077bde..6c64051a9f 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 cd66cb9caa..32225f6fdd 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 b55df9a13f..25eaf6a180 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 762c270fbe..e1c5df7c4e 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 8660c66ef0..c5982e7ce6 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 5f5ac31616..532ac0f6c9 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 f5ac8be78d..f02a09f9f8 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 ca69450e38..848bba3995 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 1f15f6fa39..d13b58ceeb 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 a61f2c6165..708ce3c6fc 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 a5d7b12ed5..33818215d4 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 42e59cb839..dd96a9783b 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 178074b5e6..c1068ca363 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 b16d445914..c64bd1c029 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 e4da7366d5..64f515a49b 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 7c69fcc21d..dd1c1e5738 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 6dbd8b585d..a4e7f70792 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 3980b90380..8db7f86226 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 3224606020..2128d2b14e 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 2ca81404b3..9c3239a73f 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 3148581acd..efa01ff36b 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 355faf9a3c..212d141c69 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 d50edaf87e..5cb45471f5 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 4483f55002..b25b940a60 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 a8e01c73f5..58fc3ba39b 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 b6cdc68df1..ecf8677d9d 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 c49797785e..489a80c884 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 60ad65fbcb..17fa9e6d78 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 5a23cc12a0..fac8d4b2ec 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 337d58c621..e4f8900083 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 6489856729..a448ef8679 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 f4540a5795..6a373f3a67 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 4618798024..281b313991 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 cdb7d1cc6a..c5abae0aed 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 d020a954d2..45752e24c4 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 1925672e8a..0c855c5afb 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 6d638e577b..b3baf78f46 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 1771c97205..0b4d33d122 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 f65dbed02f..c2ee139f5e 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 1911163004..e1a1472f1e 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 a8c920db78..ecea2493fa 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 164c401e61..07fe93c198 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 ac8ed23f7f..4f263a55e2 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 affbbc8f8c..26c7647e84 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 5fee1f1817..a4034d43f4 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 3177adea29..c7b3d1e61b 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 06bdbb5e47..6e562f9681 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 da91fe052f..c777aed35a 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 6024dbff04..6a87201e84 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 b656434d0e..43d9b7b134 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 98f097fbc8..74904d322f 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 1fb7f49764..9704013507 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 1eccdfd103..a3faed2015 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 e853b7a053..e7138555e1 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 a380079028..740fd0771c 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 ecba913b2e..7a1c18be94 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 f006f01fd3..9704aa5ffd 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 b29e082118..ebddce8361 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 4052e61a82..5f9c5fa87b 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 b35ce13170..da488ac6bf 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 7a7b95c32e..a708187338 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 31f57bb2a0..6c222b4d01 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 28f906499c..f4540aaa5c 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 19955ab04d..234aff6979 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', () => {