From 2ccfdb4f95fa3904046e6cc5c69b4839a3b0c205 Mon Sep 17 00:00:00 2001 From: Tomasz Subik Date: Thu, 7 Nov 2024 11:57:49 +0100 Subject: [PATCH] remove most of lodash --- components/form/CheckboxGroup.js | 2 +- components/form/File.js | 3 +- components/form/FmusCheckboxGroup.js | 2 +- components/form/FormElement.js | 9 +-- components/form/Validator.js | 2 +- components/map/index.js | 4 +- components/map/layer-manager/component.js | 5 +- components/map/popup/component.js | 2 +- .../map/popup/templates/fmu-aac/component.js | 7 +-- .../documentation/documents-by-operator.js | 6 +- .../documentation/documents-certification.js | 2 +- .../documentation/documents-provided.js | 2 +- .../documentation/documents-timeline.js | 2 +- components/operators-detail/fmus.js | 2 +- components/operators-detail/layout.js | 2 +- components/operators/table.js | 5 +- components/ui/card.js | 2 +- components/ui/filters.js | 2 +- components/ui/notifications.js | 1 - components/ui/sawmill-modal.js | 1 - components/ui/user-menu-list.js | 1 - components/users/newsletter.js | 3 +- modules/documents-database.js | 4 +- modules/observations.js | 4 +- modules/operators-detail-fmus.js | 7 +-- modules/operators-ranking.js | 13 ++-- modules/user.js | 3 +- package.json | 2 +- pages/database.js | 4 +- pages/observations.js | 2 +- pages/operator/edit/[[...id]].js | 2 +- pages/operators/edit.js | 2 +- pages/profile.js | 2 +- selectors/countries-detail/documentation.js | 5 +- selectors/database/filters.js | 59 +++++++------------ selectors/observations/parsed-filters.js | 38 ++++++------ .../observations/parsed-map-observations.js | 4 +- selectors/operators-detail/fmus.js | 20 +++---- selectors/operators-detail/timeline.js | 2 +- selectors/operators-ranking/index.js | 20 +++---- services/api.js | 4 +- utils/documentation.js | 7 +-- utils/general.js | 52 ++++++++++++++-- utils/observations.js | 17 +++--- utils/signup.js | 7 +-- yarn.lock | 2 +- 46 files changed, 175 insertions(+), 174 deletions(-) diff --git a/components/form/CheckboxGroup.js b/components/form/CheckboxGroup.js index 7b539e4d..2fe1d32b 100644 --- a/components/form/CheckboxGroup.js +++ b/components/form/CheckboxGroup.js @@ -1,7 +1,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import classnames from 'classnames'; -import isEqual from 'lodash/isEqual'; +import isEqual from 'react-fast-compare'; import { injectIntl } from 'react-intl'; import Checkbox from './Checkbox'; diff --git a/components/form/File.js b/components/form/File.js index 9ab820e6..3c1bca1c 100644 --- a/components/form/File.js +++ b/components/form/File.js @@ -1,7 +1,8 @@ import React from 'react'; import PropTypes from 'prop-types'; import classnames from 'classnames'; -import omit from 'lodash/omit'; + +import { omit } from 'utils/general'; // Intl import { injectIntl } from 'react-intl'; diff --git a/components/form/FmusCheckboxGroup.js b/components/form/FmusCheckboxGroup.js index 2b6b06f4..e7ab28aa 100644 --- a/components/form/FmusCheckboxGroup.js +++ b/components/form/FmusCheckboxGroup.js @@ -1,7 +1,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import classnames from 'classnames'; -import isEqual from 'lodash/isEqual'; +import isEqual from 'react-fast-compare'; import { injectIntl } from 'react-intl'; // Utils diff --git a/components/form/FormElement.js b/components/form/FormElement.js index b7b33518..7d1d33e4 100644 --- a/components/form/FormElement.js +++ b/components/form/FormElement.js @@ -1,7 +1,6 @@ import React from 'react'; import PropTypes from 'prop-types'; -import isEqual from 'lodash/isEqual'; -import pick from 'lodash/pick'; +import isEqual from 'react-fast-compare'; import Validator from './Validator'; @@ -30,10 +29,8 @@ class FormElement extends React.Component { } componentDidUpdate(prevProps) { - const prevPropsParsed = pick(prevProps, ['properties', 'validations']); - const currentPropsParsed = pick(this.props, ['properties', 'validations']); - - if (!isEqual(prevPropsParsed, currentPropsParsed)) { + if (!isEqual(prevProps.properties, this.props.properties) || + !isEqual(prevProps.validations, this.props.validations)) { this.triggerValidate(); } diff --git a/components/form/Validator.js b/components/form/Validator.js index b468e853..274e9062 100644 --- a/components/form/Validator.js +++ b/components/form/Validator.js @@ -1,4 +1,4 @@ -import isEmpty from "lodash/isEmpty"; +import { isEmpty } from "utils/general"; class Validator { constructor(intl) { diff --git a/components/map/index.js b/components/map/index.js index cabe75b2..dddaf329 100644 --- a/components/map/index.js +++ b/components/map/index.js @@ -3,8 +3,8 @@ import classnames from 'classnames'; import PropTypes from 'prop-types'; import * as Sentry from "@sentry/nextjs"; -import isEqual from 'lodash/isEqual'; -import isEmpty from 'lodash/isEmpty'; +import isEqual from 'react-fast-compare'; +import { isEmpty } from 'utils/general'; import ReactMapGL, { FlyToInterpolator } from 'react-map-gl'; import { fitBounds } from 'viewport-mercator-project'; diff --git a/components/map/layer-manager/component.js b/components/map/layer-manager/component.js index ab946739..a1eaa266 100644 --- a/components/map/layer-manager/component.js +++ b/components/map/layer-manager/component.js @@ -4,7 +4,8 @@ import PropTypes from 'prop-types'; import { LayerManager, Layer } from 'layer-manager/dist/components'; import { PluginMapboxGl, fetch } from 'layer-manager'; -import omit from 'lodash/omit'; +import { omit } from 'utils/general'; + import slugify from 'slugify'; class LayerManagerComponent extends PureComponent { @@ -147,4 +148,4 @@ class LayerManagerComponent extends PureComponent { } } -export default LayerManagerComponent; \ No newline at end of file +export default LayerManagerComponent; diff --git a/components/map/popup/component.js b/components/map/popup/component.js index 33bf27b9..f85f7568 100644 --- a/components/map/popup/component.js +++ b/components/map/popup/component.js @@ -1,7 +1,7 @@ import React, { PureComponent } from 'react'; import PropTypes from 'prop-types'; -import isEmpty from 'lodash/isEmpty'; +import { isEmpty } from 'utils/general'; import isEqual from 'react-fast-compare'; import { Popup } from 'react-map-gl'; diff --git a/components/map/popup/templates/fmu-aac/component.js b/components/map/popup/templates/fmu-aac/component.js index 64aa2bcd..24598a59 100644 --- a/components/map/popup/templates/fmu-aac/component.js +++ b/components/map/popup/templates/fmu-aac/component.js @@ -1,6 +1,5 @@ import React, { PureComponent } from 'react'; import PropTypes from 'prop-types'; -import trim from 'lodash/trim'; // Intl import { injectIntl } from 'react-intl'; @@ -21,10 +20,10 @@ class FMUAACTemplatePopup extends PureComponent {
{!!fmu &&

{fmu.data.data.fmu_name}

} - {!!aac && (!!trim(aac.data.data.period_val) || aac.data.data.nom_aac) && + {!!aac && (!!String(aac.data.data.period_val || '').trim() || aac.data.data.nom_aac) && }
diff --git a/components/operators-detail/documentation/documents-by-operator.js b/components/operators-detail/documentation/documents-by-operator.js index 28faaad2..499c4cc3 100644 --- a/components/operators-detail/documentation/documents-by-operator.js +++ b/components/operators-detail/documentation/documents-by-operator.js @@ -1,12 +1,12 @@ import React, { useState } from 'react'; import PropTypes from 'prop-types'; import sortBy from 'lodash/sortBy'; -import groupBy from 'lodash/groupBy'; -import uniq from 'lodash/uniq'; import cx from 'classnames'; import { injectIntl } from 'react-intl'; import Fuse from 'fuse.js'; +import { groupBy } from 'utils/general'; + // Redux import { connect } from 'react-redux'; @@ -52,7 +52,7 @@ function DocumentsByOperator({ groupedByCategory, searchText, user, id, intl, .. const exactSearchResults = searchText.length > 2 ? documents.filter(exactSearch) : []; const fuseSearchResults = fuse.search(searchText).map(r => r.item); - return uniq([...exactSearchResults, ...fuseSearchResults]); + return [...new Set([...exactSearchResults, ...fuseSearchResults])]; } const results = Object.keys(groupedByCategory).map((category) => { diff --git a/components/operators-detail/documentation/documents-certification.js b/components/operators-detail/documentation/documents-certification.js index 30547552..8037f5d4 100644 --- a/components/operators-detail/documentation/documents-certification.js +++ b/components/operators-detail/documentation/documents-certification.js @@ -1,6 +1,6 @@ import React from 'react'; import PropTypes from 'prop-types'; -import isEmpty from 'lodash/isEmpty'; +import { isEmpty } from 'utils/general'; // Redux import { connect } from 'react-redux'; diff --git a/components/operators-detail/documentation/documents-provided.js b/components/operators-detail/documentation/documents-provided.js index 1d2f5452..5da08466 100644 --- a/components/operators-detail/documentation/documents-provided.js +++ b/components/operators-detail/documentation/documents-provided.js @@ -1,6 +1,6 @@ import React from 'react'; import PropTypes from 'prop-types'; -import omit from 'lodash/omit'; +import { omit } from 'utils/general'; import { useRouter } from 'next/router'; // Redux diff --git a/components/operators-detail/documentation/documents-timeline.js b/components/operators-detail/documentation/documents-timeline.js index e623f30a..5e8b5c9b 100644 --- a/components/operators-detail/documentation/documents-timeline.js +++ b/components/operators-detail/documentation/documents-timeline.js @@ -3,10 +3,10 @@ import PropTypes from 'prop-types'; import { Area, AreaChart, ResponsiveContainer, Tooltip, XAxis } from 'recharts'; import { injectIntl } from 'react-intl'; import dayjs from 'dayjs'; -import groupBy from 'lodash/groupBy'; // Utils import { PALETTE } from 'utils/documentation'; +import { groupBy } from 'utils/general'; function CustomTooltip({ active, payload, label: timestamp, intl }) { if (active) { diff --git a/components/operators-detail/fmus.js b/components/operators-detail/fmus.js index f9180b60..1ee608af 100644 --- a/components/operators-detail/fmus.js +++ b/components/operators-detail/fmus.js @@ -2,7 +2,7 @@ import React, { Fragment } from 'react'; import PropTypes from 'prop-types'; -import isEqual from 'lodash/isEqual'; +import isEqual from 'react-fast-compare'; import debounce from 'lodash/debounce'; import getBBox from '@turf/bbox'; diff --git a/components/operators-detail/layout.js b/components/operators-detail/layout.js index d079d490..12e69401 100644 --- a/components/operators-detail/layout.js +++ b/components/operators-detail/layout.js @@ -1,6 +1,6 @@ import React from 'react'; import PropTypes from 'prop-types'; -import isEmpty from 'lodash/isEmpty'; +import { isEmpty } from 'utils/general'; // Utils import { HELPERS_DOC } from 'utils/documentation'; diff --git a/components/operators/table.js b/components/operators/table.js index 60ffbb27..c54f3a3d 100644 --- a/components/operators/table.js +++ b/components/operators/table.js @@ -1,7 +1,6 @@ import React from 'react'; import PropTypes from 'prop-types'; import sortBy from 'lodash/sortBy'; -import uniq from 'lodash/uniq'; import { connect } from 'react-redux'; // Next @@ -43,9 +42,9 @@ class OperatorsTable extends React.Component { }); } else { this.setState({ - expandedOperatorIds: uniq( + expandedOperatorIds: [...new Set( [id, ...this.state.expandedOperatorIds].sort() - ), + )], }); } }; diff --git a/components/ui/card.js b/components/ui/card.js index 54cb52e8..21abb123 100644 --- a/components/ui/card.js +++ b/components/ui/card.js @@ -5,7 +5,7 @@ import dynamic from 'next/dynamic'; import Link from 'next/link'; import classnames from 'classnames'; -import omit from 'lodash/omit'; +import { omit } from 'utils/general'; const Truncate = dynamic(() => import('react-truncate')); diff --git a/components/ui/filters.js b/components/ui/filters.js index 767be822..c846209a 100644 --- a/components/ui/filters.js +++ b/components/ui/filters.js @@ -1,6 +1,6 @@ import React from 'react'; import PropTypes from 'prop-types'; -import isEqual from 'lodash/isEqual'; +import isEqual from 'react-fast-compare'; class Filters extends React.Component { componentDidUpdate(prevProps) { diff --git a/components/ui/notifications.js b/components/ui/notifications.js index c1962dc3..bba5639e 100644 --- a/components/ui/notifications.js +++ b/components/ui/notifications.js @@ -11,7 +11,6 @@ import { injectIntl } from 'react-intl'; import Spinner from 'components/ui/spinner'; import modal from 'services/modal'; import { getNotifications, dismissAll } from 'modules/notifications'; -import { groupBy } from 'lodash'; function isBeforeToday(date) { const today = new Date(); diff --git a/components/ui/sawmill-modal.js b/components/ui/sawmill-modal.js index 48aa8359..3bb63378 100644 --- a/components/ui/sawmill-modal.js +++ b/components/ui/sawmill-modal.js @@ -26,7 +26,6 @@ import LocationSearch from 'components/map/location-search'; import { transformRequest } from 'utils/map'; import CancelButton from '../form/CancelButton'; -import { set } from 'lodash'; class SawmillModal extends React.Component { static propTypes = { diff --git a/components/ui/user-menu-list.js b/components/ui/user-menu-list.js index 5d8d29c7..76ddc91f 100644 --- a/components/ui/user-menu-list.js +++ b/components/ui/user-menu-list.js @@ -2,7 +2,6 @@ import React from 'react'; import { useIntl } from 'react-intl'; import { connect } from 'react-redux'; import Link from 'next/link'; -import uniq from 'lodash/uniq'; import uniqBy from 'lodash/uniqBy'; import Notifications from 'components/ui/notifications'; diff --git a/components/users/newsletter.js b/components/users/newsletter.js index 5baa7bea..eaba1970 100644 --- a/components/users/newsletter.js +++ b/components/users/newsletter.js @@ -1,7 +1,6 @@ import React, { useEffect, useRef, useState } from 'react'; import PropTypes from 'prop-types'; import sortBy from 'lodash/sortBy'; -import groupBy from 'lodash/groupBy'; // Intl import { useIntl } from 'react-intl'; @@ -9,6 +8,8 @@ import { connect } from 'react-redux'; import API from 'services/api'; +import { groupBy } from 'utils/general'; + // Components import Form, { FormProvider } from 'components/form/Form'; import Field from 'components/form/Field'; diff --git a/modules/documents-database.js b/modules/documents-database.js index bd185c4b..de068738 100644 --- a/modules/documents-database.js +++ b/modules/documents-database.js @@ -1,9 +1,7 @@ -import isEmpty from 'lodash/isEmpty'; - import API from 'services/api'; // Utils -import { encode, decode, parseObjectSelectOptions } from 'utils/general'; +import { encode, decode, parseObjectSelectOptions, isEmpty } from 'utils/general'; import { setUrlParam } from 'utils/url'; /* Constants */ diff --git a/modules/observations.js b/modules/observations.js index 21693401..85a25c0f 100644 --- a/modules/observations.js +++ b/modules/observations.js @@ -1,9 +1,7 @@ -import isEmpty from 'lodash/isEmpty'; - import API from 'services/api'; // Utils -import { encode, decode, parseObjectSelectOptions } from 'utils/general'; +import { encode, decode, parseObjectSelectOptions, isEmpty } from 'utils/general'; import { setUrlParam } from 'utils/url'; /* Constants */ diff --git a/modules/operators-detail-fmus.js b/modules/operators-detail-fmus.js index 88cba39a..9bc6880f 100644 --- a/modules/operators-detail-fmus.js +++ b/modules/operators-detail-fmus.js @@ -1,8 +1,7 @@ -import sumBy from 'lodash/sumBy'; -import uniq from 'lodash/uniq'; import dayjs from 'dayjs'; import { fetchIntegratedAlertsMetadata } from 'services/layers'; +import { sumBy } from 'utils/general'; const GET_FMU_ANALYSIS_SUCCESS = 'GET_FMU_ANALYSIS_SUCCESS'; const GET_FMU_ANALYSIS_LOADING = 'GET_FMU_ANALYSIS_LOADING'; @@ -430,11 +429,11 @@ export function getIntegratedAlertsMetadata() { // put integrated-alerts before fmusdetail dispatch({ type: SET_OPERATORS_DETAIL_MAP_LAYERS_ACTIVE, - payload: uniq([ + payload: [... new Set([ ...activeLayers.slice(0, activeLayers.indexOf('fmusdetail')), 'integrated-alerts', ...activeLayers.slice(activeLayers.indexOf('fmusdetail')) - ]) + ])] }); }) }; diff --git a/modules/operators-ranking.js b/modules/operators-ranking.js index 01cc398d..d82e5e95 100644 --- a/modules/operators-ranking.js +++ b/modules/operators-ranking.js @@ -1,13 +1,10 @@ import Router from 'next/router'; -import groupBy from 'lodash/groupBy'; -import flatten from 'lodash/flatten'; -import uniq from 'lodash/uniq'; - import dayjs from 'dayjs'; import API from 'services/api'; import { fetchIntegratedAlertsMetadata } from 'services/layers'; +import { groupBy } from 'utils/general'; import { CERTIFICATIONS } from 'constants/fmu'; @@ -246,12 +243,12 @@ export function getOperatorsRanking() { return o['percentage-valid-documents-all']; }); const groupByDocPercentageKeys = Object.keys(groupByDocPercentage).sort().reverse(); - const rankedData = flatten(groupByDocPercentageKeys.map((k, i) => { + const rankedData = groupByDocPercentageKeys.map((k, i) => { return groupByDocPercentage[k].map(o => ({ ...o, ranking: i })); - })); + }).flat(); dispatch({ type: GET_OPERATORS_RANKING_SUCCESS, @@ -386,11 +383,11 @@ export function getIntegratedAlertsMetadata() { // put integrated-alerts before fmus dispatch({ type: SET_OPERATORS_MAP_LAYERS_ACTIVE, - payload: uniq([ + payload: [...new Set([ ...activeLayers.slice(0, activeLayers.indexOf('fmus')), 'integrated-alerts', ...activeLayers.slice(activeLayers.indexOf('fmus')) - ]) + ])] }); }) }; diff --git a/modules/user.js b/modules/user.js index 4c89fe88..dfed7d65 100644 --- a/modules/user.js +++ b/modules/user.js @@ -1,5 +1,4 @@ -import omitBy from 'lodash/omitBy'; -import isEmpty from 'lodash/isEmpty'; +import { omitBy, isEmpty } from 'utils/general'; import API, { NEXTAPIClient } from 'services/api' diff --git a/package.json b/package.json index a51e80f2..a7283dd1 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,7 @@ "react-datepicker": "^4.11.0", "react-dom": "18", "react-dropzone": "^14.2.3", - "react-fast-compare": "^3.2.1", + "react-fast-compare": "^3.2.2", "react-geosuggest": "^2.7.0", "react-intl": "^6.8.4", "react-map-gl": "^5.2.1", diff --git a/pages/database.js b/pages/database.js index 41c89a8a..07ed3332 100644 --- a/pages/database.js +++ b/pages/database.js @@ -1,7 +1,7 @@ import React from 'react'; import PropTypes from 'prop-types'; -import isEmpty from 'lodash/isEmpty'; -import isEqual from 'lodash/isEqual'; +import { isEmpty } from 'utils/general'; +import isEqual from 'react-fast-compare'; // Redux import { connect } from 'react-redux'; diff --git a/pages/observations.js b/pages/observations.js index 0b34a2d4..11ac58db 100644 --- a/pages/observations.js +++ b/pages/observations.js @@ -1,6 +1,6 @@ import React, { Fragment } from 'react'; import PropTypes from 'prop-types'; -import isEqual from 'lodash/isEqual'; +import isEqual from 'react-fast-compare'; import orderBy from 'lodash/orderBy'; import debounce from 'lodash/debounce'; import { connect } from 'react-redux'; diff --git a/pages/operator/edit/[[...id]].js b/pages/operator/edit/[[...id]].js index 97199399..0ce8da1f 100644 --- a/pages/operator/edit/[[...id]].js +++ b/pages/operator/edit/[[...id]].js @@ -1,6 +1,6 @@ import React from 'react'; import PropTypes from 'prop-types'; -import isEmpty from 'lodash/isEmpty'; +import { isEmpty } from 'utils/general'; // Next import Link from 'next/link'; diff --git a/pages/operators/edit.js b/pages/operators/edit.js index ecde7376..c0dbb16d 100644 --- a/pages/operators/edit.js +++ b/pages/operators/edit.js @@ -1,6 +1,6 @@ import React from 'react'; import PropTypes from 'prop-types'; -import isEmpty from 'lodash/isEmpty'; +import { isEmpty } from 'utils/general'; // Next import Router from 'next/router'; diff --git a/pages/profile.js b/pages/profile.js index f6bdd9b0..0f09bcc7 100644 --- a/pages/profile.js +++ b/pages/profile.js @@ -1,6 +1,6 @@ import React from 'react'; import PropTypes from 'prop-types'; -import isEmpty from 'lodash/isEmpty'; +import { isEmpty } from 'utils/general'; // Redux import { connect } from 'react-redux'; diff --git a/selectors/countries-detail/documentation.js b/selectors/countries-detail/documentation.js index 655a8c14..353205bc 100644 --- a/selectors/countries-detail/documentation.js +++ b/selectors/countries-detail/documentation.js @@ -1,6 +1,5 @@ import { createSelector } from 'reselect'; import sortBy from 'lodash/sortBy'; -import compact from 'lodash/compact'; // Get the datasets and filters from state const countriesDetail = state => state.countriesDetail; @@ -60,7 +59,7 @@ const getAllParsedDocumentation = createSelector( const documentation = _countriesDetail.documentation.data; if (documentation && !!documentation.length) { - return compact(sortBy(documentation.filter(d => d.status !== 'doc_not_provided').map((doc) => { + return sortBy(documentation.filter(d => d.status !== 'doc_not_provided').map((doc) => { if (doc['required-country-document']) { return { id: doc.id, @@ -76,7 +75,7 @@ const getAllParsedDocumentation = createSelector( } return null; - }), 'title')); + }), 'title').filter(x => !!x); } return []; diff --git a/selectors/database/filters.js b/selectors/database/filters.js index 7c8fdf3d..a6c801de 100644 --- a/selectors/database/filters.js +++ b/selectors/database/filters.js @@ -1,7 +1,6 @@ import { createSelector } from 'reselect'; -import isEmpty from 'lodash/isEmpty'; -import flatten from 'lodash/flatten'; +import { isEmpty } from 'utils/general'; import sortBy from 'lodash/sortBy'; // Get the datasets and filters from state @@ -27,35 +26,27 @@ export const getParsedFilters = createSelector( newFilterOptions = { ...newFilterOptions, operator_id: sortBy( - flatten( - activeCountries.map((c) => - newFilterOptions.operator_id.filter((o) => c.operators.includes(o.id)) - ) - ), + activeCountries.map((c) => + newFilterOptions.operator_id.filter((o) => c.operators.includes(o.id)) + ).flat(), 'name' ), fmu_id: sortBy( - flatten( - activeCountries.map((c) => - newFilterOptions.fmu_id.filter((f) => c.fmus.includes(f.id)) - ) - ), + activeCountries.map((c) => + newFilterOptions.fmu_id.filter((f) => c.fmus.includes(f.id)) + ).flat(), 'name' ), required_operator_document_id: sortBy( - flatten( - activeCountries.map((c) => - newFilterOptions.required_operator_document_id.filter((f) => c.required_operator_document_ids.includes(f.id)) - ) - ), + activeCountries.map((c) => + newFilterOptions.required_operator_document_id.filter((f) => c.required_operator_document_ids.includes(f.id)) + ).flat(), 'name' ), forest_types: sortBy( - flatten( - activeCountries.map((c) => - newFilterOptions.forest_types.filter((f) => c.forest_types.map(f1 => f1.id).includes(f.id)) - ) - ), + activeCountries.map((c) => + newFilterOptions.forest_types.filter((f) => c.forest_types.map(f1 => f1.id).includes(f.id)) + ).flat(), 'name' ), }; @@ -69,19 +60,15 @@ export const getParsedFilters = createSelector( newFilterOptions = { ...newFilterOptions, fmu_id: sortBy( - flatten( - activeOperators.map((o) => - newFilterOptions.fmu_id.filter((f) => o.fmus.includes(f.id)) - ) - ), + activeOperators.map((o) => + newFilterOptions.fmu_id.filter((f) => o.fmus.includes(f.id)) + ).flat(), 'name' ), forest_types: sortBy( - flatten( - activeOperators.map((o) => - newFilterOptions.forest_types.filter((f) => o.forest_types.map(f1 => f1.id).includes(f.id)) - ) - ), + activeOperators.map((o) => + newFilterOptions.forest_types.filter((f) => o.forest_types.map(f1 => f1.id).includes(f.id)) + ).flat(), 'name' ), @@ -96,11 +83,9 @@ export const getParsedFilters = createSelector( newFilterOptions = { ...newFilterOptions, required_operator_document_id: sortBy( - flatten( - activeLegalCategories.map((o) => - newFilterOptions.required_operator_document_id.filter((f) => o.required_operator_document_ids.includes(f.id)) - ) - ), + activeLegalCategories.map((o) => + newFilterOptions.required_operator_document_id.filter((f) => o.required_operator_document_ids.includes(f.id)) + ).flat(), 'name' ), }; diff --git a/selectors/observations/parsed-filters.js b/selectors/observations/parsed-filters.js index 8491e90f..6f7f613a 100644 --- a/selectors/observations/parsed-filters.js +++ b/selectors/observations/parsed-filters.js @@ -1,7 +1,6 @@ import { createSelector } from 'reselect'; -import isEmpty from 'lodash/isEmpty'; -import flatten from 'lodash/flatten'; +import { isEmpty } from 'utils/general'; import sortBy from 'lodash/sortBy'; // Get the datasets and filters from state @@ -20,15 +19,18 @@ const getParsedFilters = createSelector( newFilterOptions = { ...newFilterOptions, - operator: sortBy(flatten(activeCountries - .map(c => _filterOptions.operator.filter(o => c.operators.includes(o.id))) - ), 'name'), - observer_id: sortBy(flatten(activeCountries - .map(c => _filterOptions.observer_id.filter(o => c.observers.includes(o.id))) - ), 'name'), - fmu_id: sortBy(flatten(activeCountries - .map(c => _filterOptions.fmu_id.filter(f => c.fmus.includes(f.id))) - ), 'name') + operator: sortBy( + activeCountries.map(c => _filterOptions.operator.filter(o => c.operators.includes(o.id))).flat(), + 'name' + ), + observer_id: sortBy( + activeCountries.map(c => _filterOptions.observer_id.filter(o => c.observers.includes(o.id))).flat(), + 'name' + ), + fmu_id: sortBy( + activeCountries.map(c => _filterOptions.fmu_id.filter(f => c.fmus.includes(f.id))).flat(), + 'name' + ) }; } @@ -38,9 +40,10 @@ const getParsedFilters = createSelector( newFilterOptions = { ...newFilterOptions, - fmu_id: sortBy(flatten(activeOperators - .map(o => _filterOptions.fmu_id.filter(f => o.fmus.includes(f.id))) - ), 'name') + fmu_id: sortBy( + activeOperators.map(o => _filterOptions.fmu_id.filter(f => o.fmus.includes(f.id))).flat(), + 'name' + ) }; } @@ -50,9 +53,10 @@ const getParsedFilters = createSelector( newFilterOptions = { ...newFilterOptions, - subcategory_id: sortBy(flatten(activeCategories - .map(o => _filterOptions.subcategory_id.filter(f => o.subcategories.includes(f.id))) - ), 'name') + subcategory_id: sortBy( + activeCategories.map(o => _filterOptions.subcategory_id.filter(f => o.subcategories.includes(f.id))).flat(), + 'name' + ) }; } diff --git a/selectors/observations/parsed-map-observations.js b/selectors/observations/parsed-map-observations.js index 26c85637..c3a37b8f 100644 --- a/selectors/observations/parsed-map-observations.js +++ b/selectors/observations/parsed-map-observations.js @@ -1,13 +1,13 @@ // Constants import { PALETTE_COLOR_1, LEGEND_SEVERITY } from 'constants/rechart'; import { LAYERS } from 'constants/layers'; -import isEmpty from 'lodash/isEmpty'; +import { isEmpty } from 'utils/general'; import sortBy from 'lodash/sortBy'; -import omitBy from 'lodash/omitBy'; import { createSelector } from 'reselect'; import { spiderifyCluster } from 'components/map/layer-manager/utils'; import { parseObservation } from 'utils/observations'; +import { omitBy } from 'utils/general'; const intl = (state, props) => props && props.intl; diff --git a/selectors/operators-detail/fmus.js b/selectors/operators-detail/fmus.js index 4c050fca..19693a86 100644 --- a/selectors/operators-detail/fmus.js +++ b/selectors/operators-detail/fmus.js @@ -1,8 +1,6 @@ import { createSelector } from 'reselect'; -import compact from 'lodash/compact'; -import isEmpty from 'lodash/isEmpty'; -import flatten from 'lodash/flatten'; +import { isEmpty } from 'utils/general'; import uniqBy from 'lodash/uniqBy'; import sortBy from 'lodash/sortBy'; import slugify from 'slugify'; @@ -72,9 +70,7 @@ export const getActiveLayers = createSelector( return null; }); - return compact([ - ...aLayers - ]); + return aLayers.filter(x => !!x); } ); @@ -104,7 +100,7 @@ export const getActiveInteractiveLayersIds = createSelector( }); }; - return flatten(compact(_layersActive.map((kActive) => { + return _layersActive.map((kActive) => { const layer = _layers.find(l => l.id === kActive); if (!layer || (layer.iso && layer.iso !== country.iso)) { @@ -126,7 +122,7 @@ export const getActiveInteractiveLayersIds = createSelector( } return getIds(layer); - }))); + }).filter(x => !!x).flat(); } ); @@ -135,7 +131,7 @@ export const getActiveInteractiveLayers = createSelector( (_layers, _interactions) => { if (!_layers || isEmpty(_interactions)) return []; - const allLayers = uniqBy(flatten(_layers.map((l) => { + const allLayers = uniqBy(_layers.map((l) => { const { config, name } = l; const { type } = config; @@ -144,7 +140,7 @@ export const getActiveInteractiveLayers = createSelector( } return l; - })), 'id'); + }).flat(), 'id'); const interactiveLayerKeys = Object.keys(_interactions); const interactiveLayers = allLayers.filter(l => interactiveLayerKeys.includes(l.id)); @@ -158,7 +154,7 @@ export const getActiveHoverInteractiveLayers = createSelector( (_layers, _hoverInteractions) => { if (!_layers || isEmpty(_hoverInteractions)) return []; - const allLayers = uniqBy(flatten(_layers.map((l) => { + const allLayers = uniqBy(_layers.map((l) => { const { config, name } = l; const { type } = config; @@ -167,7 +163,7 @@ export const getActiveHoverInteractiveLayers = createSelector( } return l; - })), 'id'); + }).flat(), 'id'); const interactiveLayerKeys = Object.keys(_hoverInteractions); const interactiveLayers = allLayers.filter(l => interactiveLayerKeys.includes(l.id)); diff --git a/selectors/operators-detail/timeline.js b/selectors/operators-detail/timeline.js index bcc89916..b02df555 100644 --- a/selectors/operators-detail/timeline.js +++ b/selectors/operators-detail/timeline.js @@ -1,5 +1,5 @@ import { createSelector } from 'reselect'; -import isEmpty from 'lodash/isEmpty'; +import { isEmpty } from 'utils/general'; import { getContractSignatureDocumentation } from 'selectors/operators-detail/documentation'; const operator = state => state.operatorsDetail && state.operatorsDetail.data; diff --git a/selectors/operators-ranking/index.js b/selectors/operators-ranking/index.js index 9430a571..42361a2b 100644 --- a/selectors/operators-ranking/index.js +++ b/selectors/operators-ranking/index.js @@ -1,9 +1,7 @@ import React from 'react'; import { createSelector } from 'reselect'; -import compact from 'lodash/compact'; -import isEmpty from 'lodash/isEmpty'; -import flatten from 'lodash/flatten'; +import { isEmpty } from 'utils/general'; import uniqBy from 'lodash/uniqBy'; import sortBy from 'lodash/sortBy'; @@ -40,7 +38,7 @@ const countryActive = state => state.operatorsRanking.filters.data.country; export const getActiveLayers = createSelector( layersActive, layers, layersSettings, interactions, hoverInteractions, countryOptions, countryActive, (_layersActive, _layers, _layersSettings, _interactions, _hoverInteractions, _countryOptions, _countryActive) => { - const cIsoCodes = compact(_countryOptions.map((c) => { + const cIsoCodes = _countryOptions.map((c) => { if (!_countryActive || !_countryActive.length) { return c.iso; } @@ -49,7 +47,7 @@ export const getActiveLayers = createSelector( return c.iso; } return null; - })); + }).filter(x => !!x); // Country layers const cLayers = _countryOptions.map((c) => { @@ -110,10 +108,10 @@ export const getActiveLayers = createSelector( return null; }); - return compact([ + return [ ...cLayers, ...aLayers - ]); + ].filter(x => !!x); } ); @@ -140,7 +138,7 @@ export const getActiveInteractiveLayersIds = createSelector( }); }; - return flatten(compact(_layersActive.map((kActive) => { + return _layersActive.map((kActive) => { const layer = _layers.find(l => l.id === kActive); if (!layer) { @@ -162,7 +160,7 @@ export const getActiveInteractiveLayersIds = createSelector( } return getIds(layer); - }))); + }).filter(l => !!l).flat(); } ); @@ -171,7 +169,7 @@ export const getActiveInteractiveLayers = createSelector( (_layers, _interactions) => { if (!_layers || isEmpty(_interactions)) return {}; - const allLayers = uniqBy(flatten(_layers.map((l) => { + const allLayers = uniqBy(_layers.map((l) => { const { config, name } = l; const { type } = config; @@ -180,7 +178,7 @@ export const getActiveInteractiveLayers = createSelector( } return l; - })), 'id'); + }).flat(), 'id'); const interactiveLayerKeys = Object.keys(_interactions); const interactiveLayers = allLayers.filter(l => interactiveLayerKeys.includes(l.id)); diff --git a/services/api.js b/services/api.js index 3cbf7a1f..2b748793 100644 --- a/services/api.js +++ b/services/api.js @@ -1,8 +1,6 @@ -import get from 'lodash/get'; - export class APIError extends Error { constructor(response, responseJSON) { - const message = get(responseJSON, 'errors[0].title') || response.statusText || 'APIError'; + const message = responseJSON?.errors?.[0]?.title || response.statusText || 'APIError'; super(message); // Maintains proper stack trace for where our error was thrown (only available on V8) diff --git a/utils/documentation.js b/utils/documentation.js index 629a4682..f224dbb1 100644 --- a/utils/documentation.js +++ b/utils/documentation.js @@ -1,5 +1,4 @@ -import groupBy from 'lodash/groupBy'; -import flatten from 'lodash/flatten'; +import { groupBy } from 'utils/general'; import sortBy from 'lodash/sortBy'; import uniqBy from 'lodash/uniqBy'; @@ -109,7 +108,7 @@ const HELPERS_DOC = { const length = data.length; const groupedByStatus = this.getGroupedByStatus(data); - return flatten(Object.keys(groupedByStatus).map(status => [ + return Object.keys(groupedByStatus).map(status => [ { id: status, label: PALETTE[status].label, @@ -117,7 +116,7 @@ const HELPERS_DOC = { fill: PALETTE[status].fill, stroke: PALETTE[status].stroke } - ])); + ]).flat(); } return []; diff --git a/utils/general.js b/utils/general.js index 5f52543e..e5343be6 100644 --- a/utils/general.js +++ b/utils/general.js @@ -1,4 +1,4 @@ -function toBase64(file, cb) { +export function toBase64(file, cb) { const reader = new FileReader(); reader.onload = (event) => { cb && cb(event.target.result); @@ -6,11 +6,11 @@ function toBase64(file, cb) { reader.readAsDataURL(file); } -function encode(obj) { +export function encode(obj) { return btoa(JSON.stringify(obj)); } -function decode(obj) { +export function decode(obj) { try { return JSON.parse(atob(obj)); } catch (e) { @@ -18,13 +18,13 @@ function decode(obj) { } } -function parseSelectOptions(options) { +export function parseSelectOptions(options) { return options.map(o => ( { ...o, label: o.name, value: o.id } )); } -function parseObjectSelectOptions(object) { +export function parseObjectSelectOptions(object) { const newObject = {}; Object.keys(object).forEach((key) => { newObject[key] = parseSelectOptions(object[key]); @@ -32,4 +32,44 @@ function parseObjectSelectOptions(object) { return newObject; } -export { toBase64, encode, decode, parseSelectOptions, parseObjectSelectOptions }; +export function omit(obj, _keys) { + const keys = [_keys].flat(); + const newObj = { ...obj }; + keys.forEach((key) => { + delete newObj[key]; + }); + return newObj; +} + +export function omitBy(obj, fn) { + return Object.keys(obj).reduce((acc, key) => { + if (!fn(obj[key])) acc[key] = obj[key]; + return acc; + }, {}); +} + +export function isEmpty(obj) { + if (obj?.length || obj?.size) return false; + if (typeof obj !== 'object') return true; + for (const key in obj) if (Object.hasOwn(obj, key)) return false; + return true; +} + +export function sumBy(arr, funcOrKey) { + if (typeof funcOrKey === 'string') { + return arr.reduce((acc, item) => acc + item[funcOrKey], 0); + } + + return arr.reduce((acc, item) => acc + func(item), 0); +} + +export function groupBy(arr, criteria) { + return arr.reduce((obj, item) => { + const key = typeof criteria === 'function' ? criteria(item) : item[criteria]; + if (!obj.hasOwnProperty(key)) { + obj[key] = []; + } + obj[key].push(item); + return obj; + }, {}); +} diff --git a/utils/observations.js b/utils/observations.js index 694a6a99..2f90e117 100644 --- a/utils/observations.js +++ b/utils/observations.js @@ -1,5 +1,4 @@ -import groupBy from 'lodash/groupBy'; -import flatten from 'lodash/flatten'; +import { groupBy } from 'utils/general'; const HELPERS_OBS = { // Groups @@ -49,14 +48,12 @@ const HELPERS_OBS = { // Values getMaxValue(data) { - const arr = flatten( - Object.keys(data || this.props.data).map((k) => { - const groupedBySeverity = groupBy(data[k], 'level'); - return Object.keys(groupedBySeverity).map( - (s) => groupedBySeverity[s].length - ); - }) - ); + const arr = Object.keys(data || this.props.data).map((k) => { + const groupedBySeverity = groupBy(data[k], 'level'); + return Object.keys(groupedBySeverity).map( + (s) => groupedBySeverity[s].length + ); + }).flat(); return Math.max(...arr); }, diff --git a/utils/signup.js b/utils/signup.js index 4c9e2116..4753554f 100644 --- a/utils/signup.js +++ b/utils/signup.js @@ -1,8 +1,7 @@ import sortBy from 'lodash/sortBy'; -import groupBy from 'lodash/groupBy'; -import compact from 'lodash/compact'; import API from 'services/api'; +import { groupBy } from 'utils/general'; const HELPERS_REGISTER = { getCountries(lang) { @@ -21,7 +20,7 @@ const HELPERS_REGISTER = { getFMUCertificationsValues(fmus) { const fmusGroups = groupBy(fmus, 'id'); Object.keys(fmusGroups).forEach((id) => { - fmusGroups[id] = compact([ + fmusGroups[id] = [ !!fmusGroups[id][0]['certification-fsc'] && 'fsc', !!fmusGroups[id][0]['certification-fsc-cw'] && 'fsc-cw', !!fmusGroups[id][0]['certification-ls'] && 'ls', @@ -29,7 +28,7 @@ const HELPERS_REGISTER = { !!fmusGroups[id][0]['certification-pefc'] && 'pefc', !!fmusGroups[id][0]['certification-olb'] && 'olb', !!fmusGroups[id][0]['certification-tlv'] && 'tlv' - ]); + ].filter(x => !!x); }); return fmusGroups; diff --git a/yarn.lock b/yarn.lock index add68a40..6c64488e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4796,7 +4796,7 @@ react-dropzone@^14.2.3: file-selector "^2.1.0" prop-types "^15.8.1" -react-fast-compare@^3.0.1, react-fast-compare@^3.2.1: +react-fast-compare@^3.0.1, react-fast-compare@^3.2.2: version "3.2.2" resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-3.2.2.tgz#929a97a532304ce9fee4bcae44234f1ce2c21d49" integrity sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==