diff --git a/odd-platform-ui/src/components/Terms/TermSearch/TermForm/TermsForm.tsx b/odd-platform-ui/src/components/Terms/TermSearch/TermForm/TermsForm.tsx index e8ee7bf44..7404ed249 100644 --- a/odd-platform-ui/src/components/Terms/TermSearch/TermForm/TermsForm.tsx +++ b/odd-platform-ui/src/components/Terms/TermSearch/TermForm/TermsForm.tsx @@ -1,7 +1,7 @@ -import React, { cloneElement, type FC, useEffect, useMemo } from 'react'; +import React, { cloneElement, type FC, useEffect, useMemo, useState } from 'react'; import { Controller, useForm } from 'react-hook-form'; import { useNavigate } from 'react-router-dom'; -import { Grid, Typography } from '@mui/material'; +import { Grid, Typography, Alert,IconButton } from '@mui/material'; import { useTranslation } from 'react-i18next'; import type { TermDetails, TermFormData } from 'generated-sources'; import { @@ -12,11 +12,14 @@ import { NamespaceAutocomplete, } from 'components/shared/elements'; import { useAppDispatch, useAppSelector } from 'redux/lib/hooks'; -import { createTerm, updateTerm } from 'redux/thunks'; +import { createTerm, updateTerm, fetchTermsSearchResults } from 'redux/thunks'; import { getTermCreatingStatuses, getTermDetails, getTermUpdatingStatuses, + getTermSearchResults, + getTermSearchId, + getTermSearchFacetsSynced, } from 'redux/selectors'; import { termDetailsPath, useTermsRouteParams } from 'routes'; import { useQueryClient } from '@tanstack/react-query'; @@ -40,6 +43,12 @@ const TermsForm: FC = ({ btnCreateEl }) => { getTermUpdatingStatuses ); + const searchId = useAppSelector(getTermSearchId); + const isTermSearchFacetsSynced = useAppSelector(getTermSearchFacetsSynced); + const existingTerms = useAppSelector(getTermSearchResults); + + const [error, setError] = useState(null); + const defaultValues = useMemo( () => ({ name: term?.name ?? '', @@ -57,13 +66,31 @@ const TermsForm: FC = ({ btnCreateEl }) => { useEffect(() => { reset(defaultValues); - }, [defaultValues]); + }, [defaultValues, reset]); + + useEffect(() => { + if (searchId && isTermSearchFacetsSynced) { + dispatch(fetchTermsSearchResults({ searchId, page: 1, size: 1000 })); + } + }, [dispatch, searchId, isTermSearchFacetsSynced]); const clearState = () => { reset(); + setError(null); }; const onSubmit = (data: TermFormData) => { + const duplicateTerm = existingTerms.find( + (existingTerm: TermDetails) => + existingTerm.name === data.name && + existingTerm.namespace.name === data.namespaceName + ); + + if (duplicateTerm) { + setError('A term with the same name already exists in this namespace.'); + return; + } + const parsedData = { ...data }; (term && term.id ? dispatch(updateTerm({ termId: term.id, termFormData: parsedData })) @@ -81,12 +108,38 @@ const TermsForm: FC = ({ btnCreateEl }) => { const termFormTitle = ( - {term.id ? t('Edit') : t('Add')} {t('term')} + {term?.id ? t('Edit') : t('Add')} {t('term')} ); const termFormContent = () => (
+ {error && ( + setError(null)} + sx={{ + fontSize: '1.1rem', + color: 'inherit', + background: 'none', + border: 'none', + cursor: 'pointer', + padding: 0, + marginLeft: 2, + lineHeight: '1.6rem', + }} + > + × + + } + > + {error} + + )} = ({ btnCreateEl }) => { const termFormActionButtons = () => (