diff --git a/client/src/pages/affiliationsTab.jsx b/client/src/pages/affiliationsTab.jsx index ab4b02b0..64fd1796 100644 --- a/client/src/pages/affiliationsTab.jsx +++ b/client/src/pages/affiliationsTab.jsx @@ -4,7 +4,6 @@ import { Col, Notice, Row, - Tab, TextInput, } from '@dataesr/react-dsfr'; import PropTypes from 'prop-types'; @@ -49,7 +48,7 @@ export default function AffiliationsTab({ affiliations, tagAffiliations }) { }; return ( - + <> {affiliationsNotice && ( @@ -110,7 +109,7 @@ export default function AffiliationsTab({ affiliations, tagAffiliations }) { {renderButtons(selectedAffiliations, tagAffiliations)} - + ); } diff --git a/client/src/pages/index.jsx b/client/src/pages/index.jsx index 9f05b8bf..75eb613c 100644 --- a/client/src/pages/index.jsx +++ b/client/src/pages/index.jsx @@ -3,21 +3,19 @@ /* eslint-disable jsx-a11y/control-has-associated-label */ /* eslint-disable no-case-declarations */ import { - Checkbox, - CheckboxGroup, Col, Container, Row, Tab, Tabs, - TextInput, } from '@dataesr/react-dsfr'; import { useQuery } from '@tanstack/react-query'; import { useEffect, useState } from 'react'; import Actions from './actions'; -import Filters from './filters'; import AffiliationsTab from './affiliationsTab'; +import Filters from './filters'; +import PublicationsTab from './publicationsTab'; import WorksView from './worksView'; import Gauge from '../components/gauge'; import { PageSpinner } from '../components/spinner'; @@ -29,35 +27,20 @@ import { getAuthorsHtmlField, getAuthorsTooltipField, } from '../utils/templates'; -import { - getData, - renderButtons, -} from '../utils/works.jsx'; +import { getData, renderButtons } from '../utils/works'; import { status } from '../config'; import 'primereact/resources/primereact.min.css'; import 'primereact/resources/themes/lara-light-indigo/theme.css'; -const DATASOURCES = [{ key: 'bso', label: 'French OSM' }, { key: 'openalex', label: 'OpenAlex' }]; - export default function Home() { const [allAffiliations, setAllAffiliations] = useState([]); const [allDatasets, setAllDatasets] = useState([]); const [allPublications, setAllPublications] = useState([]); - const [filteredAffiliationName, setFilteredAffiliationName] = useState(''); - const [filteredDatasources, setFilteredDatasources] = useState(DATASOURCES.map((datasource) => datasource.key)); - const [filteredPublications, setFilteredPublications] = useState([]); - const [filteredStatus, setFilteredStatus] = useState(Object.keys(status)); - const [filteredTypes, setFilteredTypes] = useState([]); - const [filteredYears, setFilteredYears] = useState([]); const [isLoading, setIsLoading] = useState(false); const [options, setOptions] = useState({}); const [regexp, setRegexp] = useState(); const [selectedDatasets, setSelectedDatasets] = useState([]); - const [selectedPublications, setSelectedPublications] = useState([]); - const [timer, setTimer] = useState(); - const [types, setTypes] = useState([]); - const [years, setYears] = useState([]); const { data, isFetching, refetch } = useQuery({ queryKey: ['data'], @@ -173,28 +156,8 @@ export default function Home() { } setAllDatasets(allDatasetsTmp); setAllPublications(allPublicationsTmp); - setFilteredPublications(allPublicationsTmp); - const allYears = [...new Set(allPublicationsTmp.map((publication) => publication?.year).filter((year) => !!year))]; - setYears(allYears); - setFilteredYears(allYears); - const allTypes = [...new Set(allPublicationsTmp.map((publication) => publication?.type))]; - setTypes(allTypes); - setFilteredTypes(allTypes); }, [data, regexp]); - useEffect(() => { - if (timer) { - clearTimeout(timer); - } - const timerTmp = setTimeout(() => { - const filteredPublicationsTmp = allPublications.filter((publication) => publication.affiliationsTooltip.includes(filteredAffiliationName) && filteredDatasources.includes(publication.datasource) && filteredStatus.includes(publication.status) && filteredTypes.includes(publication.type) && filteredYears.includes(publication.year)); - setFilteredPublications(filteredPublicationsTmp); - }, 500); - setTimer(timerTmp); - // The timer should not be tracked - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [allPublications, filteredAffiliationName, filteredDatasources, filteredStatus, filteredTypes, filteredYears]); - useEffect(() => { groupByAffiliations(); // eslint-disable-next-line react-hooks/exhaustive-deps @@ -205,7 +168,6 @@ export default function Home() { const publicationsIds = publications.map((publication) => publication.id); allPublicationsTmp.filter((publication) => publicationsIds.includes(publication.id)).map((publication) => publication.status = action); setAllPublications(allPublicationsTmp); - setSelectedPublications([]); }; const tagDatasets = (datasets, action) => { @@ -232,38 +194,6 @@ export default function Home() { setAllAffiliations(allAffiliationsTmp); }; - const onDatasourcesChange = (datasource) => { - if (filteredDatasources.includes(datasource.key)) { - setFilteredDatasources(filteredDatasources.filter((filteredDatasource) => filteredDatasource !== datasource.key)); - } else { - setFilteredDatasources(filteredDatasources.concat([datasource.key])); - } - }; - - const onStatusChange = (st) => { - if (filteredStatus.includes(st)) { - setFilteredStatus(filteredStatus.filter((filteredSt) => filteredSt !== st)); - } else { - setFilteredStatus(filteredStatus.concat([st])); - } - }; - - const onTypesChange = (type) => { - if (filteredTypes.includes(type)) { - setFilteredTypes(filteredTypes.filter((filteredType) => filteredType !== type)); - } else { - setFilteredTypes(filteredTypes.concat([type])); - } - }; - - const onYearsChange = (year) => { - if (filteredYears.includes(year)) { - setFilteredYears(filteredYears.filter((filteredYear) => filteredYear !== year)); - } else { - setFilteredYears(filteredYears.concat([year])); - } - }; - return ( <> @@ -286,105 +216,17 @@ export default function Home() { /> {allAffiliations.length > 0 && ( - + + + - - - {renderButtons(selectedPublications, tagPublications)} - - - ({ - ...st, - value: allPublications.filter((publication) => publication.status === st.id).length, - }))} - /> - - - {(isFetching || isLoading) && ()} - {(!isFetching && !isLoading) && ( - - - - {Object.values(status).map((st) => ( - onStatusChange(st.id)} - size="sm" - /> - ))} - - - {DATASOURCES.map((datasource) => ( - onDatasourcesChange(datasource)} - size="sm" - /> - ))} - - - {years.map((year) => ( - onYearsChange(year)} - size="sm" - /> - ))} - - - {types.map((type) => ( - onTypesChange(type)} - size="sm" - /> - ))} - - setFilteredAffiliationName(e.target.value)} - value={filteredAffiliationName} - /> - - - - - - )} - - - {renderButtons(selectedPublications, tagPublications)} - - + diff --git a/client/src/pages/publicationsTab.jsx b/client/src/pages/publicationsTab.jsx new file mode 100644 index 00000000..d782ad80 --- /dev/null +++ b/client/src/pages/publicationsTab.jsx @@ -0,0 +1,196 @@ +import { + Checkbox, + CheckboxGroup, + Col, + Row, + TextInput, +} from '@dataesr/react-dsfr'; +import PropTypes from 'prop-types'; +import { useEffect, useState } from 'react'; + +import WorksView from './worksView'; +import Gauge from '../components/gauge'; +import { status } from '../config'; +import { renderButtons } from '../utils/works'; + +const DATASOURCES = [{ key: 'bso', label: 'French OSM' }, { key: 'openalex', label: 'OpenAlex' }]; + +export default function PublicationsTab({ publications, tagPublications }) { + const [filteredPublications, setFilteredPublications] = useState([]); + const [filteredAffiliationName, setFilteredAffiliationName] = useState(''); + const [filteredDatasources, setFilteredDatasources] = useState(DATASOURCES.map((datasource) => datasource.key)); + const [filteredStatus, setFilteredStatus] = useState(Object.keys(status)); + const [filteredTypes, setFilteredTypes] = useState([]); + const [filteredYears, setFilteredYears] = useState([]); + const [selectedPublications, setSelectedPublications] = useState([]); + const [timer, setTimer] = useState(); + const [types, setTypes] = useState([]); + const [years, setYears] = useState([]); + + useEffect(() => { + setFilteredPublications(publications); + const allYears = [...new Set(publications.map((publication) => publication?.year).filter((year) => !!year))]; + setYears(allYears); + setFilteredYears(allYears); + const allTypes = [...new Set(publications.map((publication) => publication?.type))]; + setTypes(allTypes); + setFilteredTypes(allTypes); + }, [publications]); + + useEffect(() => { + if (timer) { + clearTimeout(timer); + } + const timerTmp = setTimeout(() => { + const filteredPublicationsTmp = publications.filter((publication) => publication.affiliationsTooltip.includes(filteredAffiliationName) + && filteredDatasources.includes(publication.datasource) + && filteredStatus.includes(publication.status) + && filteredTypes.includes(publication.type) + && filteredYears.includes(publication.year)); + setFilteredPublications(filteredPublicationsTmp); + }, 500); + setTimer(timerTmp); + // The timer should not be tracked + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [publications, filteredAffiliationName, filteredDatasources, filteredStatus, filteredTypes, filteredYears]); + + const onDatasourcesChange = (datasource) => { + if (filteredDatasources.includes(datasource.key)) { + setFilteredDatasources(filteredDatasources.filter((filteredDatasource) => filteredDatasource !== datasource.key)); + } else { + setFilteredDatasources(filteredDatasources.concat([datasource.key])); + } + }; + + const onStatusChange = (st) => { + if (filteredStatus.includes(st)) { + setFilteredStatus(filteredStatus.filter((filteredSt) => filteredSt !== st)); + } else { + setFilteredStatus(filteredStatus.concat([st])); + } + }; + + const onTypesChange = (type) => { + if (filteredTypes.includes(type)) { + setFilteredTypes(filteredTypes.filter((filteredType) => filteredType !== type)); + } else { + setFilteredTypes(filteredTypes.concat([type])); + } + }; + + const onYearsChange = (year) => { + if (filteredYears.includes(year)) { + setFilteredYears(filteredYears.filter((filteredYear) => filteredYear !== year)); + } else { + setFilteredYears(filteredYears.concat([year])); + } + }; + + return ( + <> + + + {renderButtons(selectedPublications, tagPublications)} + + + ({ + ...st, + value: publications.filter((publication) => publication.status === st.id).length, + }))} + /> + + + + + + {Object.values(status).map((st) => ( + onStatusChange(st.id)} + size="sm" + /> + ))} + + + {DATASOURCES.map((datasource) => ( + onDatasourcesChange(datasource)} + size="sm" + /> + ))} + + + {years.map((year) => ( + onYearsChange(year)} + size="sm" + /> + ))} + + + {types.map((type) => ( + onTypesChange(type)} + size="sm" + /> + ))} + + setFilteredAffiliationName(e.target.value)} + value={filteredAffiliationName} + /> + + + + + + + + {renderButtons(selectedPublications, tagPublications)} + + + + ); +} + +PublicationsTab.propTypes = { + publications: PropTypes.arrayOf(PropTypes.shape({ + affiliations: PropTypes.arrayOf(PropTypes.object).isRequired, + allIds: PropTypes.arrayOf(PropTypes.object).isRequired, + authors: PropTypes.arrayOf(PropTypes.object).isRequired, + datasource: PropTypes.string.isRequired, + id: PropTypes.string.isRequired, + status: PropTypes.string.isRequired, + type: PropTypes.string.isRequired, + })).isRequired, + tagPublications: PropTypes.func.isRequired, +};