-
+
diff --git a/components/Layout/Layout.js b/components/Layout/Layout.js
index 597bcbe5..36553b56 100644
--- a/components/Layout/Layout.js
+++ b/components/Layout/Layout.js
@@ -36,7 +36,7 @@ export default function AppLayout({children}) {
{children}
-
+
)
diff --git a/components/Layout/Loading.js b/components/Layout/Loading.js
index bea566b9..13cd9748 100644
--- a/components/Layout/Loading.js
+++ b/components/Layout/Loading.js
@@ -4,13 +4,9 @@ const Loading = () => {
return (
- L
- O
A
- D
- I
- N
- G
+ M
+ S
)
diff --git a/components/Layout/Loading.module.scss b/components/Layout/Loading.module.scss
index 10b55754..c1481d1e 100644
--- a/components/Layout/Loading.module.scss
+++ b/components/Layout/Loading.module.scss
@@ -6,27 +6,27 @@
}
.Loading {
- font-size: 84px;
+ font-size: 40px;
font-family: 'Montserrat', sans-serif;
font-weight: 800;
text-align: center;
span {
- animation: loading01 0.2s infinite alternate;
+ animation: loading01 1s infinite alternate;
@for $i from 1 through 6 {
&:nth-child(#{$i+1}) {
- animation-delay: #{$i*.1}s;
+ animation-delay: #{$i*.3}s;
}
}
}
@keyframes loading01 {
0% {
- filter: blur(0);
+ filter: blur(1px);
opacity: 1;
}
100% {
- filter: blur(5px);
+ filter: blur(2px);
opacity: .2;
}
}
diff --git a/components/Layout/Menu.js b/components/Layout/Menu.js
index f9dea35f..f1f9ef27 100644
--- a/components/Layout/Menu.js
+++ b/components/Layout/Menu.js
@@ -1,45 +1,78 @@
import {Menu} from "antd";
-import React from "react";
+import React, {useContext, useEffect, useState} from "react";
import config from './config/config-menu';
-import style from "./Menu.module.css";
+import style from "./Menu.module.scss";
import {useRouter} from "next/router";
+import {UserContext} from "../../utils/context/UserContext";
const AppMenu = ({collapsed}) => {
const router = useRouter();
+ const user = useContext(UserContext);
- const collectOpenKeys = () => {
- const openKeys = [];
- config.forEach(menuConfig => {
- if (menuConfig.hasOwnProperty('submenu')) {
- const activeMenu = menuConfig['submenu'].filter(submenu => router.pathname.includes(submenu.link));
- if (activeMenu.length > 0) {
- openKeys.push(menuConfig.name)
- }
- }
- });
- return openKeys;
+ const isActivePath = (link) => {
+ if (!link) {
+ return false;
+ }
+
+ return router.pathname === link || router.pathname.startsWith(`${link}/`);
};
- const collectSelectedKeys = () => {
- const selectedKeys = [];
- config.forEach(menuConfig => {
- if (menuConfig.hasOwnProperty('submenu')) {
- const activeMenu = menuConfig['submenu'].filter(submenu => router.pathname.includes(submenu.link));
- if (activeMenu.length > 0) {
- selectedKeys.push(...activeMenu.map(am => (am.name)))
- }
- } else {
- if (router.pathname.includes(menuConfig.link)) {
- selectedKeys.push(menuConfig.name)
+ const collectActiveTrail = (menuItems, parents = []) => {
+ for (const menuItem of menuItems) {
+ const currentTrail = [...parents, menuItem.name];
+
+ if (menuItem.hasOwnProperty('submenu')) {
+ const submenuTrail = collectActiveTrail(menuItem.submenu, currentTrail);
+ if (submenuTrail.length > 0) {
+ return submenuTrail;
}
}
- });
- return selectedKeys;
+
+ if (isActivePath(menuItem.link)) {
+ return currentTrail;
+ }
+ }
+
+ return [];
};
- const getItem = (label, key, icon, children) => {
- return {
- key, icon, label, children
+ const activeTrail = collectActiveTrail(config);
+ const activeOpenKeys = activeTrail.slice(0, -1);
+ const selectedKeys = activeTrail.slice(-1);
+ const [openKeys, setOpenKeys] = useState(activeOpenKeys);
+
+ useEffect(() => {
+ setOpenKeys(activeOpenKeys);
+ }, [router.pathname]);
+
+ const getItem = (label, key, icon, group, children) => {
+ let returnItem = false;
+
+ /* Check if user is admin */
+ if (user['is_admin']) {
+ returnItem = true
+ }
+
+ /* Check if menu should be displayed to everyone */
+ if (group.includes('__ALL__')) {
+ returnItem = true
+ }
+
+ /* Check if user in the allowed group */
+ const contains = user['groups'].some(element => {
+ return group.includes(element);
+ });
+
+ if (contains) {
+ returnItem = true
+ }
+
+ if (returnItem) {
+ return {
+ key, icon, label, children
+ }
+ } else {
+ return ''
}
}
@@ -49,13 +82,15 @@ const AppMenu = ({collapsed}) => {
config.hasOwnProperty('link') ?
{config.name} : config.name,
config.name,
config.icon,
+ config.group,
config.submenu.map(conf => renderItem(conf))
)
} else {
return getItem(
config.hasOwnProperty('link') ?
{config.name} : config.name,
config.name,
- config.icon
+ config.icon,
+ config.group
)
}
}
@@ -67,13 +102,16 @@ const AppMenu = ({collapsed}) => {
return (
diff --git a/components/Layout/Menu.module.css b/components/Layout/Menu.module.scss
similarity index 80%
rename from components/Layout/Menu.module.css
rename to components/Layout/Menu.module.scss
index dcaa5883..c2310f8b 100644
--- a/components/Layout/Menu.module.css
+++ b/components/Layout/Menu.module.scss
@@ -9,8 +9,12 @@
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
-}
-.Logo b {
- font-weight: 800;
+ a {
+ color: #FFF;
+ }
+
+ b {
+ font-weight: 800;
+ }
}
diff --git a/components/Layout/UserAvatar.js b/components/Layout/UserAvatar.js
index ff975357..aef06675 100644
--- a/components/Layout/UserAvatar.js
+++ b/components/Layout/UserAvatar.js
@@ -6,6 +6,7 @@ import {UserOutlined, LogoutOutlined} from "@ant-design/icons";
import {signOut} from "next-auth/react";
import {useRouter} from "next/router";
import {UserContext} from "../../utils/context/UserContext";
+import {clearLocalStorageByPrefix} from "../../utils/functions/clearLocalStorageByPrefix";
const UserAvatar = ({displayUsername=true, ...rest}) => {
const user = useContext(UserContext);
@@ -37,6 +38,7 @@ const UserAvatar = ({displayUsername=true, ...rest}) => {
router.push('/profile');
break;
case "logout":
+ clearLocalStorageByPrefix('ams-')
signOut({callbackUrl: '/auth/login'})
break;
}
diff --git a/components/Layout/config/config-help.js b/components/Layout/config/config-help.js
index d4aa3b8c..b443d87b 100644
--- a/components/Layout/config/config-help.js
+++ b/components/Layout/config/config-help.js
@@ -1,12 +1,38 @@
import React from "react";
const configHelp = {
+ 'dashboard': 'http://manual.osaarchivum.org/dashboard',
'accessions': 'http://manual.osaarchivum.org/accession-records-1',
'donors': 'http://manual.osaarchivum.org/donors',
'archival-units': 'http://manual.osaarchivum.org/archival-unit',
+
+ /* ISAAR */
'isaar': 'http://manual.osaarchivum.org/isaar-cpf',
+ 'isaar/form/required_values': 'http://manual.osaarchivum.org/required-values-tab',
+ 'isaar/form/identity': 'http://manual.osaarchivum.org/identity-tab',
+ 'isaar/form/description': 'http://manual.osaarchivum.org/description-tab',
+ 'isaar/form/control': 'http://manual.osaarchivum.org/control-tab',
+
+ /* ISAD */
'isad': 'http://manual.osaarchivum.org/isad-g',
- 'finding-aids': 'http://manual.osaarchivum.org/folders-items',
+ 'isad/form/required_values': 'http://manual.osaarchivum.org/required-values-tab-1',
+ 'isad/form/identifier': 'http://manual.osaarchivum.org/identity-tab-1',
+ 'isad/form/context': 'http://manual.osaarchivum.org/context-tab',
+ 'isad/form/content': 'http://manual.osaarchivum.org/content-tab',
+ 'isad/form/access_and_use': 'http://manual.osaarchivum.org/access-and-use-tab',
+ 'isad/form/allied_materials': 'http://manual.osaarchivum.org/allied-materials-tab',
+ 'isad/form/notes': 'http://manual.osaarchivum.org/notes-tab',
+
+ /* Finding Aids */
+ 'finding-aids/archival-units-select': 'http://manual.osaarchivum.org/finding-aids',
+ 'finding-aids/containers': 'http://manual.osaarchivum.org/folders-items',
+ 'finding-aids/form/basic': 'http://manual.osaarchivum.org/basic-metadata-tab',
+ 'finding-aids/form/extra': 'http://manual.osaarchivum.org/extra-metadata-tab',
+ 'finding-aids/form/contributors': 'http://manual.osaarchivum.org/contributors-tab',
+ 'finding-aids/form/subjects': 'http://manual.osaarchivum.org/subjects-tab',
+ 'finding-aids/form/notes': 'http://manual.osaarchivum.org/notes-tab-1',
+
+ /* Authority List */
'corporations': 'http://manual.osaarchivum.org/corporations',
'countries': 'http://manual.osaarchivum.org/countries',
'genres': 'http://manual.osaarchivum.org/genres',
@@ -14,6 +40,7 @@ const configHelp = {
'people': 'http://manual.osaarchivum.org/people',
'places': 'http://manual.osaarchivum.org/places',
'subjects': 'http://manual.osaarchivum.org/subjects',
+
'controlled-lists': 'http://manual.osaarchivum.org/controlled-list',
'mlr': 'http://manual.osaarchivum.org/mlr',
'digitization-log': 'http://manual.osaarchivum.org/digitization-log',
diff --git a/components/Layout/config/config-menu.js b/components/Layout/config/config-menu.js
index 6938a6e4..ea0f7da9 100644
--- a/components/Layout/config/config-menu.js
+++ b/components/Layout/config/config-menu.js
@@ -1,63 +1,73 @@
-import { DashboardOutlined, ApartmentOutlined, UserOutlined, ProfileOutlined, FileOutlined,
+import {
+ DashboardOutlined, ApartmentOutlined, UserOutlined, ProfileOutlined, FileOutlined,
UnorderedListOutlined, BankOutlined, FlagOutlined, DeploymentUnitOutlined, GlobalOutlined, TeamOutlined,
- EnvironmentOutlined, TagOutlined, TagsOutlined, RightCircleOutlined, IdcardOutlined
+ EnvironmentOutlined, TagOutlined, TagsOutlined, RightCircleOutlined, IdcardOutlined, SearchOutlined
} from '@ant-design/icons';
import { IoSchoolOutline } from "react-icons/io5"
-import { MdOutlineScanner } from "react-icons/md"
+import { MdOutlineScanner, MdOutlineWbCloudy } from "react-icons/md"
import { BsInboxes, BsBoxArrowInLeft } from "react-icons/bs"
-import { FaExchangeAlt } from "react-icons/fa"
+import { FaExchangeAlt, FaExclamation } from "react-icons/fa"
import { HiOutlineLibrary } from "react-icons/hi"
import { BiPieChartAlt2 } from "react-icons/bi"
+import { RiExchangeFundsLine } from "react-icons/ri"
import { ImCopy } from "react-icons/im"
+
import React from "react";
const configMenu = [
- {name: 'Dashboard', icon:
, link: '/dashboard'},
- {name: 'Accession', icon:
, module: 'acccession', submenu: [
- {name: 'Accession Records', link: '/accessions'},
- {name: 'Donors', link: '/donors'},
+ {name: 'Dashboard', icon:
, link: '/dashboard', group: ['__ALL__']},
+ {name: 'Accession', icon:
, module: 'acccession', group: ['Accessions'], submenu: [
+ {name: 'Accession Records', group: ['Accessions'], link: '/accessions'},
+ {name: 'Donors', group: ['Accessions'], link: '/donors'},
]},
- {name: 'Archival Unit', icon:
, module: 'archival-unit', link: '/archival-units'},
- {name: 'ISAAR-CPF', icon:
, module: 'isaar', link: '/isaar'},
- {name: 'ISAD(G)', icon:
, module: 'isad', link: '/isad'},
- {name: 'Finding Aids', icon:
, module: 'finding-aids', submenu: [
- {name: 'Folders / Items', link: '/finding-aids'},
+ {name: 'Archival Unit', icon:
, module: 'archival-unit', group: ['Archival Units'], link: '/archival-units'},
+ {name: 'ISAAR-CPF', icon:
, module: 'isaar', group: ['ISAAR'], link: '/isaar'},
+ {name: 'ISAD(G)', icon:
, module: 'isad', group: ['ISAD(G)'], link: '/isad'},
+ {name: 'Finding Aids', icon:
, module: 'finding-aids', group: ['Finding Aids'], submenu: [
+ {name: 'Folders / Items', group: ['Finding Aids'], link: '/finding-aids/folders-items'},
+ {name: 'Missing Folders / Items', group: ['Finding Aids'], link: '/finding-aids/missing'},
]},
- {name: 'Lists', icon:
, module: 'list', submenu: [
- {name: 'Authority List', icon:
, module: '/list/authority-list', submenu: [
- {name: 'Corporations', icon:
, link: '/authority-list/corporations'},
- {name: 'Countries', icon:
, link: '/authority-list/countries'},
- {name: 'Genres', icon:
, link: '/authority-list/genres'},
- {name: 'Languages', icon:
, link: '/authority-list/languages'},
- {name: 'People', icon:
, link: '/authority-list/people'},
- {name: 'Places', icon:
, link: '/authority-list/places'},
- {name: 'Subjects', icon:
, link: '/authority-list/subjects'},
+ {name: 'Lists', icon:
, module: 'list', group: ['Authority Lists', 'Controlled Lists'], submenu: [
+ {name: 'Authority List', icon:
, module: '/list/authority-list', group: ['Authority Lists'], submenu: [
+ {name: 'Corporations', icon:
, group: ['Authority Lists'], link: '/authority-list/corporations'},
+ {name: 'Countries', icon:
, group: ['Authority Lists'], link: '/authority-list/countries'},
+ {name: 'Genres', icon:
, group: ['Authority Lists'], link: '/authority-list/genres'},
+ {name: 'Languages', icon:
, group: ['Authority Lists'], link: '/authority-list/languages'},
+ {name: 'People', icon:
, group: ['Authority Lists'], link: '/authority-list/people'},
+ {name: 'Places', icon:
, group: ['Authority Lists'], link: '/authority-list/places'},
+ {name: 'Subjects', icon:
, group: ['Authority Lists'], link: '/authority-list/subjects'},
]},
- {name: 'Controlled List', icon:
, module: '/list/controlled-list', submenu: [
- {name: 'Access Rights', icon:
, link: '/controlled-list/access-rights'},
- {name: 'Archival Unit Themes', icon:
, link: '/controlled-list/archival-unit-themes'},
- {name: 'Building', icon:
, link: '/controlled-list/buildings'},
- {name: 'Carrier Types', icon:
, link: '/controlled-list/carrier-types'},
- {name: 'Corporation Roles', icon:
, link: '/controlled-list/corporation-roles'},
- {name: 'Date Types', icon:
, link: '/controlled-list/date-types'},
- {name: 'Extent Units', icon:
, link: '/controlled-list/extent-units'},
- {name: 'Geo Roles', icon:
, link: '/controlled-list/geo-roles'},
- {name: 'Keyword', icon:
, link: '/controlled-list/keywords'},
- {name: 'Language Usages', icon:
, link: '/controlled-list/language-usages'},
- {name: 'Person Roles', icon:
, link: '/controlled-list/person-roles'},
- {name: 'Primary Types', icon:
, link: '/controlled-list/primary-types'},
- {name: 'Reproduction Rights', icon:
, link: '/controlled-list/reproduction-rights'},
- {name: 'Restriction Reasons', icon:
, link: '/controlled-list/restriction-reasons'},
+ {name: 'Controlled List', icon:
, module: '/list/controlled-list', group: ['Controlled Lists'], submenu: [
+ {name: 'Access Rights', icon:
, group: ['Controlled Lists'], link: '/controlled-list/access-rights'},
+ {name: 'Archival Unit Themes', icon:
, group: ['Controlled Lists'], link: '/controlled-list/archival-unit-themes'},
+ {name: 'Building', icon:
, group: ['Controlled Lists'], link: '/controlled-list/buildings'},
+ {name: 'Carrier Types', icon:
, group: ['Controlled Lists'], link: '/controlled-list/carrier-types'},
+ {name: 'Corporation Roles', icon:
, group: ['Controlled Lists'], link: '/controlled-list/corporation-roles'},
+ {name: 'Date Types', icon:
, group: ['Controlled Lists'], link: '/controlled-list/date-types'},
+ {name: 'Extent Units', icon:
, group: ['Controlled Lists'], link: '/controlled-list/extent-units'},
+ {name: 'Geo Roles', icon:
, group: ['Controlled Lists'], link: '/controlled-list/geo-roles'},
+ {name: 'Identifier Types', icon:
, group: ['Controlled Lists'], link: '/controlled-list/identifier-types'},
+ {name: 'Keyword', icon:
, group: ['Controlled Lists'], link: '/controlled-list/keywords'},
+ {name: 'Language Usages', icon:
, group: ['Controlled Lists'], link: '/controlled-list/language-usages'},
+ {name: 'Nationalities', icon:
, group: ['Controlled Lists'], link: '/controlled-list/nationalities'},
+ {name: 'Person Roles', icon:
, group: ['Controlled Lists'], link: '/controlled-list/person-roles'},
+ {name: 'Primary Types', icon:
, group: ['Controlled Lists'], link: '/controlled-list/primary-types'},
+ {name: 'Reproduction Rights', icon:
, group: ['Controlled Lists'], link: '/controlled-list/reproduction-rights'},
+ {name: 'Restriction Reasons', icon:
, group: ['Controlled Lists'], link: '/controlled-list/restriction-reasons'},
]},
]},
- {name: 'MLR', icon:
, module: 'mlr', link: '/mlr'},
- {name: 'Digitization Log', icon:
, module: 'digitization', link: '/digitization'},
- {name: 'Researchers Database', icon:
, module: 'researcher', submenu: [
- {name: 'Researchers', icon:
, link: '/researchers-db/researchers'},
- {name: 'Researcher Visits', icon:
, link: '/researchers-db/visits'},
- {name: 'Researcher Statistics', icon:
, link: '/researchers-db/stats'},
- {name: 'Requests', icon:
, link: '/researchers-db/requests'},
- ]}
+ {name: 'MLR', icon:
, module: 'mlr', group: ['MLR'], link: '/mlr'},
+ {name: 'Digitization Log', icon:
, module: 'digitization', group: ['__ALL__'], link: '/digitization'},
+ {name: 'Researchers Database', icon:
, module: 'researcher', group: ['Research'], submenu: [
+ {name: 'Researchers', icon:
, group: ['Research'], link: '/researchers-db/researchers'},
+ {name: 'Researcher Visits', icon:
, group: ['Research'], link: '/researchers-db/visits'},
+ {name: 'Researcher Statistics', icon:
, group: ['Research'], link: '/researchers-db/statistics'},
+ ]},
+ {name: 'Requests', icon:
, module: 'requests', group: ['Research', 'Restricted Decision Makers'], submenu: [
+ {name: 'Requests List', icon:
, group: ['Research'], link: '/requests/list'},
+ {name: 'Digital Requests', icon:
, group: ['Research'], link: '/requests/digital'},
+ {name: 'Restricted Access Man.', icon:
, group: ['Restricted Decision Makers'], link: '/requests/restricted-access'},
+ ]}
];
export default configMenu;
diff --git a/components/Login/Login.module.css b/components/Login/Login.module.css
index 0b59b492..56a1c3e6 100644
--- a/components/Login/Login.module.css
+++ b/components/Login/Login.module.css
@@ -28,10 +28,10 @@
.Logo {
text-align: center;
- margin-top: 10px;
- margin-bottom: 30px;
+ margin-top: 30px;
+ margin-bottom: 50px;
}
.Logo img {
- width: 150px;
+ width: 200px;
}
diff --git a/components/ResearchStatistics/ResearchStatisticsView.js b/components/ResearchStatistics/ResearchStatisticsView.js
new file mode 100644
index 00000000..abbb9f23
--- /dev/null
+++ b/components/ResearchStatistics/ResearchStatisticsView.js
@@ -0,0 +1,103 @@
+import {Card, Radio} from "antd";
+import React, {useState} from "react";
+import { DatePicker, Space } from 'antd';
+import style from "./ResearchStatisticsView.module.scss";
+import dynamic from "next/dynamic";
+
+const { RangePicker } = DatePicker;
+
+const ResearchersStatistics = dynamic(
+ () => import('./parts/ResearchersStatistics'),
+ { ssr: false }
+);
+
+const ResearchersVisits = dynamic(
+ () => import('./parts/ResearchersVisits'),
+ { ssr: false }
+);
+
+const ResearchersRequests = dynamic(
+ () => import('./parts/ResearchersRequests'),
+ { ssr: false }
+);
+
+const PopularCollections = dynamic(
+ () => import('./parts/PopularCollections'),
+ { ssr: false }
+);
+
+const ResearchStatisticsView = () => {
+ const [view, setView] = useState('researchers');
+ const [dateFilter, setDateFilter] = useState({start: null, end: null});
+
+ const handleDateFilterChange = (date, dateString) => {
+ setDateFilter({ start: dateString[0], end: dateString[1] });
+ }
+
+ const getTitle = () => {
+ const getMainTitle = () => {
+ switch (view) {
+ case 'researchers':
+ return 'Researchers'
+ case 'visits':
+ return 'Visits';
+ case 'requests':
+ return 'Requests';
+ case 'popularity':
+ return 'Popular collections';
+ default:
+ break;
+ }
+ }
+
+ return (
+
+ {getMainTitle()}
+
+
+ )
+ };
+
+ const getParams = () => {
+ return {
+ date_from: dateFilter.start,
+ date_to: dateFilter.end
+ }
+ }
+
+ const getView = () => {
+ switch (view) {
+ case 'researchers':
+ return
;
+ case 'visits':
+ return
;
+ case 'requests':
+ return
;
+ case 'popularity':
+ return
;
+ default:
+ break;
+ }
+ };
+
+ const onChange = (e) => {
+ setView(e.target.value);
+ };
+
+ const viewChange = () => (
+
+ Researchers
+ Visits
+ Requests
+ Popular collections
+
+ );
+
+ return (
+
+ {getView()}
+
+ )
+}
+
+export default ResearchStatisticsView;
\ No newline at end of file
diff --git a/components/ResearchStatistics/ResearchStatisticsView.module.scss b/components/ResearchStatistics/ResearchStatisticsView.module.scss
new file mode 100644
index 00000000..1cc6b4c6
--- /dev/null
+++ b/components/ResearchStatistics/ResearchStatisticsView.module.scss
@@ -0,0 +1,8 @@
+.TitleText {
+ display: flex;
+ align-items: center;
+
+ .MainTitleText {
+ width: 140px;
+ }
+}
\ No newline at end of file
diff --git a/components/ResearchStatistics/parts/PopularCollections.js b/components/ResearchStatistics/parts/PopularCollections.js
new file mode 100644
index 00000000..85e9c3ec
--- /dev/null
+++ b/components/ResearchStatistics/parts/PopularCollections.js
@@ -0,0 +1,42 @@
+import {useData} from "../../../utils/hooks/useData";
+import {Col, Row, Statistic, Table} from "antd";
+import {Bar, Line, Pie} from '@ant-design/plots';
+import React from "react";
+
+const PopularCollections = ({params}) => {
+ const { data, loading } = useData(`/v1/research/statistics/requested-materials/archival-units`, params);
+
+ const columns = [
+ {
+ title: 'Title',
+ dataIndex: 'title',
+ key: 'title',
+ },
+ {
+ title: 'No. of requests',
+ dataIndex: 'total',
+ key: 'total',
+ width: 130
+ },
+ ];
+
+ return (
+
+
+ Most popular collections by request
+ {data &&
+
+ }
+
+
+ )
+}
+
+export default PopularCollections;
\ No newline at end of file
diff --git a/components/ResearchStatistics/parts/ResearchersRequests.js b/components/ResearchStatistics/parts/ResearchersRequests.js
new file mode 100644
index 00000000..f9ec513e
--- /dev/null
+++ b/components/ResearchStatistics/parts/ResearchersRequests.js
@@ -0,0 +1,80 @@
+import {useData} from "../../../utils/hooks/useData";
+import {Col, Row, Statistic} from "antd";
+import {Bar, Line, Pie} from '@ant-design/plots';
+import React from "react";
+
+const RequestsOrigin = ({params}) => {
+ const { data, loading } = useData(`/v1/research/statistics/requested-materials/origin`, params);
+
+ const config = {
+ appendPadding: 10,
+ data: data ? data['by_item_origin'] : [],
+ angleField: 'total',
+ colorField: 'item_origin',
+ radius: 1,
+ innerRadius: 0.6,
+ label: {
+ type: 'inner',
+ offset: '-50%',
+ content: '{value}',
+ style: {
+ textAlign: 'center',
+ fontSize: 14,
+ },
+ },
+ interactions: [
+ {
+ type: 'element-selected',
+ },
+ {
+ type: 'element-active',
+ },
+ ],
+ statistic: {
+ title: false,
+ content: {
+ style: {
+ whiteSpace: 'pre-wrap',
+ overflow: 'hidden',
+ textOverflow: 'ellipsis',
+ },
+ content: data ? `${data['total']}` : '',
+ },
+ }
+ };
+
+ return
;
+}
+
+const RequestsCarrierType = ({params}) => {
+ const { data, loading } = useData(`/v1/research/statistics/requested-materials/carrier-type`, params);
+
+ const config = {
+ data: data ? data['by_carrier_type'] : [],
+ xField: 'total',
+ yField: 'carrier_type',
+ seriesField: 'carrier_type',
+ legend: false,
+ };
+ return
;
+}
+
+const ResearchersRequests = ({params}) => {
+ return (
+
+
+ Requests by item origin
+
+
+
+
+ Requests by carrier type
+
+
+
+
+
+ )
+}
+
+export default ResearchersRequests;
\ No newline at end of file
diff --git a/components/ResearchStatistics/parts/ResearchersStatistics.js b/components/ResearchStatistics/parts/ResearchersStatistics.js
new file mode 100644
index 00000000..87447ad3
--- /dev/null
+++ b/components/ResearchStatistics/parts/ResearchersStatistics.js
@@ -0,0 +1,102 @@
+import {useData} from "../../../utils/hooks/useData";
+import {Col, Row, Statistic} from "antd";
+import {Line, Pie} from '@ant-design/plots';
+import React from "react";
+
+const ResearchersStatistics = ({params}) => {
+ const { data, loading } = useData(`/v1/research/statistics/researcher-registration`, params);
+
+ const getOccupationChart = () => {
+ const getData = () => {
+ const getOccupationName = (name) => {
+ switch (name) {
+ case 'ceu':
+ return 'CEU (General)';
+ case 'ceu_faculty':
+ return 'CEU Faculty';
+ case 'ceu_student':
+ return 'CEU Student';
+ case 'other':
+ return 'Other';
+ default:
+ return name;
+ }
+ }
+
+ return data['by_occupation'].map(item => {
+ return {
+ type: getOccupationName(item['occupation']),
+ value: item['total']
+ }
+ })
+ }
+
+ const config = {
+ appendPadding: 10,
+ data: data ? getData() : [],
+ angleField: 'value',
+ colorField: 'type',
+ radius: 1,
+ innerRadius: 0.6,
+ label: {
+ type: 'inner',
+ offset: '-50%',
+ content: '{value}',
+ style: {
+ textAlign: 'center',
+ fontSize: 14,
+ },
+ },
+ interactions: [
+ {
+ type: 'element-selected',
+ },
+ {
+ type: 'element-active',
+ },
+ ],
+ statistic: {
+ title: false,
+ content: {
+ style: {
+ whiteSpace: 'pre-wrap',
+ overflow: 'hidden',
+ textOverflow: 'ellipsis',
+ },
+ content: data ? `${data['total']}` : '',
+ },
+ },
+ };
+ return
;
+ }
+
+ const getLineChart = () => {
+ const config = {
+ data: data['by_month'],
+ padding: 'auto',
+ xField: 'month',
+ yField: 'total',
+ color: '#44be24',
+ xAxis: { tickCount: 5 }
+ };
+
+ return
+ }
+
+ return (
+
+
+ Newly registered researchers by occupation
+
+ {data && getOccupationChart()}
+
+
+ Monthly newly registered researchers
+
+ {data && getLineChart()}
+
+
+ )
+}
+
+export default ResearchersStatistics;
\ No newline at end of file
diff --git a/components/ResearchStatistics/parts/ResearchersVisits.js b/components/ResearchStatistics/parts/ResearchersVisits.js
new file mode 100644
index 00000000..59ed2a55
--- /dev/null
+++ b/components/ResearchStatistics/parts/ResearchersVisits.js
@@ -0,0 +1,43 @@
+import {useData} from "../../../utils/hooks/useData";
+import {Col, Row, Statistic} from "antd";
+import {Line, Pie} from '@ant-design/plots';
+import React from "react";
+
+const ResearchersVisits = ({params}) => {
+ const { data, loading } = useData(`/v1/research/statistics/researcher-visits`, params);
+
+ const getLineChart = () => {
+ const config = {
+ data: data['by_month'],
+ padding: 'auto',
+ xField: 'month',
+ yField: 'total',
+ color: '#ed8251',
+ xAxis: { tickCount: 5 }
+ };
+
+ return
+ }
+
+ return (
+
+
+
+
+
+
+
+
+
+
+ Number of visits per month
+
+ {data && getLineChart()}
+
+
+
+ )
+}
+
+export default ResearchersVisits;
\ No newline at end of file
diff --git a/components/Tables/ArchivalUnitTable.js b/components/Tables/ArchivalUnitTable.js
index e1f4ab19..c89475de 100644
--- a/components/Tables/ArchivalUnitTable.js
+++ b/components/Tables/ArchivalUnitTable.js
@@ -23,9 +23,8 @@ const ArchivalUnitTable = ({columns}) => {
const [module, setModule] = useState('archival-units-fonds');
const [selectedRecord, setSelectedRecord] = useState(undefined);
- const { params, tableState, handleDataChange, handleTableChange, handleFilterChange, handleDelete } = useTable(module);
-
- const {data, loading, refresh} = useData(`/v1/archival_unit/`, params);
+ const { data, loading, refresh, tableState,
+ handleDataChange, handleTableChange, handleFilterChange, handleDelete } = useTable(module, '/v1/archival_unit/');
useEffect(() => {
if (data) {
@@ -137,7 +136,11 @@ const ArchivalUnitTable = ({columns}) => {
return (
-
+
{
- const { params, tableState, handleExpandedRowsChange, handleDataChange, handleTableChange, handleDelete } = useTable(`container-table-${seriesID ? seriesID : 0}`);
+ const api = seriesID ? `/v1/container/list/${seriesID}/` : undefined;
+ const { data, loading, refresh, tableState,
+ handleExpandedRowsChange, handleDataChange, handleTableChange, handleDelete } = useTable(
+ `container-table-${seriesID ? seriesID : 0}`, api);
const [drawerShown, setDrawerShown] = useState(false);
const [action, setAction] = useState('edit');
@@ -35,7 +38,8 @@ const ContainerTable = ({seriesID, seriesTitle}) => {
const [modalVisible, setModalVisible] = useState(false);
- const { data, loading, refresh } = useData(seriesID ? `/v1/container/list/${seriesID}/` : undefined, params);
+ const [deletedContainer, setDeletedContainer] = useState(undefined);
+
const templateData = useData(seriesID ? `/v1/finding_aids/templates/select/${seriesID}/` : undefined);
useEffect(() => {
@@ -114,23 +118,59 @@ const ContainerTable = ({seriesID, seriesTitle}) => {
}
};
- return (
-
- {renderContainerPublishButton()}
- {record.total_number !== 0 &&
-
- }
-
- )
+ if (record.total_number !== 0) {
+ return (
+
+ {renderContainerPublishButton()}
+
+
+ )
+ } else {
+ return ''
+ }
+
};
+ const renderDigitalVersions = (value, record) => {
+ const masters = record['digital_versions_masters']
+ const access_copies = record['digital_versions_access_copies']
+ const digital_versions_in_fa = record['digital_versions_in_finding_aids']
+
+ if (masters > 0 || access_copies > 0) {
+ return (
+ {
+ setSelectedRecord(record.id);
+ setAction('digital versions');
+ setFormType('digital-versions');
+ setDrawerShown(true);
+ }}>
+ { masters === 1 && `Master: 1`}
+ { masters > 1 && `Masters: ${masters}`}
+ { access_copies > 0 && masters > 0 && | }
+ { access_copies === 1 && `Access: 1`}
+ { access_copies > 1 && `Access: ${access_copies}`}
+
+ )
+ }
+
+ if (masters === 0 && access_copies === 0 && digital_versions_in_fa > 0) {
+ return (
+
+ On Folder / Item level
+
+ )
+ }
+
+ return ''
+ }
+
const columns = [
{
title: 'Container No.',
@@ -147,7 +187,13 @@ const ContainerTable = ({seriesID, seriesTitle}) => {
title: 'Carrier Type',
dataIndex: 'carrier_type',
key: 'carrier_type',
- width: 300
+ width: 200
+ }, {
+ title: 'Digital Copies',
+ dataIndex: 'container-digital-versions',
+ key: 'container-digital-versions',
+ render: renderDigitalVersions,
+ width: 140
}, {
key: 'actions',
title: 'Actions',
@@ -212,6 +258,7 @@ const ContainerTable = ({seriesID, seriesTitle}) => {
handleDelete(data.length);
deleteAlert();
refresh();
+ setDeletedContainer(id);
})
}
});
@@ -294,7 +341,7 @@ const ContainerTable = ({seriesID, seriesTitle}) => {
-
+
@@ -337,7 +384,6 @@ const ContainerTable = ({seriesID, seriesTitle}) => {
selectedRecord={selectedRecord}
module={formType}
type={action}
- label={formType === 'container' ? 'Container' : 'Barcode'}
onClose={onClose}
/>
diff --git a/components/Tables/FindingAidsMissingTable.js b/components/Tables/FindingAidsMissingTable.js
new file mode 100644
index 00000000..6873fbc7
--- /dev/null
+++ b/components/Tables/FindingAidsMissingTable.js
@@ -0,0 +1,104 @@
+import {Button, Modal, Table, Tooltip} from "antd";
+import React, {useEffect, useState} from "react";
+import {
+ LoadingOutlined,
+ CloseCircleOutlined
+} from "@ant-design/icons";
+import TableFilters from "./TableFilters";
+import style from './Table.module.scss';
+import {put, remove} from "../../utils/api";
+import {useTable} from "../../utils/hooks/useTable";
+import {renderArchivalUnitReferenceCode} from "../../utils/renders/renderArchivalUnitReferenceCode";
+
+const ISADTable = ({...props}) => {
+ const { data, loading, refresh, tableState,
+ handleDataChange, handleTableChange, handleFilterChange, handleDelete } = useTable(
+ 'finding_aids',
+ `/v1/finding_aids/missing/`);
+
+ const [missingLoading, setMissingLoading] = useState(false);
+
+ useEffect(() => {
+ if (data) {
+ handleDataChange(data.count)
+ }
+ }, [data]);
+
+ const onSetNotMissing = (id) => {
+ confirm({
+ title: `Are you sure you would like to set the missing status of the record?`,
+ okText: 'Yes',
+ okType: 'warning',
+ cancelText: 'No',
+ onOk() {
+ setMissingLoading(true);
+ put(`/v1/finding_aids/set_non_missing/${id}/`).then(() => {
+ refresh();
+ setMissingLoading(false);
+ })
+ }
+ });
+ }
+
+ const renderMissingButton = (record) => {
+ return (
+
+
+ );
+ };
+
+ const columns = [
+ {
+ title: 'Archival Reference Code',
+ dataIndex: 'archival_reference_code',
+ key: 'archival_reference_code',
+ sorter: false,
+ render: renderArchivalUnitReferenceCode,
+ width: 250
+ }, {
+ title: 'Title',
+ dataIndex: 'title',
+ key: 'title',
+ sorter: false,
+ }, {
+ key: 'actions',
+ title: 'Actions',
+ width: 150,
+ className: style.ActionColumn,
+ render: (record) => renderMissingButton(record)
+ },
+ ]
+
+ return (
+
+
+ record.id}
+ dataSource={data ? data.results : []}
+ columns={columns}
+ size={'small'}
+ loading={{
+ spinning: loading,
+ indicator: ,
+ }}
+ pagination={tableState['pagination']}
+ onChange={handleTableChange}
+ />
+
+ )
+};
+
+export default ISADTable;
diff --git a/components/Tables/FindingAidsTable.js b/components/Tables/FindingAidsTable.js
index 3b50b26c..00a7aed1 100644
--- a/components/Tables/FindingAidsTable.js
+++ b/components/Tables/FindingAidsTable.js
@@ -10,11 +10,11 @@ import {
ArrowDownOutlined,
ArrowUpOutlined,
WarningOutlined,
- DownOutlined
+ DownOutlined,
+ FileUnknownOutlined, CloseCircleOutlined
} from "@ant-design/icons";
import style from './Table.module.scss';
import {post, put, remove} from "../../utils/api";
-import {useData} from "../../utils/hooks/useData";
import {useTable} from "../../utils/hooks/useTable";
import {deleteAlert} from "./functions/deleteAlert";
import {renderArchivalUnitReferenceCode} from "../../utils/renders/renderArchivalUnitReferenceCode";
@@ -24,11 +24,13 @@ import {PopupForm} from "../Forms/PopupForm";
const FindingAidsTable = ({containerID, containerListRefresh, templateData, recordTotalPublished}) => {
- const { params, tableState, handleDataChange, handleTableChange, handleDelete } = useTable(`finding-aids-table-${containerID}`);
- const { data, loading, refresh } = useData(containerID ? `/v1/finding_aids/list/${containerID}/` : undefined, params);
+ const api = containerID ? `/v1/finding_aids/list/${containerID}/` : undefined;
+ const { data, loading, refresh, tableState, handleDataChange, handleTableChange, handleDelete } = useTable(`finding-aids-table-${containerID}`, api);
const [ publishing, setPublishing ] = useState({});
const [ confidentialSetting, setConfidentialSetting ] = useState({});
+ const [ missingSetting, setMissingSetting ] = useState({});
+ const [ formType, setFormType] = useState('finding-aids-quick-edit');
const [ selectedRecord, setSelectedRecord ] = useState(undefined);
const [ drawerShown, setDrawerShown ] = useState(false);
@@ -48,18 +50,10 @@ const FindingAidsTable = ({containerID, containerListRefresh, templateData, reco
return (
-
- }
- style={{marginRight: '5px'}}
- onClick={() => onClone(record.id)}
- />
-
-
+
@@ -82,6 +76,14 @@ const FindingAidsTable = ({containerID, containerListRefresh, templateData, reco
}
+
+ }
+ style={{marginLeft: '5px'}}
+ onClick={() => onClone(record.id)}
+ />
+
)
@@ -89,7 +91,7 @@ const FindingAidsTable = ({containerID, containerListRefresh, templateData, reco
const columns = [
{
- title: 'Archiaval Reference Code',
+ title: 'Archival Reference Code',
dataIndex: 'archival_reference_code',
key: 'archival_reference_code',
sorter: false,
@@ -106,6 +108,11 @@ const FindingAidsTable = ({containerID, containerListRefresh, templateData, reco
sorter: false,
render: (record) => renderDate(record),
width: 150
+ }, {
+ title: 'Digital Copies',
+ key: 'container-digital-versions',
+ render: (record) => renderDigitalVersions(record),
+ width: 140
}, {
key: 'actions',
title: 'Actions',
@@ -162,7 +169,8 @@ const FindingAidsTable = ({containerID, containerListRefresh, templateData, reco
return (