diff --git a/frontend/craco.config.js b/frontend/craco.config.js new file mode 100644 index 0000000000..c66036ddbd --- /dev/null +++ b/frontend/craco.config.js @@ -0,0 +1,28 @@ +module.exports = { + webpack: { + configure: (webpackConfig, { env, paths }) => { + // Fix CRA #11770 + const rules = webpackConfig.module.rules; + for (const rule of rules) { + if (Object.hasOwn(rule, 'oneOf')) { + rule.oneOf.filter((currentValue, index, arr) => { + const toRemove = + currentValue.test instanceof RegExp && currentValue.test.test('something.svg'); + if (toRemove) { + arr.splice(index, 1); + } + return toRemove; + }); + rule.oneOf.push({ + test: /\.svg$/i, + issuer: { + and: [/\.(ts|tsx|js|jsx|md|mdx)$/], + }, + type: 'asset', + }); + } + } + return webpackConfig; + }, + }, +}; diff --git a/frontend/package.json b/frontend/package.json index 400ff0d483..ec4a43ced1 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -4,25 +4,22 @@ "license": "BSD-2-Clause", "private": false, "dependencies": { - "@formatjs/intl-locale": "^3.3.2", - "@formatjs/intl-pluralrules": "^5.2.4", - "@formatjs/intl-relativetimeformat": "^11.2.4", - "@formatjs/macro": "^0.2.8", "@hotosm/id": "^2.21.1", "@hotosm/underpass-ui": "^0.0.4", "@hotosm/iso-countries-languages": "^1.1.2", - "@mapbox/mapbox-gl-draw": "^1.4.1", - "@mapbox/mapbox-gl-geocoder": "^5.0.1", + "@mapbox/mapbox-gl-draw": "^1.4.3", + "@mapbox/mapbox-gl-geocoder": "^5.0.2", "@mapbox/mapbox-gl-language": "^0.10.1", - "@placemarkio/geo-viewport": "^1.0.1", + "@placemarkio/geo-viewport": "^1.0.2", "@rapideditor/rapid": "^2.1.1", - "@sentry/react": "^7.60.1", - "@tmcw/togeojson": "^4.7.0", + "@sentry/react": "^7.102.0", "@tanstack/react-query": "^4.29.7", "@tanstack/react-query-devtools": "^4.29.7", + "@tmcw/togeojson": "^5.8.1", "@turf/area": "^6.5.0", "@turf/bbox": "^6.5.0", "@turf/bbox-polygon": "^6.5.0", + "@turf/centroid": "^6.5.0", "@turf/helpers": "^6.5.0", "@turf/intersect": "^6.5.0", "@turf/line-to-polygon": "^6.5.0", @@ -30,27 +27,28 @@ "@turf/truncate": "^6.5.0", "@uiw/react-md-editor": "^3.22.0", "axios": "^1.6.7", - "chart.js": "^3.7.1", + "chart.js": "^4.4.1", "chartjs-adapter-date-fns": "^3.0.0", "date-fns": "^2.30.0", - "dompurify": "^2.4.5", + "dompurify": "^3.0.9", "downshift-hooks": "^0.8.1", - "final-form": "^4.20.9", + "final-form": "^4.20.10", "fromentries": "^1.3.2", - "humanize-duration": "^3.28.0", + "humanize-duration": "^3.31.0", "mapbox-gl": "^1.13.3", "mapbox-gl-draw-rectangle-mode": "^1.0.4", "marked": "^4.3.0", "osmtogeojson": "^3.0.0-beta.5", - "query-string": "^7.1.3", - "react": "^17.0.2", - "react-accessible-accordion": "^4.0.0", + "prop-types": "^15.8.1", + "query-string": "^8.2.0", + "react": "^18.2.0", + "react-accessible-accordion": "^5.0.0", "react-calendar-heatmap": "^1.9.0", - "react-chartjs-2": "^4.1.0", + "react-chartjs-2": "^5.2.0", "react-datepicker": "^4.14.1", - "react-dom": "^17.0.2", + "react-dom": "^18.2.0", "react-dropzone": "^14.2.3", - "react-error-boundary": "^4.0.4", + "react-error-boundary": "^4.0.12", "react-final-form": "^6.5.9", "react-hot-toast": "^2.4.1", "react-intl": "^6.4.4", @@ -58,17 +56,16 @@ "react-placeholder": "^4.1.0", "react-redux": "^8.1.1", "react-router-dom": "^6.13.0", - "react-scripts": "^4.0.3", "react-select": "^5.7.3", - "react-tooltip": "^4.2.21", - "reactjs-popup": "^2.0.5", + "react-tooltip": "^5.26.3", + "reactjs-popup": "^2.0.6", "redux": "^4.2.1", "redux-persist": "^6.0.0", "redux-thunk": "^2.4.2", - "sass": "^1.63.5", + "sass": "^1.71.0", "short-number": "^1.0.7", "shpjs": "^4.0.4", - "slug": "^8.2.2", + "slug": "^8.2.3", "tachyons": "^4.12.0", "tributejs": "^5.1.3", "use-query-params": "^2.2.1", @@ -87,11 +84,11 @@ "patch-id": "bash -c \"cp patch/imagery.min.json public/static/id/data\"", "patch-rapid": "bash -c \"cp patch/rapid-imagery.min.json public/static/rapid/data/imagery.min.json\"", "preparation": "bash -c \"if (test -a ../tasking-manager.env); then grep -hs ^ ../tasking-manager.env .env.expand > .env; else cp .env.expand .env; fi\"", - "start": "npm run preparation && npm run copy-static && npm run patch-id && npm run patch-rapid && react-scripts start", - "build": "npm run preparation && npm run update-static && npm run patch-id && npm run patch-rapid && react-scripts build && npm run sentry:sourcemaps", + "start": "npm run preparation && npm run copy-static && npm run patch-id && npm run patch-rapid && craco start", + "build": "npm run preparation && npm run update-static && npm run patch-id && npm run patch-rapid && craco build && npm run sentry:sourcemaps", "prettier": "prettier --write 'src/**/*.js'", "lint": "eslint src", - "test": "npm run lint && react-scripts test --env=jsdom", + "test": "npm run lint && craco test --env=jsdom", "coverage": "npm run test -- --coverage --watchAll=false", "analyze": "source-map-explorer 'build/static/js/*.js'", "sentry:sourcemaps": "if sentry-cli info; then sentry-cli sourcemaps inject --org humanitarian-openstreetmap-tea --project taskingmanager-frontend ./build && sentry-cli sourcemaps upload --org humanitarian-openstreetmap-tea --project taskingmanager-frontend ./build; fi" @@ -113,20 +110,27 @@ }, "devDependencies": { "@babel/plugin-proposal-private-property-in-object": "^7.21.11", - "@sentry/cli": "^2.20.5", + "@craco/craco": "^7.1.0", + "@sentry/cli": "^2.28.6", "@tanstack/eslint-plugin-query": "^4.29.8", "@testing-library/jest-dom": "^5.16.5", - "@testing-library/react": "^12.1.5", - "@testing-library/react-hooks": "^8.0.1", + "@testing-library/react": "^14.2.1", "@testing-library/user-event": "^14.4.3", "combine-react-intl-messages": "^4.0.0", - "jest-canvas-mock": "^2.5.1", - "msw": "0.49.2", + "jest-canvas-mock": "^2.5.2", + "msw": "^1.3.2", "prettier": "^2.8.8", + "react-scripts": "^5.0.1", "react-select-event": "^5.5.1", - "react-test-renderer": "^17.0.2", + "react-test-renderer": "^18.2.0", "source-map-explorer": "^2.5.3" }, + "resolutions": { + "dom-accessibility-api": "0.5.14" + }, + "overrides": { + "dom-accessibility-api": "0.5.14" + }, "jest": { "coverageReporters": [ "html" diff --git a/frontend/src/App.js b/frontend/src/App.js index 6043b0deb3..b79667f555 100644 --- a/frontend/src/App.js +++ b/frontend/src/App.js @@ -1,10 +1,10 @@ -import React, { Suspense, useEffect } from 'react'; +import { Suspense, useEffect } from 'react'; import { RouterProvider } from 'react-router-dom'; import { Toaster } from 'react-hot-toast'; import ReactPlaceholder from 'react-placeholder'; import { useMeta } from 'react-meta-elements'; import { useSelector } from 'react-redux'; -import * as Sentry from '@sentry/react'; +import { ErrorBoundary } from '@sentry/react'; import { QueryClientProvider, QueryClient } from '@tanstack/react-query'; import { ReactQueryDevtools } from '@tanstack/react-query-devtools'; @@ -49,7 +49,7 @@ const App = () => { }, []); return ( - }> + }> {isLoading ? ( ) : ( @@ -77,7 +77,7 @@ const App = () => { /> )} - + ); }; diff --git a/frontend/src/api/stats.js b/frontend/src/api/stats.js index e16661df89..de26ad87ab 100644 --- a/frontend/src/api/stats.js +++ b/frontend/src/api/stats.js @@ -87,7 +87,7 @@ export const useUserOsmStatsQuery = (id) => { export const useOsmStatsMetadataQuery = () => { const fetchOsmStatsMetadata = () => { - return fetchExternalJSONAPI(`${OHSOME_STATS_BASE_URL}/metadata`, true); + return fetchExternalJSONAPI(`${OHSOME_STATS_BASE_URL}/metadata`); }; return useQuery({ diff --git a/frontend/src/assets/styles/_extra.scss b/frontend/src/assets/styles/_extra.scss index 171413e00f..3ec39b8bcc 100644 --- a/frontend/src/assets/styles/_extra.scss +++ b/frontend/src/assets/styles/_extra.scss @@ -309,7 +309,7 @@ a[href="https://www.mapbox.com/map-feedback/"] object-fit: contain; } -#shareProject { +#shareProjectTooltip { background-color: $white; color: $blue-dark; border-color: $blue-dark; diff --git a/frontend/src/components/banner/index.js b/frontend/src/components/banner/index.js index fd63a5f3bd..db2ad57eb7 100644 --- a/frontend/src/components/banner/index.js +++ b/frontend/src/components/banner/index.js @@ -1,4 +1,3 @@ -import React from 'react'; import { FormattedMessage } from 'react-intl'; import messages from './messages'; diff --git a/frontend/src/components/banner/topBanner.js b/frontend/src/components/banner/topBanner.js index 6dfcab64c8..7cc1bcf895 100644 --- a/frontend/src/components/banner/topBanner.js +++ b/frontend/src/components/banner/topBanner.js @@ -1,4 +1,3 @@ -import React from 'react'; import { useLocation } from 'react-router-dom'; import { useFetchWithAbort } from '../../hooks/UseFetch'; import { htmlFromMarkdown } from '../../utils/htmlFromMarkdown'; diff --git a/frontend/src/components/basemapMenu.js b/frontend/src/components/basemapMenu.js index 3612791a73..d9ce7ae545 100644 --- a/frontend/src/components/basemapMenu.js +++ b/frontend/src/components/basemapMenu.js @@ -1,4 +1,4 @@ -import React, { useState } from 'react'; +import { useState } from 'react'; import { MAPBOX_TOKEN, BASEMAP_OPTIONS } from '../config'; diff --git a/frontend/src/components/checkCircle.js b/frontend/src/components/checkCircle.js index 1152246889..16a097decd 100644 --- a/frontend/src/components/checkCircle.js +++ b/frontend/src/components/checkCircle.js @@ -1,4 +1,3 @@ -import React from 'react'; import { CheckIcon } from './svgIcons'; export const CheckCircle = ({ className }: Object) => ( diff --git a/frontend/src/components/comments/commentInput.js b/frontend/src/components/comments/commentInput.js index d5ad00ee8b..96be48c554 100644 --- a/frontend/src/components/comments/commentInput.js +++ b/frontend/src/components/comments/commentInput.js @@ -1,8 +1,8 @@ -import React, { useRef, useEffect, useState } from 'react'; +import { useRef, useEffect, useState } from 'react'; import { useSelector } from 'react-redux'; import MDEditor from '@uiw/react-md-editor'; import Tribute from 'tributejs'; -import { FormattedMessage } from 'react-intl'; +import { FormattedMessage, useIntl } from 'react-intl'; import { useDropzone } from 'react-dropzone'; import 'tributejs/tribute.css'; @@ -18,7 +18,7 @@ import { iconConfig } from './editorIconConfig'; import messages from './messages'; import { CurrentUserAvatar } from '../user/avatar'; -export const CommentInputField = ({ +function CommentInputField({ comment, setComment, contributors, @@ -29,7 +29,7 @@ export const CommentInputField = ({ isShowUserPicture = false, placeholderMsg = messages.leaveAComment, markdownTextareaProps = {}, -}: Object) => { +}: Object) { const token = useSelector((state) => state.auth.token); const textareaRef = useRef(); const isBundle = useRef(false); @@ -115,26 +115,22 @@ export const CommentInputField = ({ )}
- - {(val) => ( - iconConfig[key])} - extraCommands={[]} - height={200} - value={comment} - onChange={setComment} - textareaProps={{ - ...getInputProps(), - spellCheck: 'true', - placeholder: val, - ...markdownTextareaProps, - }} - defaultTabEnable - /> - )} - + iconConfig[key])} + extraCommands={[]} + height={200} + value={comment} + onChange={setComment} + textareaProps={{ + ...getInputProps(), + spellCheck: 'true', + placeholder: useIntl().formatMessage(placeholderMsg), + ...markdownTextareaProps, + }} + defaultTabEnable + />
); -}; +} + +export default CommentInputField; diff --git a/frontend/src/components/comments/editorIconConfig.js b/frontend/src/components/comments/editorIconConfig.js index a9dfb6e651..7b3178a89a 100644 --- a/frontend/src/components/comments/editorIconConfig.js +++ b/frontend/src/components/comments/editorIconConfig.js @@ -1,10 +1,18 @@ -import { commands, selectWord } from '@uiw/react-md-editor'; +import { + bold, + italic, + quote, + link, + unorderedListCommand, + selectWord, + orderedListCommand, +} from '@uiw/react-md-editor'; const ICON_SIZE = 14; export const iconConfig = { bold: { - ...commands.bold, + ...bold, icon: ( { // Component that receives the rejected files from Dropzone return ( diff --git a/frontend/src/components/comments/hashtagPaste.js b/frontend/src/components/comments/hashtagPaste.js index 649702dd81..63eef64fc3 100644 --- a/frontend/src/components/comments/hashtagPaste.js +++ b/frontend/src/components/comments/hashtagPaste.js @@ -1,4 +1,3 @@ -import React from 'react'; import { useIntl } from 'react-intl'; import messages from './messages'; diff --git a/frontend/src/components/comments/tests/fileRejections.test.js b/frontend/src/components/comments/tests/fileRejections.test.js index 7843e7e6eb..0391f7cba8 100644 --- a/frontend/src/components/comments/tests/fileRejections.test.js +++ b/frontend/src/components/comments/tests/fileRejections.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { render, screen } from '@testing-library/react'; import '@testing-library/jest-dom'; diff --git a/frontend/src/components/comments/tests/hashtagPaste.test.js b/frontend/src/components/comments/tests/hashtagPaste.test.js index 503a5750dc..af8bfc9f20 100644 --- a/frontend/src/components/comments/tests/hashtagPaste.test.js +++ b/frontend/src/components/comments/tests/hashtagPaste.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { render, screen } from '@testing-library/react'; import '@testing-library/jest-dom'; diff --git a/frontend/src/components/comments/tests/uploadStatus.test.js b/frontend/src/components/comments/tests/uploadStatus.test.js index 9102eafe38..a86ad04a04 100644 --- a/frontend/src/components/comments/tests/uploadStatus.test.js +++ b/frontend/src/components/comments/tests/uploadStatus.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { render, screen } from '@testing-library/react'; import '@testing-library/jest-dom'; diff --git a/frontend/src/components/comments/uploadStatus.js b/frontend/src/components/comments/uploadStatus.js index ce012adb81..a6c5448463 100644 --- a/frontend/src/components/comments/uploadStatus.js +++ b/frontend/src/components/comments/uploadStatus.js @@ -1,4 +1,3 @@ -import React from 'react'; import { FormattedMessage } from 'react-intl'; import messages from './messages'; diff --git a/frontend/src/components/contributions/myProjectsDropdown.js b/frontend/src/components/contributions/myProjectsDropdown.js index b6a0ad39b4..36c9afd24e 100644 --- a/frontend/src/components/contributions/myProjectsDropdown.js +++ b/frontend/src/components/contributions/myProjectsDropdown.js @@ -1,4 +1,3 @@ -import React from 'react'; import { useSelector } from 'react-redux'; import Select from 'react-select'; import { FormattedMessage } from 'react-intl'; diff --git a/frontend/src/components/contributions/myTasksNav.js b/frontend/src/components/contributions/myTasksNav.js index dfc9cec1b7..2e300d1dd2 100644 --- a/frontend/src/components/contributions/myTasksNav.js +++ b/frontend/src/components/contributions/myTasksNav.js @@ -1,4 +1,3 @@ -import React from 'react'; import { Link } from 'react-router-dom'; import { FormattedMessage } from 'react-intl'; diff --git a/frontend/src/components/contributions/myTasksOrderDropdown.js b/frontend/src/components/contributions/myTasksOrderDropdown.js index a459a6866e..4e0db9f38f 100644 --- a/frontend/src/components/contributions/myTasksOrderDropdown.js +++ b/frontend/src/components/contributions/myTasksOrderDropdown.js @@ -1,4 +1,3 @@ -import React from 'react'; import { FormattedMessage } from 'react-intl'; import { Dropdown } from '../dropdown'; import messages from './messages'; diff --git a/frontend/src/components/contributions/taskCard.js b/frontend/src/components/contributions/taskCard.js index 1bd955ca78..b5e811bd86 100644 --- a/frontend/src/components/contributions/taskCard.js +++ b/frontend/src/components/contributions/taskCard.js @@ -1,4 +1,4 @@ -import React, { useState } from 'react'; +import { useState } from 'react'; import { Link } from 'react-router-dom'; import Popup from 'reactjs-popup'; import { FormattedMessage, useIntl } from 'react-intl'; diff --git a/frontend/src/components/contributions/taskResults.js b/frontend/src/components/contributions/taskResults.js index 8c72706844..8c6aa61362 100644 --- a/frontend/src/components/contributions/taskResults.js +++ b/frontend/src/components/contributions/taskResults.js @@ -1,4 +1,3 @@ -import React from 'react'; import { FormattedMessage, FormattedNumber } from 'react-intl'; import ReactPlaceholder from 'react-placeholder'; import 'react-placeholder/lib/reactPlaceholder.css'; diff --git a/frontend/src/components/contributions/tests/taskCard.test.js b/frontend/src/components/contributions/tests/taskCard.test.js index 3b97298d93..cc3f3de1d7 100644 --- a/frontend/src/components/contributions/tests/taskCard.test.js +++ b/frontend/src/components/contributions/tests/taskCard.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { screen } from '@testing-library/react'; import '@testing-library/jest-dom'; diff --git a/frontend/src/components/deleteModal/index.js b/frontend/src/components/deleteModal/index.js index 83028e9e42..cd36fefea9 100644 --- a/frontend/src/components/deleteModal/index.js +++ b/frontend/src/components/deleteModal/index.js @@ -1,4 +1,4 @@ -import React, { useState, useRef } from 'react'; +import { forwardRef, useState, useRef } from 'react'; import { useSelector } from 'react-redux'; import { useNavigate } from 'react-router-dom'; import { FormattedMessage } from 'react-intl'; @@ -10,6 +10,8 @@ import { DeleteButton } from '../teamsAndOrgs/management'; import { Button } from '../button'; import { AlertIcon } from '../svgIcons'; +const DeleteTrigger = forwardRef((props, ref) => ); + export function DeleteModal({ id, name, type, className, endpointURL, onDelete }: Object) { const navigate = useNavigate(); const modalRef = useRef(); @@ -46,7 +48,7 @@ export function DeleteModal({ id, name, type, className, endpointURL, onDelete } + } modal closeOnDocumentClick diff --git a/frontend/src/components/deleteModal/tests/index.test.js b/frontend/src/components/deleteModal/tests/index.test.js index b1398fb945..7720764831 100644 --- a/frontend/src/components/deleteModal/tests/index.test.js +++ b/frontend/src/components/deleteModal/tests/index.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { screen, waitFor, within } from '@testing-library/react'; import '@testing-library/jest-dom'; diff --git a/frontend/src/components/dropdown.js b/frontend/src/components/dropdown.js index 02dd0f87b4..45a4c61fe5 100644 --- a/frontend/src/components/dropdown.js +++ b/frontend/src/components/dropdown.js @@ -1,9 +1,9 @@ -import React, { useEffect, useState } from 'react'; +import { createRef, forwardRef, useEffect, useState } from 'react'; import { useNavigate } from 'react-router-dom'; import { ChevronDownIcon, CheckIcon } from './svgIcons'; import { CustomButton } from './button'; -const DropdownContent = React.forwardRef((props, ref) => { +const DropdownContent = forwardRef((props, ref) => { const navigate = useNavigate(); const isActive = (obj) => { return props.value === obj.value; @@ -119,8 +119,8 @@ const DropdownContent = React.forwardRef((props, ref) => { export function Dropdown(props) { const [display, setDisplay] = useState(false); - const contentRef = React.createRef(); - const buttonRef = React.createRef(); + const contentRef = createRef(); + const buttonRef = createRef(); useEffect(() => { const handleClickOutside = (event) => { diff --git a/frontend/src/components/editor.js b/frontend/src/components/editor.js index 68d7ff29fe..e731b2459e 100644 --- a/frontend/src/components/editor.js +++ b/frontend/src/components/editor.js @@ -1,4 +1,4 @@ -import React, { useEffect, useState } from 'react'; +import { useEffect, useState } from 'react'; import { useSelector, useDispatch } from 'react-redux'; import { useIntl } from 'react-intl'; import { gpx } from '@tmcw/togeojson'; diff --git a/frontend/src/components/footer/index.js b/frontend/src/components/footer/index.js index 8d16a86ebf..18baaf8298 100644 --- a/frontend/src/components/footer/index.js +++ b/frontend/src/components/footer/index.js @@ -1,4 +1,4 @@ -import React, { Fragment } from 'react'; +import { Fragment } from 'react'; import { useSelector } from 'react-redux'; import { Link, matchRoutes, useLocation } from 'react-router-dom'; import { FormattedMessage } from 'react-intl'; diff --git a/frontend/src/components/footer/styles.scss b/frontend/src/components/footer/styles.scss index 1768150765..3c8b253522 100644 --- a/frontend/src/components/footer/styles.scss +++ b/frontend/src/components/footer/styles.scss @@ -32,4 +32,13 @@ .socials { gap: .75rem -} \ No newline at end of file +} + +.react-tooltip#shareProjectTooltip { + border: 1px solid #2c3038; +} + +.react-tooltip__place-top#shareProjectTooltip > .react-tooltip-arrow { + border-bottom: 1px solid #2c3038; + border-right: 1px solid #2c3038; +} diff --git a/frontend/src/components/formInputs.js b/frontend/src/components/formInputs.js index e9b7157224..fa4a390ed2 100644 --- a/frontend/src/components/formInputs.js +++ b/frontend/src/components/formInputs.js @@ -1,4 +1,4 @@ -import React, { useEffect, useState, useRef } from 'react'; +import { useEffect, useState, useRef } from 'react'; import { useSelector } from 'react-redux'; import { Field } from 'react-final-form'; import Select from 'react-select'; diff --git a/frontend/src/components/header/NavLink.js b/frontend/src/components/header/NavLink.js index bbc4d2edd3..2bde7df952 100644 --- a/frontend/src/components/header/NavLink.js +++ b/frontend/src/components/header/NavLink.js @@ -1,4 +1,3 @@ -import React from 'react'; import { Link, useMatch } from 'react-router-dom'; export const TopNavLink = (props) => { diff --git a/frontend/src/components/header/burgerMenu.js b/frontend/src/components/header/burgerMenu.js index 82f417dac8..fe326ec014 100644 --- a/frontend/src/components/header/burgerMenu.js +++ b/frontend/src/components/header/burgerMenu.js @@ -1,8 +1,8 @@ -import React from 'react'; +import { forwardRef } from 'react'; import { MenuIcon, CloseIcon } from '../svgIcons'; -export const BurgerMenu = React.forwardRef((props, ref) => ( +export const BurgerMenu = forwardRef((props, ref) => ( - {alternativeSignUpText ? ( - - ) : ( - - )} - + } modal closeOnDocumentClick diff --git a/frontend/src/components/header/notificationBell.js b/frontend/src/components/header/notificationBell.js index cccbb3ac9b..0386f90c46 100644 --- a/frontend/src/components/header/notificationBell.js +++ b/frontend/src/components/header/notificationBell.js @@ -1,4 +1,4 @@ -import React, { useState, useEffect, useRef, useCallback } from 'react'; +import { useState, useEffect, useRef, useCallback } from 'react'; import { useSelector, useDispatch } from 'react-redux'; import { TopNavLink } from './NavLink'; diff --git a/frontend/src/components/header/signUp.js b/frontend/src/components/header/signUp.js index f6cbad843f..d56f9b1167 100644 --- a/frontend/src/components/header/signUp.js +++ b/frontend/src/components/header/signUp.js @@ -1,4 +1,4 @@ -import React, { useState } from 'react'; +import { useState } from 'react'; import { FormattedMessage } from 'react-intl'; import messages from './messages'; @@ -8,7 +8,7 @@ import { registerUser } from '../../store/actions/user'; import { store } from '../../store'; import { createLoginWindow } from '../../utils/login'; import { ORG_PRIVACY_POLICY_URL, OSM_REGISTER_URL } from '../../config'; -import * as safeStorage from '../../utils/safe_storage'; +import { setItem } from '../../utils/safe_storage'; export const LoginModal = ({ step, login }) => { return ( @@ -51,8 +51,8 @@ export const ProceedOSM = ({ data, step, setStep, login }) => { const handleLogin = () => { login(); - safeStorage.setItem('email_address', data.email); - safeStorage.setItem('name', data.name); + setItem('email_address', data.email); + setItem('name', data.name); }; return ( @@ -103,8 +103,8 @@ const SignupForm = ({ data, setData, step, setStep }) => { const registerPromise = store.dispatch(registerUser(formData)); registerPromise.then((res) => { if (res.success === true) { - safeStorage.setItem('email_address', data.email); - safeStorage.setItem('name', data.name); + setItem('email_address', data.email); + setItem('name', data.name); setStep({ number: 2, errMessage: null }); } else { setStep({ number: 1, errMessage: res.details }); diff --git a/frontend/src/components/header/tests/authButtons.test.js b/frontend/src/components/header/tests/authButtons.test.js index 4fbfc62cb8..1f6111a5af 100644 --- a/frontend/src/components/header/tests/authButtons.test.js +++ b/frontend/src/components/header/tests/authButtons.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { render, screen } from '@testing-library/react'; import '@testing-library/jest-dom'; diff --git a/frontend/src/components/header/topBar.js b/frontend/src/components/header/topBar.js index e24d344e09..d69bdc86cc 100644 --- a/frontend/src/components/header/topBar.js +++ b/frontend/src/components/header/topBar.js @@ -1,5 +1,3 @@ -import React from 'react'; - export function TopBar({ pageName }: Object) { return (
diff --git a/frontend/src/components/header/updateDialog.js b/frontend/src/components/header/updateDialog.js index 58af091ae4..63a8f54940 100644 --- a/frontend/src/components/header/updateDialog.js +++ b/frontend/src/components/header/updateDialog.js @@ -1,4 +1,4 @@ -import React, { useState, useEffect } from 'react'; +import { useState, useEffect } from 'react'; import { useLocation } from 'react-router-dom'; import { FormattedMessage } from 'react-intl'; diff --git a/frontend/src/components/header/updateEmail.js b/frontend/src/components/header/updateEmail.js index 811b167f26..6eb44f3eaf 100644 --- a/frontend/src/components/header/updateEmail.js +++ b/frontend/src/components/header/updateEmail.js @@ -1,6 +1,6 @@ -import React, { useState } from 'react'; +import { useState } from 'react'; import { useSelector, useDispatch } from 'react-redux'; -import PropTypes from 'prop-types'; +import { func } from 'prop-types'; import { FormattedMessage } from 'react-intl'; import messages from './messages'; @@ -83,5 +83,5 @@ export const UpdateEmail = ({ closeModal }) => { }; UpdateEmail.propTypes = { - closeModal: PropTypes.func.isRequired, + closeModal: func.isRequired, }; diff --git a/frontend/src/components/homepage/contactForm.js b/frontend/src/components/homepage/contactForm.js index e0ce90f255..95281b5ead 100644 --- a/frontend/src/components/homepage/contactForm.js +++ b/frontend/src/components/homepage/contactForm.js @@ -1,4 +1,3 @@ -import React from 'react'; import { Form, Field } from 'react-final-form'; import { FormattedMessage } from 'react-intl'; diff --git a/frontend/src/components/homepage/featuredProjects.js b/frontend/src/components/homepage/featuredProjects.js index 798beab859..9791d51a74 100644 --- a/frontend/src/components/homepage/featuredProjects.js +++ b/frontend/src/components/homepage/featuredProjects.js @@ -1,11 +1,10 @@ -import React from 'react'; import { FormattedMessage } from 'react-intl'; import ReactPlaceholder from 'react-placeholder'; import { nCardPlaceholders } from '../projectCard/nCardPlaceholder'; import 'react-placeholder/lib/reactPlaceholder.css'; import { RightIcon, LeftIcon } from '../svgIcons'; -import { ProjectCard } from '../../components/projectCard/projectCard'; +import { ProjectCard } from '../projectCard/projectCard'; import messages from './messages'; diff --git a/frontend/src/components/homepage/jumbotron.js b/frontend/src/components/homepage/jumbotron.js index 61ada5ad3d..ac7066646b 100644 --- a/frontend/src/components/homepage/jumbotron.js +++ b/frontend/src/components/homepage/jumbotron.js @@ -1,4 +1,4 @@ -import React, { useLayoutEffect, useState } from 'react'; +import { useLayoutEffect, useState } from 'react'; import { useSelector } from 'react-redux'; import { Link } from 'react-router-dom'; import Popup from 'reactjs-popup'; diff --git a/frontend/src/components/homepage/mappingFlow.js b/frontend/src/components/homepage/mappingFlow.js index 8300a0a47c..261b58bb44 100644 --- a/frontend/src/components/homepage/mappingFlow.js +++ b/frontend/src/components/homepage/mappingFlow.js @@ -1,4 +1,3 @@ -import React from 'react'; import { FormattedMessage, FormattedNumber } from 'react-intl'; import messages from './messages'; diff --git a/frontend/src/components/homepage/testimonials.js b/frontend/src/components/homepage/testimonials.js index 121c603519..9ccda871f2 100644 --- a/frontend/src/components/homepage/testimonials.js +++ b/frontend/src/components/homepage/testimonials.js @@ -1,7 +1,7 @@ -import React from 'react'; import { FormattedMessage } from 'react-intl'; import messages from './messages'; +import IfrcImage from '../../assets/img/testimonials/ifrc.jpg'; // import {RightIcon, LeftIcon} from '../../svgIcons'; export function Testimonials() { @@ -11,7 +11,7 @@ export function Testimonials() { bio: messages.ifrcBio, citation: messages.ifrcCitation, cssCode: 'ifrc', - image: '.../../images/ifrc.png', + image: IfrcImage, }, ]; @@ -30,11 +30,7 @@ export function Testimonials() {
{/*
*/}
- {person.name} + {person.name}

diff --git a/frontend/src/components/homepage/tests/featuredProjects.test.js b/frontend/src/components/homepage/tests/featuredProjects.test.js index 504d176a83..5a7635a7d3 100644 --- a/frontend/src/components/homepage/tests/featuredProjects.test.js +++ b/frontend/src/components/homepage/tests/featuredProjects.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { screen, waitFor } from '@testing-library/react'; import '@testing-library/jest-dom'; diff --git a/frontend/src/components/homepage/whoIsMapping.js b/frontend/src/components/homepage/whoIsMapping.js index 9740d9885b..719b3f4045 100644 --- a/frontend/src/components/homepage/whoIsMapping.js +++ b/frontend/src/components/homepage/whoIsMapping.js @@ -1,4 +1,3 @@ -import React from 'react'; import { useNavigate } from 'react-router-dom'; import { FormattedMessage } from 'react-intl'; diff --git a/frontend/src/components/horizontalScroll/index.js b/frontend/src/components/horizontalScroll/index.js index f8487b601f..04216b2035 100644 --- a/frontend/src/components/horizontalScroll/index.js +++ b/frontend/src/components/horizontalScroll/index.js @@ -1,4 +1,4 @@ -import React, { useState, useEffect } from 'react'; +import { useState, useEffect } from 'react'; import { ChevronRightIcon } from '../svgIcons'; import { useWindowSize } from '../../hooks/UseWindowSize'; diff --git a/frontend/src/components/interests/index.js b/frontend/src/components/interests/index.js index 0172a90d87..b0227f8915 100644 --- a/frontend/src/components/interests/index.js +++ b/frontend/src/components/interests/index.js @@ -1,4 +1,4 @@ -import React, { useState } from 'react'; +import { useState } from 'react'; import { Link } from 'react-router-dom'; import { Form, Field } from 'react-final-form'; import { FormattedMessage } from 'react-intl'; diff --git a/frontend/src/components/licenses/index.js b/frontend/src/components/licenses/index.js index f905367f95..7ec1db9981 100644 --- a/frontend/src/components/licenses/index.js +++ b/frontend/src/components/licenses/index.js @@ -1,4 +1,4 @@ -import React, { useState } from 'react'; +import { useState } from 'react'; import { Link } from 'react-router-dom'; import { Form, Field } from 'react-final-form'; import { FormattedMessage } from 'react-intl'; diff --git a/frontend/src/components/licenses/licensesPlaceholder.js b/frontend/src/components/licenses/licensesPlaceholder.js index 2d53f92def..743e8f9568 100644 --- a/frontend/src/components/licenses/licensesPlaceholder.js +++ b/frontend/src/components/licenses/licensesPlaceholder.js @@ -1,4 +1,3 @@ -import React from 'react'; import { TextRow } from 'react-placeholder/lib/placeholders'; import { CopyrightIcon } from '../svgIcons'; diff --git a/frontend/src/components/licenses/tests/licenses.test.js b/frontend/src/components/licenses/tests/licenses.test.js index 105469335b..6019975536 100644 --- a/frontend/src/components/licenses/tests/licenses.test.js +++ b/frontend/src/components/licenses/tests/licenses.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { render, screen } from '@testing-library/react'; import '@testing-library/jest-dom'; diff --git a/frontend/src/components/localeSelect.js b/frontend/src/components/localeSelect.js index 478d02cd02..5c716723a9 100644 --- a/frontend/src/components/localeSelect.js +++ b/frontend/src/components/localeSelect.js @@ -1,4 +1,3 @@ -import React from 'react'; import { connect } from 'react-redux'; import { FormattedMessage } from 'react-intl'; import Select from 'react-select'; diff --git a/frontend/src/components/mappingLevel.js b/frontend/src/components/mappingLevel.js index baec3bdf08..cb45dede84 100644 --- a/frontend/src/components/mappingLevel.js +++ b/frontend/src/components/mappingLevel.js @@ -1,4 +1,3 @@ -import React from 'react'; import { FormattedMessage } from 'react-intl'; import messages from './messages'; diff --git a/frontend/src/components/mappingTypes.js b/frontend/src/components/mappingTypes.js index b9c951ec70..63b4cb5dad 100644 --- a/frontend/src/components/mappingTypes.js +++ b/frontend/src/components/mappingTypes.js @@ -1,4 +1,3 @@ -import React from 'react'; import { useIntl } from 'react-intl'; import messages from './messages'; diff --git a/frontend/src/components/menu.js b/frontend/src/components/menu.js index f7e7fcb6d6..7b259b050a 100644 --- a/frontend/src/components/menu.js +++ b/frontend/src/components/menu.js @@ -1,4 +1,3 @@ -import React from 'react'; import { useLocation, Link } from 'react-router-dom'; export function SectionMenu({ items }: Object) { diff --git a/frontend/src/components/notifications/inboxNav.js b/frontend/src/components/notifications/inboxNav.js index ba0a4bd671..bb57cb4da4 100644 --- a/frontend/src/components/notifications/inboxNav.js +++ b/frontend/src/components/notifications/inboxNav.js @@ -1,4 +1,3 @@ -import React from 'react'; import { useSelector } from 'react-redux'; import { Link } from 'react-router-dom'; import { FormattedMessage } from 'react-intl'; diff --git a/frontend/src/components/notifications/notificationBodyCard.js b/frontend/src/components/notifications/notificationBodyCard.js index 2b55f65dd2..27bc692e06 100644 --- a/frontend/src/components/notifications/notificationBodyCard.js +++ b/frontend/src/components/notifications/notificationBodyCard.js @@ -1,4 +1,4 @@ -import React, { useEffect } from 'react'; +import { useEffect } from 'react'; import { useSelector } from 'react-redux'; import ReactPlaceholder from 'react-placeholder'; import 'react-placeholder/lib/reactPlaceholder.css'; diff --git a/frontend/src/components/notifications/notificationCard.js b/frontend/src/components/notifications/notificationCard.js index 9d5e444348..b5e1486e7b 100644 --- a/frontend/src/components/notifications/notificationCard.js +++ b/frontend/src/components/notifications/notificationCard.js @@ -1,7 +1,7 @@ -import React, { useRef } from 'react'; +import { useRef } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import Popup from 'reactjs-popup'; -import ReactTooltip from 'react-tooltip'; +import { Tooltip } from 'react-tooltip'; import DOMPurify from 'dompurify'; import { FormattedMessage } from 'react-intl'; @@ -159,12 +159,13 @@ export function NotificationCard({ onClick={() => setMessageAsRead()} style={{ width: '20px', height: '20px' }} className={`dn dib-ns h1 w1 pr1 nr4 mv1 pv1 hover-red blue-light ml3`} - data-tip={msg} + data-tooltip-id={'setMessageAsReadTooltip'} + data-tooltip-content={msg} aria-label="Mark notification as read" /> )} - + )}

diff --git a/frontend/src/components/notifications/notificationOrderBy.js b/frontend/src/components/notifications/notificationOrderBy.js index e770a49e0e..65df558e40 100644 --- a/frontend/src/components/notifications/notificationOrderBy.js +++ b/frontend/src/components/notifications/notificationOrderBy.js @@ -1,4 +1,3 @@ -import React from 'react'; import { FormattedMessage } from 'react-intl'; import messages from './messages'; diff --git a/frontend/src/components/notifications/notificationResults.js b/frontend/src/components/notifications/notificationResults.js index 9a77f648b7..18ccf62868 100644 --- a/frontend/src/components/notifications/notificationResults.js +++ b/frontend/src/components/notifications/notificationResults.js @@ -1,4 +1,4 @@ -import React, { useEffect, useState } from 'react'; +import { useEffect, useState } from 'react'; import ReactPlaceholder from 'react-placeholder'; import { FormattedMessage, FormattedNumber } from 'react-intl'; import 'react-placeholder/lib/reactPlaceholder.css'; diff --git a/frontend/src/components/notifications/paginator.js b/frontend/src/components/notifications/paginator.js index 4de7fade02..88dd7d9bce 100644 --- a/frontend/src/components/notifications/paginator.js +++ b/frontend/src/components/notifications/paginator.js @@ -1,4 +1,3 @@ -import React from 'react'; import { PaginatorLine } from '../paginator'; function Paginator({ inboxQuery, notifications, setInboxQuery }) { diff --git a/frontend/src/components/notifications/tests/actionButtons.test.js b/frontend/src/components/notifications/tests/actionButtons.test.js index 8bd32c0af0..54dec20196 100644 --- a/frontend/src/components/notifications/tests/actionButtons.test.js +++ b/frontend/src/components/notifications/tests/actionButtons.test.js @@ -11,10 +11,12 @@ import { generateSampleNotifications } from '../../../network/tests/mockData/not describe('Action Buttons', () => { const retryFnMock = jest.fn(); const setSelectedMock = jest.fn(); - it('should return nothing if no notification is selected', () => { + beforeEach(() => { act(() => { store.dispatch({ type: 'SET_TOKEN', token: 'validToken' }); }); + }); + it('should return nothing if no notification is selected', () => { const { container } = render( { // Error are consoled in all cases of POST error it('should catch error when marking multiple selected notifications as read', async () => { + global.console = { ...global.console, log: jest.fn() }; const user = userEvent.setup(); setupFaultyHandlers(); render( @@ -142,9 +145,11 @@ describe('Action Buttons', () => { }), ); // Error is then consoled + await waitFor(() => expect(console.log).toBeCalledWith('Network request failed')); }); it('should catch error when marking all notifications in a category as read', async () => { + global.console = { ...global.console, log: jest.fn() }; const user = userEvent.setup(); setupFaultyHandlers(); render( @@ -164,11 +169,12 @@ describe('Action Buttons', () => { }), ); // Error is then consoled + await waitFor(() => expect(console.log).toBeCalledWith('Network request failed')); }); it('should catch error when deleting multiple selected notifications', async () => { + global.console = { ...global.console, log: jest.fn() }; const user = userEvent.setup(); - act(() => {}); setupFaultyHandlers(); render( @@ -188,9 +194,11 @@ describe('Action Buttons', () => { }), ); // Error is then consoled + await waitFor(() => expect(console.log).toBeCalledWith('Network request failed')); }); it('should catch error when deleting all notifications in a category', async () => { + global.console = { ...global.console, log: jest.fn() }; const user = userEvent.setup(); setupFaultyHandlers(); render( @@ -210,6 +218,7 @@ describe('Action Buttons', () => { }), ); // Error is then consoled + await waitFor(() => expect(console.log).toBeCalledWith('Network request failed')); }); it('should decrement the page query by 1 if the user deletes all notifications on the last page', async () => { @@ -217,7 +226,7 @@ describe('Action Buttons', () => { // all the six notifications in the last page const setInboxQueryMock = jest.fn(); const user = userEvent.setup(); - render( + const { getByRole } = render( { , ); await user.click( - screen.getByRole('button', { + getByRole('button', { name: /delete/i, }), ); diff --git a/frontend/src/components/paginator/index.js b/frontend/src/components/paginator/index.js index 15b94396bd..7dd5742cce 100644 --- a/frontend/src/components/paginator/index.js +++ b/frontend/src/components/paginator/index.js @@ -1,4 +1,3 @@ -import React from 'react'; import './styles.scss'; export function listPageOptions(page, lastPage) { diff --git a/frontend/src/components/paginator/tests/index.test.js b/frontend/src/components/paginator/tests/index.test.js index fb0aa7a81c..e82fe0ac8b 100644 --- a/frontend/src/components/paginator/tests/index.test.js +++ b/frontend/src/components/paginator/tests/index.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import TestRenderer from 'react-test-renderer'; import { listPageOptions, howManyPages, PageButton, PaginatorLine } from '../index'; diff --git a/frontend/src/components/portal.js b/frontend/src/components/portal.js index 14603c1799..1c19a479cc 100644 --- a/frontend/src/components/portal.js +++ b/frontend/src/components/portal.js @@ -1,5 +1,5 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; +import { Component } from 'react'; +import { createPortal } from 'react-dom'; let portalRoot = document.getElementById('action-root'); if (!portalRoot) { @@ -8,7 +8,7 @@ if (!portalRoot) { document.body.appendChild(portalRoot); } -class Portal extends React.Component { +class Portal extends Component { el = document.createElement('div'); componentDidMount() { @@ -22,7 +22,7 @@ class Portal extends React.Component { } render() { - return ReactDOM.createPortal(this.props.children, this.el); + return createPortal(this.props.children, this.el); } } diff --git a/frontend/src/components/preloader.js b/frontend/src/components/preloader.js index 9b1c3fb20f..096bc93023 100644 --- a/frontend/src/components/preloader.js +++ b/frontend/src/components/preloader.js @@ -1,5 +1,3 @@ -import React from 'react'; - import { LoadingIcon } from './svgIcons'; export function Preloader() { diff --git a/frontend/src/components/progressBar.js b/frontend/src/components/progressBar.js index afa7ba5266..fb9edf6872 100644 --- a/frontend/src/components/progressBar.js +++ b/frontend/src/components/progressBar.js @@ -1,5 +1,3 @@ -import React from 'react'; - import { useHover } from '../hooks/UseHover'; export const ProgressBar = ({ diff --git a/frontend/src/components/projectCard/dueDateBox.js b/frontend/src/components/projectCard/dueDateBox.js index db06de09b5..5370ab996d 100644 --- a/frontend/src/components/projectCard/dueDateBox.js +++ b/frontend/src/components/projectCard/dueDateBox.js @@ -1,7 +1,7 @@ -import React, { useState, useEffect } from 'react'; +import { useState, useEffect } from 'react'; import { FormattedMessage, useIntl } from 'react-intl'; import humanizeDuration from 'humanize-duration'; -import ReactTooltip from 'react-tooltip'; +import { Tooltip } from 'react-tooltip'; import { ClockIcon } from '../svgIcons'; import messages from './messages'; @@ -48,7 +48,7 @@ export function DueDateBox({ ? 'bg-red white' : 'bg-tan blue-grey' } ${intervalMili ? '' : 'mw4'}`} - data-tip={tooltipMsg} + data-tooltip-id="dueDateBoxTooltip" style={{ paddingTop: '0.375rem', paddingBottom: '0.375rem' }} > {!isTaskStatusPage ? ( @@ -66,7 +66,7 @@ export function DueDateBox({ /> - {tooltipMsg && } + {tooltipMsg && } ); } else { diff --git a/frontend/src/components/projectCard/nCardPlaceholder.js b/frontend/src/components/projectCard/nCardPlaceholder.js index 3b773ec956..450ea547b5 100644 --- a/frontend/src/components/projectCard/nCardPlaceholder.js +++ b/frontend/src/components/projectCard/nCardPlaceholder.js @@ -1,4 +1,3 @@ -import React from 'react'; import { TextBlock, RoundShape } from 'react-placeholder/lib/placeholders'; export const projectCardPlaceholderTemplate = () => (_, i) => diff --git a/frontend/src/components/projectCard/priorityBox.js b/frontend/src/components/projectCard/priorityBox.js index 0b3e5cdbfa..334e33be48 100644 --- a/frontend/src/components/projectCard/priorityBox.js +++ b/frontend/src/components/projectCard/priorityBox.js @@ -1,4 +1,3 @@ -import React from 'react'; import { FormattedMessage } from 'react-intl'; import messages from './messages'; diff --git a/frontend/src/components/projectCard/projectCard.js b/frontend/src/components/projectCard/projectCard.js index 0ee829168f..c5b9219e63 100644 --- a/frontend/src/components/projectCard/projectCard.js +++ b/frontend/src/components/projectCard/projectCard.js @@ -1,4 +1,4 @@ -import React, { useState } from 'react'; +import { useState } from 'react'; import { FormattedMessage } from 'react-intl'; import { Link } from 'react-router-dom'; diff --git a/frontend/src/components/projectCard/projectProgressBar.js b/frontend/src/components/projectCard/projectProgressBar.js index 983333fb5e..d16d69e000 100644 --- a/frontend/src/components/projectCard/projectProgressBar.js +++ b/frontend/src/components/projectCard/projectProgressBar.js @@ -1,4 +1,3 @@ -import React from 'react'; import { FormattedMessage } from 'react-intl'; import messages from './messages'; diff --git a/frontend/src/components/projectCard/tests/dueDateBox.test.js b/frontend/src/components/projectCard/tests/dueDateBox.test.js index 2b325eb042..a03be977bc 100644 --- a/frontend/src/components/projectCard/tests/dueDateBox.test.js +++ b/frontend/src/components/projectCard/tests/dueDateBox.test.js @@ -1,9 +1,8 @@ -import React from 'react'; import userEvent from '@testing-library/user-event'; import { render, screen, waitFor } from '@testing-library/react'; import '@testing-library/jest-dom'; -import { DueDateBox } from '../../../components/projectCard/dueDateBox'; +import { DueDateBox } from '../dueDateBox'; import { ReduxIntlProviders } from '../../../utils/testWithIntl'; describe('test DueDate', () => { diff --git a/frontend/src/components/projectCard/tests/projectProgressBar.test.js b/frontend/src/components/projectCard/tests/projectProgressBar.test.js index 62efb6113a..c3c5f4ee81 100644 --- a/frontend/src/components/projectCard/tests/projectProgressBar.test.js +++ b/frontend/src/components/projectCard/tests/projectProgressBar.test.js @@ -1,5 +1,3 @@ -import React from 'react'; - import ProjectProgressBar from '../projectProgressBar'; import { createComponentWithIntl } from '../../../utils/testWithIntl'; diff --git a/frontend/src/components/projectCreate/fileUploadErrors.js b/frontend/src/components/projectCreate/fileUploadErrors.js index b66c889b49..60052dfd66 100644 --- a/frontend/src/components/projectCreate/fileUploadErrors.js +++ b/frontend/src/components/projectCreate/fileUploadErrors.js @@ -1,4 +1,3 @@ -import React from 'react'; import { FormattedMessage } from 'react-intl'; import { MAX_FILESIZE } from '../../config'; diff --git a/frontend/src/components/projectCreate/index.js b/frontend/src/components/projectCreate/index.js index f53e7246ad..d5cb5cb31c 100644 --- a/frontend/src/components/projectCreate/index.js +++ b/frontend/src/components/projectCreate/index.js @@ -1,4 +1,4 @@ -import React, { useState, useLayoutEffect, useCallback, Suspense, useEffect } from 'react'; +import { lazy, useState, useLayoutEffect, useCallback, Suspense, useEffect } from 'react'; import { useSelector } from 'react-redux'; import { useNavigate } from 'react-router-dom'; import { useQueryParam, NumberParam } from 'use-query-params'; @@ -34,7 +34,7 @@ import { } from '../../utils/geoFileFunctions'; import { getErrorMsg } from './fileUploadErrors'; -const ProjectCreationMap = React.lazy(() => +const ProjectCreationMap = lazy(() => import('./projectCreationMap' /* webpackChunkName: "projectCreationMap" */), ); diff --git a/frontend/src/components/projectCreate/navButtons.js b/frontend/src/components/projectCreate/navButtons.js index 1f05fb63ee..eb80376edf 100644 --- a/frontend/src/components/projectCreate/navButtons.js +++ b/frontend/src/components/projectCreate/navButtons.js @@ -1,4 +1,3 @@ -import React from 'react'; import { featureCollection } from '@turf/helpers'; import { FormattedMessage, useIntl } from 'react-intl'; diff --git a/frontend/src/components/projectCreate/projectCreationMap.js b/frontend/src/components/projectCreate/projectCreationMap.js index 08738e07d7..9e98a292d2 100644 --- a/frontend/src/components/projectCreate/projectCreationMap.js +++ b/frontend/src/components/projectCreate/projectCreationMap.js @@ -1,4 +1,4 @@ -import React, { useLayoutEffect, useEffect, useCallback, useState } from 'react'; +import { useLayoutEffect, useEffect, useCallback, useState, createRef } from 'react'; import { useSelector } from 'react-redux'; import mapboxgl from 'mapbox-gl'; import 'mapbox-gl/dist/mapbox-gl.css'; @@ -30,7 +30,7 @@ try { } const ProjectCreationMap = ({ mapObj, setMapObj, metadata, updateMetadata, step, uploadFile }) => { - const mapRef = React.createRef(); + const mapRef = createRef(); const locale = useSelector((state) => state.preferences['locale']); const token = useSelector((state) => state.auth.token); const [showProjectsAOILayer, setShowProjectsAOILayer] = useState(true); diff --git a/frontend/src/components/projectCreate/projectsAOILayerCheckBox.js b/frontend/src/components/projectCreate/projectsAOILayerCheckBox.js index 14d784a9e2..c87b69febe 100644 --- a/frontend/src/components/projectCreate/projectsAOILayerCheckBox.js +++ b/frontend/src/components/projectCreate/projectsAOILayerCheckBox.js @@ -1,6 +1,6 @@ import { CheckBoxInput } from '../formInputs'; import { FormattedMessage } from 'react-intl'; -import ReactTooltip from 'react-tooltip'; +import { Tooltip } from 'react-tooltip'; import messages from './messages'; import statusMessages from '../projectDetail/messages'; @@ -17,11 +17,11 @@ export const ProjectsAOILayerCheckBox = ({ isActive, setActive, disabled, isAoiL changeState={() => setActive(!isActive)} className="dib mr2 v-mid" /> - + {isAoiLoading && } - + {disabled ? ( ) : ( @@ -46,7 +46,7 @@ export const ProjectsAOILayerCheckBox = ({ isActive, setActive, disabled, isAoiL
)} - +
); diff --git a/frontend/src/components/projectCreate/review.js b/frontend/src/components/projectCreate/review.js index 8818996099..1bd556f1d0 100644 --- a/frontend/src/components/projectCreate/review.js +++ b/frontend/src/components/projectCreate/review.js @@ -1,4 +1,4 @@ -import React, { useState } from 'react'; +import { useState } from 'react'; import { FormattedMessage } from 'react-intl'; import messages from './messages'; diff --git a/frontend/src/components/projectCreate/setAOI.js b/frontend/src/components/projectCreate/setAOI.js index b1e36fcc8f..e626a6c80b 100644 --- a/frontend/src/components/projectCreate/setAOI.js +++ b/frontend/src/components/projectCreate/setAOI.js @@ -1,4 +1,3 @@ -import React from 'react'; import { FormattedMessage } from 'react-intl'; import { useDropzone } from 'react-dropzone'; diff --git a/frontend/src/components/projectCreate/setTaskSizes.js b/frontend/src/components/projectCreate/setTaskSizes.js index 167257f576..18cbd78ff1 100644 --- a/frontend/src/components/projectCreate/setTaskSizes.js +++ b/frontend/src/components/projectCreate/setTaskSizes.js @@ -1,4 +1,4 @@ -import React, { useEffect, useLayoutEffect, useState, useCallback } from 'react'; +import { useEffect, useLayoutEffect, useState, useCallback } from 'react'; import area from '@turf/area'; import transformScale from '@turf/transform-scale'; import { featureCollection } from '@turf/helpers'; diff --git a/frontend/src/components/projectCreate/tests/projectsAOILayerCheckBox.test.js b/frontend/src/components/projectCreate/tests/projectsAOILayerCheckBox.test.js index 2c1fc34ae3..ce40e232c0 100644 --- a/frontend/src/components/projectCreate/tests/projectsAOILayerCheckBox.test.js +++ b/frontend/src/components/projectCreate/tests/projectsAOILayerCheckBox.test.js @@ -1,4 +1,4 @@ -import { render, screen } from '@testing-library/react'; +import { render, screen, waitFor } from '@testing-library/react'; import '@testing-library/jest-dom'; import userEvent from '@testing-library/user-event'; @@ -18,11 +18,13 @@ describe('ProjectsAOILayerCheckBox', () => { expect(screen.getByRole('checkbox').className).toContain('b--grey-light'); expect(screen.getByRole('checkbox').className).not.toContain('b--red'); await user.hover(screen.getByText('Show existing projects AoIs')); - expect( - screen.getByText( - "Zoom in to be able to activate the visualization of other projects' areas of interest.", - ), - ).toBeInTheDocument(); + await waitFor(() => + expect( + screen.getByText( + "Zoom in to be able to activate the visualization of other projects' areas of interest.", + ), + ).toBeInTheDocument(), + ); await user.click(screen.getByRole('checkbox')); expect(testFn).not.toHaveBeenCalled(); }); @@ -37,9 +39,11 @@ describe('ProjectsAOILayerCheckBox', () => { expect(screen.getByRole('checkbox').className).not.toContain('b--grey-light'); expect(screen.getByRole('checkbox').className).toContain('b--red'); await user.hover(screen.getByText('Show existing projects AoIs')); - expect( - screen.getByText("Enable the visualization of the existing projects' areas of interest."), - ).toBeInTheDocument(); + await waitFor(() => + expect( + screen.getByText("Enable the visualization of the existing projects' areas of interest."), + ).toBeInTheDocument(), + ); await user.click(screen.getByRole('checkbox')); expect(testFn).toHaveBeenCalled(); }); diff --git a/frontend/src/components/projectCreate/tests/setTaskSizes.test.js b/frontend/src/components/projectCreate/tests/setTaskSizes.test.js index b241a3b3ee..c8373ce3b7 100644 --- a/frontend/src/components/projectCreate/tests/setTaskSizes.test.js +++ b/frontend/src/components/projectCreate/tests/setTaskSizes.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { render, screen } from '@testing-library/react'; import '@testing-library/jest-dom'; import mapboxgl from 'mapbox-gl'; diff --git a/frontend/src/components/projectCreate/trimProject.js b/frontend/src/components/projectCreate/trimProject.js index 788c22a9d6..fb296c84ec 100644 --- a/frontend/src/components/projectCreate/trimProject.js +++ b/frontend/src/components/projectCreate/trimProject.js @@ -1,4 +1,4 @@ -import React, { useState, useEffect } from 'react'; +import { useState, useEffect } from 'react'; import { useSelector } from 'react-redux'; import area from '@turf/area'; import { featureCollection } from '@turf/helpers'; diff --git a/frontend/src/components/projectDetail/bigProjectTeaser.js b/frontend/src/components/projectDetail/bigProjectTeaser.js index 7c7a3e6eb0..5a1e15232e 100644 --- a/frontend/src/components/projectDetail/bigProjectTeaser.js +++ b/frontend/src/components/projectDetail/bigProjectTeaser.js @@ -1,4 +1,3 @@ -import React from 'react'; import { FormattedMessage } from 'react-intl'; import messages from './messages'; diff --git a/frontend/src/components/projectDetail/downloadButtons.js b/frontend/src/components/projectDetail/downloadButtons.js index c8fa6edfe3..2bf57c69bf 100644 --- a/frontend/src/components/projectDetail/downloadButtons.js +++ b/frontend/src/components/projectDetail/downloadButtons.js @@ -1,4 +1,3 @@ -import React from 'react'; import { FormattedMessage } from 'react-intl'; import messages from './messages'; diff --git a/frontend/src/components/projectDetail/favorites.js b/frontend/src/components/projectDetail/favorites.js index 6ffdcf2940..06a25a5b00 100644 --- a/frontend/src/components/projectDetail/favorites.js +++ b/frontend/src/components/projectDetail/favorites.js @@ -1,4 +1,3 @@ -import React from 'react'; import { useSelector } from 'react-redux'; import { useNavigate } from 'react-router-dom'; import { FormattedMessage } from 'react-intl'; diff --git a/frontend/src/components/projectDetail/footer.js b/frontend/src/components/projectDetail/footer.js index c3c5c9899c..05f8fe1910 100644 --- a/frontend/src/components/projectDetail/footer.js +++ b/frontend/src/components/projectDetail/footer.js @@ -1,4 +1,4 @@ -import React, { useRef, Fragment } from 'react'; +import { useRef, Fragment } from 'react'; import { Link } from 'react-router-dom'; import { useSelector } from 'react-redux'; import { FormattedMessage } from 'react-intl'; diff --git a/frontend/src/components/projectDetail/header.js b/frontend/src/components/projectDetail/header.js index 60ca9d466a..9d401df435 100644 --- a/frontend/src/components/projectDetail/header.js +++ b/frontend/src/components/projectDetail/header.js @@ -1,4 +1,3 @@ -import React from 'react'; import { useSelector } from 'react-redux'; import { Link } from 'react-router-dom'; import { FormattedMessage } from 'react-intl'; diff --git a/frontend/src/components/projectDetail/index.js b/frontend/src/components/projectDetail/index.js index 71f43535a5..c40ab63ad0 100644 --- a/frontend/src/components/projectDetail/index.js +++ b/frontend/src/components/projectDetail/index.js @@ -1,4 +1,4 @@ -import React, { useState } from 'react'; +import { lazy, Suspense, useState } from 'react'; import { Link } from 'react-router-dom'; import ReactPlaceholder from 'react-placeholder'; import centroid from '@turf/centroid'; @@ -33,7 +33,7 @@ import { DownloadOsmData } from './downloadOsmData.js'; import { ENABLE_EXPORT_TOOL } from '../../config/index.js'; /* lazy imports must be last import */ -const ProjectTimeline = React.lazy(() => import('./timeline' /* webpackChunkName: "timeline" */)); +const ProjectTimeline = lazy(() => import('./timeline' /* webpackChunkName: "timeline" */)); const ProjectDetailMap = (props) => { const [taskBordersOnly, setTaskBordersOnly] = useState(true); @@ -335,9 +335,9 @@ export const ProjectDetail = (props) => { )} {timelineDataStatus === 'success' && ( - Loading...}> + Loading...}> - + )}
diff --git a/frontend/src/components/projectDetail/infoPanel.js b/frontend/src/components/projectDetail/infoPanel.js index 8e5912de80..8f4e2ac41e 100644 --- a/frontend/src/components/projectDetail/infoPanel.js +++ b/frontend/src/components/projectDetail/infoPanel.js @@ -1,4 +1,3 @@ -import React from 'react'; import ReactPlaceholder from 'react-placeholder'; import { FormattedMessage, useIntl } from 'react-intl'; diff --git a/frontend/src/components/projectDetail/liveViewButton.js b/frontend/src/components/projectDetail/liveViewButton.js index 9e6b8c26e2..013052dd0c 100644 --- a/frontend/src/components/projectDetail/liveViewButton.js +++ b/frontend/src/components/projectDetail/liveViewButton.js @@ -17,4 +17,4 @@ export const LiveViewButton = ({ projectId, className, compact = false }) => ( } -); \ No newline at end of file +); diff --git a/frontend/src/components/projectDetail/osmchaButton.js b/frontend/src/components/projectDetail/osmchaButton.js index e5f8175534..3734ab88cb 100644 --- a/frontend/src/components/projectDetail/osmchaButton.js +++ b/frontend/src/components/projectDetail/osmchaButton.js @@ -1,4 +1,3 @@ -import React from 'react'; import { FormattedMessage } from 'react-intl'; import messages from './messages'; diff --git a/frontend/src/components/projectDetail/permissionBox.js b/frontend/src/components/projectDetail/permissionBox.js index 76f533717e..5cfe1d2517 100644 --- a/frontend/src/components/projectDetail/permissionBox.js +++ b/frontend/src/components/projectDetail/permissionBox.js @@ -1,4 +1,3 @@ -import React from 'react'; import ReactPlaceholder from 'react-placeholder'; import { FormattedMessage } from 'react-intl'; diff --git a/frontend/src/components/projectDetail/privateProjectError.js b/frontend/src/components/projectDetail/privateProjectError.js index dbbbae648d..c357b8f53d 100644 --- a/frontend/src/components/projectDetail/privateProjectError.js +++ b/frontend/src/components/projectDetail/privateProjectError.js @@ -1,4 +1,3 @@ -import React from 'react'; import { useNavigate } from 'react-router-dom'; import { FormattedMessage } from 'react-intl'; diff --git a/frontend/src/components/projectDetail/projectDetailPlaceholder.js b/frontend/src/components/projectDetail/projectDetailPlaceholder.js index 8cfdcb4ea7..4730c1702b 100644 --- a/frontend/src/components/projectDetail/projectDetailPlaceholder.js +++ b/frontend/src/components/projectDetail/projectDetailPlaceholder.js @@ -1,4 +1,3 @@ -import React from 'react'; import { TextBlock, TextRow, RectShape } from 'react-placeholder/lib/placeholders'; import { LoadingIcon } from '../svgIcons'; diff --git a/frontend/src/components/projectDetail/questionsAndComments.js b/frontend/src/components/projectDetail/questionsAndComments.js index 4e826e8aa8..4fb083ef64 100644 --- a/frontend/src/components/projectDetail/questionsAndComments.js +++ b/frontend/src/components/projectDetail/questionsAndComments.js @@ -1,4 +1,4 @@ -import React, { useState } from 'react'; +import { lazy, Suspense, useState } from 'react'; import { useSelector } from 'react-redux'; import { FormattedMessage } from 'react-intl'; import { useMutation } from '@tanstack/react-query'; @@ -9,7 +9,6 @@ import { RelativeTimeWithUnit } from '../../utils/formattedRelativeTime'; import { PaginatorLine } from '../paginator'; import { Button } from '../button'; import { Alert } from '../alert'; -import { CommentInputField } from '../comments/commentInput'; import { MessageStatus } from '../comments/status'; import { UserAvatar } from '../user/avatar'; import { htmlFromMarkdown, formatUserNamesToLink } from '../../utils/htmlFromMarkdown'; @@ -19,6 +18,10 @@ import { postProjectComment, useCommentsQuery } from '../../api/questionsAndComm import './styles.scss'; +const CommentInputField = lazy(() => + import('../comments/commentInput' /* webpackChunkName: "commentInput" */), +); + export const PostProjectComment = ({ projectId, refetchComments, contributors }) => { const token = useSelector((state) => state.auth.token); const locale = useSelector((state) => state.preferences['locale']); @@ -39,17 +42,19 @@ export const PostProjectComment = ({ projectId, refetchComments, contributors }) return (
- user.username) : undefined - } - /> + }> + user.username) : undefined + } + /> +
diff --git a/frontend/src/components/projectDetail/shareButton.js b/frontend/src/components/projectDetail/shareButton.js index 5135a0279e..acdce7cf4b 100644 --- a/frontend/src/components/projectDetail/shareButton.js +++ b/frontend/src/components/projectDetail/shareButton.js @@ -1,5 +1,4 @@ -import React from 'react'; -import ReactTooltip from 'react-tooltip'; +import { Tooltip } from 'react-tooltip'; import { FormattedMessage } from 'react-intl'; import messages from './messages'; @@ -24,13 +23,13 @@ export function ShareButton({ projectId }: Object) { return ( <> -
+
- +
- + ); } diff --git a/frontend/src/components/projectDetail/statusBox.js b/frontend/src/components/projectDetail/statusBox.js index b318c9d532..35d1a27343 100644 --- a/frontend/src/components/projectDetail/statusBox.js +++ b/frontend/src/components/projectDetail/statusBox.js @@ -1,4 +1,3 @@ -import React from 'react'; import { FormattedMessage } from 'react-intl'; import messages from './messages'; diff --git a/frontend/src/components/projectDetail/styles.scss b/frontend/src/components/projectDetail/styles.scss index 4bce604633..41c4a8b923 100644 --- a/frontend/src/components/projectDetail/styles.scss +++ b/frontend/src/components/projectDetail/styles.scss @@ -32,3 +32,7 @@ position: relative; border: 1px solid #d73f3f; } + +.react-tooltip#dueDateBoxTooltip { + z-index: 999; +} diff --git a/frontend/src/components/projectDetail/tests/bigProjectTeaser.test.js b/frontend/src/components/projectDetail/tests/bigProjectTeaser.test.js index 721bfbdf0b..25543a6751 100644 --- a/frontend/src/components/projectDetail/tests/bigProjectTeaser.test.js +++ b/frontend/src/components/projectDetail/tests/bigProjectTeaser.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { render, screen } from '@testing-library/react'; import '@testing-library/jest-dom'; diff --git a/frontend/src/components/projectDetail/tests/downloadButtons.test.js b/frontend/src/components/projectDetail/tests/downloadButtons.test.js index fa55ef0c47..a4e0b08ead 100644 --- a/frontend/src/components/projectDetail/tests/downloadButtons.test.js +++ b/frontend/src/components/projectDetail/tests/downloadButtons.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { render, screen } from '@testing-library/react'; import '@testing-library/jest-dom'; diff --git a/frontend/src/components/projectDetail/tests/footer.test.js b/frontend/src/components/projectDetail/tests/footer.test.js index c4ad8f4ebd..e73ac8a9f3 100644 --- a/frontend/src/components/projectDetail/tests/footer.test.js +++ b/frontend/src/components/projectDetail/tests/footer.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { screen } from '@testing-library/react'; import '@testing-library/jest-dom'; diff --git a/frontend/src/components/projectDetail/tests/header.test.js b/frontend/src/components/projectDetail/tests/header.test.js index f44566f44e..f15dd7a17d 100644 --- a/frontend/src/components/projectDetail/tests/header.test.js +++ b/frontend/src/components/projectDetail/tests/header.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { screen, act, render } from '@testing-library/react'; import '@testing-library/jest-dom'; diff --git a/frontend/src/components/projectDetail/tests/infoPanel.test.js b/frontend/src/components/projectDetail/tests/infoPanel.test.js index 6124a3cb74..91a5f8b15d 100644 --- a/frontend/src/components/projectDetail/tests/infoPanel.test.js +++ b/frontend/src/components/projectDetail/tests/infoPanel.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { render, screen } from '@testing-library/react'; import '@testing-library/jest-dom'; diff --git a/frontend/src/components/projectDetail/tests/osmchaButton.test.js b/frontend/src/components/projectDetail/tests/osmchaButton.test.js index 72c56a0d22..fcb893f12f 100644 --- a/frontend/src/components/projectDetail/tests/osmchaButton.test.js +++ b/frontend/src/components/projectDetail/tests/osmchaButton.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { render, screen } from '@testing-library/react'; import '@testing-library/jest-dom'; diff --git a/frontend/src/components/projectDetail/tests/permissionBox.test.js b/frontend/src/components/projectDetail/tests/permissionBox.test.js index 57a6b71ee8..cdde5b8b00 100644 --- a/frontend/src/components/projectDetail/tests/permissionBox.test.js +++ b/frontend/src/components/projectDetail/tests/permissionBox.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { FormattedMessage } from 'react-intl'; import { createComponentWithIntl } from '../../../utils/testWithIntl'; diff --git a/frontend/src/components/projectDetail/tests/questionsAndComments.test.js b/frontend/src/components/projectDetail/tests/questionsAndComments.test.js index 32742177d0..ba844a3cd9 100644 --- a/frontend/src/components/projectDetail/tests/questionsAndComments.test.js +++ b/frontend/src/components/projectDetail/tests/questionsAndComments.test.js @@ -11,6 +11,8 @@ import { } from '../../../utils/testWithIntl'; import { getProjectSummary, projectComments } from '../../../network/tests/mockData/projects'; import { QuestionsAndComments, PostProjectComment, CommentList } from '../questionsAndComments'; +// This is a late import in a React.lazy call; it takes awhile for commentInput to load +import '../../comments/commentInput'; describe('test if QuestionsAndComments component', () => { const project = getProjectSummary(1); @@ -34,9 +36,10 @@ describe('test if QuestionsAndComments component', () => { , ); - const previewBtn = screen.getByRole('button', { name: /preview/i }); + const previewBtn = await screen.findByRole('button', { name: /preview/i }); expect(screen.getAllByRole('button').length).toBe(11); expect(screen.getByRole('button', { name: /write/i })).toBeInTheDocument(); + expect(screen.getAllByRole('button')).toHaveLength(11); expect(previewBtn).toBeInTheDocument(); expect(screen.getByRole('textbox')).toBeInTheDocument(); await user.click(previewBtn); diff --git a/frontend/src/components/projectDetail/tests/shareButton.test.js b/frontend/src/components/projectDetail/tests/shareButton.test.js index 4c42d44b86..5c55cae7bb 100644 --- a/frontend/src/components/projectDetail/tests/shareButton.test.js +++ b/frontend/src/components/projectDetail/tests/shareButton.test.js @@ -1,19 +1,21 @@ import '@testing-library/jest-dom'; -import { render, screen } from '@testing-library/react'; +import { render, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { IntlProviders } from '../../../utils/testWithIntl'; import { ShareButton } from '../shareButton'; describe('test if shareButton', () => { - it('render shareButton for project with id 1', () => { + it('render shareButton for project with id 1', async () => { + const user = userEvent.setup(); const { container } = render( , ); expect(screen.getByText('Share')).toBeInTheDocument(); - expect(screen.getByText('Tweet')).toBeInTheDocument(); + await user.hover(screen.getByText('Share')); + await waitFor(() => expect(screen.getByText('Tweet')).toBeInTheDocument()); expect(screen.getByText('Post on Facebook')).toBeInTheDocument(); expect(screen.getByText('Share on LinkedIn')).toBeInTheDocument(); @@ -37,9 +39,12 @@ describe('test if shareButton', () => { , ); + await user.hover(screen.getByText('Share')); + await waitFor(() => expect(screen.getByText(/tweet/i)).toBeInTheDocument()); await user.click(screen.getByText(/tweet/i)); await user.click(screen.getByText(/post on facebook/i)); await user.click(screen.getByText(/share on linkedin/i)); + expect(global.open).toHaveBeenCalledTimes(3); }); }); diff --git a/frontend/src/components/projectDetail/tests/statusBox.test.js b/frontend/src/components/projectDetail/tests/statusBox.test.js index 8f29a2f323..340baa6eec 100644 --- a/frontend/src/components/projectDetail/tests/statusBox.test.js +++ b/frontend/src/components/projectDetail/tests/statusBox.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { render, screen } from '@testing-library/react'; import '@testing-library/jest-dom'; diff --git a/frontend/src/components/projectDetail/timeline.js b/frontend/src/components/projectDetail/timeline.js index 291cb4bf5d..c62efbb854 100644 --- a/frontend/src/components/projectDetail/timeline.js +++ b/frontend/src/components/projectDetail/timeline.js @@ -1,4 +1,3 @@ -import React from 'react'; import { Chart as ChartJS, LineElement, diff --git a/frontend/src/components/projectDetail/visibilityBox.js b/frontend/src/components/projectDetail/visibilityBox.js index ec8f5d3c14..c0bf422fe9 100644 --- a/frontend/src/components/projectDetail/visibilityBox.js +++ b/frontend/src/components/projectDetail/visibilityBox.js @@ -1,4 +1,3 @@ -import React from 'react'; import { FormattedMessage } from 'react-intl'; import { LockIcon } from '../svgIcons'; diff --git a/frontend/src/components/projectEdit/actionsForm.js b/frontend/src/components/projectEdit/actionsForm.js index fa5930c091..d9f1561027 100644 --- a/frontend/src/components/projectEdit/actionsForm.js +++ b/frontend/src/components/projectEdit/actionsForm.js @@ -1,4 +1,4 @@ -import React, { useState, useContext, useEffect } from 'react'; +import { useState, useContext, useEffect, Suspense, lazy, forwardRef } from 'react'; import { useSelector } from 'react-redux'; import Popup from 'reactjs-popup'; import Select from 'react-select'; @@ -13,7 +13,10 @@ import { styleClasses, StateContext } from '../../views/projectEdit'; import { fetchLocalJSONAPI, pushToLocalJSONAPI } from '../../network/genericJSONRequest'; import { useFetch } from '../../hooks/UseFetch'; import { useAsync } from '../../hooks/UseAsync'; -import { CommentInputField } from '../comments/commentInput'; +import ReactPlaceholder from 'react-placeholder'; +const CommentInputField = lazy(() => + import('../comments/commentInput' /* webpackChunkName: "commentInput" */), +); const ActionStatus = ({ status, action }) => { let successMessage = ''; @@ -324,13 +327,17 @@ const MessageContributorsModal = ({ projectId, close }: Object) => { {(msg) => { return (
- + } + > + +
); }} @@ -501,6 +508,10 @@ const TransferProject = ({ projectId, orgId }: Object) => { ); }; +const FormattedButtonTrigger = forwardRef((props, ref) => ( + +)); + export const ActionsForm = ({ projectId, projectName, orgId }: Object) => { const navigate = useNavigate(); @@ -512,9 +523,9 @@ export const ActionsForm = ({ projectId, projectName, orgId }: Object) => { + - + } modal closeOnDocumentClick @@ -538,9 +549,9 @@ export const ActionsForm = ({ projectId, projectName, orgId }: Object) => {

+ - + } modal closeOnDocumentClick @@ -549,9 +560,9 @@ export const ActionsForm = ({ projectId, projectName, orgId }: Object) => { + - + } modal closeOnDocumentClick @@ -560,9 +571,9 @@ export const ActionsForm = ({ projectId, projectName, orgId }: Object) => { + - + } modal closeOnDocumentClick @@ -586,9 +597,9 @@ export const ActionsForm = ({ projectId, projectName, orgId }: Object) => {

+ - + } modal closeOnDocumentClick @@ -597,9 +608,9 @@ export const ActionsForm = ({ projectId, projectName, orgId }: Object) => { + - + } modal closeOnDocumentClick diff --git a/frontend/src/components/projectEdit/customEditorForm.js b/frontend/src/components/projectEdit/customEditorForm.js index ae6afa8218..f439a2f5df 100644 --- a/frontend/src/components/projectEdit/customEditorForm.js +++ b/frontend/src/components/projectEdit/customEditorForm.js @@ -1,4 +1,4 @@ -import React, { useContext } from 'react'; +import { useContext } from 'react'; import { FormattedMessage } from 'react-intl'; import messages from './messages'; diff --git a/frontend/src/components/projectEdit/descriptionForm.js b/frontend/src/components/projectEdit/descriptionForm.js index 2a77f184f0..0035743010 100644 --- a/frontend/src/components/projectEdit/descriptionForm.js +++ b/frontend/src/components/projectEdit/descriptionForm.js @@ -1,4 +1,4 @@ -import React, { useContext } from 'react'; +import { useContext } from 'react'; import DatePicker from 'react-datepicker'; import 'react-datepicker/dist/react-datepicker.css'; import { FormattedMessage } from 'react-intl'; diff --git a/frontend/src/components/projectEdit/imageryForm.js b/frontend/src/components/projectEdit/imageryForm.js index e80e9d585f..b9f32e6b0c 100644 --- a/frontend/src/components/projectEdit/imageryForm.js +++ b/frontend/src/components/projectEdit/imageryForm.js @@ -1,4 +1,4 @@ -import React, { useContext, useState, useLayoutEffect } from 'react'; +import { useContext, useState, useLayoutEffect } from 'react'; import Select from 'react-select'; import { FormattedMessage } from 'react-intl'; diff --git a/frontend/src/components/projectEdit/inputLocale.js b/frontend/src/components/projectEdit/inputLocale.js index 05611a2dd3..6007f76c51 100644 --- a/frontend/src/components/projectEdit/inputLocale.js +++ b/frontend/src/components/projectEdit/inputLocale.js @@ -1,10 +1,20 @@ -import React, { useState, useEffect, useLayoutEffect, useCallback, useContext } from 'react'; +import React, { + useState, + useEffect, + useLayoutEffect, + useCallback, + useContext, + Suspense, +} from 'react'; import { FormattedMessage } from 'react-intl'; import messages from './messages'; import { StateContext, styleClasses } from '../../views/projectEdit'; import { LocaleOption } from './localeOption'; -import { CommentInputField } from '../comments/commentInput'; +import ReactPlaceholder from 'react-placeholder'; +const CommentInputField = React.lazy(() => + import('../comments/commentInput' /* webpackChunkName: "commentInput" */), +); export const InputLocale = ({ children, name, type, maxLength, languages }) => { const { projectInfo, setProjectInfo, setSuccess, setError } = useContext(StateContext); @@ -142,19 +152,23 @@ const LocalizedInputField = ({ type, maxLength, name, locale, updateContext }) = /> ) : (
- updateContext(name, value, locale), - maxLength: maxLength || null, - name: name, - }} - placeholderMsg={messages.typeHere} - /> + } + > + updateContext(name, value, locale), + maxLength: maxLength || null, + name: name, + }} + placeholderMsg={messages.typeHere} + /> +
)} {maxLength && ( diff --git a/frontend/src/components/projectEdit/instructionsForm.js b/frontend/src/components/projectEdit/instructionsForm.js index 2634e07c2d..4319f01bc6 100644 --- a/frontend/src/components/projectEdit/instructionsForm.js +++ b/frontend/src/components/projectEdit/instructionsForm.js @@ -1,4 +1,4 @@ -import React, { useContext } from 'react'; +import { useContext } from 'react'; import { FormattedMessage } from 'react-intl'; import messages from './messages'; diff --git a/frontend/src/components/projectEdit/localeOption.js b/frontend/src/components/projectEdit/localeOption.js index 9e8ef9c55f..3e2d63b0e6 100644 --- a/frontend/src/components/projectEdit/localeOption.js +++ b/frontend/src/components/projectEdit/localeOption.js @@ -1,5 +1,3 @@ -import React from 'react'; - export const LocaleOption = ({ localeCode, name, isActive, hasValue, onClick }) => { const additionalClasses = isActive ? 'bg-blue-grey fw6 white' diff --git a/frontend/src/components/projectEdit/metadataForm.js b/frontend/src/components/projectEdit/metadataForm.js index 6847f38da1..707f0e65ed 100644 --- a/frontend/src/components/projectEdit/metadataForm.js +++ b/frontend/src/components/projectEdit/metadataForm.js @@ -1,4 +1,4 @@ -import React, { useContext, useEffect, useState } from 'react'; +import { useContext, useEffect, useState } from 'react'; import { useSelector } from 'react-redux'; import Select from 'react-select'; import { FormattedMessage } from 'react-intl'; diff --git a/frontend/src/components/projectEdit/permissionsBlock.js b/frontend/src/components/projectEdit/permissionsBlock.js index a843911f51..dc9aa7fcd3 100644 --- a/frontend/src/components/projectEdit/permissionsBlock.js +++ b/frontend/src/components/projectEdit/permissionsBlock.js @@ -1,4 +1,4 @@ -import React, { useContext } from 'react'; +import { useContext } from 'react'; import { FormattedMessage } from 'react-intl'; import messages from './messages.js'; import { StateContext, styleClasses } from '../../views/projectEdit'; diff --git a/frontend/src/components/projectEdit/permissionsForm.js b/frontend/src/components/projectEdit/permissionsForm.js index bebc705681..105bdd70c6 100644 --- a/frontend/src/components/projectEdit/permissionsForm.js +++ b/frontend/src/components/projectEdit/permissionsForm.js @@ -1,4 +1,4 @@ -import React, { useContext } from 'react'; +import { useContext } from 'react'; import { FormattedMessage } from 'react-intl'; import messages from './messages'; diff --git a/frontend/src/components/projectEdit/priorityAreasForm.js b/frontend/src/components/projectEdit/priorityAreasForm.js index 02b1400f7d..f0c7bd7d35 100644 --- a/frontend/src/components/projectEdit/priorityAreasForm.js +++ b/frontend/src/components/projectEdit/priorityAreasForm.js @@ -1,4 +1,4 @@ -import React, { useState, useContext, useLayoutEffect } from 'react'; +import { useState, useContext, useLayoutEffect, createRef } from 'react'; import { useSelector } from 'react-redux'; import mapboxgl from 'mapbox-gl'; import 'mapbox-gl/dist/mapbox-gl.css'; @@ -36,7 +36,7 @@ try { export const PriorityAreasForm = () => { const { projectInfo, setProjectInfo } = useContext(StateContext); const locale = useSelector((state) => state.preferences['locale']); - const mapRef = React.createRef(); + const mapRef = createRef(); const [error, setError] = useState({ error: false, message: null }); const modes = MapboxDraw.modes; diff --git a/frontend/src/components/projectEdit/projectInterests.js b/frontend/src/components/projectEdit/projectInterests.js index 7557b27309..c559f10c9d 100644 --- a/frontend/src/components/projectEdit/projectInterests.js +++ b/frontend/src/components/projectEdit/projectInterests.js @@ -1,4 +1,3 @@ -import React from 'react'; import { InterestsList } from '../formInputs'; export const ProjectInterests = ({ interests, projectInterests, setProjectInfo }) => { diff --git a/frontend/src/components/projectEdit/settingsForm.js b/frontend/src/components/projectEdit/settingsForm.js index 2ede63c99d..b22af5cbff 100644 --- a/frontend/src/components/projectEdit/settingsForm.js +++ b/frontend/src/components/projectEdit/settingsForm.js @@ -1,4 +1,4 @@ -import React, { useContext } from 'react'; +import { useContext } from 'react'; import { FormattedMessage } from 'react-intl'; import messages from './messages'; diff --git a/frontend/src/components/projectEdit/teamSelect.js b/frontend/src/components/projectEdit/teamSelect.js index 480233ec96..3a97b3fafc 100644 --- a/frontend/src/components/projectEdit/teamSelect.js +++ b/frontend/src/components/projectEdit/teamSelect.js @@ -1,10 +1,10 @@ -import React, { useState, useContext } from 'react'; +import { useState, useContext } from 'react'; import Select from 'react-select'; import { FormattedMessage, useIntl } from 'react-intl'; import messages from './messages'; import commonMessages from '../messages'; -import { Button } from '../../components/button'; +import { Button } from '../button'; import { StateContext } from '../../views/projectEdit'; import { PencilIcon, WasteIcon, ExternalLinkIcon } from '../svgIcons'; import { useFetchWithAbort } from '../../hooks/UseFetch'; diff --git a/frontend/src/components/projectEdit/tests/localeOption.test.js b/frontend/src/components/projectEdit/tests/localeOption.test.js index 175d779de5..7a081d3683 100644 --- a/frontend/src/components/projectEdit/tests/localeOption.test.js +++ b/frontend/src/components/projectEdit/tests/localeOption.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { render, screen } from '@testing-library/react'; import '@testing-library/jest-dom'; diff --git a/frontend/src/components/projectStats/completion.js b/frontend/src/components/projectStats/completion.js index f858111ea1..ab96b71a77 100644 --- a/frontend/src/components/projectStats/completion.js +++ b/frontend/src/components/projectStats/completion.js @@ -1,4 +1,3 @@ -import React from 'react'; import { FormattedMessage, FormattedNumber } from 'react-intl'; import messages from './messages'; diff --git a/frontend/src/components/projectStats/contributorsStats.js b/frontend/src/components/projectStats/contributorsStats.js index f67a306f2d..a22bd168cf 100644 --- a/frontend/src/components/projectStats/contributorsStats.js +++ b/frontend/src/components/projectStats/contributorsStats.js @@ -1,4 +1,3 @@ -import React from 'react'; import { Doughnut, Bar } from 'react-chartjs-2'; import { Chart as ChartJS, diff --git a/frontend/src/components/projectStats/edits.js b/frontend/src/components/projectStats/edits.js index 7f76e9733f..9059c5ba76 100644 --- a/frontend/src/components/projectStats/edits.js +++ b/frontend/src/components/projectStats/edits.js @@ -1,4 +1,3 @@ -import React from 'react'; import { FormattedMessage } from 'react-intl'; import projectMessages from './messages'; diff --git a/frontend/src/components/projectStats/taskStatus.js b/frontend/src/components/projectStats/taskStatus.js index 5271db70da..65e3b8f6f3 100644 --- a/frontend/src/components/projectStats/taskStatus.js +++ b/frontend/src/components/projectStats/taskStatus.js @@ -1,4 +1,3 @@ -import React from 'react'; import { Chart as ChartJS, ArcElement, diff --git a/frontend/src/components/projectStats/tests/completion.test.js b/frontend/src/components/projectStats/tests/completion.test.js index 3f02fb0784..f384aa7f93 100644 --- a/frontend/src/components/projectStats/tests/completion.test.js +++ b/frontend/src/components/projectStats/tests/completion.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { render, screen } from '@testing-library/react'; import '@testing-library/jest-dom'; diff --git a/frontend/src/components/projectStats/tests/contributorsStats.test.js b/frontend/src/components/projectStats/tests/contributorsStats.test.js index a1a3646b82..5235b430b3 100644 --- a/frontend/src/components/projectStats/tests/contributorsStats.test.js +++ b/frontend/src/components/projectStats/tests/contributorsStats.test.js @@ -1,6 +1,5 @@ -import React from 'react'; import { Provider } from 'react-redux'; -import { render, screen } from '@testing-library/react'; +import { render, waitFor } from '@testing-library/react'; import '@testing-library/jest-dom'; import { store } from '../../../store'; @@ -13,31 +12,32 @@ jest.mock('react-chartjs-2', () => ({ Bar: () => null, })); -test('ContributorsStats renders the correct labels and numbers', () => { - render( +test('ContributorsStats renders the correct labels and numbers', async () => { + const { getByText } = render( , ); - expect(screen.getByText('4')).toBeInTheDocument(); - expect(screen.getByText('3')).toBeInTheDocument(); - expect(screen.getByText('5')).toBeInTheDocument(); - expect(screen.getByText('Mappers')).toBeInTheDocument(); - expect(screen.getByText('Validators')).toBeInTheDocument(); - expect(screen.getByText('Total contributors')).toBeInTheDocument(); - expect(screen.getByText('Users by experience on Tasking Manager')).toBeInTheDocument(); - expect(screen.getByText('Users by level')).toBeInTheDocument(); + await waitFor(() => expect(getByText('4')).toBeInTheDocument()); + expect(getByText('3')).toBeInTheDocument(); + expect(getByText('5')).toBeInTheDocument(); + expect(getByText('Mappers')).toBeInTheDocument(); + expect(getByText('Validators')).toBeInTheDocument(); + expect(getByText('Total contributors')).toBeInTheDocument(); + expect(getByText('Users by experience on Tasking Manager')).toBeInTheDocument(); + expect(getByText('Users by level')).toBeInTheDocument(); }); -test('ContributorsStats renders values as 0 if the project did not received contributions', () => { - render( +test('ContributorsStats renders values as 0 if the project did not received contributions', async () => { + const { getAllByText } = render( , ); - expect(screen.getAllByText('0').length).toBe(3); + await waitFor(() => expect(getAllByText('0').length).toBe(3)); + expect(getAllByText('0').length).toBe(3); }); diff --git a/frontend/src/components/projectStats/tests/edits.test.js b/frontend/src/components/projectStats/tests/edits.test.js index ebd8c01402..547a978589 100644 --- a/frontend/src/components/projectStats/tests/edits.test.js +++ b/frontend/src/components/projectStats/tests/edits.test.js @@ -1,6 +1,5 @@ -import React from 'react'; import { Provider } from 'react-redux'; -import { render } from '@testing-library/react'; +import { render, waitFor } from '@testing-library/react'; import '@testing-library/jest-dom'; import { EditsStats } from '../edits'; @@ -16,7 +15,7 @@ describe('EditsStats component', () => { edits: 310483, }; - it('render contents', () => { + it('render contents', async () => { const { getByText } = render( @@ -27,6 +26,7 @@ describe('EditsStats component', () => { , ); + await waitFor(() => expect(getByText('Changesets')).toBeInTheDocument()); expect(getByText('Changesets')).toBeInTheDocument(); expect(getByText('Buildings mapped')).toBeInTheDocument(); expect(getByText('Km road mapped')).toBeInTheDocument(); diff --git a/frontend/src/components/projectStats/tests/taskStats.test.js b/frontend/src/components/projectStats/tests/taskStats.test.js index 8d9722fe6a..854d52ddf8 100644 --- a/frontend/src/components/projectStats/tests/taskStats.test.js +++ b/frontend/src/components/projectStats/tests/taskStats.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { render, screen } from '@testing-library/react'; import '@testing-library/jest-dom'; diff --git a/frontend/src/components/projectStats/timeStats.js b/frontend/src/components/projectStats/timeStats.js index 944660a11f..4c37aefb51 100644 --- a/frontend/src/components/projectStats/timeStats.js +++ b/frontend/src/components/projectStats/timeStats.js @@ -1,4 +1,3 @@ -import React from 'react'; import ReactPlaceholder from 'react-placeholder'; import { FormattedMessage } from 'react-intl'; diff --git a/frontend/src/components/projects/clearFilters.js b/frontend/src/components/projects/clearFilters.js index 22119dad37..2104594b24 100644 --- a/frontend/src/components/projects/clearFilters.js +++ b/frontend/src/components/projects/clearFilters.js @@ -1,4 +1,3 @@ -import React from 'react'; import { Link } from 'react-router-dom'; import { FormattedMessage } from 'react-intl'; diff --git a/frontend/src/components/projects/filterSelectFields.js b/frontend/src/components/projects/filterSelectFields.js index bbc2fb9b50..277f86e059 100644 --- a/frontend/src/components/projects/filterSelectFields.js +++ b/frontend/src/components/projects/filterSelectFields.js @@ -1,4 +1,4 @@ -import React, { useEffect, useState } from 'react'; +import { useEffect, useState } from 'react'; import Select from 'react-select'; import { format, parse } from 'date-fns'; import DatePicker from 'react-datepicker'; diff --git a/frontend/src/components/projects/list.js b/frontend/src/components/projects/list.js index 813ff0d2e8..62653a275d 100644 --- a/frontend/src/components/projects/list.js +++ b/frontend/src/components/projects/list.js @@ -1,6 +1,5 @@ -import React from 'react'; import { Link } from 'react-router-dom'; -import ReactTooltip from 'react-tooltip'; +import { Tooltip } from 'react-tooltip'; import { FormattedMessage } from 'react-intl'; import messages from '../projectCard/messages'; @@ -29,22 +28,30 @@ export function ProjectListItem({ project }: Object) { {(msg) => ( <> -
+
{project.percentMapped}%
- + )} {(msg) => ( <> -
+
{project.percentValidated}%
- + )} @@ -54,11 +61,15 @@ export function ProjectListItem({ project }: Object) { > {(msg) => ( <> -
+
{project.totalContributors}
- + )} diff --git a/frontend/src/components/projects/mappingTypeFilterPicker.js b/frontend/src/components/projects/mappingTypeFilterPicker.js index db95211f33..bd59616101 100644 --- a/frontend/src/components/projects/mappingTypeFilterPicker.js +++ b/frontend/src/components/projects/mappingTypeFilterPicker.js @@ -1,4 +1,3 @@ -import React from 'react'; import { useIntl } from 'react-intl'; import messages from '../messages'; diff --git a/frontend/src/components/projects/moreFiltersForm.js b/frontend/src/components/projects/moreFiltersForm.js index 0f54d6494d..e8734457b0 100644 --- a/frontend/src/components/projects/moreFiltersForm.js +++ b/frontend/src/components/projects/moreFiltersForm.js @@ -1,4 +1,3 @@ -import React from 'react'; import { useSelector } from 'react-redux'; import { Link } from 'react-router-dom'; import { useQueryParam, BooleanParam } from 'use-query-params'; diff --git a/frontend/src/components/projects/myProjectNav.js b/frontend/src/components/projects/myProjectNav.js index 54728df85a..e94d7c3624 100644 --- a/frontend/src/components/projects/myProjectNav.js +++ b/frontend/src/components/projects/myProjectNav.js @@ -1,4 +1,3 @@ -import React from 'react'; import { Link } from 'react-router-dom'; import { useSelector } from 'react-redux'; import { FormattedMessage } from 'react-intl'; diff --git a/frontend/src/components/projects/orderBy.js b/frontend/src/components/projects/orderBy.js index 5e25a2fb70..0cc5577906 100644 --- a/frontend/src/components/projects/orderBy.js +++ b/frontend/src/components/projects/orderBy.js @@ -1,4 +1,3 @@ -import React from 'react'; import { FormattedMessage } from 'react-intl'; import messages from './messages'; diff --git a/frontend/src/components/projects/projectCardPaginator.js b/frontend/src/components/projects/projectCardPaginator.js index c5be0fd17a..2707a2baa6 100644 --- a/frontend/src/components/projects/projectCardPaginator.js +++ b/frontend/src/components/projects/projectCardPaginator.js @@ -1,5 +1,3 @@ -import React from 'react'; - import { PaginatorLine } from '../paginator'; export const ProjectCardPaginator = ({ status, pagination, fullProjectsQuery, setQueryParam }) => { diff --git a/frontend/src/components/projects/projectNav.js b/frontend/src/components/projects/projectNav.js index 7b9d32033e..e4aba2a6e6 100644 --- a/frontend/src/components/projects/projectNav.js +++ b/frontend/src/components/projects/projectNav.js @@ -1,4 +1,4 @@ -import React, { useEffect } from 'react'; +import { useEffect } from 'react'; import { Link, useLocation } from 'react-router-dom'; import { FormattedMessage } from 'react-intl'; import { useSelector, useDispatch } from 'react-redux'; @@ -90,12 +90,12 @@ export const ProjectNav = (props) => { setQuery( { ...fullProjectsQuery, - omitMapResults:!isMapShown + omitMapResults: !isMapShown, }, 'pushIn', ); // eslint-disable-next-line react-hooks/exhaustive-deps - },[isMapShown]) + }, [isMapShown]); const linkCombo = 'link ph3 f6 pv2 ba b--tan br1 ph3 fw5'; const moreFiltersAnyActive = diff --git a/frontend/src/components/projects/projectSearchBox.js b/frontend/src/components/projects/projectSearchBox.js index 058c352667..2eb691af8b 100644 --- a/frontend/src/components/projects/projectSearchBox.js +++ b/frontend/src/components/projects/projectSearchBox.js @@ -1,4 +1,4 @@ -import React, { useRef, useCallback } from 'react'; +import { useRef, useCallback } from 'react'; import { SearchIcon, CloseIcon } from '../svgIcons'; export const ProjectSearchBox = ({ diff --git a/frontend/src/components/projects/projectSearchResults.js b/frontend/src/components/projects/projectSearchResults.js index 9b27cd90e3..c4eb56f919 100644 --- a/frontend/src/components/projects/projectSearchResults.js +++ b/frontend/src/components/projects/projectSearchResults.js @@ -1,4 +1,3 @@ -import React from 'react'; import { useSelector } from 'react-redux'; import { FormattedMessage, FormattedNumber } from 'react-intl'; import ReactPlaceholder from 'react-placeholder'; diff --git a/frontend/src/components/projects/projectsActionFilter.js b/frontend/src/components/projects/projectsActionFilter.js index 5b55aeaedc..d6bd81536e 100644 --- a/frontend/src/components/projects/projectsActionFilter.js +++ b/frontend/src/components/projects/projectsActionFilter.js @@ -1,4 +1,4 @@ -import React, { useEffect } from 'react'; +import { useEffect } from 'react'; import { FormattedMessage } from 'react-intl'; import { useSelector, useDispatch } from 'react-redux'; diff --git a/frontend/src/components/projects/projectsMap.js b/frontend/src/components/projects/projectsMap.js index 94782468f3..762cfc37ad 100644 --- a/frontend/src/components/projects/projectsMap.js +++ b/frontend/src/components/projects/projectsMap.js @@ -1,4 +1,4 @@ -import React, { useLayoutEffect, useState, useCallback } from 'react'; +import { createRef, useLayoutEffect, useState, useCallback } from 'react'; import { useSelector } from 'react-redux'; import mapboxgl from 'mapbox-gl'; import 'mapbox-gl/dist/mapbox-gl.css'; @@ -96,7 +96,7 @@ export const mapboxLayerDefn = (map, mapResults, clickOnProjectID, disablePoiCli }; export const ProjectsMap = ({ mapResults, fullProjectsQuery, setQuery, className }) => { - const mapRef = React.createRef(); + const mapRef = createRef(); const locale = useSelector((state) => state.preferences['locale']); const [map, setMapObj] = useState(null); diff --git a/frontend/src/components/projects/tests/clearFilters.test.js b/frontend/src/components/projects/tests/clearFilters.test.js index 25cf06b4cf..fd6d17c3b0 100644 --- a/frontend/src/components/projects/tests/clearFilters.test.js +++ b/frontend/src/components/projects/tests/clearFilters.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { FormattedMessage } from 'react-intl'; import ClearFilters from '../clearFilters'; diff --git a/frontend/src/components/projects/tests/moreFiltersForm.test.js b/frontend/src/components/projects/tests/moreFiltersForm.test.js index 8f1c7ad6ec..b0bf72ff02 100644 --- a/frontend/src/components/projects/tests/moreFiltersForm.test.js +++ b/frontend/src/components/projects/tests/moreFiltersForm.test.js @@ -1,5 +1,5 @@ import '@testing-library/jest-dom'; -import { parse } from 'query-string'; +import queryString from 'query-string'; import { act, render, screen, waitFor } from '@testing-library/react'; import { ReactRouter6Adapter } from 'use-query-params/adapters/react-router-6'; @@ -52,7 +52,7 @@ describe('MoreFiltersForm', () => { { basedOnMyInterests: BooleanParam, }, - parse(router.state.location.search), + queryString.parse(router.state.location.search), ), ).toEqual({ basedOnMyInterests: true }), ); diff --git a/frontend/src/components/projects/tests/projectNav.test.js b/frontend/src/components/projects/tests/projectNav.test.js index 3ddfe8c6c7..9c40535d6e 100644 --- a/frontend/src/components/projects/tests/projectNav.test.js +++ b/frontend/src/components/projects/tests/projectNav.test.js @@ -11,7 +11,7 @@ import { } from '../../../utils/testWithIntl'; import { ProjectNav } from '../projectNav'; import messages from '../messages'; -import { parse } from 'query-string'; +import queryString from 'query-string'; describe('Project Navigation Bar', () => { it('should render component details', () => { @@ -40,7 +40,9 @@ describe('Project Navigation Bar', () => { { route: '?text=something' }, ); - expect(decodeQueryParams({ text: StringParam }, parse(router.state.location.search))).toEqual({ + expect( + decodeQueryParams({ text: StringParam }, queryString.parse(router.state.location.search)), + ).toEqual({ text: 'something', }); }); diff --git a/frontend/src/components/projects/tests/projectsActionFilter.test.js b/frontend/src/components/projects/tests/projectsActionFilter.test.js index 7b7a1b298e..383dd3d008 100644 --- a/frontend/src/components/projects/tests/projectsActionFilter.test.js +++ b/frontend/src/components/projects/tests/projectsActionFilter.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { screen, act } from '@testing-library/react'; import '@testing-library/jest-dom'; diff --git a/frontend/src/components/projects/tests/toggles.test.js b/frontend/src/components/projects/tests/toggles.test.js index 82f504b760..288771a549 100644 --- a/frontend/src/components/projects/tests/toggles.test.js +++ b/frontend/src/components/projects/tests/toggles.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { act } from 'react-test-renderer'; import { store } from '../../../store'; diff --git a/frontend/src/components/rapidEditor.js b/frontend/src/components/rapidEditor.js index 05fbc219f9..35378c0549 100644 --- a/frontend/src/components/rapidEditor.js +++ b/frontend/src/components/rapidEditor.js @@ -7,9 +7,9 @@ import { OSM_CLIENT_ID, OSM_CLIENT_SECRET, OSM_REDIRECT_URI, OSM_SERVER_URL } fr import { types } from '../store/actions/editor'; // We import from a CDN using a SEMVER minor version range -import { version as rapidVersion, name as rapidName } from '@rapideditor/rapid/package.json'; +import rapidPackage from '@rapideditor/rapid/package.json'; -const baseCdnUrl = `https://cdn.jsdelivr.net/npm/${rapidName}@~${rapidVersion}/dist/`; +const baseCdnUrl = `https://cdn.jsdelivr.net/npm/${rapidPackage.name}@~${rapidPackage.version}/dist/`; // We currently copy rapid files to the public/static/rapid directory. This should probably remain, // since it can be useful for debugging rapid issues in the TM. // const baseCdnUrl = '/static/rapid/'; diff --git a/frontend/src/components/statsCard.js b/frontend/src/components/statsCard.js index 15d31c9345..a0777314e6 100644 --- a/frontend/src/components/statsCard.js +++ b/frontend/src/components/statsCard.js @@ -1,4 +1,3 @@ -import React from 'react'; import { FormattedNumber } from 'react-intl'; import shortNumber from 'short-number'; diff --git a/frontend/src/components/statsTimestamp/index.js b/frontend/src/components/statsTimestamp/index.js index a92ddb2dc5..00c8dd3c61 100644 --- a/frontend/src/components/statsTimestamp/index.js +++ b/frontend/src/components/statsTimestamp/index.js @@ -1,5 +1,5 @@ import { useIntl } from 'react-intl'; -import ReactTooltip from 'react-tooltip'; +import { Tooltip } from 'react-tooltip'; import { InfoIcon } from '../svgIcons'; import messages from './messages'; @@ -22,13 +22,13 @@ function StatsTimestamp({ messageType }) {
- +
); } diff --git a/frontend/src/components/svgIcons/alert.js b/frontend/src/components/svgIcons/alert.js index bb9f8a07db..4085c6e251 100644 --- a/frontend/src/components/svgIcons/alert.js +++ b/frontend/src/components/svgIcons/alert.js @@ -1,6 +1,6 @@ -import React from 'react'; +import { PureComponent } from 'react'; -export class AlertIcon extends React.PureComponent { +export class AlertIcon extends PureComponent { render() { return ( diff --git a/frontend/src/components/svgIcons/area.js b/frontend/src/components/svgIcons/area.js index 8a18a8ba01..df16345bd9 100644 --- a/frontend/src/components/svgIcons/area.js +++ b/frontend/src/components/svgIcons/area.js @@ -1,6 +1,6 @@ -import React from 'react'; +import { PureComponent } from 'react'; -export class AreaIcon extends React.PureComponent { +export class AreaIcon extends PureComponent { render() { return ( diff --git a/frontend/src/components/svgIcons/asterisk.js b/frontend/src/components/svgIcons/asterisk.js index 50f6f7e695..5f8de49bc1 100644 --- a/frontend/src/components/svgIcons/asterisk.js +++ b/frontend/src/components/svgIcons/asterisk.js @@ -1,8 +1,8 @@ -import React from 'react'; +import { PureComponent } from 'react'; // Icon produced by FontAwesome project: https://github.com/FortAwesome/Font-Awesome/ // License: CC-By 4.0 -export class AsteriskIcon extends React.PureComponent { +export class AsteriskIcon extends PureComponent { render() { return ( diff --git a/frontend/src/components/svgIcons/ban.js b/frontend/src/components/svgIcons/ban.js index 2aca80d86c..0daa94515a 100644 --- a/frontend/src/components/svgIcons/ban.js +++ b/frontend/src/components/svgIcons/ban.js @@ -1,8 +1,8 @@ -import React from 'react'; +import { PureComponent } from 'react'; // Icon produced by FontAwesome project: https://github.com/FortAwesome/Font-Awesome/ // License: CC-By 4.0 -export class BanIcon extends React.PureComponent { +export class BanIcon extends PureComponent { render() { return (
{['ID', 'RAPID'].includes(editor) ? ( - )} - + ) : ( + import('../comments/commentInput' /* webpackChunkName: "commentInput" */), +); export function CompletionTabForMapping({ project, @@ -262,7 +266,7 @@ export function CompletionTabForMapping({

-

+ }> -

+
{directedFrom && (
@@ -289,7 +293,7 @@ export function CompletionTabForMapping({
)} -
+
{disabled && ( - + - + )}
)} -
+
{disabled && ( - + - + )}
- {/* This can handle displaying a messaage for the no comments section + {/* This can handle displaying a messaage for the no comments section because no activities will be handled earlier */} {shownHistory.length === 0 ? (
diff --git a/frontend/src/components/taskSelection/taskList.js b/frontend/src/components/taskSelection/taskList.js index 43c7cf30d3..00c2fd214c 100644 --- a/frontend/src/components/taskSelection/taskList.js +++ b/frontend/src/components/taskSelection/taskList.js @@ -1,4 +1,4 @@ -import React, { useState, useEffect, useRef, useCallback } from 'react'; +import { useState, useEffect, useRef, useCallback } from 'react'; import { useLocation } from 'react-router-dom'; import Popup from 'reactjs-popup'; import { useQueryParam, NumberParam, StringParam } from 'use-query-params'; diff --git a/frontend/src/components/taskSelection/tests/action.test.js b/frontend/src/components/taskSelection/tests/action.test.js index 1da5528821..34023f81a6 100644 --- a/frontend/src/components/taskSelection/tests/action.test.js +++ b/frontend/src/components/taskSelection/tests/action.test.js @@ -1,5 +1,5 @@ import '@testing-library/jest-dom'; -import { screen, waitFor, within } from '@testing-library/react'; +import { act, screen, waitFor, within } from '@testing-library/react'; import { getProjectSummary } from '../../../network/tests/mockData/projects'; import { userMultipleLockedTasksDetails } from '../../../network/tests/mockData/userStats'; @@ -81,14 +81,14 @@ describe('Session Expire Dialogs', () => { jest.useFakeTimers(); }); - afterEach(() => { - jest.runOnlyPendingTimers(); + afterEach(async () => { + await act(() => jest.runOnlyPendingTimers()); jest.useRealTimers(); }); it('should display modal to notify user session about to expire', async () => { setup(); - jest.advanceTimersByTime(6900000); + await act(() => jest.advanceTimersByTime(6900000)); const extendSessionDialog = screen.getByRole('dialog'); expect(within(extendSessionDialog).getByRole('heading')).toHaveTextContent( messages.sessionAboutToExpireTitle.defaultMessage, @@ -97,7 +97,7 @@ describe('Session Expire Dialogs', () => { it('should display modal to notify user session has ended', async () => { setup(); - jest.advanceTimersByTime(7200000); + await act(() => jest.advanceTimersByTime(7200000)); const extendSessionDialog = screen.getByRole('dialog'); expect(within(extendSessionDialog).getByRole('heading')).toHaveTextContent( messages.sessionExpiredTitle.defaultMessage, diff --git a/frontend/src/components/taskSelection/tests/actionSidebars.test.js b/frontend/src/components/taskSelection/tests/actionSidebars.test.js index bfd2770f9b..3635db56b6 100644 --- a/frontend/src/components/taskSelection/tests/actionSidebars.test.js +++ b/frontend/src/components/taskSelection/tests/actionSidebars.test.js @@ -23,6 +23,8 @@ import { TaskMapAction } from '../action'; import { getProjectSummary } from '../../../network/tests/mockData/projects'; import tasksGeojson from '../../../utils/tests/snippets/tasksGeometry'; import { userMultipleLockedTasksDetails } from '../../../network/tests/mockData/userStats'; +// This is a late import in a React.lazy call; it takes awhile for commentInput to load +import '../../comments/commentInput'; jest.mock('react-hot-toast', () => ({ error: jest.fn(), @@ -56,13 +58,17 @@ describe('Appearance of unsaved map changes to be dealt with while mapping', () }); test('when submitting a task', async () => { - renderWithRouter( + const { user } = renderWithRouter( , ); + const button = screen.getByRole('button', { name: 'Submit task' }); + expect(button).toBeDisabled(); + await user.hover(button); + await waitFor(() => expect(screen.getByRole('tooltip')).toBeInTheDocument()); expect(screen.getByText(messages.unsavedChangesTooltip.defaultMessage)).toBeInTheDocument(); }); @@ -220,7 +226,7 @@ describe('Appearance of unsaved map changes to be dealt with while validating', }); test('when submitting a task', async () => { - renderWithRouter( + const { user } = renderWithRouter( , ); + const button = screen.getByRole('button', { name: 'Submit task' }); + expect(button).toBeDisabled(); + await user.hover(button); + await waitFor(() => expect(screen.getByRole('tooltip')).toBeInTheDocument()); expect(screen.getByText(messages.unsavedChangesTooltip.defaultMessage)).toBeInTheDocument(); }); }); diff --git a/frontend/src/components/taskSelection/tests/actionsTabsNav.test.js b/frontend/src/components/taskSelection/tests/actionsTabsNav.test.js index 52823d3fc3..ceed3cf72a 100644 --- a/frontend/src/components/taskSelection/tests/actionsTabsNav.test.js +++ b/frontend/src/components/taskSelection/tests/actionsTabsNav.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import '@testing-library/jest-dom'; import { render, screen } from '@testing-library/react'; diff --git a/frontend/src/components/taskSelection/tests/contributions.test.js b/frontend/src/components/taskSelection/tests/contributions.test.js index 079aa7dfe2..96a0b9d85a 100644 --- a/frontend/src/components/taskSelection/tests/contributions.test.js +++ b/frontend/src/components/taskSelection/tests/contributions.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import '@testing-library/jest-dom'; import { screen } from '@testing-library/react'; import selectEvent from 'react-select-event'; diff --git a/frontend/src/components/taskSelection/tests/footer.test.js b/frontend/src/components/taskSelection/tests/footer.test.js index 49fc05a965..16bdf9d51c 100644 --- a/frontend/src/components/taskSelection/tests/footer.test.js +++ b/frontend/src/components/taskSelection/tests/footer.test.js @@ -1,5 +1,4 @@ import '@testing-library/jest-dom'; -import React from 'react'; import { FormattedMessage } from 'react-intl'; import { act, screen, waitFor } from '@testing-library/react'; import { MemoryRouter } from 'react-router-dom'; diff --git a/frontend/src/components/taskSelection/tests/imagery.test.js b/frontend/src/components/taskSelection/tests/imagery.test.js index d8eb1611ae..7e9c4b6fc4 100644 --- a/frontend/src/components/taskSelection/tests/imagery.test.js +++ b/frontend/src/components/taskSelection/tests/imagery.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { render, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import '@testing-library/jest-dom'; diff --git a/frontend/src/components/taskSelection/tests/index.test.js b/frontend/src/components/taskSelection/tests/index.test.js index 6b3cc9846c..e3d8302e90 100644 --- a/frontend/src/components/taskSelection/tests/index.test.js +++ b/frontend/src/components/taskSelection/tests/index.test.js @@ -43,7 +43,7 @@ describe('Contributions', () => { ); await user.click( await screen.findByRole('button', { - name: 'Select tasks mapped by user_3', + description: 'Select tasks mapped by user_3', }), ); expect( @@ -74,7 +74,7 @@ describe('Contributions', () => { ); await user.click( await screen.findByRole('button', { - name: 'Select tasks validated by user_3', + description: 'Select tasks validated by user_3', }), ); expect( diff --git a/frontend/src/components/taskSelection/tests/legend.test.js b/frontend/src/components/taskSelection/tests/legend.test.js index 61c5831c64..033b66656a 100644 --- a/frontend/src/components/taskSelection/tests/legend.test.js +++ b/frontend/src/components/taskSelection/tests/legend.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { render, screen } from '@testing-library/react'; import '@testing-library/jest-dom'; diff --git a/frontend/src/components/taskSelection/tests/lockedTasks.test.js b/frontend/src/components/taskSelection/tests/lockedTasks.test.js index 7b10f43afc..4a1e5e2f1f 100644 --- a/frontend/src/components/taskSelection/tests/lockedTasks.test.js +++ b/frontend/src/components/taskSelection/tests/lockedTasks.test.js @@ -1,5 +1,4 @@ import '@testing-library/jest-dom'; -import React from 'react'; import TestRenderer from 'react-test-renderer'; import { FormattedMessage } from 'react-intl'; import { MemoryRouter } from 'react-router-dom'; diff --git a/frontend/src/components/taskSelection/tests/mappingLevelIcon.test.js b/frontend/src/components/taskSelection/tests/mappingLevelIcon.test.js index e3e678114c..37e641f9ee 100644 --- a/frontend/src/components/taskSelection/tests/mappingLevelIcon.test.js +++ b/frontend/src/components/taskSelection/tests/mappingLevelIcon.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { FormattedMessage } from 'react-intl'; import { createComponentWithIntl } from '../../../utils/testWithIntl'; @@ -38,7 +37,7 @@ describe('if user is BEGINNER, MappingLevelIcon should not return', () => { new Error('No instances found with node type: "HalfStarIcon"'), ); expect(() => instance.findByType(FormattedMessage)).toThrow( - new Error('No instances found with node type: "FormattedMessage"'), + new Error('No instances found with node type: "MemoizedFormattedMessage"'), ); }); }); diff --git a/frontend/src/components/taskSelection/tests/multipleTaskHistories.test.js b/frontend/src/components/taskSelection/tests/multipleTaskHistories.test.js index dd31c40d2d..afd31988b3 100644 --- a/frontend/src/components/taskSelection/tests/multipleTaskHistories.test.js +++ b/frontend/src/components/taskSelection/tests/multipleTaskHistories.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import '@testing-library/jest-dom'; import { render, screen } from '@testing-library/react'; diff --git a/frontend/src/components/taskSelection/tests/permissionErrorModal.test.js b/frontend/src/components/taskSelection/tests/permissionErrorModal.test.js index 006322f6e0..1ea96145a7 100644 --- a/frontend/src/components/taskSelection/tests/permissionErrorModal.test.js +++ b/frontend/src/components/taskSelection/tests/permissionErrorModal.test.js @@ -1,5 +1,4 @@ import '@testing-library/jest-dom'; -import React from 'react'; import { FormattedMessage } from 'react-intl'; import { MemoryRouter } from 'react-router-dom'; import { screen } from '@testing-library/react'; diff --git a/frontend/src/components/taskSelection/tests/resourcesTab.test.js b/frontend/src/components/taskSelection/tests/resourcesTab.test.js index aee4be1b88..fa75cb5660 100644 --- a/frontend/src/components/taskSelection/tests/resourcesTab.test.js +++ b/frontend/src/components/taskSelection/tests/resourcesTab.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import '@testing-library/jest-dom'; import { render, screen, waitFor } from '@testing-library/react'; diff --git a/frontend/src/components/taskSelection/tests/tabSelector.test.js b/frontend/src/components/taskSelection/tests/tabSelector.test.js index 62cf75fb83..cafd75648a 100644 --- a/frontend/src/components/taskSelection/tests/tabSelector.test.js +++ b/frontend/src/components/taskSelection/tests/tabSelector.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import '@testing-library/jest-dom'; import { render, screen } from '@testing-library/react'; diff --git a/frontend/src/components/taskSelection/tests/taskList.test.js b/frontend/src/components/taskSelection/tests/taskList.test.js index 622cd9522f..667314e672 100644 --- a/frontend/src/components/taskSelection/tests/taskList.test.js +++ b/frontend/src/components/taskSelection/tests/taskList.test.js @@ -12,6 +12,8 @@ import { renderWithRouter, } from '../../../utils/testWithIntl'; import { TaskFilter, TaskItem } from '../taskList'; +// This is a late import in a React.lazy call; it takes awhile for commentInput to load +import '../../comments/commentInput'; describe('Task Item', () => { const task = { @@ -84,7 +86,7 @@ describe('Task Item', () => { ); await user.click(screen.getByTitle(/See task history/i)); expect( - within(screen.getByRole('dialog')).getByRole('radio', { name: /activities/i }), + await within(screen.getByRole('dialog')).findByRole('radio', { name: /activities/i }), ).toBeInTheDocument(); }); }); diff --git a/frontend/src/components/taskSelection/tests/taskStatus.test.js b/frontend/src/components/taskSelection/tests/taskStatus.test.js index 89f36653aa..c826823868 100644 --- a/frontend/src/components/taskSelection/tests/taskStatus.test.js +++ b/frontend/src/components/taskSelection/tests/taskStatus.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { FormattedMessage } from 'react-intl'; import { createComponentWithIntl } from '../../../utils/testWithIntl'; diff --git a/frontend/src/components/teamsAndOrgs/campaigns.js b/frontend/src/components/teamsAndOrgs/campaigns.js index f8674ef82f..f87aaf85b8 100644 --- a/frontend/src/components/teamsAndOrgs/campaigns.js +++ b/frontend/src/components/teamsAndOrgs/campaigns.js @@ -1,4 +1,4 @@ -import React, { useState } from 'react'; +import { useState } from 'react'; import { Link } from 'react-router-dom'; import { FormattedMessage } from 'react-intl'; import { Form, Field } from 'react-final-form'; diff --git a/frontend/src/components/teamsAndOrgs/campaignsPlaceholder.js b/frontend/src/components/teamsAndOrgs/campaignsPlaceholder.js index 17902f5790..df2346200a 100644 --- a/frontend/src/components/teamsAndOrgs/campaignsPlaceholder.js +++ b/frontend/src/components/teamsAndOrgs/campaignsPlaceholder.js @@ -1,4 +1,3 @@ -import React from 'react'; import { TextRow } from 'react-placeholder/lib/placeholders'; import { HashtagIcon } from '../svgIcons'; diff --git a/frontend/src/components/teamsAndOrgs/editMode.js b/frontend/src/components/teamsAndOrgs/editMode.js index 09d96f8ac2..23454d778e 100644 --- a/frontend/src/components/teamsAndOrgs/editMode.js +++ b/frontend/src/components/teamsAndOrgs/editMode.js @@ -1,4 +1,3 @@ -import React from 'react'; import { FormattedMessage } from 'react-intl'; import messages from './messages'; diff --git a/frontend/src/components/teamsAndOrgs/featureStats.js b/frontend/src/components/teamsAndOrgs/featureStats.js index 9f919f53e0..19704f3b63 100644 --- a/frontend/src/components/teamsAndOrgs/featureStats.js +++ b/frontend/src/components/teamsAndOrgs/featureStats.js @@ -1,4 +1,4 @@ -import React, { useEffect, useState } from 'react'; +import { useEffect, useState } from 'react'; import axios from 'axios'; import { FormattedMessage } from 'react-intl'; diff --git a/frontend/src/components/teamsAndOrgs/management.js b/frontend/src/components/teamsAndOrgs/management.js index c35dd62c44..e344dbdf66 100644 --- a/frontend/src/components/teamsAndOrgs/management.js +++ b/frontend/src/components/teamsAndOrgs/management.js @@ -1,7 +1,6 @@ -import React from 'react'; import { Link } from 'react-router-dom'; import { useIntl, FormattedMessage } from 'react-intl'; -import ReactTooltip from 'react-tooltip'; +import { Tooltip } from 'react-tooltip'; import messages from './messages'; import { CustomButton } from '../button'; @@ -28,7 +27,10 @@ export const DeleteButton = ({ className, onClick, showText = true }: Object) => const intl = useIntl(); return ( -
+
{showText && ( @@ -36,7 +38,7 @@ export const DeleteButton = ({ className, onClick, showText = true }: Object) => )}
- + ); }; diff --git a/frontend/src/components/teamsAndOrgs/members.js b/frontend/src/components/teamsAndOrgs/members.js index a87358bb69..8b84e783a4 100644 --- a/frontend/src/components/teamsAndOrgs/members.js +++ b/frontend/src/components/teamsAndOrgs/members.js @@ -1,4 +1,4 @@ -import React, { useState, useEffect, useCallback, useRef } from 'react'; +import { useState, useEffect, useCallback, useRef } from 'react'; import { Link } from 'react-router-dom'; import { useSelector } from 'react-redux'; import { FormattedMessage } from 'react-intl'; diff --git a/frontend/src/components/teamsAndOrgs/menu.js b/frontend/src/components/teamsAndOrgs/menu.js index 95c0743cf2..bc346bc589 100644 --- a/frontend/src/components/teamsAndOrgs/menu.js +++ b/frontend/src/components/teamsAndOrgs/menu.js @@ -1,4 +1,3 @@ -import React from 'react'; import { FormattedMessage } from 'react-intl'; import messages from './messages'; diff --git a/frontend/src/components/teamsAndOrgs/messageMembers.js b/frontend/src/components/teamsAndOrgs/messageMembers.js index 8f47bbcb4c..c6c6698c0a 100644 --- a/frontend/src/components/teamsAndOrgs/messageMembers.js +++ b/frontend/src/components/teamsAndOrgs/messageMembers.js @@ -1,13 +1,17 @@ -import React, { useState } from 'react'; +import { lazy, Suspense, useState } from 'react'; import { useSelector } from 'react-redux'; import { FormattedMessage } from 'react-intl'; import toast from 'react-hot-toast'; import messages from './messages'; import { Button } from '../button'; -import { CommentInputField } from '../comments/commentInput'; import { MessageStatus } from '../comments/status'; import { pushToLocalJSONAPI } from '../../network/genericJSONRequest'; +import ReactPlaceholder from 'react-placeholder'; + +const CommentInputField = lazy(() => + import('../comments/commentInput' /* webpackChunkName: "commentInput" */), +); export function MessageMembers({ teamId, members }: Object) { const token = useSelector((state) => state.auth.token); @@ -64,12 +68,16 @@ export function MessageMembers({ teamId, members }: Object) {
)}
- member.username)} - isShowTabNavs - /> + } + > + member.username)} + isShowTabNavs + /> +
{!message && }
diff --git a/frontend/src/components/teamsAndOrgs/newUsersStats.js b/frontend/src/components/teamsAndOrgs/newUsersStats.js index 044da23c7b..4658586f51 100644 --- a/frontend/src/components/teamsAndOrgs/newUsersStats.js +++ b/frontend/src/components/teamsAndOrgs/newUsersStats.js @@ -1,4 +1,3 @@ -import React from 'react'; import ReactPlaceholder from 'react-placeholder'; import { FormattedMessage } from 'react-intl'; diff --git a/frontend/src/components/teamsAndOrgs/orgUsageLevel.js b/frontend/src/components/teamsAndOrgs/orgUsageLevel.js index 5e05422d3f..802cb458c2 100644 --- a/frontend/src/components/teamsAndOrgs/orgUsageLevel.js +++ b/frontend/src/components/teamsAndOrgs/orgUsageLevel.js @@ -1,4 +1,3 @@ -import React from 'react'; import { getYear } from 'date-fns'; import { FormattedMessage, FormattedNumber } from 'react-intl'; diff --git a/frontend/src/components/teamsAndOrgs/organisationProjectStats.js b/frontend/src/components/teamsAndOrgs/organisationProjectStats.js index 890721b3a9..b0f15afc35 100644 --- a/frontend/src/components/teamsAndOrgs/organisationProjectStats.js +++ b/frontend/src/components/teamsAndOrgs/organisationProjectStats.js @@ -1,4 +1,3 @@ -import React from 'react'; import { setDayOfYear, format } from 'date-fns'; import { FormattedMessage } from 'react-intl'; diff --git a/frontend/src/components/teamsAndOrgs/organisations.js b/frontend/src/components/teamsAndOrgs/organisations.js index 86357d7999..40fca489f3 100644 --- a/frontend/src/components/teamsAndOrgs/organisations.js +++ b/frontend/src/components/teamsAndOrgs/organisations.js @@ -1,4 +1,4 @@ -import React, { useState } from 'react'; +import { useState } from 'react'; import { useSelector } from 'react-redux'; import { Link } from 'react-router-dom'; import { Form, Field } from 'react-final-form'; diff --git a/frontend/src/components/teamsAndOrgs/organisationsPlaceholder.js b/frontend/src/components/teamsAndOrgs/organisationsPlaceholder.js index 696f0cee5d..501c769e91 100644 --- a/frontend/src/components/teamsAndOrgs/organisationsPlaceholder.js +++ b/frontend/src/components/teamsAndOrgs/organisationsPlaceholder.js @@ -1,4 +1,3 @@ -import React from 'react'; import { TextRow, RoundShape, RectShape } from 'react-placeholder/lib/placeholders'; export const organisationCardPlaceholderTemplate = () => (_n, i) => diff --git a/frontend/src/components/teamsAndOrgs/projects.js b/frontend/src/components/teamsAndOrgs/projects.js index 92169c76da..70a5f083d6 100644 --- a/frontend/src/components/teamsAndOrgs/projects.js +++ b/frontend/src/components/teamsAndOrgs/projects.js @@ -1,4 +1,3 @@ -import React from 'react'; import { Link } from 'react-router-dom'; import { FormattedMessage } from 'react-intl'; import ReactPlaceholder from 'react-placeholder'; diff --git a/frontend/src/components/teamsAndOrgs/remainingTasksStats.js b/frontend/src/components/teamsAndOrgs/remainingTasksStats.js index a1105bb3e7..f77605f6d8 100644 --- a/frontend/src/components/teamsAndOrgs/remainingTasksStats.js +++ b/frontend/src/components/teamsAndOrgs/remainingTasksStats.js @@ -1,5 +1,4 @@ -import React from 'react'; -import ReactTooltip from 'react-tooltip'; +import { Tooltip } from 'react-tooltip'; import { FormattedMessage, FormattedNumber, useIntl } from 'react-intl'; import messages from './messages'; @@ -10,11 +9,14 @@ const ActionsNeededLabel = () => { const intl = useIntl(); return ( <> - + - + ); }; diff --git a/frontend/src/components/teamsAndOrgs/tasksStats.js b/frontend/src/components/teamsAndOrgs/tasksStats.js index 8ca89cadec..7cf4f51c27 100644 --- a/frontend/src/components/teamsAndOrgs/tasksStats.js +++ b/frontend/src/components/teamsAndOrgs/tasksStats.js @@ -1,4 +1,4 @@ -import React, { Suspense, useState } from 'react'; +import { lazy, Suspense, useState } from 'react'; import ReactPlaceholder from 'react-placeholder'; import { FormattedMessage } from 'react-intl'; import messages from './messages'; @@ -12,7 +12,7 @@ import { } from '../projects/filterSelectFields'; import { TasksStatsSummary } from './tasksStatsSummary'; -const TasksStatsChart = React.lazy(() => +const TasksStatsChart = lazy(() => import('./tasksStatsChart' /* webpackChunkName: "taskStatsChart" */), ); diff --git a/frontend/src/components/teamsAndOrgs/tasksStatsChart.js b/frontend/src/components/teamsAndOrgs/tasksStatsChart.js index ca69e1584b..a0c3d6ed7f 100644 --- a/frontend/src/components/teamsAndOrgs/tasksStatsChart.js +++ b/frontend/src/components/teamsAndOrgs/tasksStatsChart.js @@ -1,4 +1,3 @@ -import React from 'react'; import { Chart as ChartJS, CategoryScale, diff --git a/frontend/src/components/teamsAndOrgs/tasksStatsSummary.js b/frontend/src/components/teamsAndOrgs/tasksStatsSummary.js index 4381b6570f..93fd7ef867 100644 --- a/frontend/src/components/teamsAndOrgs/tasksStatsSummary.js +++ b/frontend/src/components/teamsAndOrgs/tasksStatsSummary.js @@ -1,4 +1,3 @@ -import React from 'react'; import { FormattedMessage, FormattedNumber } from 'react-intl'; import messages from './messages'; diff --git a/frontend/src/components/teamsAndOrgs/teams.js b/frontend/src/components/teamsAndOrgs/teams.js index a20ef59578..11222882d6 100644 --- a/frontend/src/components/teamsAndOrgs/teams.js +++ b/frontend/src/components/teamsAndOrgs/teams.js @@ -1,10 +1,10 @@ -import React, { useState } from 'react'; +import { useState } from 'react'; import { useSelector } from 'react-redux'; import { Link } from 'react-router-dom'; import { FormattedMessage, useIntl } from 'react-intl'; import ReactPlaceholder from 'react-placeholder'; import { Form, Field, useFormState } from 'react-final-form'; -import ReactTooltip from 'react-tooltip'; +import { Tooltip } from 'react-tooltip'; import messages from './messages'; import { InfoIcon } from '../svgIcons'; @@ -214,9 +214,12 @@ export function TeamInformation(props) { width={12} height={12} className="blue-grey v-mid pb1 ml2" - data-tip={intl.formatMessage(messages[`${joinMethods[method]}Description`])} + data-tooltip-id={'joinMethodDescriptionTooltip'} + data-tooltip-content={intl.formatMessage( + messages[`${joinMethods[method]}Description`], + )} /> - +
))}
@@ -234,7 +237,8 @@ export function TeamInformation(props) { width={12} height={12} className="blue-grey v-mid pb1 ml2" - data-tip={intl.formatMessage(messages['publicDescription'])} + data-tooltip-id={'visibilityDescriptionTooltip'} + data-tooltip-content={intl.formatMessage(messages['publicDescription'])} />
@@ -246,9 +250,10 @@ export function TeamInformation(props) { width={12} height={12} className="blue-grey v-mid pb1 ml2" - data-tip={intl.formatMessage(messages['privateDescription'])} + data-tooltip-id={'visibilityDescriptionTooltip'} + data-tooltip-content={intl.formatMessage(messages['privateDescription'])} /> - +
)} diff --git a/frontend/src/components/teamsAndOrgs/teamsPlaceholder.js b/frontend/src/components/teamsAndOrgs/teamsPlaceholder.js index 1e912cb25f..68b4b083c9 100644 --- a/frontend/src/components/teamsAndOrgs/teamsPlaceholder.js +++ b/frontend/src/components/teamsAndOrgs/teamsPlaceholder.js @@ -1,4 +1,4 @@ -import React, { Fragment } from 'react'; +import { Fragment } from 'react'; import { TextRow, TextBlock, RoundShape, RectShape } from 'react-placeholder/lib/placeholders'; diff --git a/frontend/src/components/teamsAndOrgs/tests/featureStats.test.js b/frontend/src/components/teamsAndOrgs/tests/featureStats.test.js index ee4fc20d1a..67c5afd38f 100644 --- a/frontend/src/components/teamsAndOrgs/tests/featureStats.test.js +++ b/frontend/src/components/teamsAndOrgs/tests/featureStats.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { render, screen, waitFor } from '@testing-library/react'; import axios from 'axios'; import '@testing-library/jest-dom'; diff --git a/frontend/src/components/teamsAndOrgs/tests/members.test.js b/frontend/src/components/teamsAndOrgs/tests/members.test.js index 3db914800f..9186dca089 100644 --- a/frontend/src/components/teamsAndOrgs/tests/members.test.js +++ b/frontend/src/components/teamsAndOrgs/tests/members.test.js @@ -1,5 +1,4 @@ import '@testing-library/jest-dom'; -import React from 'react'; import { Provider } from 'react-redux'; import { screen } from '@testing-library/react'; diff --git a/frontend/src/components/teamsAndOrgs/tests/menu.test.js b/frontend/src/components/teamsAndOrgs/tests/menu.test.js index 7142f888a0..c2913907e4 100644 --- a/frontend/src/components/teamsAndOrgs/tests/menu.test.js +++ b/frontend/src/components/teamsAndOrgs/tests/menu.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { screen } from '@testing-library/react'; import '@testing-library/jest-dom'; diff --git a/frontend/src/components/teamsAndOrgs/tests/newUsersStats.test.js b/frontend/src/components/teamsAndOrgs/tests/newUsersStats.test.js index 4a26f75955..8dca8aa798 100644 --- a/frontend/src/components/teamsAndOrgs/tests/newUsersStats.test.js +++ b/frontend/src/components/teamsAndOrgs/tests/newUsersStats.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { render, screen, waitFor } from '@testing-library/react'; import '@testing-library/jest-dom'; diff --git a/frontend/src/components/teamsAndOrgs/tests/orgUsageLevel.test.js b/frontend/src/components/teamsAndOrgs/tests/orgUsageLevel.test.js index 50c8ac89ee..8b835af801 100644 --- a/frontend/src/components/teamsAndOrgs/tests/orgUsageLevel.test.js +++ b/frontend/src/components/teamsAndOrgs/tests/orgUsageLevel.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { render, screen, within } from '@testing-library/react'; import { getYear } from 'date-fns'; import '@testing-library/jest-dom'; diff --git a/frontend/src/components/teamsAndOrgs/tests/organisationProjectStats.test.js b/frontend/src/components/teamsAndOrgs/tests/organisationProjectStats.test.js index a294004730..13589e7db4 100644 --- a/frontend/src/components/teamsAndOrgs/tests/organisationProjectStats.test.js +++ b/frontend/src/components/teamsAndOrgs/tests/organisationProjectStats.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { setDayOfYear, format } from 'date-fns'; import { screen } from '@testing-library/react'; import '@testing-library/jest-dom'; diff --git a/frontend/src/components/teamsAndOrgs/tests/remainingTasksStats.test.js b/frontend/src/components/teamsAndOrgs/tests/remainingTasksStats.test.js index 61669a428f..6dade63e48 100644 --- a/frontend/src/components/teamsAndOrgs/tests/remainingTasksStats.test.js +++ b/frontend/src/components/teamsAndOrgs/tests/remainingTasksStats.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { render, screen } from '@testing-library/react'; import '@testing-library/jest-dom'; diff --git a/frontend/src/components/teamsAndOrgs/tests/tasksStats.test.js b/frontend/src/components/teamsAndOrgs/tests/tasksStats.test.js index ab055371d6..7fa9e888b7 100644 --- a/frontend/src/components/teamsAndOrgs/tests/tasksStats.test.js +++ b/frontend/src/components/teamsAndOrgs/tests/tasksStats.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { render, screen } from '@testing-library/react'; import '@testing-library/jest-dom'; diff --git a/frontend/src/components/teamsAndOrgs/tests/tasksStatsSummary.test.js b/frontend/src/components/teamsAndOrgs/tests/tasksStatsSummary.test.js index 6c4ab86253..263d3a20f9 100644 --- a/frontend/src/components/teamsAndOrgs/tests/tasksStatsSummary.test.js +++ b/frontend/src/components/teamsAndOrgs/tests/tasksStatsSummary.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { render, screen } from '@testing-library/react'; import '@testing-library/jest-dom'; diff --git a/frontend/src/components/tests/basemapMenu.test.js b/frontend/src/components/tests/basemapMenu.test.js index 1d9e063567..6473c8079f 100644 --- a/frontend/src/components/tests/basemapMenu.test.js +++ b/frontend/src/components/tests/basemapMenu.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { render, screen } from '@testing-library/react'; import '@testing-library/jest-dom'; diff --git a/frontend/src/components/tests/checkBox.test.js b/frontend/src/components/tests/checkBox.test.js index e5cdf7b493..c2ed161afc 100644 --- a/frontend/src/components/tests/checkBox.test.js +++ b/frontend/src/components/tests/checkBox.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { render, screen } from '@testing-library/react'; import '@testing-library/jest-dom'; diff --git a/frontend/src/components/tests/checkCircle.test.js b/frontend/src/components/tests/checkCircle.test.js index 78fda9beaa..36f0793d1d 100644 --- a/frontend/src/components/tests/checkCircle.test.js +++ b/frontend/src/components/tests/checkCircle.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import TestRenderer from 'react-test-renderer'; import { CheckIcon } from '../svgIcons'; diff --git a/frontend/src/components/tests/code.test.js b/frontend/src/components/tests/code.test.js index d93a7a039f..cd427f1316 100644 --- a/frontend/src/components/tests/code.test.js +++ b/frontend/src/components/tests/code.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { render, screen } from '@testing-library/react'; import '@testing-library/jest-dom'; diff --git a/frontend/src/components/tests/dropdown.test.js b/frontend/src/components/tests/dropdown.test.js index 626361f519..87312db1c1 100644 --- a/frontend/src/components/tests/dropdown.test.js +++ b/frontend/src/components/tests/dropdown.test.js @@ -1,9 +1,9 @@ -import React from 'react'; import { MemoryRouter } from 'react-router-dom'; import TestRenderer from 'react-test-renderer'; import { CustomButton } from '../button'; import { Dropdown } from '../dropdown'; +import { act } from '@testing-library/react'; export const createTestDropdown = (options) => { const testElement = TestRenderer.create( @@ -40,10 +40,12 @@ test('dropdown-content is not rendered before the user clicks on the button', () test('dropdown-content disappear after click on option', () => { const elementInstance = createTestDropdown([{ label: 'English' }, { label: 'Portuguese (pt)' }]); - elementInstance.findByType(CustomButton).props.onClick(); - elementInstance - .findAllByProps({ className: 'pa3 nowrap bg-animate bg-white hover-bg-tan' })[0] - .children[0].props.onClick(); + act(() => elementInstance.findByType(CustomButton).props.onClick()); + act(() => + elementInstance + .findAllByProps({ className: 'pa3 nowrap bg-animate bg-white hover-bg-tan' })[0] + .children[0].props.onClick(), + ); // dropdown-content should disappear after selecting an option expect(() => elementInstance.findByProps({ @@ -62,7 +64,7 @@ test('dropdown behaviour with href props', () => { { label: 'B', href: 'http://b.co' }, { label: 'C', href: 'http://c.co' }, ]); - elementInstance.findByType(CustomButton).props.onClick(); + act(() => elementInstance.findByType(CustomButton).props.onClick()); // dropdown-content must be rendered after the click expect( elementInstance.findByProps({ @@ -99,7 +101,7 @@ test('dropdown behaviour with multi enabled', () => { , ); const elementInstance = testElement.root; - elementInstance.findByType(CustomButton).props.onClick(); + act(() => elementInstance.findByType(CustomButton).props.onClick()); // dropdown-content must be rendered after the click expect( elementInstance.findByProps({ @@ -132,7 +134,7 @@ test('dropdown with toTop enabled should have bottom-3 class', () => { , ); const elementInstance = testElement.root; - elementInstance.findByType(CustomButton).props.onClick(); + act(() => elementInstance.findByType(CustomButton).props.onClick()); // dropdown-content must be rendered after the click expect( elementInstance.findByProps({ @@ -169,7 +171,7 @@ test('dropdown with more than 9 options has "h5 overflow-y-scroll" classes', () , ); const elementInstance = testElement.root; - elementInstance.findByType(CustomButton).props.onClick(); + act(() => elementInstance.findByType(CustomButton).props.onClick()); // dropdown-content must be rendered after the click expect( elementInstance.findByProps({ diff --git a/frontend/src/components/tests/mappingTypes.test.js b/frontend/src/components/tests/mappingTypes.test.js index f31851715c..52ff0a1b4a 100644 --- a/frontend/src/components/tests/mappingTypes.test.js +++ b/frontend/src/components/tests/mappingTypes.test.js @@ -1,5 +1,3 @@ -import React from 'react'; - import { RoadIcon, HomeIcon, WavesIcon, TaskIcon, AsteriskIcon } from '../svgIcons'; import { MappingTypes } from '../mappingTypes'; import { createComponentWithIntl } from '../../utils/testWithIntl'; diff --git a/frontend/src/components/tests/menu.test.js b/frontend/src/components/tests/menu.test.js index 6d725fa472..7a3745a96b 100644 --- a/frontend/src/components/tests/menu.test.js +++ b/frontend/src/components/tests/menu.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { Link, MemoryRouter } from 'react-router-dom'; import TestRenderer from 'react-test-renderer'; diff --git a/frontend/src/components/tests/organisationSelect.test.js b/frontend/src/components/tests/organisationSelect.test.js index 578c72bb3f..61f55bc1fe 100644 --- a/frontend/src/components/tests/organisationSelect.test.js +++ b/frontend/src/components/tests/organisationSelect.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { render, screen } from '@testing-library/react'; import '@testing-library/jest-dom'; diff --git a/frontend/src/components/tests/preloader.test.js b/frontend/src/components/tests/preloader.test.js index 8ac582f530..b2379ba2d8 100644 --- a/frontend/src/components/tests/preloader.test.js +++ b/frontend/src/components/tests/preloader.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { render } from '@testing-library/react'; import '@testing-library/jest-dom'; diff --git a/frontend/src/components/tests/selectAll.test.js b/frontend/src/components/tests/selectAll.test.js index b9e005f60c..06f3aab5ce 100644 --- a/frontend/src/components/tests/selectAll.test.js +++ b/frontend/src/components/tests/selectAll.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { render, screen } from '@testing-library/react'; import '@testing-library/jest-dom'; diff --git a/frontend/src/components/tests/statsCard.test.js b/frontend/src/components/tests/statsCard.test.js index 26a52f64a3..ffa0b1cf0a 100644 --- a/frontend/src/components/tests/statsCard.test.js +++ b/frontend/src/components/tests/statsCard.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { render, screen } from '@testing-library/react'; import '@testing-library/jest-dom'; diff --git a/frontend/src/components/user/avatar.js b/frontend/src/components/user/avatar.js index 1bf52a1918..4ce38236d4 100644 --- a/frontend/src/components/user/avatar.js +++ b/frontend/src/components/user/avatar.js @@ -1,4 +1,3 @@ -import React from 'react'; import { Link } from 'react-router-dom'; import { useSelector } from 'react-redux'; diff --git a/frontend/src/components/user/completeness.js b/frontend/src/components/user/completeness.js index 5ae0ec19fe..30366e5917 100644 --- a/frontend/src/components/user/completeness.js +++ b/frontend/src/components/user/completeness.js @@ -1,4 +1,3 @@ -import React from 'react'; import { FormattedMessage, FormattedNumber } from 'react-intl'; import messages from './messages'; diff --git a/frontend/src/components/user/content.js b/frontend/src/components/user/content.js index f785beedfb..9f7d425130 100644 --- a/frontend/src/components/user/content.js +++ b/frontend/src/components/user/content.js @@ -1,4 +1,3 @@ -import React from 'react'; import { useSelector } from 'react-redux'; import { Link } from 'react-router-dom'; import { FormattedMessage, FormattedNumber, FormattedRelativeTime } from 'react-intl'; diff --git a/frontend/src/components/user/forms/customField.js b/frontend/src/components/user/forms/customField.js index 73527ec503..171e42fda2 100644 --- a/frontend/src/components/user/forms/customField.js +++ b/frontend/src/components/user/forms/customField.js @@ -1,4 +1,3 @@ -import React from 'react'; import { FormattedMessage } from 'react-intl'; import messages from '../messages'; diff --git a/frontend/src/components/user/forms/interests.js b/frontend/src/components/user/forms/interests.js index a06ac27f25..57b58e247c 100644 --- a/frontend/src/components/user/forms/interests.js +++ b/frontend/src/components/user/forms/interests.js @@ -1,4 +1,4 @@ -import React, { useState, useEffect } from 'react'; +import { useState, useEffect } from 'react'; import { useSelector } from 'react-redux'; import { FormattedMessage } from 'react-intl'; diff --git a/frontend/src/components/user/forms/notifications.js b/frontend/src/components/user/forms/notifications.js index 7313ad8661..da94d3d2a9 100644 --- a/frontend/src/components/user/forms/notifications.js +++ b/frontend/src/components/user/forms/notifications.js @@ -1,4 +1,3 @@ -import React from 'react'; import { FormattedMessage } from 'react-intl'; import messages from '../messages'; diff --git a/frontend/src/components/user/forms/personalInformation.js b/frontend/src/components/user/forms/personalInformation.js index 239f8655b0..bd6a20a202 100644 --- a/frontend/src/components/user/forms/personalInformation.js +++ b/frontend/src/components/user/forms/personalInformation.js @@ -1,7 +1,7 @@ -import React, { useState } from 'react'; +import { useState } from 'react'; import { connect } from 'react-redux'; import { Form, Field } from 'react-final-form'; -import ReactTooltip from 'react-tooltip'; +import { Tooltip } from 'react-tooltip'; import { FormattedMessage, useIntl } from 'react-intl'; import messages from '../messages'; @@ -142,9 +142,10 @@ function _PersonalInformationForm({ userDetails, token, pushUserDetails }) { - + {({ input, meta }) => ( @@ -222,9 +223,10 @@ function _PersonalInformationForm({ userDetails, token, pushUserDetails }) { - + {genderOptions.map((option) => (
diff --git a/frontend/src/components/user/forms/settings.js b/frontend/src/components/user/forms/settings.js index 55134d0128..b6f9a53fc9 100644 --- a/frontend/src/components/user/forms/settings.js +++ b/frontend/src/components/user/forms/settings.js @@ -1,4 +1,4 @@ -import React, { useState, useEffect } from 'react'; +import { useState, useEffect } from 'react'; import { connect } from 'react-redux'; import { Link } from 'react-router-dom'; import { FormattedMessage } from 'react-intl'; diff --git a/frontend/src/components/user/forms/switchToggleField.js b/frontend/src/components/user/forms/switchToggleField.js index fe242a0b2e..54bed17173 100644 --- a/frontend/src/components/user/forms/switchToggleField.js +++ b/frontend/src/components/user/forms/switchToggleField.js @@ -1,4 +1,4 @@ -import React, { useState, useEffect } from 'react'; +import { useState, useEffect } from 'react'; import { connect } from 'react-redux'; import { SwitchToggle } from '../../formInputs'; diff --git a/frontend/src/components/user/list.js b/frontend/src/components/user/list.js index ea70ec7099..1ddc5651db 100644 --- a/frontend/src/components/user/list.js +++ b/frontend/src/components/user/list.js @@ -1,4 +1,4 @@ -import React, { useEffect, useState, useRef } from 'react'; +import { useEffect, useState, useRef } from 'react'; import { useSelector } from 'react-redux'; import { FormattedMessage } from 'react-intl'; import ReactPlaceholder from 'react-placeholder'; diff --git a/frontend/src/components/user/tests/completeness.test.js b/frontend/src/components/user/tests/completeness.test.js index 9ad83f9ae2..3012b75afe 100644 --- a/frontend/src/components/user/tests/completeness.test.js +++ b/frontend/src/components/user/tests/completeness.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { FormattedMessage, FormattedNumber } from 'react-intl'; import { ProfileCompleteness } from '../completeness'; diff --git a/frontend/src/components/user/tests/topBar.test.js b/frontend/src/components/user/tests/topBar.test.js index 3623188c5a..86d87a8a2c 100644 --- a/frontend/src/components/user/tests/topBar.test.js +++ b/frontend/src/components/user/tests/topBar.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { FormattedNumber } from 'react-intl'; import { NextMappingLevel } from '../topBar'; diff --git a/frontend/src/components/user/tests/userAvatar.test.js b/frontend/src/components/user/tests/userAvatar.test.js index 76bd55fbbc..ab9ff1793c 100644 --- a/frontend/src/components/user/tests/userAvatar.test.js +++ b/frontend/src/components/user/tests/userAvatar.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import TestRenderer, { act } from 'react-test-renderer'; import { UserAvatar, UserAvatarList } from '../avatar'; diff --git a/frontend/src/components/user/topBar.js b/frontend/src/components/user/topBar.js index 2feb662ebe..8be3b6c10b 100644 --- a/frontend/src/components/user/topBar.js +++ b/frontend/src/components/user/topBar.js @@ -1,4 +1,3 @@ -import React from 'react'; import { useSelector } from 'react-redux'; import { FormattedMessage, FormattedNumber } from 'react-intl'; import ReactPlaceholder from 'react-placeholder'; diff --git a/frontend/src/components/user/usersPlaceholder.js b/frontend/src/components/user/usersPlaceholder.js index aa34f20f52..acf36d35c6 100644 --- a/frontend/src/components/user/usersPlaceholder.js +++ b/frontend/src/components/user/usersPlaceholder.js @@ -1,4 +1,3 @@ -import React from 'react'; import { TextRow, RoundShape } from 'react-placeholder/lib/placeholders'; export const userCardPlaceholderTemplate = () => (_n, i) => diff --git a/frontend/src/components/userDetail/barListChart.js b/frontend/src/components/userDetail/barListChart.js index f68d3980d5..2e1b3f42bf 100644 --- a/frontend/src/components/userDetail/barListChart.js +++ b/frontend/src/components/userDetail/barListChart.js @@ -1,4 +1,3 @@ -import React from 'react'; import { Link } from 'react-router-dom'; import { FormattedMessage } from 'react-intl'; diff --git a/frontend/src/components/userDetail/contributionTimeline.js b/frontend/src/components/userDetail/contributionTimeline.js index 965b332015..86a59f5658 100644 --- a/frontend/src/components/userDetail/contributionTimeline.js +++ b/frontend/src/components/userDetail/contributionTimeline.js @@ -1,6 +1,5 @@ -import React from 'react'; import CalendarHeatmap from 'react-calendar-heatmap'; -import ReactTooltip from 'react-tooltip'; +import { Tooltip } from 'react-tooltip'; import { FormattedMessage, useIntl } from 'react-intl'; import messages from './messages'; @@ -81,11 +80,13 @@ export const ContributionTimeline = ({ userStats }) => { } return { - 'data-tip': val, + 'data-tooltip-float': true, + 'data-tooltip-content': val, + 'data-tooltip-id': 'calendarHeatmapContributionTimelineTooltip', }; }} /> - +
diff --git a/frontend/src/components/userDetail/countriesMapped.js b/frontend/src/components/userDetail/countriesMapped.js index 176b687437..322a8d5f75 100644 --- a/frontend/src/components/userDetail/countriesMapped.js +++ b/frontend/src/components/userDetail/countriesMapped.js @@ -1,4 +1,4 @@ -import React, { useLayoutEffect, useState } from 'react'; +import { createRef, useLayoutEffect, useState } from 'react'; import { useSelector } from 'react-redux'; import { useNavigate } from 'react-router-dom'; import mapboxgl from 'mapbox-gl'; @@ -23,7 +23,7 @@ const UserCountriesMap = ({ projects }) => { const locale = useSelector((state) => state.preferences['locale']); const [map, setMap] = useState(null); - const mapRef = React.createRef(); + const mapRef = createRef(); useLayoutEffect(() => { mapboxgl.supported() && diff --git a/frontend/src/components/userDetail/editsByNumbers.js b/frontend/src/components/userDetail/editsByNumbers.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/frontend/src/components/userDetail/elementsMapped.js b/frontend/src/components/userDetail/elementsMapped.js index b3dc556061..4a2f175f94 100644 --- a/frontend/src/components/userDetail/elementsMapped.js +++ b/frontend/src/components/userDetail/elementsMapped.js @@ -1,4 +1,3 @@ -import React from 'react'; import humanizeDuration from 'humanize-duration'; import { useIntl, FormattedMessage } from 'react-intl'; diff --git a/frontend/src/components/userDetail/headerProfile.js b/frontend/src/components/userDetail/headerProfile.js index 6a9e969aa1..30f2fac45e 100644 --- a/frontend/src/components/userDetail/headerProfile.js +++ b/frontend/src/components/userDetail/headerProfile.js @@ -1,4 +1,4 @@ -import React, { useState, useEffect } from 'react'; +import { useState, useEffect } from 'react'; import { useSelector } from 'react-redux'; import { FormattedMessage, useIntl } from 'react-intl'; diff --git a/frontend/src/components/userDetail/tests/barListChart.test.js b/frontend/src/components/userDetail/tests/barListChart.test.js index 1799389a90..d6576fc776 100644 --- a/frontend/src/components/userDetail/tests/barListChart.test.js +++ b/frontend/src/components/userDetail/tests/barListChart.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { render, screen } from '@testing-library/react'; import '@testing-library/jest-dom'; diff --git a/frontend/src/components/userDetail/tests/elementsMapped.test.js b/frontend/src/components/userDetail/tests/elementsMapped.test.js index 1171eb6bd9..da2743a56e 100644 --- a/frontend/src/components/userDetail/tests/elementsMapped.test.js +++ b/frontend/src/components/userDetail/tests/elementsMapped.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { render } from '@testing-library/react'; import '@testing-library/jest-dom'; diff --git a/frontend/src/components/userDetail/tests/topCauses.test.js b/frontend/src/components/userDetail/tests/topCauses.test.js index be23879581..cf7edef8f4 100644 --- a/frontend/src/components/userDetail/tests/topCauses.test.js +++ b/frontend/src/components/userDetail/tests/topCauses.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { render, screen } from '@testing-library/react'; import '@testing-library/jest-dom'; diff --git a/frontend/src/components/userDetail/tests/topProjects.test.js b/frontend/src/components/userDetail/tests/topProjects.test.js index a30e8b2cce..382815a78f 100644 --- a/frontend/src/components/userDetail/tests/topProjects.test.js +++ b/frontend/src/components/userDetail/tests/topProjects.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { screen } from '@testing-library/react'; import '@testing-library/jest-dom'; diff --git a/frontend/src/components/userDetail/topCauses.js b/frontend/src/components/userDetail/topCauses.js index 88f9919ac9..b2a752b95d 100644 --- a/frontend/src/components/userDetail/topCauses.js +++ b/frontend/src/components/userDetail/topCauses.js @@ -1,4 +1,3 @@ -import React from 'react'; import { Chart as ChartJS, ArcElement, Tooltip, Legend } from 'chart.js'; import { Doughnut } from 'react-chartjs-2'; import { FormattedMessage, useIntl } from 'react-intl'; diff --git a/frontend/src/components/userDetail/topProjects.js b/frontend/src/components/userDetail/topProjects.js index 61fd2a4a9c..837bfba115 100644 --- a/frontend/src/components/userDetail/topProjects.js +++ b/frontend/src/components/userDetail/topProjects.js @@ -1,4 +1,3 @@ -import React from 'react'; import { FormattedMessage } from 'react-intl'; import messages from './messages'; diff --git a/frontend/src/components/userDetail/userTeamsOrgs.js b/frontend/src/components/userDetail/userTeamsOrgs.js index 1b86050278..b75ac7a3a0 100644 --- a/frontend/src/components/userDetail/userTeamsOrgs.js +++ b/frontend/src/components/userDetail/userTeamsOrgs.js @@ -1,4 +1,3 @@ -import React from 'react'; import { FormattedMessage } from 'react-intl'; import { TeamBox } from '../teamsAndOrgs/teams'; diff --git a/frontend/src/components/webglUnsupported.js b/frontend/src/components/webglUnsupported.js index 3e5bc587e8..4441efd2c2 100644 --- a/frontend/src/components/webglUnsupported.js +++ b/frontend/src/components/webglUnsupported.js @@ -1,4 +1,3 @@ -import React from 'react'; import { Alert } from './alert'; import { FormattedMessage } from 'react-intl'; import messages from './messages'; diff --git a/frontend/src/hooks/UseInboxQueryAPI.js b/frontend/src/hooks/UseInboxQueryAPI.js index 26a0f68fac..54cdea4a62 100644 --- a/frontend/src/hooks/UseInboxQueryAPI.js +++ b/frontend/src/hooks/UseInboxQueryAPI.js @@ -1,11 +1,11 @@ import { useEffect } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { useQueryParams, StringParam, NumberParam } from 'use-query-params'; -import { stringify as stringifyUQP } from 'query-string'; +import queryString from 'query-string'; import axios from 'axios'; import { CommaArrayParam } from '../utils/CommaArrayParam'; -import { useThrottle } from '../hooks/UseThrottle'; +import { useThrottle } from './UseThrottle'; import { remapParamsToAPI } from '../utils/remapParamsToAPI'; import { API_URL } from '../config'; @@ -163,4 +163,4 @@ export const useInboxQueryAPI = ( return [state, dispatch]; }; -export const stringify = stringifyUQP; +export const stringify = queryString.stringify; diff --git a/frontend/src/hooks/UseProjectsQueryAPI.js b/frontend/src/hooks/UseProjectsQueryAPI.js index 9b8de56b72..01e7d2b130 100644 --- a/frontend/src/hooks/UseProjectsQueryAPI.js +++ b/frontend/src/hooks/UseProjectsQueryAPI.js @@ -7,7 +7,7 @@ import { NumberParam, BooleanParam, } from 'use-query-params'; -import { stringify as stringifyUQP } from 'query-string'; +import queryString from 'query-string'; import axios from 'axios'; import { subMonths, format } from 'date-fns'; @@ -71,7 +71,7 @@ const backendToQueryConversion = { stale: 'lastUpdatedTo', createdFrom: 'createdFrom', basedOnMyInterests: 'basedOnMyInterests', - omitMapResults:'omitMapResults', + omitMapResults: 'omitMapResults', }; const dataFetchReducer = (state, action) => { @@ -228,5 +228,5 @@ export const useProjectsQueryAPI = ( export const stringify = (obj) => { const encodedQuery = encodeQueryParams(projectQueryAllSpecification, obj); - return stringifyUQP(encodedQuery); + return queryString.stringify(encodedQuery); }; diff --git a/frontend/src/hooks/UseTaskContributionAPI.js b/frontend/src/hooks/UseTaskContributionAPI.js index 3fb86fd619..66d96fe0a1 100644 --- a/frontend/src/hooks/UseTaskContributionAPI.js +++ b/frontend/src/hooks/UseTaskContributionAPI.js @@ -3,7 +3,7 @@ import { useEffect, useReducer } from 'react'; import axios from 'axios'; import { useQueryParams, StringParam, NumberParam } from 'use-query-params'; -import { stringify as stringifyUQP } from 'query-string'; +import queryString from 'query-string'; import { CommaArrayParam } from '../utils/CommaArrayParam'; import { useThrottle } from '../hooks/UseThrottle'; import { remapParamsToAPI } from '../utils/remapParamsToAPI'; @@ -204,4 +204,4 @@ export const useTaskContributionAPI = ( return [state, dispatch]; }; -export const stringify = stringifyUQP; +export const stringify = queryString.stringify; diff --git a/frontend/src/hooks/UseTasksStatsQueryAPI.js b/frontend/src/hooks/UseTasksStatsQueryAPI.js index 2a80542c29..95358ceaf8 100644 --- a/frontend/src/hooks/UseTasksStatsQueryAPI.js +++ b/frontend/src/hooks/UseTasksStatsQueryAPI.js @@ -7,7 +7,7 @@ import { NumberParam, withDefault, } from 'use-query-params'; -import { stringify as stringifyUQP } from 'query-string'; +import queryString from 'query-string'; import axios from 'axios'; import { format, startOfYear } from 'date-fns'; @@ -151,5 +151,5 @@ export const useTasksStatsQueryAPI = ( export const stringify = (obj) => { const encodedQuery = encodeQueryParams(statsQueryAllSpecification, obj); - return stringifyUQP(encodedQuery); + return queryString.stringify(encodedQuery); }; diff --git a/frontend/src/hooks/tests/UseAsync.test.js b/frontend/src/hooks/tests/UseAsync.test.js index a212c9bfa3..397b783a2d 100644 --- a/frontend/src/hooks/tests/UseAsync.test.js +++ b/frontend/src/hooks/tests/UseAsync.test.js @@ -1,4 +1,4 @@ -import { renderHook, act } from '@testing-library/react-hooks'; +import { renderHook, act } from '@testing-library/react'; import { useAsync } from '../UseAsync'; diff --git a/frontend/src/hooks/tests/UseAvatarStyle.test.js b/frontend/src/hooks/tests/UseAvatarStyle.test.js index 53cbee0775..2c2d35257a 100644 --- a/frontend/src/hooks/tests/UseAvatarStyle.test.js +++ b/frontend/src/hooks/tests/UseAvatarStyle.test.js @@ -1,4 +1,4 @@ -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { useAvatarStyle } from '../UseAvatarStyle'; diff --git a/frontend/src/hooks/tests/UseAvatarText.test.js b/frontend/src/hooks/tests/UseAvatarText.test.js index 62d6ede1c4..fbd106219c 100644 --- a/frontend/src/hooks/tests/UseAvatarText.test.js +++ b/frontend/src/hooks/tests/UseAvatarText.test.js @@ -1,4 +1,4 @@ -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { useAvatarText } from '../UseAvatarText'; diff --git a/frontend/src/hooks/tests/UseContributorStats.test.js b/frontend/src/hooks/tests/UseContributorStats.test.js index 455c21ab6c..1c921bd72d 100644 --- a/frontend/src/hooks/tests/UseContributorStats.test.js +++ b/frontend/src/hooks/tests/UseContributorStats.test.js @@ -1,4 +1,4 @@ -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { useContributorStats } from '../UseContributorStats'; import { projectContributions } from '../../network/tests/mockData/contributions'; diff --git a/frontend/src/hooks/tests/UseDateRangeQueryParams.test.js b/frontend/src/hooks/tests/UseDateRangeQueryParams.test.js index 644370b27a..2e63b0b88a 100644 --- a/frontend/src/hooks/tests/UseDateRangeQueryParams.test.js +++ b/frontend/src/hooks/tests/UseDateRangeQueryParams.test.js @@ -1,4 +1,4 @@ -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { subWeeks, subMonths, format, endOfToday } from 'date-fns'; import { useDateRangeQueryParams } from '../UseDateRangeQueryParams'; diff --git a/frontend/src/hooks/tests/UseDisableBadImagery.test.js b/frontend/src/hooks/tests/UseDisableBadImagery.test.js index b2d205eb06..5045756107 100644 --- a/frontend/src/hooks/tests/UseDisableBadImagery.test.js +++ b/frontend/src/hooks/tests/UseDisableBadImagery.test.js @@ -1,4 +1,4 @@ -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { invalidatedTaskHistory, history, diff --git a/frontend/src/hooks/tests/UseEditOrgPermissions.test.js b/frontend/src/hooks/tests/UseEditOrgPermissions.test.js index 080b58cde4..bc75239219 100644 --- a/frontend/src/hooks/tests/UseEditOrgPermissions.test.js +++ b/frontend/src/hooks/tests/UseEditOrgPermissions.test.js @@ -1,6 +1,5 @@ -import React from 'react'; import { Provider } from 'react-redux'; -import { renderHook, act } from '@testing-library/react-hooks'; +import { renderHook, act } from '@testing-library/react'; import { store } from '../../store'; import { useEditOrgAllowed } from '../UsePermissions'; diff --git a/frontend/src/hooks/tests/UseEditProjectPermissions.test.js b/frontend/src/hooks/tests/UseEditProjectPermissions.test.js index d194458399..01152a8810 100644 --- a/frontend/src/hooks/tests/UseEditProjectPermissions.test.js +++ b/frontend/src/hooks/tests/UseEditProjectPermissions.test.js @@ -1,6 +1,5 @@ -import React from 'react'; import { Provider } from 'react-redux'; -import { renderHook, act } from '@testing-library/react-hooks'; +import { renderHook, act } from '@testing-library/react'; import { store } from '../../store'; import { useEditProjectAllowed } from '../UsePermissions'; diff --git a/frontend/src/hooks/tests/UseEditTeamPermissions.test.js b/frontend/src/hooks/tests/UseEditTeamPermissions.test.js index baafd544a5..d003846f39 100644 --- a/frontend/src/hooks/tests/UseEditTeamPermissions.test.js +++ b/frontend/src/hooks/tests/UseEditTeamPermissions.test.js @@ -1,6 +1,5 @@ -import React from 'react'; import { Provider } from 'react-redux'; -import { renderHook, act } from '@testing-library/react-hooks'; +import { renderHook, act } from '@testing-library/react'; import { store } from '../../store'; import { useEditTeamAllowed } from '../UsePermissions'; diff --git a/frontend/src/hooks/tests/UseFilterContributors.test.js b/frontend/src/hooks/tests/UseFilterContributors.test.js index 06d662b86a..1baacd9983 100644 --- a/frontend/src/hooks/tests/UseFilterContributors.test.js +++ b/frontend/src/hooks/tests/UseFilterContributors.test.js @@ -1,4 +1,4 @@ -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { useFilterContributors } from '../UseFilterContributors'; import { projectContributions } from '../../network/tests/mockData/contributions'; diff --git a/frontend/src/hooks/tests/UseFirstTaskActionDate.test.js b/frontend/src/hooks/tests/UseFirstTaskActionDate.test.js index 00df44ca75..f73d77eebe 100644 --- a/frontend/src/hooks/tests/UseFirstTaskActionDate.test.js +++ b/frontend/src/hooks/tests/UseFirstTaskActionDate.test.js @@ -1,4 +1,4 @@ -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import useFirstTaskActionDate from '../UseFirstTaskActionDate'; import { history } from '../../network/tests/mockData/taskHistory'; diff --git a/frontend/src/hooks/tests/UseGeomContainsMultiplePolygons.test.js b/frontend/src/hooks/tests/UseGeomContainsMultiplePolygons.test.js index 069cf8fc7e..d6be5d5c49 100644 --- a/frontend/src/hooks/tests/UseGeomContainsMultiplePolygons.test.js +++ b/frontend/src/hooks/tests/UseGeomContainsMultiplePolygons.test.js @@ -1,4 +1,4 @@ -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { useContainsMultiplePolygons } from '../UseGeomContainsMultiplePolygons'; diff --git a/frontend/src/hooks/tests/UseGetContributors.test.js b/frontend/src/hooks/tests/UseGetContributors.test.js index b4d85f716b..71a7a64536 100644 --- a/frontend/src/hooks/tests/UseGetContributors.test.js +++ b/frontend/src/hooks/tests/UseGetContributors.test.js @@ -1,4 +1,4 @@ -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import useGetContributors from '../UseGetContributors'; import { history } from '../../network/tests/mockData/taskHistory'; diff --git a/frontend/src/hooks/tests/UseImageryOption.test.js b/frontend/src/hooks/tests/UseImageryOption.test.js index c1f071ecb3..fb67af8022 100644 --- a/frontend/src/hooks/tests/UseImageryOption.test.js +++ b/frontend/src/hooks/tests/UseImageryOption.test.js @@ -1,4 +1,4 @@ -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { useImageryOption } from '../UseImageryOption'; diff --git a/frontend/src/hooks/tests/UseLockedTasks.test.js b/frontend/src/hooks/tests/UseLockedTasks.test.js index 3e42471fc8..7e87925306 100644 --- a/frontend/src/hooks/tests/UseLockedTasks.test.js +++ b/frontend/src/hooks/tests/UseLockedTasks.test.js @@ -1,6 +1,5 @@ -import React from 'react'; import { Provider } from 'react-redux'; -import { renderHook, act } from '@testing-library/react-hooks'; +import { renderHook, act } from '@testing-library/react'; import { store } from '../../store'; import { useGetLockedTasks } from '../UseLockedTasks'; diff --git a/frontend/src/hooks/tests/UseOrgYearStats.test.js b/frontend/src/hooks/tests/UseOrgYearStats.test.js index a144093efb..e110f1bcf9 100644 --- a/frontend/src/hooks/tests/UseOrgYearStats.test.js +++ b/frontend/src/hooks/tests/UseOrgYearStats.test.js @@ -1,4 +1,4 @@ -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { startOfYear, format, add, sub } from 'date-fns'; import { useIsOrgYearQuery } from '../UseOrgYearStats'; diff --git a/frontend/src/hooks/tests/UseOrganisationLevel.test.js b/frontend/src/hooks/tests/UseOrganisationLevel.test.js index 175ee47c12..a47f3a4ee5 100644 --- a/frontend/src/hooks/tests/UseOrganisationLevel.test.js +++ b/frontend/src/hooks/tests/UseOrganisationLevel.test.js @@ -1,4 +1,4 @@ -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { useOrganisationLevel, useGetLevel, usePredictLevel } from '../UseOrganisationLevel'; diff --git a/frontend/src/hooks/tests/UsePredictYearlyTasks.test.js b/frontend/src/hooks/tests/UsePredictYearlyTasks.test.js index 958283b222..6f13742cbb 100644 --- a/frontend/src/hooks/tests/UsePredictYearlyTasks.test.js +++ b/frontend/src/hooks/tests/UsePredictYearlyTasks.test.js @@ -1,4 +1,4 @@ -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { parse } from 'date-fns'; import { usePredictYearlyTasks } from '../UsePredictYearlyTasks'; diff --git a/frontend/src/hooks/tests/UseProjectCompletenessCalc.test.js b/frontend/src/hooks/tests/UseProjectCompletenessCalc.test.js index c8f48db2bd..3b7407f615 100644 --- a/frontend/src/hooks/tests/UseProjectCompletenessCalc.test.js +++ b/frontend/src/hooks/tests/UseProjectCompletenessCalc.test.js @@ -1,4 +1,4 @@ -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { useComputeCompleteness, useTasksByStatus } from '../UseProjectCompletenessCalc'; import tasksGeojson from '../../utils/tests/snippets/tasksGeometry'; diff --git a/frontend/src/hooks/tests/UseReadTaskComments.test.js b/frontend/src/hooks/tests/UseReadTaskComments.test.js index 3bccf3e294..d196b7dc7e 100644 --- a/frontend/src/hooks/tests/UseReadTaskComments.test.js +++ b/frontend/src/hooks/tests/UseReadTaskComments.test.js @@ -1,4 +1,4 @@ -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { invalidatedTaskHistory, history } from '../../network/tests/mockData/taskHistory'; import { useReadTaskComments } from '../UseReadTaskComments'; diff --git a/frontend/src/hooks/tests/UseTaskBbox.test.js b/frontend/src/hooks/tests/UseTaskBbox.test.js index 5b0c64c2d0..ad75ecb6ca 100644 --- a/frontend/src/hooks/tests/UseTaskBbox.test.js +++ b/frontend/src/hooks/tests/UseTaskBbox.test.js @@ -1,4 +1,4 @@ -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { useTaskBbox } from '../UseTaskBbox'; import { tasks } from '../../network/tests/mockData/taskGrid'; diff --git a/frontend/src/hooks/tests/UseTimeDiff.test.js b/frontend/src/hooks/tests/UseTimeDiff.test.js index 5c1d9dd9b7..4640cf6f6f 100644 --- a/frontend/src/hooks/tests/UseTimeDiff.test.js +++ b/frontend/src/hooks/tests/UseTimeDiff.test.js @@ -1,4 +1,4 @@ -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { useTimeDiff } from '../UseTimeDiff'; diff --git a/frontend/src/hooks/tests/UseTotalTasksStats.test.js b/frontend/src/hooks/tests/UseTotalTasksStats.test.js index dc7d7acf30..f3aef83320 100644 --- a/frontend/src/hooks/tests/UseTotalTasksStats.test.js +++ b/frontend/src/hooks/tests/UseTotalTasksStats.test.js @@ -1,4 +1,4 @@ -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { useTotalTasksStats } from '../UseTotalTasksStats'; import { tasksStats } from '../../network/tests/mockData/tasksStats'; diff --git a/frontend/src/hooks/tests/UseUploadImage.test.js b/frontend/src/hooks/tests/UseUploadImage.test.js index be573524d3..f645b00a0c 100644 --- a/frontend/src/hooks/tests/UseUploadImage.test.js +++ b/frontend/src/hooks/tests/UseUploadImage.test.js @@ -1,4 +1,4 @@ -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { useUploadImage } from '../UseUploadImage'; diff --git a/frontend/src/hooks/tests/UseValidateDateRange.test.js b/frontend/src/hooks/tests/UseValidateDateRange.test.js index 4968c5d4b0..a41bba2378 100644 --- a/frontend/src/hooks/tests/UseValidateDateRange.test.js +++ b/frontend/src/hooks/tests/UseValidateDateRange.test.js @@ -1,4 +1,4 @@ -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { format, add } from 'date-fns'; import { useValidateDateRange } from '../UseValidateDateRange'; diff --git a/frontend/src/index.js b/frontend/src/index.js index efc9ab628c..6f8255a64c 100644 --- a/frontend/src/index.js +++ b/frontend/src/index.js @@ -1,28 +1,28 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; +import { createRoot } from 'react-dom/client'; import { PersistGate } from 'redux-persist/integration/react'; import { Provider } from 'react-redux'; -import WebFont from 'webfontloader'; -import * as Sentry from '@sentry/react'; +import { load } from 'webfontloader'; +import { init, BrowserTracing, Replay } from '@sentry/react'; +import 'react-tooltip/dist/react-tooltip.css'; // Needed by for { Tooltip } from 'react-tooltip' to work properly import App from './App'; import { store, persistor } from './store'; import { ConnectedIntl } from './utils/internationalization'; -import * as serviceWorkerRegistration from './serviceWorkerRegistration'; +import { register, unregister, onServiceWorkerUpdate } from './serviceWorkerRegistration'; import { ENABLE_SERVICEWORKER, SENTRY_FRONTEND_DSN, ENVIRONMENT } from './config'; if (SENTRY_FRONTEND_DSN) { - Sentry.init({ + init({ dsn: SENTRY_FRONTEND_DSN, environment: ENVIRONMENT, integrations: [ - new Sentry.BrowserTracing(), - new Sentry.Replay({ + new BrowserTracing(), + new Replay({ // Additional SDK configuration goes in here, for example: maskAllText: true, blockAllMedia: true, - }), - ], + }), + ], tracesSampleRate: 0.1, // Session Replays integration @@ -30,17 +30,18 @@ if (SENTRY_FRONTEND_DSN) { // If the entire session is not sampled, use the below sample rate to sample // sessions when an error occurs. replaysOnErrorSampleRate: 1.0, - }); } -WebFont.load({ +load({ google: { families: ['Barlow Condensed:400,500,600,700', 'Archivo:400,500,600,700', 'sans-serif'], }, }); -ReactDOM.render( +const container = document.getElementById('root'); +const root = createRoot(container); +root.render( @@ -48,7 +49,6 @@ ReactDOM.render( , - document.getElementById('root'), ); // If you want your app to work offline and load faster, you can change @@ -60,7 +60,7 @@ if ( ENABLE_SERVICEWORKER === 'true' || ENABLE_SERVICEWORKER === true ) { - serviceWorkerRegistration.register({ onUpdate: serviceWorkerRegistration.onServiceWorkerUpdate }); + register({ onUpdate: onServiceWorkerUpdate }); } else { - serviceWorkerRegistration.unregister(); + unregister(); } diff --git a/frontend/src/network/genericJSONRequest.js b/frontend/src/network/genericJSONRequest.js index efc7b331c6..5f1f5a9a8a 100644 --- a/frontend/src/network/genericJSONRequest.js +++ b/frontend/src/network/genericJSONRequest.js @@ -1,14 +1,22 @@ import { handleErrors } from '../utils/promise'; import { API_URL } from '../config'; -export function fetchExternalJSONAPI(url): Promise<*> { - const headers = { - 'Content-Type': 'application/json', - }; + +/** + * Fetch data from an external JSON API + * @param {string} url The url to fetch from + * @param {RequestInit} [init={}}] Any specific init options you want to pass the fetch (such as an {@link AbortSignal}) + * @returns {Promise<*>} A promise that returns a JSON or an error + */ +export function fetchExternalJSONAPI(url, init = {}): Promise<*> { + if (!init.headers) { + init.headers = {'Content-Type': 'application/json'}; + } + init.headers['Content-Type'] = 'application/json'; return fetch(url, { method: 'GET', - headers: headers, + ...init, }) .then(handleErrors) .then((res) => { diff --git a/frontend/src/network/tests/mockData/projects.js b/frontend/src/network/tests/mockData/projects.js index c6b676662c..258bf929e5 100644 --- a/frontend/src/network/tests/mockData/projects.js +++ b/frontend/src/network/tests/mockData/projects.js @@ -1,6 +1,5 @@ import { TM_DEFAULT_CHANGESET_COMMENT } from '../../../config'; -import nextDay from 'date-fns/nextDay'; -import { formatISO } from 'date-fns'; +import { formatISO, nextDay } from 'date-fns'; export const PROJECT_ID_WITH_RANDOM_TASK_ENFORCED = 963; export const PROJECT_ID_ALL_VALIDATED = 6; diff --git a/frontend/src/network/tests/server-handlers.js b/frontend/src/network/tests/server-handlers.js index 66851658df..f724f597fc 100644 --- a/frontend/src/network/tests/server-handlers.js +++ b/frontend/src/network/tests/server-handlers.js @@ -364,6 +364,15 @@ const handlers = [ rest.get('http://127.0.0.1:8111/version', (req, res, ctx) => { return res(ctx.json(josmRemote)); }), + rest.get('http://127.0.0.1:8111/load_data', (req, res, ctx) => { + return res(ctx.text('OK')); + }), + rest.get('http://127.0.0.1:8111/load_and_zoom', (req, res, ctx) => { + return res(ctx.text('OK')); + }), + rest.get('http://127.0.0.1:8111/import', (req, res, ctx) => { + return res(ctx.text('OK')); + }), ]; const failedToConnectError = (req, res, ctx) => { diff --git a/frontend/src/routes.js b/frontend/src/routes.js index dcdb6c0f0a..7265c8c60f 100644 --- a/frontend/src/routes.js +++ b/frontend/src/routes.js @@ -9,10 +9,13 @@ import { Redirect } from './components/redirect'; export const router = createBrowserRouter( createRoutesFromElements( } ErrorBoundary={FallbackComponent}> - { - const { Home } = await import('./views/home' /* webpackChunkName: "home" */); - return { Component: Home }; - }} /> + { + const { Home } = await import('./views/home' /* webpackChunkName: "home" */); + return { Component: Home }; + }} + /> { diff --git a/frontend/src/setupTests.js b/frontend/src/setupTests.js index 27610e774e..b1a53245d6 100644 --- a/frontend/src/setupTests.js +++ b/frontend/src/setupTests.js @@ -1,4 +1,5 @@ import 'jest-canvas-mock'; +import { configure } from '@testing-library/react'; import { server } from './network/tests/server.js'; // Used from https://github.com/mapbox/mapbox-gl-js/issues/3436#issuecomment-485535598 @@ -13,6 +14,22 @@ jest.mock('mapbox-gl/dist/mapbox-gl', () => ({ supported: jest.fn(), })); +// Fix various timeout errors +configure({ asyncUtilTimeout: 4000 }); + +// Needed for react-tooltip dependency (@floating-ui/dom). See https://github.com/floating-ui/floating-ui/issues/1774 . +// This can be removed after https://github.com/jsdom/jsdom/issues/3368 is fixed. +beforeEach(() => { + window.ResizeObserver = jest.fn().mockImplementation(() => ({ + observe: jest.fn(), + unobserve: jest.fn(), + disconnect: jest.fn(), + })); +}); + +// Fix various timeout errors +configure({ asyncUtilTimeout: 4000 }); + beforeAll(() => server.listen()); // if you need to add a handler after calling setupServer for some specific test // this will remove that handler for the rest of them diff --git a/frontend/src/store/actions/auth.js b/frontend/src/store/actions/auth.js index 75556a10d3..ef38b19b94 100644 --- a/frontend/src/store/actions/auth.js +++ b/frontend/src/store/actions/auth.js @@ -1,4 +1,4 @@ -import * as safeStorage from '../../utils/safe_storage'; +import { setItem, removeItem, getItem } from '../../utils/safe_storage'; import { pushToLocalJSONAPI, fetchLocalJSONAPI } from '../../network/genericJSONRequest'; import { setLoader } from './loader'; @@ -39,11 +39,11 @@ export const updateUserEmail = (userDetails, token, relevant_fields) => (dispatc }; export const logout = () => (dispatch) => { - safeStorage.removeItem('username'); - safeStorage.removeItem('token'); - safeStorage.removeItem('action'); - safeStorage.removeItem('osm_oauth_token'); - safeStorage.removeItem('tasksSortOrder'); + removeItem('username'); + removeItem('token'); + removeItem('action'); + removeItem('osm_oauth_token'); + removeItem('tasksSortOrder'); dispatch(clearUserDetails()); }; @@ -91,9 +91,9 @@ export function updateSession(session) { export const setAuthDetails = (username, token, osm_oauth_token) => (dispatch) => { const encoded_token = btoa(token); - safeStorage.setItem('token', encoded_token); - safeStorage.setItem('username', username); - safeStorage.setItem('osm_oauth_token', osm_oauth_token); + setItem('token', encoded_token); + setItem('username', username); + setItem('osm_oauth_token', osm_oauth_token); dispatch(updateToken(encoded_token)); dispatch( updateSession({ @@ -152,6 +152,6 @@ export const pushUserDetails = (userDetails, token, update = false) => (dispatch) => { pushToLocalJSONAPI(`users/me/actions/set-user/`, userDetails, token, 'PATCH').then((data) => - dispatch(setUserDetails(safeStorage.getItem('username'), token, update)), + dispatch(setUserDetails(getItem('username'), token, update)), ); }; diff --git a/frontend/src/store/actions/user.js b/frontend/src/store/actions/user.js index 9d893c5ba3..e493cf2e8a 100644 --- a/frontend/src/store/actions/user.js +++ b/frontend/src/store/actions/user.js @@ -1,11 +1,11 @@ -import * as safeStorage from '../../utils/safe_storage'; +import { setItem } from '../../utils/safe_storage'; import { postNewUser } from '../../network/user'; -import { types } from '../actions/auth'; +import { types } from './auth'; export const registerUser = (postData) => (dispatch) => { - let response = postNewUser(postData).then((res) => { + return postNewUser(postData).then((res) => { if (res.success === true) { - safeStorage.setItem('userId', res.id); + setItem('userId', res.id); } dispatch({ @@ -15,6 +15,4 @@ export const registerUser = (postData) => (dispatch) => { return res; }); - - return response; }; diff --git a/frontend/src/store/actions/userPreferences.js b/frontend/src/store/actions/userPreferences.js index 0b2e71db38..f7995c303b 100644 --- a/frontend/src/store/actions/userPreferences.js +++ b/frontend/src/store/actions/userPreferences.js @@ -1,4 +1,4 @@ -import * as safeStorage from '../../utils/safe_storage'; +import { setItem } from '../../utils/safe_storage'; export const types = { SET_LOCALE: 'SET_LOCALE', @@ -16,6 +16,6 @@ export function updateLocale(locale) { } export const setLocale = (locale) => (dispatch) => { - safeStorage.setItem('locale', locale); + setItem('locale', locale); dispatch(updateLocale(locale)); }; diff --git a/frontend/src/store/index.js b/frontend/src/store/index.js index e43b5a1d71..3e798a3fdd 100644 --- a/frontend/src/store/index.js +++ b/frontend/src/store/index.js @@ -4,7 +4,7 @@ import thunk from 'redux-thunk'; import { persistReducer, persistStore } from 'redux-persist'; import storage from 'redux-persist/lib/storage'; -import * as safeStorage from '../utils/safe_storage'; +import { setItem } from '../utils/safe_storage'; import reducers from './reducers'; const persistConfig = { @@ -28,9 +28,9 @@ const store = createStore(persistedReducer, {}, composedEnhancers); const persistor = persistStore(store); store.subscribe(() => { - safeStorage.setItem('mapShown', store.getState().preferences['mapShown']); - safeStorage.setItem('action', store.getState().preferences['action']); - safeStorage.setItem('projectListView', store.getState().preferences['projectListView']); + setItem('mapShown', store.getState().preferences['mapShown']); + setItem('action', store.getState().preferences['action']); + setItem('projectListView', store.getState().preferences['projectListView']); }); export { store, persistor }; diff --git a/frontend/src/utils/formattedRelativeTime.js b/frontend/src/utils/formattedRelativeTime.js index 041c96876d..58cfd3b1ed 100644 --- a/frontend/src/utils/formattedRelativeTime.js +++ b/frontend/src/utils/formattedRelativeTime.js @@ -1,4 +1,3 @@ -import React from 'react'; import { FormattedRelativeTime } from 'react-intl'; import { selectUnit } from './selectUnit'; diff --git a/frontend/src/utils/internationalization.js b/frontend/src/utils/internationalization.js index cc8e419f15..aa5bf50cd1 100644 --- a/frontend/src/utils/internationalization.js +++ b/frontend/src/utils/internationalization.js @@ -1,66 +1,10 @@ -import React, { useEffect } from 'react'; +import { Fragment, useEffect, useState } from 'react'; import { connect } from 'react-redux'; import { IntlProvider } from 'react-intl'; import { polyfill } from './polyfill'; -import ar from '../locales/ar.json'; -import cs from '../locales/cs.json'; -import de from '../locales/de.json'; -import el from '../locales/el.json'; -import en from '../locales/en.json'; -import es from '../locales/es.json'; -import fa_IR from '../locales/fa_IR.json'; -import fr from '../locales/fr.json'; -import he from '../locales/he.json'; -import hu from '../locales/hu.json'; -import id from '../locales/id.json'; -import it from '../locales/it.json'; -import ja from '../locales/ja.json'; -import ko from '../locales/ko.json'; -import mg from '../locales/mg.json'; -import ml from '../locales/ml.json'; -import nl_NL from '../locales/nl_NL.json'; -import pt from '../locales/pt.json'; -import pt_BR from '../locales/pt_BR.json'; -import ru from '../locales/ru.json'; -import sv from '../locales/sv.json'; -import sw from '../locales/sw.json'; -import tl from '../locales/tl.json'; -import tr from '../locales/tr.json'; -import uk from '../locales/uk.json'; -import zh_TW from '../locales/zh_TW.json'; - import { setLocale } from '../store/actions/userPreferences'; -import * as config from '../config'; - -const translatedMessages = { - ar: ar, - cs: cs, - de: de, - el: el, - en: en, - es: es, - 'fa-IR': fa_IR, - fr: fr, - he: he, - hu: hu, - id: id, - it: it, - ja: ja, - ko: ko, - mg: mg, - ml: ml, - nl: nl_NL, - pt: pt, - 'pt-BR': pt_BR, - ru: ru, - sv: sv, - sw: sw, - tl: tl, - tr: tr, - uk: uk, - zh: zh_TW, -}; +import { DEFAULT_LOCALE } from '../config'; // commented values doesn't have a good amount of strings translated const supportedLocales = [ @@ -107,30 +51,45 @@ function getSupportedLocale(locale) { return { value: 'en', label: 'English' }; } -function getTranslatedMessages(locale) { +async function getTranslatedMessages(locale) { let localeCode = getSupportedLocale(locale); + let val = localeCode; if (localeCode.hasOwnProperty('value')) { - return translatedMessages[localeCode.value]; + val = localeCode.value; + } + if (val) { + const parsed = val.replace('-', '_'); + return await import(/* webpackChunkName: "lang-[request]" */ `../locales/${parsed}.json`); } - return translatedMessages[locale]; + return await import(/* webpackChunkName: "lang-en" */ '../locales/en.json'); } /* textComponent is for orderBy