From 08034da727d3bc5964d0cfe5963c29fa3a302b1d Mon Sep 17 00:00:00 2001 From: jerem Date: Wed, 13 Nov 2024 15:02:07 +0100 Subject: [PATCH] chore(openAlex): move openAlexTab code --- client/src/pages/openalex-ror/openalexTab.jsx | 199 ------------------ client/src/pages/openalex-ror/results.jsx | 190 ++++++++++++++--- 2 files changed, 166 insertions(+), 223 deletions(-) delete mode 100644 client/src/pages/openalex-ror/openalexTab.jsx diff --git a/client/src/pages/openalex-ror/openalexTab.jsx b/client/src/pages/openalex-ror/openalexTab.jsx deleted file mode 100644 index 0855529..0000000 --- a/client/src/pages/openalex-ror/openalexTab.jsx +++ /dev/null @@ -1,199 +0,0 @@ -import { - Button, - Modal, ModalContent, ModalFooter, ModalTitle, - TextInput, -} from '@dataesr/dsfr-plus'; -import PropTypes from 'prop-types'; -import { useEffect, useState } from 'react'; - -import { status } from '../../config'; -import { getAffiliationsCorrections } from '../../utils/curations'; -import { isRor } from '../../utils/ror'; -import { capitalize, removeDiacritics } from '../../utils/strings'; -import ExportErrorsButton from './export-errors-button'; -import OpenalexView from './openalexView'; -import SendFeedbackButton from './send-feedback-button'; - -export default function OpenalexTab({ - affiliations, - allOpenalexCorrections, - options, - setAllOpenalexCorrections, - undo, -}) { - const [action, setAction] = useState(); - const [filteredAffiliations, setFilteredAffiliations] = useState([]); - const [filteredAffiliationName, setFilteredAffiliationName] = useState(''); - const [filteredStatus] = useState([ - status.tobedecided.id, - status.validated.id, - status.excluded.id, - ]); - const [isModalOpen, setIsModalOpen] = useState(false); - const [ror, setRor] = useState(''); - const [selectedOpenAlex, setSelectedOpenAlex] = useState([]); - const [timer, setTimer] = useState(); - - const actionToOpenAlex = (_action, _selectedOpenAlex, _ror) => { - _selectedOpenAlex.map((item) => { - let rorsToCorrect = item.rorsToCorrect.trim().split(';'); - if (action === 'add') { - rorsToCorrect.push(_ror); - } else if (action === 'remove') { - rorsToCorrect = rorsToCorrect.filter((item2) => item2 !== _ror); - } - // eslint-disable-next-line no-param-reassign - item.rorsToCorrect = [...new Set(rorsToCorrect)].join(';'); - // eslint-disable-next-line no-param-reassign - item.hasCorrection = item.rors.map((r) => r.rorId).join(';') !== item.rorsToCorrect; - return item; - }); - setAllOpenalexCorrections(getAffiliationsCorrections(_selectedOpenAlex)); - }; - - useEffect(() => { - if (timer) { - clearTimeout(timer); - } - const timerTmp = setTimeout(() => { - const filteredAffiliationsTmp = affiliations.filter((affiliation) => { - const regex = new RegExp(removeDiacritics(filteredAffiliationName)); - return regex.test( - affiliation.key.replace('[ source: ', '').replace(' ]', ''), - ); - }); - // Recompute corrections only when the array has changed - if (filteredAffiliationsTmp.length !== filteredAffiliations.length) { - setAllOpenalexCorrections( - getAffiliationsCorrections(filteredAffiliationsTmp), - ); - } - setFilteredAffiliations(filteredAffiliationsTmp); - }, 500); - setTimer(timerTmp); - // The timer should not be tracked - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [affiliations, filteredAffiliationName, filteredStatus]); - - return ( -
- setIsModalOpen((prev) => !prev)}> - - {`${capitalize(action)} ROR to ${ - selectedOpenAlex.length - } OpenAlex affiliation${selectedOpenAlex.length > 1 ? 's' : ''}`} - - - setRor(e.target.value)} - required - /> - - - - - - {/* */} -
-
- - {selectedOpenAlex.length} - {` selected affiliation${selectedOpenAlex.length === 1 ? '' : 's'}`} - - - - - -
-
- actions relatives au tableau du dessous -
-
- - {/* */} -
- ); -} - -OpenalexTab.propTypes = { - affiliations: PropTypes.arrayOf( - PropTypes.shape({ - name: PropTypes.string.isRequired, - nameHtml: PropTypes.string.isRequired, - status: PropTypes.string.isRequired, - works: PropTypes.arrayOf(PropTypes.string).isRequired, - worksNumber: PropTypes.number.isRequired, - }), - ).isRequired, - allOpenalexCorrections: PropTypes.arrayOf(PropTypes.shape({ - correctedRors: PropTypes.string.isRequired, - rawAffiliationString: PropTypes.string.isRequired, - rorsInOpenAlex: PropTypes.arrayOf(PropTypes.shape({ - rorCountry: PropTypes.string.isRequired, - rorId: PropTypes.string.isRequired, - rorName: PropTypes.string.isRequired, - })).isRequired, - worksExample: PropTypes.arrayOf(PropTypes.shape({ - id_type: PropTypes.string.isRequired, - id_value: PropTypes.string.isRequired, - })).isRequired, - worksOpenAlex: PropTypes.arrayOf(PropTypes.string).isRequired, - })).isRequired, - options: PropTypes.object.isRequired, - setAllOpenalexCorrections: PropTypes.func.isRequired, - undo: PropTypes.func.isRequired, -}; diff --git a/client/src/pages/openalex-ror/results.jsx b/client/src/pages/openalex-ror/results.jsx index f2b4e7a..2a247d1 100644 --- a/client/src/pages/openalex-ror/results.jsx +++ b/client/src/pages/openalex-ror/results.jsx @@ -1,4 +1,10 @@ -import { Col, Container, Row, Spinner, Text } from '@dataesr/dsfr-plus'; +import { + Button, + Container, Row, Col, + Modal, ModalContent, ModalFooter, ModalTitle, + Text, + TextInput, +} from '@dataesr/dsfr-plus'; import { useQuery } from '@tanstack/react-query'; import { useEffect, useState } from 'react'; import { useSearchParams } from 'react-router-dom'; @@ -7,13 +13,18 @@ import useToast from '../../hooks/useToast'; import Header from '../../layout/header'; import { getAffiliationsCorrections } from '../../utils/curations'; import { isRor } from '../../utils/ror'; -import { normalize } from '../../utils/strings'; +import { normalize, capitalize, removeDiacritics } from '../../utils/strings'; import { getWorks } from '../../utils/works'; -import OpenalexTab from './openalexTab'; import 'primereact/resources/primereact.min.css'; import 'primereact/resources/themes/lara-light-indigo/theme.css'; +import { status } from '../../config'; + +import ExportErrorsButton from './export-errors-button'; +import OpenalexView from './openalexView'; +import SendFeedbackButton from './send-feedback-button'; + const { VITE_APP_TAG_LIMIT } = import.meta.env; export default function Affiliations() { @@ -23,6 +34,19 @@ export default function Affiliations() { const [options, setOptions] = useState({}); const { toast } = useToast(); + const [action, setAction] = useState(); + const [filteredAffiliations, setFilteredAffiliations] = useState([]); + const [filteredAffiliationName, setFilteredAffiliationName] = useState(''); + const [filteredStatus] = useState([ + status.tobedecided.id, + status.validated.id, + status.excluded.id, + ]); + const [isModalOpen, setIsModalOpen] = useState(false); + const [ror, setRor] = useState(''); + const [selectedOpenAlex, setSelectedOpenAlex] = useState([]); + const [timer, setTimer] = useState(); + const { data, error, isFetched, isFetching, refetch } = useQuery({ queryKey: ['openalex-ror', JSON.stringify(options)], queryFn: () => getWorks(options, toast), @@ -88,26 +112,63 @@ export default function Affiliations() { setAffiliations(data?.affiliations ?? []); }, [data]); - const openAlexAffiliations = affiliations.filter((affiliation) => affiliation.source === 'OpenAlex'); + const actionToOpenAlex = (_action, _selectedOpenAlex, _ror) => { + _selectedOpenAlex.map((item) => { + let rorsToCorrect = item.rorsToCorrect.trim().split(';'); + if (action === 'add') { + rorsToCorrect.push(_ror); + } else if (action === 'remove') { + rorsToCorrect = rorsToCorrect.filter((item2) => item2 !== _ror); + } + // eslint-disable-next-line no-param-reassign + item.rorsToCorrect = [...new Set(rorsToCorrect)].join(';'); + // eslint-disable-next-line no-param-reassign + item.hasCorrection = item.rors.map((r) => r.rorId).join(';') !== item.rorsToCorrect; + return item; + }); + setAllOpenalexCorrections(getAffiliationsCorrections(_selectedOpenAlex)); + }; + + useEffect(() => { + if (timer) { + clearTimeout(timer); + } + const timerTmp = setTimeout(() => { + const openAlexAffiliations = affiliations.filter((affiliation) => affiliation.source === 'OpenAlex'); + const filteredAffiliationsTmp = openAlexAffiliations.filter((affiliation) => { + const regex = new RegExp(removeDiacritics(filteredAffiliationName)); + return regex.test( + affiliation.key.replace('[ source: ', '').replace(' ]', ''), + ); + }); + // Recompute corrections only when the array has changed + if (filteredAffiliationsTmp.length !== filteredAffiliations.length) { + setAllOpenalexCorrections( + getAffiliationsCorrections(filteredAffiliationsTmp), + ); + } + setFilteredAffiliations(filteredAffiliationsTmp); + }, 500); + setTimer(timerTmp); + // The timer should not be tracked + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [affiliations, filteredAffiliationName, filteredStatus]); return ( <>
{isFetching && ( - <> -
- -
- Loading data from OpenAlex, please wait... -
-
- OpenAlex -
- Loading -
-
- + +
+ Loading data from OpenAlex, please wait... +
+
+ OpenAlex +
+ Loading +
+
)} {error && ( @@ -127,13 +188,94 @@ export default function Affiliations() { params: - +
+ setIsModalOpen((prev) => !prev)}> + + {`${capitalize(action)} ROR to ${ + selectedOpenAlex.length + } OpenAlex affiliation${selectedOpenAlex.length > 1 ? 's' : ''}`} + + + setRor(e.target.value)} + required + /> + + + + + +
+
+ + {selectedOpenAlex.length} + {` selected affiliation${selectedOpenAlex.length === 1 ? '' : 's'}`} + + + + + +
+
+ actions relatives au tableau du dessous +
+
+ +
)}