diff --git a/client/src/pages/affiliationsTab.jsx b/client/src/pages/affiliationsTab.jsx
new file mode 100644
index 00000000..ab4b02b0
--- /dev/null
+++ b/client/src/pages/affiliationsTab.jsx
@@ -0,0 +1,128 @@
+import {
+ Checkbox,
+ CheckboxGroup,
+ Col,
+ Notice,
+ Row,
+ Tab,
+ TextInput,
+} from '@dataesr/react-dsfr';
+import PropTypes from 'prop-types';
+import { useEffect, useState } from 'react';
+
+import AffiliationsView from './affiliationsView';
+import Gauge from '../components/gauge';
+import { status } from '../config';
+import { renderButtons } from '../utils/works';
+
+export default function AffiliationsTab({ affiliations, tagAffiliations }) {
+ const [affiliationsNotice, setAffiliationsNotice] = useState(true);
+ const [filteredAffiliations, setFilteredAffiliations] = useState([]);
+ const [filteredAffiliationName, setFilteredAffiliationName] = useState('');
+ const [filteredStatus, setFilteredStatus] = useState(Object.keys(status));
+ const [selectedAffiliations, setSelectedAffiliations] = useState([]);
+ const [timer, setTimer] = useState();
+
+ useEffect(() => {
+ setFilteredAffiliations(affiliations);
+ }, [affiliations]);
+
+ useEffect(() => {
+ if (timer) {
+ clearTimeout(timer);
+ }
+ const timerTmp = setTimeout(() => {
+ const filteredAffiliationsTmp = affiliations.filter((affiliation) => affiliation.name.includes(filteredAffiliationName) && filteredStatus.includes(affiliation.status));
+ setFilteredAffiliations(filteredAffiliationsTmp);
+ }, 500);
+ setTimer(timerTmp);
+ // The timer should not be tracked
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [affiliations, filteredAffiliationName, filteredStatus]);
+
+ const onStatusChange = (st) => {
+ if (filteredStatus.includes(st)) {
+ setFilteredStatus(filteredStatus.filter((filteredSt) => filteredSt !== st));
+ } else {
+ setFilteredStatus(filteredStatus.concat([st]));
+ }
+ };
+
+ return (
+
+ {affiliationsNotice && (
+
+
+ { setAffiliationsNotice(false); }}
+ title="All the affiliations of the works found in the French OSM and OpenAlex are listed below.
+ A filter is applied to view only the affiliations containing at least one of the matching query input"
+ />
+
+
+ )}
+
+
+ {renderButtons(selectedAffiliations, tagAffiliations)}
+
+
+ ({
+ ...st,
+ value: affiliations.filter((affiliation) => affiliation.status === st.id).length,
+ }))}
+ />
+
+
+
+
+
+ {Object.values(status).map((st) => (
+ onStatusChange(st.id)}
+ size="sm"
+ />
+ ))}
+
+ setFilteredAffiliationName(e.target.value)}
+ value={filteredAffiliationName}
+ />
+
+
+ !!affiliation.matches)}
+ selectedAffiliations={selectedAffiliations}
+ setSelectedAffiliations={setSelectedAffiliations}
+ />
+
+
+
+
+ {renderButtons(selectedAffiliations, tagAffiliations)}
+
+
+
+ );
+}
+
+AffiliationsTab.propTypes = {
+ affiliations: PropTypes.arrayOf(PropTypes.shape({
+ id: PropTypes.string.isRequired,
+ matches: PropTypes.number.isRequired,
+ name: PropTypes.string.isRequired,
+ nameHtml: PropTypes.string.isRequired,
+ status: PropTypes.string.isRequired,
+ works: PropTypes.arrayOf(PropTypes.string).isRequired,
+ worksNumber: PropTypes.number.isRequired,
+ })).isRequired,
+ tagAffiliations: PropTypes.func.isRequired,
+};
diff --git a/client/src/pages/affiliationsView.jsx b/client/src/pages/affiliationsView.jsx
index e63293da..10d4f942 100644
--- a/client/src/pages/affiliationsView.jsx
+++ b/client/src/pages/affiliationsView.jsx
@@ -1,6 +1,6 @@
-import PropTypes from 'prop-types';
import { Column } from 'primereact/column';
import { DataTable } from 'primereact/datatable';
+import PropTypes from 'prop-types';
import { nameTemplate, statusTemplate } from '../utils/templates';
diff --git a/client/src/pages/index.jsx b/client/src/pages/index.jsx
index 78470d9d..9f05b8bf 100644
--- a/client/src/pages/index.jsx
+++ b/client/src/pages/index.jsx
@@ -3,12 +3,10 @@
/* eslint-disable jsx-a11y/control-has-associated-label */
/* eslint-disable no-case-declarations */
import {
- Button,
Checkbox,
CheckboxGroup,
Col,
Container,
- Notice,
Row,
Tab,
Tabs,
@@ -19,7 +17,7 @@ import { useEffect, useState } from 'react';
import Actions from './actions';
import Filters from './filters';
-import AffiliationsView from './affiliationsView';
+import AffiliationsTab from './affiliationsTab';
import WorksView from './worksView';
import Gauge from '../components/gauge';
import { PageSpinner } from '../components/spinner';
@@ -33,7 +31,8 @@ import {
} from '../utils/templates';
import {
getData,
-} from '../utils/works';
+ renderButtons,
+} from '../utils/works.jsx';
import { status } from '../config';
import 'primereact/resources/primereact.min.css';
@@ -42,27 +41,21 @@ 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 [affiliationsNotice, setAffiliationsNotice] = useState(true);
const [allAffiliations, setAllAffiliations] = useState([]);
const [allDatasets, setAllDatasets] = useState([]);
const [allPublications, setAllPublications] = useState([]);
- const [filteredAffiliations, setFilteredAffiliations] = useState([]);
const [filteredAffiliationName, setFilteredAffiliationName] = useState('');
- const [filteredAffiliationName2, setFilteredAffiliationName2] = useState('');
const [filteredDatasources, setFilteredDatasources] = useState(DATASOURCES.map((datasource) => datasource.key));
const [filteredPublications, setFilteredPublications] = useState([]);
const [filteredStatus, setFilteredStatus] = useState(Object.keys(status));
- const [filteredStatus2, setFilteredStatus2] = 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 [selectedAffiliations, setSelectedAffiliations] = useState([]);
const [selectedDatasets, setSelectedDatasets] = useState([]);
const [selectedPublications, setSelectedPublications] = useState([]);
const [timer, setTimer] = useState();
- const [timer2, setTimer2] = useState();
const [types, setTypes] = useState([]);
const [years, setYears] = useState([]);
@@ -89,7 +82,6 @@ export default function Home() {
.replace(/[^a-zA-Z0-9]/g, '');
const groupByAffiliations = () => {
- setIsLoading(true);
// Save already decided affiliations
const decidedAffiliations = Object.values(allAffiliations).filter((affiliation) => affiliation.status !== status.tobedecided.id);
// Compute distinct affiliations of the undecided works
@@ -133,7 +125,6 @@ export default function Home() {
allAffiliationsTmp = Object.values(allAffiliationsTmp)
.map((affiliation, index) => ({ ...affiliation, id: index.toString(), works: [...new Set(affiliation.works)], worksNumber: [...new Set(affiliation.works)].length }));
setAllAffiliations(allAffiliationsTmp);
- setFilteredAffiliations(allAffiliationsTmp);
setIsLoading(false);
};
@@ -204,19 +195,6 @@ export default function Home() {
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [allPublications, filteredAffiliationName, filteredDatasources, filteredStatus, filteredTypes, filteredYears]);
- useEffect(() => {
- if (timer2) {
- clearTimeout(timer2);
- }
- const timerTmp2 = setTimeout(() => {
- const filteredAffiliationsTmp = allAffiliations.filter((affiliation) => affiliation.name.includes(filteredAffiliationName2) && filteredStatus2.includes(affiliation.status));
- setFilteredAffiliations(filteredAffiliationsTmp);
- }, 500);
- setTimer2(timerTmp2);
- // The timer should not be tracked
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, [allAffiliations, filteredAffiliationName2, filteredStatus2]);
-
useEffect(() => {
groupByAffiliations();
// eslint-disable-next-line react-hooks/exhaustive-deps
@@ -252,26 +230,8 @@ export default function Home() {
const affiliationIds = affiliations.map((affiliation) => affiliation.id);
allAffiliationsTmp.filter((affiliation) => affiliationIds.includes(affiliation.id)).map((affiliation) => affiliation.status = action);
setAllAffiliations(allAffiliationsTmp);
- setSelectedAffiliations([]);
};
- const renderButtons = (selected, fn) => (
- <>
- {Object.values(status).map((st) => (
- fn(selected, st.id)}
- size="sm"
- >
- {`${st.buttonLabel} (${selected.length})`}
-
- ))}
- >
- );
-
const onDatasourcesChange = (datasource) => {
if (filteredDatasources.includes(datasource.key)) {
setFilteredDatasources(filteredDatasources.filter((filteredDatasource) => filteredDatasource !== datasource.key));
@@ -288,14 +248,6 @@ export default function Home() {
}
};
- const onStatusChange2 = (st) => {
- if (filteredStatus2.includes(st)) {
- setFilteredStatus2(filteredStatus2.filter((filteredSt2) => filteredSt2 !== st));
- } else {
- setFilteredStatus2(filteredStatus2.concat([st]));
- }
- };
-
const onTypesChange = (type) => {
if (filteredTypes.includes(type)) {
setFilteredTypes(filteredTypes.filter((filteredType) => filteredType !== type));
@@ -332,73 +284,13 @@ export default function Home() {
setAllPublications={setAllPublications}
tagAffiliations={tagAffiliations}
/>
- {isLoading && }
{allAffiliations.length > 0 && (
-
- {affiliationsNotice && (
-
-
- { setAffiliationsNotice(false); }}
- title="All the affiliations of the works found in the French OSM and OpenAlex are listed below. A filter is applied to view only the affiliations containing at least one of the matching query input"
- />
-
-
- )}
-
-
- {renderButtons(selectedAffiliations, tagAffiliations)}
-
-
- ({
- ...st,
- value: allAffiliations.filter((affiliation) => affiliation.status === st.id).length,
- }))}
- />
-
-
- {(isFetching || isLoading) && ( )}
- {!isFetching && !isLoading && (
-
-
-
- {Object.values(status).map((st) => (
- onStatusChange2(st.id)}
- size="sm"
- />
- ))}
-
- setFilteredAffiliationName2(e.target.value)}
- value={filteredAffiliationName2}
- />
-
-
- !!affiliation.matches)}
- selectedAffiliations={selectedAffiliations}
- setSelectedAffiliations={setSelectedAffiliations}
- />
-
-
- )}
-
-
- {renderButtons(selectedAffiliations, tagAffiliations)}
-
-
-
+
diff --git a/client/src/pages/views/affiliationsTab.jsx b/client/src/pages/views/affiliationsTab.jsx
deleted file mode 100644
index fd2a7c19..00000000
--- a/client/src/pages/views/affiliationsTab.jsx
+++ /dev/null
@@ -1 +0,0 @@
-export default function AffiliationsTab({
\ No newline at end of file
diff --git a/client/src/utils/templates.jsx b/client/src/utils/templates.jsx
index 95695955..0c5ade23 100644
--- a/client/src/utils/templates.jsx
+++ b/client/src/utils/templates.jsx
@@ -3,7 +3,7 @@
import { Badge } from '@dataesr/react-dsfr';
import { Tooltip } from 'react-tooltip';
-import { getIdLink } from './works';
+import { getIdLink } from './works.jsx';
import { status } from '../config';
const affiliationsTemplate = (rowData) => (
diff --git a/client/src/utils/works.js b/client/src/utils/works.jsx
similarity index 64%
rename from client/src/utils/works.js
rename to client/src/utils/works.jsx
index 5031a1c5..ed636504 100644
--- a/client/src/utils/works.js
+++ b/client/src/utils/works.jsx
@@ -1,3 +1,7 @@
+import { Button } from '@dataesr/react-dsfr';
+
+import { status } from '../config';
+
const {
VITE_API,
} = import.meta.env;
@@ -36,7 +40,25 @@ const getIdLink = (type, id) => {
return (prefix !== null) ? `${prefix}${id}` : false;
};
+const renderButtons = (selected, fn) => (
+ <>
+ {Object.values(status).map((st) => (
+ fn(selected, st.id)}
+ size="sm"
+ >
+ {`${st.buttonLabel} (${selected.length})`}
+
+ ))}
+ >
+);
+
export {
getData,
getIdLink,
+ renderButtons,
};