diff --git a/components/application/repository-select.jsx b/components/application/repository-select.jsx
index 156edece..b64a4dc9 100644
--- a/components/application/repository-select.jsx
+++ b/components/application/repository-select.jsx
@@ -1,19 +1,26 @@
-import React, { useCallback, useState, useEffect } from 'react'
+import React, { useCallback, useState, useEffect, useRef } from 'react'
import { AppBar, Select } from '@oacore/design'
import { useRouter } from 'next/router'
import styles from './repository-select.module.css'
+import { TextField } from '../../design'
+import close from 'components/upload/assets/closeLight.svg'
import { withGlobalStore } from 'store'
const RepositorySelect = ({ store }) => {
const router = useRouter()
const [suggestions, setSuggestions] = useState(store.user.dataProviders)
const [value, setValue] = useState(store.dataProvider.name)
+ const [showSecondDropdown, setShowSecondDropdown] = useState(false)
+ const [isOpen, setIsOpen] = useState(false)
+ const [selectedItem, setSelectedItem] = useState(null)
+ const [inputValue, setInputValue] = useState('')
+ const providerId = router.query['data-provider-id']
+ const setsRef = useRef(null)
const handleOnChange = useCallback(
(data) => {
- if (data.value === store.dataProvider.name) return
if (!data.id) {
setValue(store.dataProvider.name)
return
@@ -22,6 +29,8 @@ const RepositorySelect = ({ store }) => {
const actualPath = `/data-providers/${data.id}`
router.push(routePath, actualPath)
+ setShowSecondDropdown(true)
+ store.updateSelectedSetSpec(null)
},
[router, store.dataProvider.name]
)
@@ -36,19 +45,73 @@ const RepositorySelect = ({ store }) => {
setValue(data.value)
}, [])
+ const handleDropdownClick = async () => {
+ setIsOpen(!isOpen)
+ }
+
+ const handleSelect = (item) => {
+ setSelectedItem(item)
+ setIsOpen(false)
+ setInputValue(item.setName)
+ store.updateSelectedSetSpec(item)
+ store.dataProvider?.getDeduplicationData(providerId)
+ store.dataProvider?.getRrslistData(providerId)
+ store.dataProvider?.doi?.doiRecords.load()
+ store.dataProvider.works.resetWorks()
+ store.dataProvider.depositDates.resetCompliance()
+ store.dataProvider.doi.resetDoiRecords()
+ store.dataProvider?.depositDates?.publicReleaseDatesPages?.load()
+ store.dataProvider.retrieve()
+ }
+
+ useEffect(() => {
+ store.getSetsEnabledList()
+ }, [providerId])
+
useEffect(() => {
setValue(store.dataProvider.name)
}, [store.dataProvider.name])
+ useEffect(() => {
+ const handleClickOutside = (event) => {
+ if (setsRef.current && !setsRef.current.contains(event.target))
+ setIsOpen(false)
+ }
+
+ document.addEventListener('mousedown', handleClickOutside)
+
+ return () => {
+ document.removeEventListener('mousedown', handleClickOutside)
+ }
+ }, [setsRef])
+
+ const handleSelectClick = () => {
+ if (value === store.dataProvider.name) setShowSecondDropdown(true)
+ }
+
+ const handleClear = () => {
+ // eslint-disable-next-line no-console
+ console.log('reset')
+ }
+
+ const handleSetInputChange = (event) => {
+ setInputValue(event.target.value)
+ }
+
+ const filteredData = store.enabledList.filter((item) =>
+ item.setName.toLowerCase().includes(inputValue.toLowerCase())
+ )
+
return (
+ {store.enabledList.length > 0 && showSecondDropdown && (
+
+
+
+ {selectedItem ? (
+
+ {selectedItem?.setName.length > 25
+ ? `${selectedItem?.setName.substring(0, 25)}...`
+ : inputValue}
+ {/* eslint-disable-next-line max-len */}
+ {/* eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-noninteractive-element-interactions */}
+
+
+ ) : (
+
+ )}
+
+
+ {isOpen && (
+
+
+ {filteredData.map((item) => (
+ // eslint-disable-next-line max-len
+ // eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-noninteractive-element-interactions
+ - handleSelect(item)}
+ className={styles.selectItem}
+ >
+ {item.setName}
+
+ ))}
+
+
+ )}
+
+ )}
)
}
diff --git a/components/application/repository-select.module.css b/components/application/repository-select.module.css
index d4ccedda..5be8c260 100644
--- a/components/application/repository-select.module.css
+++ b/components/application/repository-select.module.css
@@ -8,6 +8,7 @@
display: flex;
flex: 2 2 60%;
align-items: center;
+ gap: 20px;
}
.repository-select {
@@ -40,3 +41,64 @@
.repository-select ul {
font-weight: initial;
}
+
+.select-form-wrapper {
+ display: flex;
+ width: 100%;
+ gap: 24px;
+}
+
+.select-wrapper {
+ width: 100%;
+}
+
+.select-input input {
+ background: #fff;
+ border: 1px solid #b75400;
+ border-radius: 2px;
+}
+
+/* stylelint-disable declaration-no-important */
+.select-input label {
+ color: #9e9e9e !important;
+}
+
+.dropdown-menu-wrapper {
+ position: relative;
+ flex: 1;
+}
+
+.dropdown-menu {
+ position: absolute;
+ padding: 10px;
+ background: #fff;
+ border-radius: 2px;
+ border-top-left-radius: 0;
+ border-top-right-radius: 0;
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05), 0 1px 2px rgba(0, 0, 0, 0.25);
+}
+
+.select-item {
+ padding: 10px;
+ margin: 4px 0;
+ color: #b75400;
+ cursor: pointer;
+}
+
+.selected-item {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ width: max-content;
+ max-width: 290px;
+ padding: 2px 10px;
+ font-size: 16px;
+ font-style: normal;
+ font-weight: 500;
+ line-height: 130%;
+ color: #fff;
+ letter-spacing: 0.01px;
+ background: #5a9216;
+ border-radius: 4px;
+ gap: 24px;
+}
diff --git a/components/textWithTooltip/styles.module.css b/components/textWithTooltip/styles.module.css
new file mode 100644
index 00000000..ad801793
--- /dev/null
+++ b/components/textWithTooltip/styles.module.css
@@ -0,0 +1,12 @@
+.container {
+ display: inline-flex;
+ cursor: pointer;
+}
+
+.pure {
+ color: var(--gray-600);
+}
+
+.popover {
+ max-width: 20rem;
+}
diff --git a/components/textWithTooltip/textWithtooltip.jsx b/components/textWithTooltip/textWithtooltip.jsx
new file mode 100644
index 00000000..08eea3f2
--- /dev/null
+++ b/components/textWithTooltip/textWithtooltip.jsx
@@ -0,0 +1,17 @@
+import React from 'react'
+import { Popover } from '@oacore/design'
+import classNames from '@oacore/design/lib/utils/class-names'
+
+import styles from './styles.module.css'
+
+const TextWithTooltip = ({ tag: Tag = 'div', className, text }) => (
+
+
+ 25 ? text : ''}>
+ {text.length > 25 ? `${text.substring(0, 25)}..` : text}
+
+
+
+)
+
+export default TextWithTooltip
diff --git a/components/upload/assets/checkGreen.svg b/components/upload/assets/checkGreen.svg
new file mode 100644
index 00000000..ac8ee0b5
--- /dev/null
+++ b/components/upload/assets/checkGreen.svg
@@ -0,0 +1,3 @@
+
diff --git a/components/upload/assets/close.svg b/components/upload/assets/close.svg
new file mode 100644
index 00000000..9f152db8
--- /dev/null
+++ b/components/upload/assets/close.svg
@@ -0,0 +1,3 @@
+
diff --git a/components/upload/assets/closeLight.svg b/components/upload/assets/closeLight.svg
new file mode 100644
index 00000000..7eaf3385
--- /dev/null
+++ b/components/upload/assets/closeLight.svg
@@ -0,0 +1,3 @@
+
diff --git a/components/upload/assets/dropdownArrow.svg b/components/upload/assets/dropdownArrow.svg
new file mode 100644
index 00000000..a7db9999
--- /dev/null
+++ b/components/upload/assets/dropdownArrow.svg
@@ -0,0 +1,5 @@
+
diff --git a/components/upload/assets/removeBin.svg b/components/upload/assets/removeBin.svg
new file mode 100644
index 00000000..a702f6fd
--- /dev/null
+++ b/components/upload/assets/removeBin.svg
@@ -0,0 +1,3 @@
+
diff --git a/pages/data-providers/[data-provider-id]/content.jsx b/pages/data-providers/[data-provider-id]/content.jsx
index dbe86141..1e40d8fe 100644
--- a/pages/data-providers/[data-provider-id]/content.jsx
+++ b/pages/data-providers/[data-provider-id]/content.jsx
@@ -6,7 +6,7 @@ import ContentTemplate from 'templates/content'
const Content = ({ store: { dataProvider }, ...props }) => (
diff --git a/pages/data-providers/[data-provider-id]/doi.jsx b/pages/data-providers/[data-provider-id]/doi.jsx
index 5a684914..bd161e58 100644
--- a/pages/data-providers/[data-provider-id]/doi.jsx
+++ b/pages/data-providers/[data-provider-id]/doi.jsx
@@ -9,8 +9,8 @@ const DoiPage = ({ store: { dataProvider, organisation }, ...props }) => (
doiUrl={dataProvider?.doi?.doiUrl}
isExportDisabled={
dataProvider?.doi?.enrichmentSize === 0 ||
- dataProvider?.doi?.doiRecords.error != null ||
- dataProvider?.doi?.doiRecords.data.length === 0
+ dataProvider?.doi?.doiRecords?.error != null ||
+ dataProvider?.doi?.doiRecords?.data.length === 0
}
doiCount={dataProvider?.doi?.originCount}
dataProviderName={dataProvider.name}
diff --git a/pages/data-providers/[data-provider-id]/repository.jsx b/pages/data-providers/[data-provider-id]/repository.jsx
index f1507aed..c0ffc93d 100644
--- a/pages/data-providers/[data-provider-id]/repository.jsx
+++ b/pages/data-providers/[data-provider-id]/repository.jsx
@@ -11,6 +11,20 @@ const RepositoryPage = ({ store, ...restProps }) => (
dataProviderLogo={store.dataProvider.logo}
updateDataProvider={store.updateDataProvider}
updateLogo={store.updateLogo}
+ setsList={store.setsList}
+ loadingSets={store.loadingSets}
+ enableSet={store.enableSet}
+ getSetsEnabledList={store.getSetsEnabledList}
+ enabledList={store.enabledList}
+ disabledList={store.disabledList}
+ deleteSet={store.deleteSet}
+ getSetsWholeList={store.getSetsWholeList}
+ wholeSetData={store.wholeSetData}
+ loadingWholeSets={store.loadingWholeSets}
+ loadingWholeSetsBtn={store.loadingWholeSetsBtn}
+ setLoadingWholeSetsBtn={store.setLoadingWholeSetsBtn}
+ loadingRemoveItem={store.loadingRemoveItem}
+ setLoadingRemoveAction={store.setLoadingRemoveAction}
oaiMapping={store.dataProvider.oaiMapping}
setGlobalRorName={store.dataProvider.setGlobalRorName}
setGlobalRorId={store.dataProvider.setGlobalRorId}
diff --git a/store/data-provider/deposit-dates.js b/store/data-provider/deposit-dates.js
index d820b266..8aec0220 100644
--- a/store/data-provider/deposit-dates.js
+++ b/store/data-provider/deposit-dates.js
@@ -1,4 +1,4 @@
-import { action, computed, observable } from 'mobx'
+import { action, computed, observable, reaction } from 'mobx'
import { Pages } from '../helpers/pages'
import Store from '../store'
@@ -7,6 +7,8 @@ import { PaymentRequiredError } from '../errors'
import { NotFoundError } from 'api/errors'
class DepositDates extends Store {
+ baseStore = null
+
@observable isRetrieveDepositDatesInProgress = false
@observable timeLagData = null
@@ -17,16 +19,54 @@ class DepositDates extends Store {
@observable publicationDatesValidate = null
- constructor(baseUrl, options) {
+ constructor(rootStore, baseUrl, options) {
super(baseUrl, options)
+ this.baseStore = rootStore
+ this.fetchOptions = {
+ cache: 'no-store',
+ }
+ this.updateOaiUrl(baseUrl)
+ reaction(
+ () => this.baseStore?.setSelectedItem,
+ () => {
+ this.updateOaiUrl(baseUrl)
+ }
+ )
+ }
- const datesUrl = `${baseUrl}/public-release-dates`
+ @action
+ resetCompliance() {
+ this.timeLagData = null
+ this.publicReleaseDates = null
+ this.crossDepositLag = null
+ this.publicationDatesValidate = null
+ }
+
+ @action
+ updateOaiUrl = (baseUrl) => {
+ const datesUrl = `${baseUrl}/public-release-dates${
+ this.baseStore.setSelectedItem
+ ? `?set=${this.baseStore.setSelectedItem.setSpec}`
+ : ''
+ }`
this.publicReleaseDates = new Pages(datesUrl, this.options)
this.datesUrl = `${process.env.API_URL}${datesUrl}?accept=text/csv`
- this.depositTimeLagUrl = `${baseUrl}/statistics/deposit-time-lag`
- this.crossDepositLagUrl = `${baseUrl}/cross-deposit-lag`
+ this.depositTimeLagUrl = `${baseUrl}/statistics/deposit-time-lag${
+ this.baseStore.setSelectedItem
+ ? `?set=${this.baseStore.setSelectedItem.setSpec}`
+ : ''
+ }`
+ this.crossDepositLagUrl = `${baseUrl}/cross-deposit-lag${
+ this.baseStore.setSelectedItem
+ ? `?set=${this.baseStore.setSelectedItem.setSpec}`
+ : ''
+ }`
this.crossDepositLagCsvUrl = `${process.env.API_URL}${this.crossDepositLagUrl}?accept=text/csv`
- this.publicationDatesValidateUrl = `${baseUrl}/publication-dates-validate`
+ this.publicationDatesValidateUrl = `${baseUrl}/publication-dates-validate${
+ this.baseStore.setSelectedItem
+ ? `?set=${this.baseStore.setSelectedItem.setSpec}`
+ : ''
+ }`
this.retrieve()
}
diff --git a/store/data-provider/doi.js b/store/data-provider/doi.js
index f1461906..5a05fe4f 100644
--- a/store/data-provider/doi.js
+++ b/store/data-provider/doi.js
@@ -1,13 +1,63 @@
-import { action, observable, computed } from 'mobx'
+import { action, computed, observable, reaction } from 'mobx'
import { Pages } from '../helpers/pages'
import Store from '../store'
class DOI extends Store {
+ baseStore = null
+
+ constructor(rootStore, baseUrl, options) {
+ super(baseUrl, options)
+ this.baseStore = rootStore
+ this.fetchOptions = {
+ cache: 'no-store',
+ }
+
+ this.updateStatisticsUrl(baseUrl)
+ this.updateDoiRecords(baseUrl)
+ this.retrieveStatistics()
+ reaction(
+ () => this.baseStore?.setSelectedItem,
+ () => {
+ this.updateDoiRecords(baseUrl)
+ this.updateStatisticsUrl(baseUrl)
+ }
+ )
+ }
+
@observable originCount = null
@observable totalCount = null
+ @observable doiRecords = null
+
+ @action
+ resetDoiRecords() {
+ this.originCount = null
+ this.totalCount = null
+ this.doiRecords = null
+ }
+
+ @action
+ updateStatisticsUrl = (baseUrl) => {
+ this.statisticsUrl = `${baseUrl}/statistics/doi${
+ this.baseStore?.setSelectedItem
+ ? `?set=${this.baseStore?.setSelectedItem.setSpec}`
+ : ''
+ }`
+ }
+
+ @action
+ updateDoiRecords = (baseUrl) => {
+ const DUrl = `${baseUrl}/doi${
+ this.baseStore?.setSelectedItem
+ ? `?set=${this.baseStore?.setSelectedItem.setSpec}`
+ : ''
+ }`
+ this.doiRecords = new Pages(DUrl, this.options)
+ this.doiUrl = `${process.env.API_URL}${DUrl}?accept=text/csv`
+ }
+
@computed
get enrichmentSize() {
const { totalCount, originCount } = this
@@ -25,21 +75,9 @@ class DOI extends Store {
return lag
}
- @observable doiRecords = null
-
- constructor(baseUrl, options) {
- super(baseUrl, options)
-
- const doiUrl = `${baseUrl}/doi`
- this.doiRecords = new Pages(doiUrl, this.options)
- this.doiUrl = `${process.env.API_URL}${doiUrl}?accept=text/csv`
- this.statisticsUrl = `${baseUrl}/statistics/doi`
- this.retrieveStatistics()
- }
-
@action
retrieveStatistics = async () => {
- const { data } = await this.request(this.statisticsUrl)
+ const { data } = await this.request(this.statisticsUrl, this.fetchOptions)
this.originCount = data.dataProviderDoiCount
this.totalCount = data.totalDoiCount
}
diff --git a/store/data-provider/index.js b/store/data-provider/index.js
index 56c44516..b80f48c0 100644
--- a/store/data-provider/index.js
+++ b/store/data-provider/index.js
@@ -11,6 +11,13 @@ import { NotFoundError as NetworkNotFoundError } from '../../api/errors'
import { NotFoundError } from '../errors'
class DataProvider extends Resource {
+ rootStore = null
+
+ constructor(rootStore, init, options) {
+ super(init, options)
+ this.rootStore = rootStore
+ }
+
@observable id = ''
@observable name = ''
@@ -154,7 +161,10 @@ class DataProvider extends Resource {
getDeduplicationData = async (id, refresh = false) => {
this.duplicateDataLoading = true
try {
- let url = `${process.env.API_URL}/data-providers/${id}/duplicates`
+ const specData = this.rootStore.setSelectedItem.setSpec
+ let url = `${process.env.API_URL}/data-providers/${id}/duplicates${
+ specData ? `?set=${specData}` : ''
+ }`
if (refresh) url += '?refresh=true'
const options = refresh ? { cache: 'reload' } : {}
@@ -177,9 +187,14 @@ class DataProvider extends Resource {
getRrslistData = async (id) => {
this.rrsDataLoading = true
try {
- const response = await fetch(
- `${process.env.API_URL}/data-providers/${id}/rights-retention`
- )
+ const specData = this.rootStore.setSelectedItem.setSpec
+ const url = `${
+ process.env.API_URL
+ }/data-providers/${id}/rights-retention${
+ specData ? `?set=${specData}` : ''
+ }`
+
+ const response = await fetch(url)
if (response.ok && response.status === 200) {
const data = await response.json()
@@ -351,9 +366,9 @@ class DataProvider extends Resource {
this.retrieveLogo()
const url = `/data-providers/${this.id}`
- this.works = new Works(url, this.options)
- this.depositDates = new DepositDates(url, this.options)
- this.doi = new DOI(url, this.options)
+ this.works = new Works(this.rootStore, url, this.options)
+ this.depositDates = new DepositDates(this.rootStore, url, this.options)
+ this.doi = new DOI(this.rootStore, url, this.options)
this.issues = new Issues(url, this.options)
this.allMembers = new Membership(url, this.options)
this.duplicatesUrl = `${process.env.API_URL}${url}/duplicates?accept=text/csv`
diff --git a/store/data-provider/works.js b/store/data-provider/works.js
index 4985115a..3d584fe8 100644
--- a/store/data-provider/works.js
+++ b/store/data-provider/works.js
@@ -1,11 +1,32 @@
-import { action } from 'mobx'
+import { action, observable } from 'mobx'
import { Pages } from '../helpers/pages'
+import Store from '../store'
-class Works extends Pages {
- constructor(baseUrl, options) {
- const url = `${baseUrl}/works`
- super(url, options)
+class Works extends Store {
+ baseStore = null
+
+ @observable workRecords = null
+
+ @action
+ resetWorks() {
+ this.workRecords = null
+ }
+
+ constructor(rootStore, baseUrl, options) {
+ super(baseUrl, options)
+ this.baseStore = rootStore
+ this.updateWorks(baseUrl)
+ }
+
+ @action
+ updateWorks = (baseUrl) => {
+ const url = `${baseUrl}/works${
+ this.baseStore?.setSelectedItem
+ ? `?set=${this.baseStore?.setSelectedItem.setSpec}`
+ : ''
+ }`
+ this.workRecords = new Pages(url, this.options)
this.contentExportUrl = `${process.env.API_URL}${url}?accept=text/csv`
}
diff --git a/store/helpers/pages/pages.js b/store/helpers/pages/pages.js
index ae7bf639..05c96229 100644
--- a/store/helpers/pages/pages.js
+++ b/store/helpers/pages/pages.js
@@ -1,7 +1,6 @@
import { observable } from 'mobx'
import getOrder from '../order'
-import invalidatePreviousRequests from '../invalidatePreviousRequests'
import Store from '../../store'
import { PaymentRequiredError } from '../../errors'
@@ -48,7 +47,6 @@ class Pages extends Store {
this.type = type
}
- @invalidatePreviousRequests
load(signal) {
const order = getOrder(this.columnOrder)
@@ -63,7 +61,6 @@ class Pages extends Store {
if (this.type) params.type = this.type
if (order) params.orderBy = order
if (this.searchTerm) params.q = this.searchTerm
-
const request = this.request(this.url, { searchParams: params, signal })
return new Promise((resolve, reject) =>
request
diff --git a/store/root.js b/store/root.js
index 14dcd8b6..0ce049e5 100644
--- a/store/root.js
+++ b/store/root.js
@@ -91,6 +91,22 @@ class Root extends Store {
@observable deduplicationNotifications = null
+ @observable loadingSets = false
+
+ @observable loadingWholeSets = false
+
+ @observable loadingWholeSetsBtn = false
+
+ @observable loadingRemoveItem = false
+
+ @observable setsList = []
+
+ @observable enabledList = []
+
+ @observable disabledList = []
+
+ @observable wholeSetData = []
+
@observable tutorial = {
currentStep: 1,
isModalOpen: false,
@@ -127,6 +143,13 @@ class Root extends Store {
@observable responseData = null
+ @observable setSelectedItem = ''
+
+ @action
+ updateSelectedSetSpec = (value) => {
+ this.setSelectedItem = value
+ }
+
@action
setHarvestNotifications = (data) => {
this.harvestNotifications = data
@@ -152,6 +175,36 @@ class Root extends Store {
return this.organisation ? this.organisation.id : ''
}
+ @action
+ setSetsList(data) {
+ this.setsList = data
+ }
+
+ @action
+ setEnabledList(data) {
+ this.enabledList = data
+ }
+
+ @action
+ setDisabledList(data) {
+ this.disabledList = data
+ }
+
+ @action
+ setWholeSetData(data) {
+ this.wholeSetData = data
+ }
+
+ @action
+ setLoadingWholeSetsBtn = (value) => {
+ this.loadingWholeSetsBtn = value
+ }
+
+ @action
+ setLoadingRemoveAction = (value, id) => {
+ this.loadingRemoveItem = { value, id }
+ }
+
@computed
get dataProviders() {
// The current data provider can be loaded asynchronously to the user's
@@ -203,7 +256,7 @@ class Root extends Store {
const dataProviderInit = this.findDataProvider(id)
- this.dataProvider = new DataProvider(dataProviderInit, {
+ this.dataProvider = new DataProvider(this, dataProviderInit, {
...this.options,
prefetch: true,
})
@@ -357,6 +410,87 @@ class Root extends Store {
}
}
+ @action
+ getSetsWholeList = async () => {
+ this.loadingWholeSets = true
+ try {
+ const response = await fetch(
+ `https://api-dev.core.ac.uk/internal/data-providers/${this.dataProvider.id}/set/available`
+ )
+ if (response.ok) {
+ const data = await response.json()
+ this.setWholeSetData(data)
+ } else throw new Error('Failed to fetch rrs data')
+ } catch (error) {
+ console.error('Error fetching rrs data:', error)
+ this.setWholeSetData([])
+ } finally {
+ this.loadingWholeSets = false
+ }
+ }
+
+ @action
+ getSetsEnabledList = async () => {
+ this.loadingSets = true
+ try {
+ const response = await fetch(
+ `https://api-dev.core.ac.uk/internal/data-providers/${this.dataProvider.id}/set`
+ )
+ if (response.ok) {
+ const data = await response.json()
+ this.setEnabledList(data)
+ } else throw new Error('Failed to fetch rrs data')
+ } catch (error) {
+ console.error('Error fetching rrs data:', error)
+ this.setEnabledList([])
+ } finally {
+ this.loadingSets = false
+ }
+ }
+
+ @action
+ enableSet = async (body) => {
+ try {
+ const response = await fetch(
+ `https://api-dev.core.ac.uk/internal/data-providers/${this.dataProvider.id}/set/settings`,
+ {
+ method: 'PATCH',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify(body),
+ }
+ )
+
+ if (!response.ok) throw new Error('Failed to patch settings')
+ } catch (error) {
+ console.error('Error patching settings:', error)
+ throw error
+ }
+ }
+
+ @action
+ deleteSet = async (idSet) => {
+ this.loadingSets = true
+ try {
+ const response = await fetch(
+ `https://api-dev.core.ac.uk/internal/data-providers/${this.dataProvider.id}/set/settings/${idSet}`,
+ {
+ method: 'DELETE',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ }
+ )
+ if (!response.ok) throw new Error('Failed to patch settings')
+ } catch (error) {
+ console.error('Error patching settings:', error)
+ throw error
+ } finally {
+ this.loadingSets = false
+ }
+ }
+
@action
getNotifications = async (userId, organisationId, type) => {
try {
diff --git a/templates/content/cards/table-card.jsx b/templates/content/cards/table-card.jsx
index f1d0df07..69ff92ed 100644
--- a/templates/content/cards/table-card.jsx
+++ b/templates/content/cards/table-card.jsx
@@ -1,8 +1,11 @@
-import React from 'react'
+import React, { useContext } from 'react'
import { observer } from 'mobx-react-lite'
import { classNames } from '@oacore/design/lib/utils'
import styles from '../styles.module.css'
+import checked from '../../../components/upload/assets/checkGreen.svg'
+import { GlobalContext } from '../../../store'
+import TextWithTooltip from '../../../components/textWithTooltip/textWithtooltip'
import { formatDate } from 'utils/helpers'
import { Card, DetailList, Icon } from 'design'
@@ -80,57 +83,73 @@ const SidebarContent = observer(
}
)
-const TableCard = ({ works, changeVisibility, exportUrl, ...props }) => {
- const [tableProps, fetchData] = useDynamicTableData({ pages: works })
- return (
-
-
- {
- const { oai } = v.identifiers
- if (oai) return oai.split(':').pop()
- return '-'
- }}
- className={styles.oaiColumn}
- />
-
- v.authors.map((a) => a.name).join(' ')}
- />
- formatDate(v.lastUpdate)}
- />
-
-
-
-
-
- {texts.exporting.download}
-
-
-
-
- )
-}
+const TableCard = observer(
+ ({ works, changeVisibility, exportUrl, ...props }) => {
+ const { ...globalStore } = useContext(GlobalContext)
+ const [tableProps, fetchData] = useDynamicTableData({ pages: works })
+ return (
+
+
+ {globalStore?.setSelectedItem && (
+
+
+
+
+
+
+ )}
+
+
+ {
+ const { oai } = v.identifiers
+ if (oai) return oai.split(':').pop()
+ return '-'
+ }}
+ className={styles.oaiColumn}
+ />
+
+ v.authors.map((a) => a.name).join(' ')}
+ />
+ formatDate(v.lastUpdate)}
+ />
+
+
+
+
+
+ {texts.exporting.download}
+
+
+
+
+ )
+ }
+)
export default TableCard
diff --git a/templates/content/index.jsx b/templates/content/index.jsx
index 4046bf1d..18e143e9 100644
--- a/templates/content/index.jsx
+++ b/templates/content/index.jsx
@@ -1,20 +1,23 @@
import React from 'react'
+import { observer } from 'mobx-react-lite'
import TableCard from './cards/table-card'
import Title from '../../components/title'
-const ContentTemplate = ({ works, changeVisibility, exportUrl, ...props }) => (
- <>
-
Content
- {works && (
-
- )}
- >
+const ContentTemplate = observer(
+ ({ works, changeVisibility, exportUrl, ...props }) => (
+ <>
+ Content
+ {works && (
+
+ )}
+ >
+ )
)
export default ContentTemplate
diff --git a/templates/content/styles.module.css b/templates/content/styles.module.css
index f6a89a20..01dd13fb 100644
--- a/templates/content/styles.module.css
+++ b/templates/content/styles.module.css
@@ -60,3 +60,20 @@
fill: var(--danger);
}
}
+
+.set-end-wrapper {
+ display: flex;
+ justify-content: flex-end;
+ width: 100%;
+ margin-bottom: 12px;
+}
+
+.set-name {
+ margin-right: 8px;
+ font-size: 12px;
+ font-style: normal;
+ font-weight: 400;
+ line-height: 130%;
+ color: var(--success-dark);
+ letter-spacing: 0.048px;
+}
diff --git a/templates/deduplication/cards/deduplicationInfo.jsx b/templates/deduplication/cards/deduplicationInfo.jsx
index 7f5b1ac1..05905d14 100644
--- a/templates/deduplication/cards/deduplicationInfo.jsx
+++ b/templates/deduplication/cards/deduplicationInfo.jsx
@@ -1,34 +1,58 @@
-import React from 'react'
+import React, { useContext } from 'react'
+import { classNames } from '@oacore/design/lib/utils'
import styles from '../styles.module.css'
import texts from '../../../texts/deduplication/deduplication.yml'
import { formatDate, valueOrDefault } from '../../../utils/helpers'
+import checked from '../../../components/upload/assets/checkGreen.svg'
+import { GlobalContext } from '../../../store'
+import TextWithTooltip from '../../../components/textWithTooltip/textWithtooltip'
import { Card } from 'design'
-const DeduplicationInfoCard = ({ harvestingStatus }) => (
-
-
-
- {texts.info.title}
-
-
-
-
- {valueOrDefault(
- formatDate(harvestingStatus?.lastHarvestingDate),
- 'Loading...'
- )}
-
-
-
- {texts.info.description}
-
-
-)
+const DeduplicationInfoCard = ({ harvestingStatus }) => {
+ const { ...globalStore } = useContext(GlobalContext)
+ return (
+
+
+
+ {texts.info.title}
+
+
+ {globalStore?.setSelectedItem && (
+
+
+
+
+
+
+ )}
+
+
+
+
+ {valueOrDefault(
+ formatDate(harvestingStatus?.lastHarvestingDate),
+ 'Loading...'
+ )}
+
+
+
+ {texts.info.description}
+
+
+ )
+}
export default DeduplicationInfoCard
diff --git a/templates/deduplication/cards/deduplicationStatistics.jsx b/templates/deduplication/cards/deduplicationStatistics.jsx
index 254661ea..e0c6df56 100644
--- a/templates/deduplication/cards/deduplicationStatistics.jsx
+++ b/templates/deduplication/cards/deduplicationStatistics.jsx
@@ -1,4 +1,4 @@
-import React from 'react'
+import React, { useContext } from 'react'
import { Icon } from '@oacore/design'
import styles from '../styles.module.css'
@@ -6,6 +6,9 @@ import texts from '../../../texts/deduplication/deduplication.yml'
import Actions from '../../../components/actions'
import ExportButton from '../../../components/export-button'
import { formatNumber } from '../../../utils/helpers'
+import { GlobalContext } from '../../../store'
+import checked from '../../../components/upload/assets/checkGreen.svg'
+import TextWithTooltip from '../../../components/textWithTooltip/textWithtooltip'
import { ProgressSpinner, Card } from 'design'
@@ -13,47 +16,65 @@ const DeduplicationStatistics = ({
duplicateList,
duplicatesUrl,
checkBillingType,
-}) => (
-
-
-
- {texts.info.countTitle}
-
-
- }
- />
-
-
-
{texts.info.subTitle}
- {duplicateList.count ? (
-
{formatNumber(duplicateList.count)}
- ) : (
-
-
-
- This may take a while, longer for larger repositories ...
-
+}) => {
+ const { ...globalStore } = useContext(GlobalContext)
+ return (
+
+
+
+
+ {texts.info.countTitle}
+
+ {globalStore?.setSelectedItem && (
+
+
+
+
+
+
+ )}
- )}
- {!checkBillingType && (
-
- {texts.info.action}
-
- )}
-
-
-)
+
+ }
+ />
+
+
+
{texts.info.subTitle}
+ {duplicateList.count !== undefined && duplicateList.count !== null ? (
+
+ {formatNumber(duplicateList.count)}
+
+ ) : (
+
+
+
+ This may take a while, longer for larger repositories ...
+
+
+ )}
+ {!checkBillingType && (
+
+ {texts.info.action}
+
+ )}
+
+
+ )
+}
export default DeduplicationStatistics
diff --git a/templates/deduplication/index.jsx b/templates/deduplication/index.jsx
index edaa1756..f3ec6759 100644
--- a/templates/deduplication/index.jsx
+++ b/templates/deduplication/index.jsx
@@ -85,10 +85,7 @@ const DeduplicationPageTemplate = observer(
}
/>
-
+
{
+ const { ...globalStore } = useContext(GlobalContext)
const [page, setPage] = useState(0)
const [records, setRecords] = useState([])
const [localSearchTerm, setLocalSearchTerm] = useState('')
@@ -39,10 +43,13 @@ const DeduplicationListTable = observer(
else {
const startIndex = page * 10
const endIndex = Math.min(startIndex + 10, list.length)
- const newRecords = [...records, ...list.slice(startIndex, endIndex)]
+ let newRecords
+ if (globalStore.setSelectedItem) newRecords = list
+ else newRecords = [...records, ...list.slice(startIndex, endIndex)]
+
setRecords(newRecords)
}
- }, [page, list, checkBillingType])
+ }, [page, list, checkBillingType, globalStore.setSelectedItem])
const searchChange = (event) => {
setLocalSearchTerm(event.target.value)
@@ -93,9 +100,22 @@ const DeduplicationListTable = observer(
return (
<>
-
- List of potential duplicates and alternative versions
-
+
+
+ List of potential duplicates and alternative versions
+
+ {globalStore?.setSelectedItem && (
+
+
+
+
+
+
+ )}
+
{checkBillingType ? (
(
-
- {texts.dataOverview.title}
-
-
- {totalCount > 0 && (
+const DataOverviewCard = ({ totalCount, complianceLevel }) => {
+ const { ...globalStore } = useContext(GlobalContext)
+ return (
+
+
+
{texts.dataOverview.title}
+ {globalStore?.setSelectedItem && (
+
+
+
+
+
+
+ )}
+
+
- )}
-
-
-
-)
+ {totalCount > 0 && (
+
+ )}
+
+
+
+ )
+}
export default DataOverviewCard
diff --git a/templates/deposit-compliance/cards/deposit-time-lag-card.jsx b/templates/deposit-compliance/cards/deposit-time-lag-card.jsx
index 23117575..6e1f6dc9 100644
--- a/templates/deposit-compliance/cards/deposit-time-lag-card.jsx
+++ b/templates/deposit-compliance/cards/deposit-time-lag-card.jsx
@@ -1,4 +1,9 @@
-import React from 'react'
+import React, { useContext } from 'react'
+
+import checked from '../../../components/upload/assets/checkGreen.svg'
+import styles from '../styles.module.css'
+import { GlobalContext } from '../../../store'
+import TextWithTooltip from '../../../components/textWithTooltip/textWithtooltip'
import { Card } from 'design'
import * as texts from 'texts/depositing'
@@ -8,19 +13,35 @@ import Markdown from 'components/markdown'
const DepositTimeLagCard = ({
timeLagData,
isRetrieveDepositDatesInProgress,
-}) => (
-
- {texts.chart.title}
- {timeLagData?.length > 0 && (
- <>
-
- {texts.chart.body}
- >
- )}
- {!timeLagData?.length && !isRetrieveDepositDatesInProgress && (
- {texts.noData.body}
- )}
-
-)
+}) => {
+ const { ...globalStore } = useContext(GlobalContext)
+ return (
+
+
+
{texts.chart.title}
+ {globalStore?.setSelectedItem && (
+
+
+
+
+
+
+ )}
+
+ {timeLagData?.length > 0 && (
+ <>
+
+ {texts.chart.body}
+ >
+ )}
+ {!timeLagData?.length && !isRetrieveDepositDatesInProgress && (
+ {texts.noData.body}
+ )}
+
+ )
+}
export default DepositTimeLagCard
diff --git a/templates/deposit-compliance/styles.module.css b/templates/deposit-compliance/styles.module.css
index 57288a98..630d83ae 100644
--- a/templates/deposit-compliance/styles.module.css
+++ b/templates/deposit-compliance/styles.module.css
@@ -22,6 +22,21 @@
width: 100%;
}
+.set-header-wrapper {
+ display: flex;
+ justify-content: space-between;
+ width: 100%;
+}
+
+.set-name {
+ font-size: 12px;
+ font-style: normal;
+ font-weight: 400;
+ line-height: 130%;
+ color: var(--success-dark);
+ letter-spacing: 0.048px;
+}
+
.numbers {
display: flex;
flex-wrap: wrap;
diff --git a/templates/doi/cards/coverage-card.jsx b/templates/doi/cards/coverage-card.jsx
index fc8532f2..e227fcdb 100644
--- a/templates/doi/cards/coverage-card.jsx
+++ b/templates/doi/cards/coverage-card.jsx
@@ -1,8 +1,11 @@
-import React from 'react'
+import React, { useContext } from 'react'
import { classNames } from '@oacore/design/lib/utils'
import Parser from 'html-react-parser'
import styles from '../styles.module.css'
+import { GlobalContext } from '../../../store'
+import checked from '../../../components/upload/assets/checkGreen.svg'
+import TextWithTooltip from '../../../components/textWithTooltip/textWithtooltip'
import { Card } from 'design'
import Markdown from 'components/markdown'
@@ -54,49 +57,65 @@ const CoverageEnrichmentChart = ({
)
}
-const CoverageCard = ({ doiCount, totalCount, enrichmentSize }) => (
-
- {texts.coverage.title}
-
-
-
-
-
-
+const CoverageCard = ({ doiCount, totalCount, enrichmentSize }) => {
+ const { ...globalStore } = useContext(GlobalContext)
+ return (
+
+
+
{texts.coverage.title}
+ {globalStore?.setSelectedItem && (
+
+
+
+
+
+
+ )}
-
-
0 && styles.enrichment)}
- tag="p"
- title={Parser(texts.coverage.enrichmentLabelTooltip)}
- />
+
+
+
+
+
+
+
+
+ 0 && styles.enrichment)}
+ tag="p"
+ title={Parser(texts.coverage.enrichmentLabelTooltip)}
+ />
+
-
-
- {enrichmentSize > 0 && (
-
- {texts.coverage.body.render({ count: enrichmentSize })}
-
- )}
-
-)
+
+ {enrichmentSize > 0 && (
+
+ {texts.coverage.body.render({ count: enrichmentSize })}
+
+ )}
+
+ )
+}
export default CoverageCard
diff --git a/templates/doi/cards/table-card.jsx b/templates/doi/cards/table-card.jsx
index 89c63c27..70a20aff 100644
--- a/templates/doi/cards/table-card.jsx
+++ b/templates/doi/cards/table-card.jsx
@@ -1,8 +1,11 @@
-import React from 'react'
+import React, { useContext } from 'react'
import { useObserver } from 'mobx-react-lite'
import { classNames } from '@oacore/design/lib/utils'
import styles from '../styles.module.css'
+import checked from '../../../components/upload/assets/checkGreen.svg'
+import { GlobalContext } from '../../../store'
+import TextWithTooltip from '../../../components/textWithTooltip/textWithtooltip'
import { PaymentRequiredError } from 'store/errors'
import { Card, Icon } from 'design'
@@ -28,6 +31,7 @@ const formatDOI = (entity) => {
}
const TableCard = ({ pages, exportUrl }) => {
+ const { ...globalStore } = useContext(GlobalContext)
const [tableProps, fetchData] = useDynamicTableData({
pages,
defaultSize: 5,
@@ -38,7 +42,20 @@ const TableCard = ({ pages, exportUrl }) => {
return (
- Browse DOI records
+
+
Browse DOI records
+ {globalStore?.setSelectedItem && (
+
+
+
+
+
+
+ )}
+
{
+ const { ...globalStore } = useContext(GlobalContext)
const rrsToReviewList = rrsList.filter(
(item) => item.validationStatusRRS !== 1 && item.validationStatusRRS !== 2
)
@@ -52,6 +56,17 @@ const RrsReviewCard = ({ rrsList, rrsDataLoading }) => {
+ {globalStore?.setSelectedItem && (
+
+
+
+
+
+
+ )}
)
diff --git a/templates/rrs-policy/cards/rrsStatsCard.jsx b/templates/rrs-policy/cards/rrsStatsCard.jsx
index dc249d93..fdc61a5d 100644
--- a/templates/rrs-policy/cards/rrsStatsCard.jsx
+++ b/templates/rrs-policy/cards/rrsStatsCard.jsx
@@ -1,8 +1,11 @@
-import React from 'react'
+import React, { useContext } from 'react'
import styles from '../styles.module.css'
import { formatNumber } from '../../../utils/helpers'
import { Button } from '../../../design'
+import { GlobalContext } from '../../../store'
+import checked from '../../../components/upload/assets/checkGreen.svg'
+import TextWithTooltip from '../../../components/textWithTooltip/textWithtooltip'
import rrs from 'texts/rrs-retention'
import { Card } from 'design'
@@ -12,40 +15,56 @@ const RrsStatsCard = ({
rrsList,
rrsDataLoading,
checkBillingType,
-}) => (
-
-
-
-
- {rrs.statsCard.title}
-
-
-
-
- {rrs.statsCard.description}
-
-
-
- {rrsDataLoading ? (
-
-
+}) => {
+ const { ...globalStore } = useContext(GlobalContext)
+ return (
+
+
+
+
+ {rrs.statsCard.title}
+
- ) : (
-
{formatNumber(rrsList.length)}
- )}
-
-
- {!checkBillingType && (
-
- )}
-
-
-)
+
+
+ {rrs.statsCard.description}
+
+
+
+ {rrsDataLoading ? (
+
+ ) : (
+
{formatNumber(rrsList.length)}
+ )}
+
+
+ {!checkBillingType && (
+
+
+ {globalStore?.setSelectedItem && (
+
+
+
+
+
+
+ )}
+
+ )}
+
+
+ )
+}
export default RrsStatsCard
diff --git a/templates/rrs-policy/styles.module.css b/templates/rrs-policy/styles.module.css
index 26d2c077..f1079011 100644
--- a/templates/rrs-policy/styles.module.css
+++ b/templates/rrs-policy/styles.module.css
@@ -83,6 +83,21 @@
justify-content: space-between;
}
+.set-header-wrapper {
+ display: flex;
+ justify-content: space-between;
+ width: 100%;
+}
+
+.set-name {
+ font-size: 12px;
+ font-style: normal;
+ font-weight: 400;
+ line-height: 130%;
+ color: var(--success-dark);
+ letter-spacing: 0.048px;
+}
+
.sub-footer {
margin: 28px 0;
font-size: 48px;
diff --git a/templates/rrs-policy/tables/rrsTable.jsx b/templates/rrs-policy/tables/rrsTable.jsx
index 714fbd40..198097a9 100644
--- a/templates/rrs-policy/tables/rrsTable.jsx
+++ b/templates/rrs-policy/tables/rrsTable.jsx
@@ -1,5 +1,5 @@
import { observer } from 'mobx-react-lite'
-import React, { useEffect, useRef, useState } from 'react'
+import React, { useContext, useEffect, useRef, useState } from 'react'
import { useRouter } from 'next/router'
import { Button } from '@oacore/design/lib/elements'
import { Popover } from '@oacore/design'
@@ -20,6 +20,9 @@ import request from '../../../api'
import StatusCard from '../cards/statusCard'
import AccessPlaceholder from '../../../components/access-placeholder/AccessPlaceholder'
import Tablev2 from '../../../components/tablev2/tablev2'
+import { GlobalContext } from '../../../store'
+import checked from '../../../components/upload/assets/checkGreen.svg'
+import TextWithTooltip from '../../../components/textWithTooltip/textWithtooltip'
import Table from 'components/table'
@@ -36,6 +39,7 @@ const RrsTable = observer(
dataProviderData,
rrsUrl,
}) => {
+ const { ...globalStore } = useContext(GlobalContext)
const [visibleHelp, setVisibleHelp] = useState(
localStorage.getItem('rrsHelp') === 'true'
)
@@ -191,7 +195,20 @@ const RrsTable = observer(
return (
- {texts.table.title}
+
+
{texts.table.title}
+ {globalStore?.setSelectedItem && (
+
+
+
+
+
+
+ )}
+
{texts.table.subTitle}
{rrsDataLoading ? (
diff --git a/templates/settings/repository.jsx b/templates/settings/repository.jsx
index d6ddb665..c435501a 100644
--- a/templates/settings/repository.jsx
+++ b/templates/settings/repository.jsx
@@ -5,7 +5,7 @@ import { Button } from '@oacore/design/lib/elements'
import { useRouter } from 'next/router'
import styles from './styles.module.css'
-import { Card, TextField } from '../../design'
+import { Card, ProgressSpinner, TextField } from '../../design'
import content from '../../texts/settings'
import Markdown from '../../components/markdown'
import Upload from '../../components/upload'
@@ -16,6 +16,8 @@ import DropdownInput from '../../components/input-select/input-select'
import warning from './assets/warning.svg'
import { GlobalContext } from '../../store'
import infoGreen from '../../components/upload/assets/infoGreen.svg'
+import removeBin from '../../components/upload/assets/removeBin.svg'
+import toggleArrow from '../../components/upload/assets/dropdownArrow.svg'
const UploadSection = ({
className,
@@ -76,6 +78,20 @@ const RepositoryPageTemplate = observer(
setGlobalRorId,
init,
status,
+ setsList,
+ loadingSets,
+ enableSet,
+ enabledList,
+ disabledList,
+ deleteSet,
+ getSetsWholeList,
+ wholeSetData,
+ loadingWholeSets,
+ loadingWholeSetsBtn,
+ getSetsEnabledList,
+ setLoadingWholeSetsBtn,
+ loadingRemoveItem,
+ setLoadingRemoveAction,
tag: Tag = 'main',
...restProps
}) => {
@@ -93,9 +109,18 @@ const RepositoryPageTemplate = observer(
const [isChanged, setChanged] = useState(false)
const [isNameOpen, setNameIsOpen] = useState(false)
const [isIdOpen, setIdIsOpen] = useState(false)
-
const [isNameChanged, setNameChanged] = useState(false)
const [isFormSubmitted, setFormSubmitted] = useState(false)
+ const [selectedItem, setSelectedItem] = useState(null)
+ const dropdownRef = useRef(null)
+ const [isOpen, setIsOpen] = useState(false)
+ const [setNameDisplay, setSetNameDisplay] = useState({})
+ const [isEditing, setIsEditing] = useState({})
+ const [showFullList, setShowFullList] = useState(false)
+ const [inputValue, setInputValue] = useState('')
+
+ const router = useRouter()
+ const providerId = router.query['data-provider-id']
useEffect(() => {
fetch(`https://api.ror.org/organizations?query=${rorId}`)
@@ -119,15 +144,20 @@ const RepositoryPageTemplate = observer(
})
}, [rorName])
+ useEffect(() => {
+ getSetsEnabledList()
+ }, [providerId])
+
const uploadRef = useRef(null)
const mappingRef = useRef(null)
- const router = useRouter()
+ const setRef = useRef(null)
const isStartingMember = membershipPlan.billing_type === 'starting'
const scrollTarget = {
upload: uploadRef,
mapping: mappingRef,
+ sets: setRef,
}
useScrollEffect(scrollTarget[router.query.referrer])
@@ -142,6 +172,7 @@ const RepositoryPageTemplate = observer(
const present = {
'data-provider': updateDataProvider,
'mapping': mappingSubmit,
+ 'sets': mappingSubmit,
}[scope]
const result = await present(data)
@@ -206,6 +237,108 @@ const RepositoryPageTemplate = observer(
return null
}
+ const handleDropdownClick = async () => {
+ setIsOpen(!isOpen)
+ if (!wholeSetData.length) await getSetsWholeList()
+ }
+
+ const handleSelect = (item) => {
+ setSelectedItem(item)
+ setInputValue(item.setName)
+ setIsOpen(false)
+ }
+
+ const handleAddClick = async () => {
+ if (selectedItem) {
+ try {
+ setLoadingWholeSetsBtn(true)
+ await enableSet({
+ setSpec: selectedItem.setSpec,
+ setName: selectedItem.setName,
+ setNameDisplay: selectedItem.setNameDisplay,
+ })
+ setSelectedItem(null)
+ await getSetsWholeList()
+ await getSetsEnabledList()
+ } catch (error) {
+ console.error('Error patching settings:', error)
+ } finally {
+ setLoadingWholeSetsBtn(false)
+ }
+ }
+ }
+
+ const handleDelete = async (id) => {
+ try {
+ setLoadingRemoveAction(true, id)
+ await deleteSet(id)
+ await getSetsWholeList()
+ await getSetsEnabledList()
+ } catch (error) {
+ console.error('Error patching settings:', error)
+ } finally {
+ setLoadingRemoveAction(false, id)
+ }
+ }
+
+ const handleInputChange = (id, event) => {
+ setSetNameDisplay((prevState) => ({
+ ...prevState,
+ [id]: event.target.value,
+ }))
+ }
+
+ const handleEditClick = (id) => {
+ setIsEditing((prevState) => ({
+ ...prevState,
+ [id]: true,
+ }))
+ }
+
+ const handleButtonClick = async (item) => {
+ try {
+ await enableSet({
+ id: item.id,
+ setSpec: item.setSpec,
+ setName: item.setName,
+ setNameDisplay: setNameDisplay[item.id],
+ })
+ setIsEditing((prevState) => ({
+ ...prevState,
+ [item.id]: false,
+ }))
+ } catch (error) {
+ console.error('Error patching settings:', error)
+ }
+ }
+
+ useEffect(() => {
+ const handleClickOutside = (event) => {
+ if (dropdownRef.current && !dropdownRef.current.contains(event.target))
+ setIsOpen(false)
+ }
+
+ document.addEventListener('mousedown', handleClickOutside)
+
+ return () => {
+ document.removeEventListener('mousedown', handleClickOutside)
+ }
+ }, [dropdownRef])
+
+ const displayAllSets = showFullList ? enabledList : enabledList.slice(0, 3)
+
+ const toggleList = () => {
+ setShowFullList(!showFullList)
+ }
+
+ const handleSetInputChange = (event) => {
+ setInputValue(event.target.value)
+ }
+
+ const filteredData = wholeSetData.filter((item) =>
+ item.setName.toLowerCase().includes(inputValue.toLowerCase())
+ )
+
return (
)}
+ {globalStore.enabledList.length > 0 ? (
+
+
+
+
+
{content.sets.title}
+
+ {content.sets.description}
+
+
+ {displayAllSets.map((item) => (
+
+
+
+
100
+ ? `${setNameDisplay[item.id].substring(
+ 0,
+ 100
+ )}...`
+ : setNameDisplay[item.id]) ||
+ (item?.setNameDisplay?.length > 100
+ ? `${item.setNameDisplay.substring(
+ 0,
+ 100
+ )}...`
+ : item.setNameDisplay)
+ }
+ onChange={(event) =>
+ handleInputChange(item.id, event)
+ }
+ className={styles.setInnerField}
+ disabled={!isEditing[item.id]}
+ />
+ {!isEditing[item.id] ? (
+
+ ) : (
+
+ )}
+
+
+ {loadingRemoveItem.id === item.id &&
+ loadingRemoveItem.value ? (
+
+ ) : (
+ // eslint-disable-next-line max-len
+ // eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-noninteractive-element-interactions
+
handleDelete(item.id)}
+ src={removeBin}
+ alt=""
+ />
+ )}
+
+
+
+
+
setName
+
+ {item.setName.length > 110
+ ? `${item.setName.substring(0, 110)}...`
+ : item.setName}
+
+
+
+
setSpec
+
+ {item.setSpec.length > 110
+ ? `${item.setSpec.substring(0, 110)}...`
+ : item.setSpec}
+
+
+
+
+ ))}
+ {enabledList.length > 3 && (
+
+ )}
+
+
+
+
+
+
+
+
+
+ {isOpen && (
+
+ {loadingWholeSets ? (
+
Loading...
+ ) : (
+
+ {filteredData.map((item) => (
+ // eslint-disable-next-line max-len
+ // eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-noninteractive-element-interactions
+ - handleSelect(item)}
+ className={styles.selectItem}
+ >
+ {item.setName}
+
+ ))}
+
+ )}
+
+ )}
+
+
+
+
+
+ ) : (
+ <>>
+ )}