From ad97f1c3acfceba8330ee002a88f12085e0dab71 Mon Sep 17 00:00:00 2001 From: Siarhei Karol Date: Mon, 16 Dec 2024 13:43:17 +0300 Subject: [PATCH 1/9] assign validated marc record --- src/common/constants/api.constants.ts | 3 +- src/common/helpers/complexLookup.helper.ts | 12 ++++ src/common/hooks/useApi.ts | 63 ++++++++++++++++++ src/common/hooks/useComplexLookup.ts | 76 ++++++++++++++++++---- translations/ui-linked-data/en.json | 4 +- 5 files changed, 143 insertions(+), 15 deletions(-) create mode 100644 src/common/hooks/useApi.ts diff --git a/src/common/constants/api.constants.ts b/src/common/constants/api.constants.ts index aa6b3921..3ddba46b 100644 --- a/src/common/constants/api.constants.ts +++ b/src/common/constants/api.constants.ts @@ -5,10 +5,11 @@ export const EDITOR_API_BASE_PATH = 'EDITOR_API_BASE_PATH'; // API endpoints export const BIBFRAME_API_ENDPOINT = '/linked-data/resource'; -export const INVENTORY_API_ENDPOINT = '/linked-data/inventory-instance' +export const INVENTORY_API_ENDPOINT = '/linked-data/inventory-instance'; export const PROFILE_API_ENDPOINT = '/linked-data/profile'; export const SEARCH_API_ENDPOINT = '/search/linked-data'; export const SEARCH_RESOURCE_API_ENDPOINT = `${SEARCH_API_ENDPOINT}/works`; +export const AUTHORITY_ASSIGNMENT_CHECK_API_ENDPOINT = '/linked-data/authority-assignment-check'; export const DEFAULT_PAGES_METADATA = { totalElements: 0, diff --git a/src/common/helpers/complexLookup.helper.ts b/src/common/helpers/complexLookup.helper.ts index 859cccdc..61faff6e 100644 --- a/src/common/helpers/complexLookup.helper.ts +++ b/src/common/helpers/complexLookup.helper.ts @@ -66,3 +66,15 @@ export const getUpdatedSelectedEntries = ({ return selectedEntriesService.get(); }; + +export const generateValidationRequestBody = (marcData: MarcDTO | null, target = 'CREATOR_OF_WORK') => { + if (!marcData) return {}; + + const rawMarcEncoded = JSON.stringify(marcData?.parsedRecord?.content, null, 2); + const excapedString = rawMarcEncoded.replace(/\r/g, '\r').replace(/\n/g, '\n'); + + return { + rawMarc: excapedString, + target, + }; +}; diff --git a/src/common/hooks/useApi.ts b/src/common/hooks/useApi.ts new file mode 100644 index 00000000..50838a17 --- /dev/null +++ b/src/common/hooks/useApi.ts @@ -0,0 +1,63 @@ +import { useState, useCallback } from 'react'; +import BaseApi from '@common/api/base.api'; +import { StatusType } from '@common/constants/status.constants'; +import { UserNotificationFactory } from '@common/services/userNotification'; +import { useLoadingState, useStatusState } from '@src/store'; + +interface RequestConfig { + url: string; + method?: 'GET' | 'POST' | 'PUT' | 'DELETE'; + urlParams?: Record; + urlParam?: { name: string; value: string | number }; + requestParams?: RequestInit; + body?: unknown; + errorMessageId?: string; +} + +interface ApiResponse { + data: T | null; +} + +export function useApi() { + const { setIsLoading } = useLoadingState(); + const { addStatusMessagesItem } = useStatusState(); + const [state, setState] = useState>({ + data: null, + }); + + const makeRequest = useCallback( + async ({ url, method = 'GET', urlParams, urlParam, requestParams, body, errorMessageId }: RequestConfig) => { + setIsLoading(true); + + try { + const finalUrl = BaseApi.generateUrl(url, urlParam); + + const response = await BaseApi.getJson({ + url: finalUrl, + urlParams, + requestParams: { + method, + ...requestParams, + ...(typeof body === 'object' && body !== null ? { body: JSON.stringify(body, null, 2) } : {}), + }, + }); + + setState({ data: response }); + + return response; + } catch (error) { + addStatusMessagesItem?.( + UserNotificationFactory.createMessage(StatusType.error, errorMessageId ?? 'ld.errorMakingApiRequest'), + ); + } finally { + setIsLoading(false); + } + }, + [], + ); + + return { + ...state, + makeRequest, + }; +} diff --git a/src/common/hooks/useComplexLookup.ts b/src/common/hooks/useComplexLookup.ts index 2def26c4..d39f0e3e 100644 --- a/src/common/hooks/useComplexLookup.ts +++ b/src/common/hooks/useComplexLookup.ts @@ -1,6 +1,7 @@ import { ChangeEvent, useCallback, useState } from 'react'; import { generateEmptyValueUuid, + generateValidationRequestBody, getLinkedField, getUpdatedSelectedEntries, updateLinkedFieldValue, @@ -10,7 +11,10 @@ import { AdvancedFieldType } from '@common/constants/uiControls.constants'; import { useModalControls } from './useModalControls'; import { useMarcData } from './useMarcData'; import { useServicesContext } from './useServicesContext'; -import { useInputsState, useMarcPreviewState, useProfileState, useUIState } from '@src/store'; +import { useInputsState, useMarcPreviewState, useProfileState, useStatusState, useUIState } from '@src/store'; +import { useApi } from './useApi'; +import { UserNotificationFactory } from '@common/services/userNotification'; +import { StatusType } from '@common/constants/status.constants'; export const useComplexLookup = ({ entry, @@ -28,6 +32,7 @@ export const useComplexLookup = ({ const { schema } = useProfileState(); const { selectedEntries, setSelectedEntries } = useInputsState(); const { + complexValue, setComplexValue, resetComplexValue: resetMarcPreviewData, metadata: marcPreviewMetadata, @@ -38,6 +43,8 @@ export const useComplexLookup = ({ const { fetchMarcData } = useMarcData(setComplexValue); const { uuid, linkedEntry } = entry; const linkedField = getLinkedField({ schema, linkedEntry }); + const { makeRequest } = useApi(); + const { addStatusMessagesItem } = useStatusState(); const handleDelete = (id?: string) => { onChange(uuid, []); @@ -59,17 +66,36 @@ export const useComplexLookup = ({ setIsModalOpen(false); }, []); - const handleAssign = async ({ id, title, linkedFieldValue }: ComplexLookupAssignRecordDTO) => { - let srsId; - - if (marcPreviewMetadata?.baseId === id) { - srsId = marcPreviewMetadata.srsId; - } else { - const marcData = await fetchMarcData(id, lookupConfig.api.endpoints.marcPreview); + const reset = () => { + resetMarcPreviewData(); + resetMarcPreviewMetadata(); + resetIsMarcPreviewOpen(); + }; - srsId = marcData?.matchedId; - } + const validateMarcRecord = async (marcData: MarcDTO | null) => { + return await makeRequest({ + url: '/linked-data/authority-assignment-check', + method: 'POST', + body: generateValidationRequestBody(marcData), + requestParams: { + headers: { + 'content-type': 'application/json', + }, + }, + }); + }; + const assignMarcRecord = ({ + id, + title, + srsId, + linkedFieldValue, + }: { + id: string; + title: string; + srsId?: string; + linkedFieldValue?: string; + }) => { const newValue = { id, label: title, @@ -95,10 +121,34 @@ export const useComplexLookup = ({ setSelectedEntries(updatedSelectedEntries); } + }; - resetMarcPreviewData(); - resetMarcPreviewMetadata(); - resetIsMarcPreviewOpen(); + const handleAssign = async ({ id, title, linkedFieldValue }: ComplexLookupAssignRecordDTO) => { + let srsId; + let marcData = complexValue; + + if (marcPreviewMetadata?.baseId === id) { + srsId = marcPreviewMetadata.srsId; + } else { + const response = await fetchMarcData(id, lookupConfig.api.endpoints.marcPreview); + + if (response) { + marcData = response; + srsId = marcData?.matchedId; + } + } + + const isValid = await validateMarcRecord(marcData); + + if (isValid) { + assignMarcRecord({ id, title, srsId, linkedFieldValue }); + } else { + addStatusMessagesItem?.( + UserNotificationFactory.createMessage(StatusType.error, 'ld.errorValidatingAuthorityRecord'), + ); + } + + reset(); closeModal(); }; diff --git a/translations/ui-linked-data/en.json b/translations/ui-linked-data/en.json index 4b824f9d..52f9e1c8 100644 --- a/translations/ui-linked-data/en.json +++ b/translations/ui-linked-data/en.json @@ -208,5 +208,7 @@ "ld.aria.filters.reset": "Reset filters button", "ld.aria.filters.reset.announce": "Search field and filters are reset", "ld.duplicateImportWarn": "Duplicate import warning", - "ld.rdPropertiesMatchContinue": "Properties of this resource match an existing resource. Do you want to continue?" + "ld.rdPropertiesMatchContinue": "Properties of this resource match an existing resource. Do you want to continue?", + "ld.errorMakingApiRequest": "Error making API request", + "ld.errorValidatingAuthorityRecord": "Error validating authority record" } From c6a868988145525a97234a0cb77bf0d7dc53d0b8 Mon Sep 17 00:00:00 2001 From: Siarhei Karol Date: Tue, 17 Dec 2024 12:36:41 +0300 Subject: [PATCH 2/9] authorities lookup config extended --- src/common/hooks/useApi.ts | 1 + src/common/hooks/useComplexLookup.ts | 24 +++++++++---------- .../ComplexLookupField/ComplexLookupField.tsx | 1 + .../configs/Authorities.tsx | 6 ++--- .../complexLookup/complexLookup.config.ts | 5 ++++ src/types/complexLookup.d.ts | 2 ++ 6 files changed, 24 insertions(+), 15 deletions(-) diff --git a/src/common/hooks/useApi.ts b/src/common/hooks/useApi.ts index 50838a17..960bada9 100644 --- a/src/common/hooks/useApi.ts +++ b/src/common/hooks/useApi.ts @@ -37,6 +37,7 @@ export function useApi() { urlParams, requestParams: { method, + headers: { 'content-type': 'application/json' }, ...requestParams, ...(typeof body === 'object' && body !== null ? { body: JSON.stringify(body, null, 2) } : {}), }, diff --git a/src/common/hooks/useComplexLookup.ts b/src/common/hooks/useComplexLookup.ts index d39f0e3e..0877fe8a 100644 --- a/src/common/hooks/useComplexLookup.ts +++ b/src/common/hooks/useComplexLookup.ts @@ -8,23 +8,26 @@ import { } from '@common/helpers/complexLookup.helper'; import { __MOCK_URI_CHANGE_WHEN_IMPLEMENTING } from '@common/constants/complexLookup.constants'; import { AdvancedFieldType } from '@common/constants/uiControls.constants'; +import { useInputsState, useMarcPreviewState, useProfileState, useStatusState, useUIState } from '@src/store'; +import { UserNotificationFactory } from '@common/services/userNotification'; +import { StatusType } from '@common/constants/status.constants'; +import { AUTHORITY_ASSIGNMENT_CHECK_API_ENDPOINT } from '@common/constants/api.constants'; import { useModalControls } from './useModalControls'; import { useMarcData } from './useMarcData'; import { useServicesContext } from './useServicesContext'; -import { useInputsState, useMarcPreviewState, useProfileState, useStatusState, useUIState } from '@src/store'; import { useApi } from './useApi'; -import { UserNotificationFactory } from '@common/services/userNotification'; -import { StatusType } from '@common/constants/status.constants'; export const useComplexLookup = ({ entry, value, lookupConfig, + baseLabelType = 'creator', onChange, }: { entry: SchemaEntry; value?: UserValueContents[]; lookupConfig: ComplexLookupsConfigEntry; + baseLabelType?: string; onChange: (uuid: string, contents: Array) => void; }) => { const { selectedEntriesService } = useServicesContext() as Required; @@ -72,16 +75,13 @@ export const useComplexLookup = ({ resetIsMarcPreviewOpen(); }; - const validateMarcRecord = async (marcData: MarcDTO | null) => { - return await makeRequest({ - url: '/linked-data/authority-assignment-check', + const validateMarcRecord = (marcData: MarcDTO | null) => { + const { endpoints, validationTarget } = lookupConfig.api; + + return makeRequest({ + url: endpoints.validation ?? AUTHORITY_ASSIGNMENT_CHECK_API_ENDPOINT, method: 'POST', - body: generateValidationRequestBody(marcData), - requestParams: { - headers: { - 'content-type': 'application/json', - }, - }, + body: generateValidationRequestBody(marcData, validationTarget?.[baseLabelType]), }); }; diff --git a/src/components/ComplexLookupField/ComplexLookupField.tsx b/src/components/ComplexLookupField/ComplexLookupField.tsx index d1897d13..7c792720 100644 --- a/src/components/ComplexLookupField/ComplexLookupField.tsx +++ b/src/components/ComplexLookupField/ComplexLookupField.tsx @@ -30,6 +30,7 @@ export const ComplexLookupField: FC = ({ value = undefined, id, entry, on entry, value, lookupConfig, + baseLabelType: layout?.baseLabelType, onChange, }); diff --git a/src/components/ComplexLookupField/configs/Authorities.tsx b/src/components/ComplexLookupField/configs/Authorities.tsx index 3a2c416d..f4b80271 100644 --- a/src/components/ComplexLookupField/configs/Authorities.tsx +++ b/src/components/ComplexLookupField/configs/Authorities.tsx @@ -16,18 +16,18 @@ export const authoritiesTableConfig: SearchResultsTableConfig = { }, title: { label: 'ld.headingReference', - position: 1, + position: 2, className: 'cell-fixed cell-fixed-370', formatter: TitleFormatter, }, subclass: { label: 'ld.typeOfHeading', - position: 2, + position: 3, className: 'cell-fixed cell-fixed-140', }, authoritySource: { label: 'ld.authoritySource', - position: 3, + position: 4, className: 'cell-fixed cell-fixed-250', }, }, diff --git a/src/configs/complexLookup/complexLookup.config.ts b/src/configs/complexLookup/complexLookup.config.ts index 310ac4b9..d985e627 100644 --- a/src/configs/complexLookup/complexLookup.config.ts +++ b/src/configs/complexLookup/complexLookup.config.ts @@ -1,5 +1,6 @@ import { SearchSegment } from '@common/constants/search.constants'; import { ComplexLookupType, SearchableIndex } from '@common/constants/complexLookup.constants'; +import { AUTHORITY_ASSIGNMENT_CHECK_API_ENDPOINT } from '@common/constants/api.constants'; import { COMPLEX_LOOKUP_FILTERS_CONFIG } from './complexLookupFilters.config'; import { COMPLEX_LOOKUP_SEARCH_BY_CONFIG } from './complexLookupSearchBy.config'; import { COMPLEX_LOOKUP_SEARCHABLE_INDICES_MAP } from './complexLookupSeachableIndicesMap'; @@ -16,6 +17,10 @@ export const COMPLEX_LOOKUPS_CONFIG: ComplexLookupsConfig = { [SearchSegment.Browse]: '/browse/authorities', }, marcPreview: '/source-storage/records/:recordId/formatted?idType=AUTHORITY', + validation: AUTHORITY_ASSIGNMENT_CHECK_API_ENDPOINT, + }, + validationTarget: { + creator: 'CREATOR_OF_WORK', }, sourceKey: 'authoritySourceFiles', searchQuery: { diff --git a/src/types/complexLookup.d.ts b/src/types/complexLookup.d.ts index 3265ff28..3c53718d 100644 --- a/src/types/complexLookup.d.ts +++ b/src/types/complexLookup.d.ts @@ -40,7 +40,9 @@ type ComplexLookupApiEntryConfig = { [key in SearchSegment]: string; }; marcPreview?: string; + validation?: string; }; + validationTarget?: Record; sourceKey?: string; searchQuery: { filter?: string; From ae6acb1eaec31078fed11affbbad452c33e93873 Mon Sep 17 00:00:00 2001 From: Siarhei Karol Date: Tue, 17 Dec 2024 14:28:42 +0300 Subject: [PATCH 3/9] code refactoring --- src/common/hooks/useComplexLookup.ts | 6 +++++- src/common/hooks/useComplexLookupValidation.ts | 15 +++++++++++++++ .../MarcPreviewComplexLookup.tsx | 8 ++++---- src/store/selectors.ts | 2 ++ src/store/stores/complexLookup.ts | 15 +++++++++++++++ 5 files changed, 41 insertions(+), 5 deletions(-) create mode 100644 src/common/hooks/useComplexLookupValidation.ts create mode 100644 src/store/stores/complexLookup.ts diff --git a/src/common/hooks/useComplexLookup.ts b/src/common/hooks/useComplexLookup.ts index 0877fe8a..f048f417 100644 --- a/src/common/hooks/useComplexLookup.ts +++ b/src/common/hooks/useComplexLookup.ts @@ -16,6 +16,7 @@ import { useModalControls } from './useModalControls'; import { useMarcData } from './useMarcData'; import { useServicesContext } from './useServicesContext'; import { useApi } from './useApi'; +import { useComplexLookupValidation } from './useComplexLookupValidation'; export const useComplexLookup = ({ entry, @@ -48,6 +49,7 @@ export const useComplexLookup = ({ const linkedField = getLinkedField({ schema, linkedEntry }); const { makeRequest } = useApi(); const { addStatusMessagesItem } = useStatusState(); + const { addFailedEntryId } = useComplexLookupValidation(); const handleDelete = (id?: string) => { onChange(uuid, []); @@ -140,9 +142,11 @@ export const useComplexLookup = ({ const isValid = await validateMarcRecord(marcData); - if (isValid) { + if (!isValid) { assignMarcRecord({ id, title, srsId, linkedFieldValue }); } else { + addFailedEntryId(id); + addStatusMessagesItem?.( UserNotificationFactory.createMessage(StatusType.error, 'ld.errorValidatingAuthorityRecord'), ); diff --git a/src/common/hooks/useComplexLookupValidation.ts b/src/common/hooks/useComplexLookupValidation.ts new file mode 100644 index 00000000..194cf8bb --- /dev/null +++ b/src/common/hooks/useComplexLookupValidation.ts @@ -0,0 +1,15 @@ +import { useComplexLookup } from '@src/store'; + +export const useComplexLookupValidation = () => { + const { addAuthorityAssignmentCheckFailedIdsItem, resetAuthorityAssignmentCheckFailedIds } = useComplexLookup(); + + const addFailedEntryId = (id: string) => { + addAuthorityAssignmentCheckFailedIdsItem?.(id); + }; + + const clearFailedEntryIds = () => { + resetAuthorityAssignmentCheckFailedIds(); + }; + + return { addFailedEntryId, clearFailedEntryIds }; +}; diff --git a/src/components/ComplexLookupField/MarcPreviewComplexLookup.tsx b/src/components/ComplexLookupField/MarcPreviewComplexLookup.tsx index de3037b2..1d612b27 100644 --- a/src/components/ComplexLookupField/MarcPreviewComplexLookup.tsx +++ b/src/components/ComplexLookupField/MarcPreviewComplexLookup.tsx @@ -41,9 +41,9 @@ export const MarcPreviewComplexLookup: FC = ({ on const onClickAssignButton = () => { onAssignRecord?.({ - id: marcPreviewMetadata?.baseId || '', - title: marcPreviewMetadata?.title || '', - linkedFieldValue: marcPreviewMetadata?.headingType || '', + id: marcPreviewMetadata?.baseId ?? '', + title: marcPreviewMetadata?.title ?? '', + linkedFieldValue: marcPreviewMetadata?.headingType ?? '', }); }; @@ -52,7 +52,7 @@ export const MarcPreviewComplexLookup: FC = ({ on {isMarcPreviewOpen && marcPreviewData ? (
diff --git a/src/store/selectors.ts b/src/store/selectors.ts index 0282941f..5c97f722 100644 --- a/src/store/selectors.ts +++ b/src/store/selectors.ts @@ -6,6 +6,7 @@ import { useInputsStore } from './stores/inputs'; import { useConfigStore } from './stores/config'; import { useUIStore } from './stores/ui'; import { useSearchStore } from './stores/search'; +import { useComplexLookupStore } from './stores/complexLookup'; // The "createSelectors" function can be utilized here to generate memoized selectors // Note: "createSelectors" is currently unoptimized and may result in memory leaks if used as is @@ -17,3 +18,4 @@ export const useInputsState = useInputsStore; export const useConfigState = useConfigStore; export const useUIState = useUIStore; export const useSearchState = useSearchStore; +export const useComplexLookup = useComplexLookupStore; diff --git a/src/store/stores/complexLookup.ts b/src/store/stores/complexLookup.ts new file mode 100644 index 00000000..74ac2d49 --- /dev/null +++ b/src/store/stores/complexLookup.ts @@ -0,0 +1,15 @@ +import { type SliceState } from '../utils/slice'; +import { createStoreFactory, SliceConfigs } from '../utils/createStoreFactory'; + +export type ComplexLookupState = SliceState<'authorityAssignmentCheckFailedIds', string[], string>; + +const STORE_NAME = 'ComplexLookup'; + +const sliceConfigs: SliceConfigs = { + authorityAssignmentCheckFailedIds: { + initialValue: [], + singleItem: { type: '' }, + }, +}; + +export const useComplexLookupStore = createStoreFactory(sliceConfigs, STORE_NAME); From 6e2798ae3523897c35991d3c57d33d46db480ab3 Mon Sep 17 00:00:00 2001 From: Siarhei Karol Date: Tue, 17 Dec 2024 16:27:37 +0300 Subject: [PATCH 4/9] disable Assign button --- src/common/hooks/useComplexLookup.ts | 2 +- src/common/hooks/useComplexLookupValidation.ts | 16 +++++++++++++--- .../MarcPreviewComplexLookup.tsx | 5 +++++ .../ComplexLookupField/formatters/Assign.tsx | 4 ++++ src/store/selectors.ts | 2 +- 5 files changed, 24 insertions(+), 5 deletions(-) diff --git a/src/common/hooks/useComplexLookup.ts b/src/common/hooks/useComplexLookup.ts index f048f417..6575ec9f 100644 --- a/src/common/hooks/useComplexLookup.ts +++ b/src/common/hooks/useComplexLookup.ts @@ -142,7 +142,7 @@ export const useComplexLookup = ({ const isValid = await validateMarcRecord(marcData); - if (!isValid) { + if (isValid) { assignMarcRecord({ id, title, srsId, linkedFieldValue }); } else { addFailedEntryId(id); diff --git a/src/common/hooks/useComplexLookupValidation.ts b/src/common/hooks/useComplexLookupValidation.ts index 194cf8bb..ef1c642e 100644 --- a/src/common/hooks/useComplexLookupValidation.ts +++ b/src/common/hooks/useComplexLookupValidation.ts @@ -1,7 +1,11 @@ -import { useComplexLookup } from '@src/store'; +import { useComplexLookupState } from '@src/store'; export const useComplexLookupValidation = () => { - const { addAuthorityAssignmentCheckFailedIdsItem, resetAuthorityAssignmentCheckFailedIds } = useComplexLookup(); + const { + authorityAssignmentCheckFailedIds, + addAuthorityAssignmentCheckFailedIdsItem, + resetAuthorityAssignmentCheckFailedIds, + } = useComplexLookupState(); const addFailedEntryId = (id: string) => { addAuthorityAssignmentCheckFailedIdsItem?.(id); @@ -11,5 +15,11 @@ export const useComplexLookupValidation = () => { resetAuthorityAssignmentCheckFailedIds(); }; - return { addFailedEntryId, clearFailedEntryIds }; + const checkFailedId = (id?: string) => { + if (!id) return false; + + return authorityAssignmentCheckFailedIds?.includes(id); + }; + + return { addFailedEntryId, clearFailedEntryIds, checkFailedId }; }; diff --git a/src/components/ComplexLookupField/MarcPreviewComplexLookup.tsx b/src/components/ComplexLookupField/MarcPreviewComplexLookup.tsx index 1d612b27..36d6cacc 100644 --- a/src/components/ComplexLookupField/MarcPreviewComplexLookup.tsx +++ b/src/components/ComplexLookupField/MarcPreviewComplexLookup.tsx @@ -1,6 +1,7 @@ import { FC } from 'react'; import { FormattedDate, FormattedMessage, useIntl } from 'react-intl'; import { useSearchContext } from '@common/hooks/useSearchContext'; +import { useComplexLookupValidation } from '@common/hooks/useComplexLookupValidation'; import { useMarcPreviewState, useUIState } from '@src/store'; import { SearchControlPane } from '@components/SearchControlPane'; import { MarcContent } from '@components/MarcContent'; @@ -17,6 +18,7 @@ export const MarcPreviewComplexLookup: FC = ({ on const { formatMessage } = useIntl(); const { isMarcPreviewOpen } = useUIState(); const { complexValue: marcPreviewData, metadata: marcPreviewMetadata } = useMarcPreviewState(); + const { checkFailedId } = useComplexLookupValidation(); const renderCloseButton = () => ( diff --git a/src/components/ComplexLookupField/formatters/Assign.tsx b/src/components/ComplexLookupField/formatters/Assign.tsx index b214c1a0..d3110ff5 100644 --- a/src/components/ComplexLookupField/formatters/Assign.tsx +++ b/src/components/ComplexLookupField/formatters/Assign.tsx @@ -1,4 +1,5 @@ import { FormattedMessage } from 'react-intl'; +import { useComplexLookupValidation } from '@common/hooks/useComplexLookupValidation'; import { AuthRefType } from '@common/constants/search.constants'; import { Button, ButtonType } from '@components/Button'; @@ -9,7 +10,9 @@ export const AssignFormatter = ({ row: SearchResultsTableRow; onAssign: ({ id, title, linkedFieldValue }: ComplexLookupAssignRecordDTO) => void; }) => { + const { checkFailedId } = useComplexLookupValidation(); const isAuthorized = row.authorized.label === AuthRefType.Authorized; + const isDisabled = checkFailedId(row.__meta.id); return isAuthorized ? ( diff --git a/src/store/selectors.ts b/src/store/selectors.ts index 5c97f722..fd8aed7e 100644 --- a/src/store/selectors.ts +++ b/src/store/selectors.ts @@ -18,4 +18,4 @@ export const useInputsState = useInputsStore; export const useConfigState = useConfigStore; export const useUIState = useUIStore; export const useSearchState = useSearchStore; -export const useComplexLookup = useComplexLookupStore; +export const useComplexLookupState = useComplexLookupStore; From a79a586c78e47cb71ebb362596e311c0aeebc0a1 Mon Sep 17 00:00:00 2001 From: Siarhei Karol Date: Wed, 18 Dec 2024 11:17:31 +0300 Subject: [PATCH 5/9] reset validated ids --- src/common/hooks/useComplexLookup.ts | 9 +++++---- src/common/hooks/useComplexLookupSearchResults.ts | 10 +++++++++- .../ComplexLookupField/formatters/Assign.tsx | 6 +++--- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src/common/hooks/useComplexLookup.ts b/src/common/hooks/useComplexLookup.ts index 6575ec9f..559b97cf 100644 --- a/src/common/hooks/useComplexLookup.ts +++ b/src/common/hooks/useComplexLookup.ts @@ -49,7 +49,7 @@ export const useComplexLookup = ({ const linkedField = getLinkedField({ schema, linkedEntry }); const { makeRequest } = useApi(); const { addStatusMessagesItem } = useStatusState(); - const { addFailedEntryId } = useComplexLookupValidation(); + const { addFailedEntryId, clearFailedEntryIds } = useComplexLookupValidation(); const handleDelete = (id?: string) => { onChange(uuid, []); @@ -68,6 +68,7 @@ export const useComplexLookup = ({ }; const closeModal = useCallback(() => { + clearFailedEntryIds(); setIsModalOpen(false); }, []); @@ -144,6 +145,9 @@ export const useComplexLookup = ({ if (isValid) { assignMarcRecord({ id, title, srsId, linkedFieldValue }); + clearFailedEntryIds(); + reset(); + closeModal(); } else { addFailedEntryId(id); @@ -151,9 +155,6 @@ export const useComplexLookup = ({ UserNotificationFactory.createMessage(StatusType.error, 'ld.errorValidatingAuthorityRecord'), ); } - - reset(); - closeModal(); }; const handleOnChangeBase = ({ target: { value } }: ChangeEvent) => { diff --git a/src/common/hooks/useComplexLookupSearchResults.ts b/src/common/hooks/useComplexLookupSearchResults.ts index fb068384..271d4351 100644 --- a/src/common/hooks/useComplexLookupSearchResults.ts +++ b/src/common/hooks/useComplexLookupSearchResults.ts @@ -4,6 +4,7 @@ import { type Row } from '@components/Table'; import { useSearchContext } from '@common/hooks/useSearchContext'; import { ComplexLookupSearchResultsProps } from '@components/ComplexLookupField/ComplexLookupSearchResults'; import { useSearchState } from '@src/store'; +import { useComplexLookupValidation } from './useComplexLookupValidation'; export const useComplexLookupSearchResults = ({ onTitleClick, @@ -13,6 +14,7 @@ export const useComplexLookupSearchResults = ({ const { onAssignRecord } = useSearchContext(); const { data, sourceData } = useSearchState(); const { formatMessage } = useIntl(); + const { checkFailedId } = useComplexLookupValidation(); const applyActionItems = useCallback( (rows: Row[]): Row[] => @@ -23,7 +25,13 @@ export const useComplexLookupSearchResults = ({ formattedRow[key] = { ...row[key], children: column.formatter - ? column.formatter({ row, formatMessage, onAssign: onAssignRecord, onTitleClick }) + ? column.formatter({ + row, + formatMessage, + onAssign: onAssignRecord, + onTitleClick, + validateId: checkFailedId, + }) : row[key].label, }; }); diff --git a/src/components/ComplexLookupField/formatters/Assign.tsx b/src/components/ComplexLookupField/formatters/Assign.tsx index d3110ff5..ed51436b 100644 --- a/src/components/ComplexLookupField/formatters/Assign.tsx +++ b/src/components/ComplexLookupField/formatters/Assign.tsx @@ -1,18 +1,18 @@ import { FormattedMessage } from 'react-intl'; -import { useComplexLookupValidation } from '@common/hooks/useComplexLookupValidation'; import { AuthRefType } from '@common/constants/search.constants'; import { Button, ButtonType } from '@components/Button'; export const AssignFormatter = ({ row, onAssign, + validateId, }: { row: SearchResultsTableRow; onAssign: ({ id, title, linkedFieldValue }: ComplexLookupAssignRecordDTO) => void; + validateId: (id: string) => boolean; }) => { - const { checkFailedId } = useComplexLookupValidation(); const isAuthorized = row.authorized.label === AuthRefType.Authorized; - const isDisabled = checkFailedId(row.__meta.id); + const isDisabled = validateId(row.__meta.id); return isAuthorized ? (