Skip to content

Commit

Permalink
UILD-405: change state management library (#52)
Browse files Browse the repository at this point in the history
  • Loading branch information
SKarolFolio authored Dec 14, 2024
1 parent 253452e commit a4c7a4c
Show file tree
Hide file tree
Showing 139 changed files with 1,637 additions and 1,327 deletions.
21 changes: 0 additions & 21 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@
"react-intl": "^6.4.4",
"react-router-dom": "^6.20.0",
"react-select": "^5.8.0",
"recoil": "^0.7.7",
"uuid": "^9.0.0"
"uuid": "^9.0.0",
"zustand": "^5.0.1"
},
"devDependencies": {
"@testing-library/dom": "^10.4.0",
Expand Down
12 changes: 3 additions & 9 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
import { FC, Suspense, useEffect, useRef } from 'react';
import { Navigate, RouteObject, RouterProvider, createBrowserRouter } from 'react-router-dom';
import { RecoilRoot, useSetRecoilState } from 'recoil';
import { ErrorBoundary } from '@components/ErrorBoundary';
import { Loading } from '@components/Loading';
import { ROUTES } from '@common/constants/routes.constants';
import { DEFAULT_LOCALE } from '@common/constants/i18n.constants';
import { OKAPI_CONFIG } from '@common/constants/api.constants';
import { localStorageService } from '@common/services/storage';
import { Root, Search, EditWrapper, ExternalResourcePreview } from '@views';
import state from '@state';
import en from '../translations/ui-linked-data/en.json';
import { AsyncIntlProvider, ServicesProvider } from './providers';
import './App.scss';
import { useConfigState } from './store';

type IContainer = {
routePrefix?: string;
Expand Down Expand Up @@ -54,8 +53,7 @@ export const routes: RouteObject[] = [
const createRouter = (basename: string) => createBrowserRouter(routes, { basename });

const Container: FC<IContainer> = ({ routePrefix = '', config }) => {
const setCustomEvents = useSetRecoilState(state.config.customEvents);
const setHasNavigationOrigin = useSetRecoilState(state.config.hasNavigationOrigin);
const { setCustomEvents, setHasNavigationOrigin } = useConfigState();
const cachedMessages = useRef({ [DEFAULT_LOCALE]: en });

useEffect(() => {
Expand All @@ -82,9 +80,5 @@ export const App: FC<IContainer> = ({ routePrefix = '', config }) => {
config && localStorageService.serialize(OKAPI_CONFIG, config);
}, [config]);

return (
<RecoilRoot>
<Container routePrefix={routePrefix} config={config} />
</RecoilRoot>
);
return <Container routePrefix={routePrefix} config={config} />;
};
1 change: 1 addition & 0 deletions src/common/constants/bundle.constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const IS_PROD_MODE = import.meta.env.PROD;
7 changes: 3 additions & 4 deletions src/common/hooks/useCommonStatus.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import { useSetRecoilState } from 'recoil';
import { UserNotificationFactory } from '@common/services/userNotification';
import state from '@state';
import { useStatusState } from '@src/store';

export const useCommonStatus = () => {
const setCommonStatus = useSetRecoilState(state.status.commonMessages);
const { addStatusMessagesItem } = useStatusState();

return {
set: (l10nId: string, type: StatusType) => {
setCommonStatus(currentStatus => [...currentStatus, UserNotificationFactory.createMessage(type, l10nId)]);
addStatusMessagesItem?.(UserNotificationFactory.createMessage(type, l10nId));
},
};
};
20 changes: 11 additions & 9 deletions src/common/hooks/useComplexLookup.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { ChangeEvent, useCallback, useState } from 'react';
import { useRecoilState, useRecoilValue, useResetRecoilState } from 'recoil';
import {
generateEmptyValueUuid,
getLinkedField,
Expand All @@ -8,10 +7,10 @@ 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 state from '@state';
import { useModalControls } from './useModalControls';
import { useMarcData } from './useMarcData';
import { useServicesContext } from './useServicesContext';
import { useInputsState, useMarcPreviewState, useProfileState, useUIState } from '@src/store';

export const useComplexLookup = ({
entry,
Expand All @@ -26,14 +25,17 @@ export const useComplexLookup = ({
}) => {
const { selectedEntriesService } = useServicesContext() as Required<ServicesParams>;
const [localValue, setLocalValue] = useState<UserValueContents[]>(value || []);
const schema = useRecoilValue(state.config.schema);
const marcPreviewMetadata = useRecoilValue(state.data.marcPreviewMetadata);
const [selectedEntries, setSelectedEntries] = useRecoilState(state.config.selectedEntries);
const resetMarcPreviewData = useResetRecoilState(state.data.marcPreviewData);
const resetMarcPreviewMetadata = useResetRecoilState(state.data.marcPreviewMetadata);
const resetIsMarcPreviewOpen = useResetRecoilState(state.ui.isMarcPreviewOpen);
const { schema } = useProfileState();
const { selectedEntries, setSelectedEntries } = useInputsState();
const {
setComplexValue,
resetComplexValue: resetMarcPreviewData,
metadata: marcPreviewMetadata,
resetMetadata: resetMarcPreviewMetadata,
} = useMarcPreviewState();
const { resetIsMarcPreviewOpen } = useUIState();
const { isModalOpen, setIsModalOpen, openModal } = useModalControls();
const { fetchMarcData } = useMarcData(state.data.marcPreviewData);
const { fetchMarcData } = useMarcData(setComplexValue);
const { uuid, linkedEntry } = entry;
const linkedField = getLinkedField({ schema, linkedEntry });

Expand Down
6 changes: 2 additions & 4 deletions src/common/hooks/useComplexLookupSearchResults.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,17 @@
import { useCallback, useMemo } from 'react';
import { useRecoilValue } from 'recoil';
import { useIntl } from 'react-intl';
import { type Row } from '@components/Table';
import { useSearchContext } from '@common/hooks/useSearchContext';
import { ComplexLookupSearchResultsProps } from '@components/ComplexLookupField/ComplexLookupSearchResults';
import state from '@state';
import { useSearchState } from '@src/store';

export const useComplexLookupSearchResults = ({
onTitleClick,
tableConfig,
searchResultsFormatter,
}: ComplexLookupSearchResultsProps) => {
const { onAssignRecord } = useSearchContext();
const data = useRecoilValue(state.search.data);
const sourceData = useRecoilValue(state.search.sourceData);
const { data, sourceData } = useSearchState();
const { formatMessage } = useIntl();

const applyActionItems = useCallback(
Expand Down
27 changes: 14 additions & 13 deletions src/common/hooks/useConfig.hook.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import { useRef } from 'react';
import { useRecoilState, useSetRecoilState } from 'recoil';
import { v4 as uuidv4 } from 'uuid';
import state from '@state';
import { fetchProfiles } from '@common/api/profiles.api';
import { PROFILE_NAMES } from '@common/constants/bibframe.constants';
import { getPrimaryEntitiesFromRecord, getRecordTitle } from '@common/helpers/record.helper';
import { useInputsState, useProfileState } from '@src/store';
import { useProcessedRecordAndSchema } from './useProcessedRecordAndSchema.hook';
import { useServicesContext } from './useServicesContext';

Expand All @@ -31,15 +30,17 @@ type IBuildSchema = {
export const useConfig = () => {
const { schemaCreatorService, userValuesService, selectedEntriesService } =
useServicesContext() as Required<ServicesParams>;
const [profiles, setProfiles] = useRecoilState(state.config.profiles);
const setSelectedProfile = useSetRecoilState(state.config.selectedProfile);
const setUserValues = useSetRecoilState(state.inputs.userValues);
const [preparedFields, setPreparedFields] = useRecoilState(state.config.preparedFields);
const setSchema = useSetRecoilState(state.config.schema);
const setInitialSchemaKey = useSetRecoilState(state.config.initialSchemaKey);
const setSelectedEntries = useSetRecoilState(state.config.selectedEntries);
const setPreviewContent = useSetRecoilState(state.inputs.previewContent);
const setSelectedRecordBlocks = useSetRecoilState(state.inputs.selectedRecordBlocks);
const {
profiles,
setProfiles,
setSelectedProfile,
preparedFields,
setPreparedFields,
setInitialSchemaKey,
setSchema,
} = useProfileState();
const { setUserValues, previewContent, setPreviewContent, setSelectedRecordBlocks, setSelectedEntries } =
useInputsState();
const { getProcessedRecordAndSchema } = useProcessedRecordAndSchema();
const isProcessingProfiles = useRef(false);

Expand Down Expand Up @@ -125,8 +126,8 @@ export const useConfig = () => {
});

if (previewParams && recordId) {
setPreviewContent(prev => [
...(previewParams.singular ? [] : prev.filter(({ id }) => id !== recordId)),
setPreviewContent([
...(previewParams.singular ? [] : previewContent.filter(({ id }) => id !== recordId)),
{
id: recordId,
base: updatedSchema,
Expand Down
14 changes: 7 additions & 7 deletions src/common/hooks/useContainerEvents.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import state from '@state';
import { useRecoilValue } from 'recoil';
import { IS_EMBEDDED_MODE } from '@common/constants/build.constants';
import { dispatchEventWrapper, getWrapperAsWebComponent } from '@common/helpers/dom.helper';
import { useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
import { IS_EMBEDDED_MODE } from '@common/constants/build.constants';
import { dispatchEventWrapper, getWrapperAsWebComponent } from '@common/helpers/dom.helper';
import { ROUTES } from '@common/constants/routes.constants';
import { useConfigState, useStatusState } from '@src/store';

type IUseContainerEvents =
| {
Expand All @@ -14,16 +13,17 @@ type IUseContainerEvents =
| undefined;

export const useContainerEvents = ({ onTriggerModal, watchEditedState = false }: IUseContainerEvents = {}) => {
const hasNavigationOrigin = useRecoilValue(state.config.hasNavigationOrigin);
const isEdited = useRecoilValue(state.status.recordIsEdited);
const { hasNavigationOrigin } = useConfigState();
const { isRecordEdited: isEdited } = useStatusState();
const { customEvents } = useConfigState();
const {
BLOCK_NAVIGATION,
UNBLOCK_NAVIGATION,
TRIGGER_MODAL,
PROCEED_NAVIGATION,
NAVIGATE_TO_ORIGIN,
DROP_NAVIGATE_TO_ORIGIN,
} = useRecoilValue(state.config.customEvents) ?? {};
} = customEvents ?? {};
const navigate = useNavigate();

useEffect(() => {
Expand Down
24 changes: 6 additions & 18 deletions src/common/hooks/useFetchSearchData.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import { useCallback } from 'react';
import { useSetRecoilState, useRecoilState, SetterOrUpdater, useResetRecoilState } from 'recoil';
import { getByIdentifier } from '@common/api/search.api';
import { SearchIdentifiers, SearchSegment } from '@common/constants/search.constants';
import { SearchableIndexQuerySelector } from '@common/constants/complexLookup.constants';
import { StatusType } from '@common/constants/status.constants';
import { normalizeQuery } from '@common/helpers/search.helper';
import { normalizeLccn } from '@common/helpers/validations.helper';
import { UserNotificationFactory } from '@common/services/userNotification';
import state from '@state';
import { useLoadingState, useSearchState, useStatusState } from '@src/store';
import { useSearchContext } from './useSearchContext';

export const useFetchSearchData = () => {
Expand All @@ -24,13 +23,9 @@ export const useFetchSearchData = () => {
buildSearchQuery,
precedingRecordsCount,
} = useSearchContext();
const setIsLoading = useSetRecoilState(state.loadingState.isLoading);
const setMessage = useSetRecoilState(state.search.message);
const [data, setData] = useRecoilState(state.search.data);
const resetData = useResetRecoilState(state.search.data);
const setPageMetadata = useSetRecoilState(state.search.pageMetadata);
const setStatusMessages = useSetRecoilState(state.status.commonMessages);
const resetStatusMessage = useResetRecoilState(state.status.commonMessages);
const { setIsLoading } = useLoadingState();
const { setMessage, data, setData, resetData, setPageMetadata } = useSearchState();
const { addStatusMessagesItem, resetStatusMessages } = useStatusState();

const validateAndNormalizeQuery = useCallback(
(type: SearchIdentifiers, query: string) => {
Expand Down Expand Up @@ -130,13 +125,6 @@ export const useFetchSearchData = () => {
});
};

const handleFetchError = (setStatusMessages: SetterOrUpdater<StatusEntry[]>) => {
setStatusMessages(currentStatus => [
...currentStatus,
UserNotificationFactory.createMessage(StatusType.error, 'ld.errorFetching'),
]);
};

const fetchData = useCallback(
async ({
query,
Expand All @@ -145,7 +133,7 @@ export const useFetchSearchData = () => {
selectedSegment,
baseQuerySelector = SearchableIndexQuerySelector.Query,
}: FetchDataParams) => {
resetStatusMessage();
resetStatusMessages();
const selectedNavigationSegment = selectedSegment ?? navigationSegment?.value;

data && resetData();
Expand Down Expand Up @@ -189,7 +177,7 @@ export const useFetchSearchData = () => {
setData(content);
setPageMetadata({ totalPages, totalElements: totalRecords, prev, next });
} catch {
handleFetchError(setStatusMessages);
addStatusMessagesItem?.(UserNotificationFactory.createMessage(StatusType.error, 'ld.errorFetching'));
} finally {
setIsLoading(false);
}
Expand Down
11 changes: 3 additions & 8 deletions src/common/hooks/useLoadSearchResults.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,17 @@
import { useEffect, useRef } from 'react';
import { useSearchParams } from 'react-router-dom';
import { useRecoilState, useResetRecoilState, useSetRecoilState } from 'recoil';
import { SearchQueryParams } from '@common/constants/routes.constants';
import { SEARCH_RESULTS_LIMIT, SearchIdentifiers } from '@common/constants/search.constants';
import { useLoadingState, useSearchState } from '@src/store';
import { useSearchContext } from './useSearchContext';
import state from '@state';

export const useLoadSearchResults = (
fetchData: ({ query, searchBy, offset, selectedSegment, baseQuerySelector }: FetchDataParams) => Promise<void>,
) => {
const { hasSearchParams, defaultSearchBy, defaultQuery, getSearchSourceData, getSearchFacetsData } =
useSearchContext();
const setData = useSetRecoilState(state.search.data);
const setSearchBy = useSetRecoilState(state.search.index);
const setIsLoading = useSetRecoilState(state.loadingState.isLoading);
const setQuery = useSetRecoilState(state.search.query);
const [forceRefresh, setForceRefresh] = useRecoilState(state.search.forceRefresh);
const resetFacetsData = useResetRecoilState(state.search.facetsData);
const { setIsLoading } = useLoadingState();
const { setQuery, setData, setSearchBy, forceRefresh, setForceRefresh, resetFacetsData } = useSearchState();
const [searchParams] = useSearchParams();
const queryParam = searchParams.get(SearchQueryParams.Query);
const searchByParam = searchParams.get(SearchQueryParams.SearchBy);
Expand Down
18 changes: 6 additions & 12 deletions src/common/hooks/useMarcData.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
import { RecoilState, useResetRecoilState, useSetRecoilState } from 'recoil';
import { getMarcRecord } from '@common/api/records.api';
import { StatusType } from '@common/constants/status.constants';
import { UserNotificationFactory } from '@common/services/userNotification';
import state from '@state';
import { useLoadingState, useStatusState } from '@src/store';

export const useMarcData = <T>(marcState: RecoilState<T>) => {
const setMarcPreviewData = useSetRecoilState(marcState);
const clearMarcData = useResetRecoilState(marcState);
const setIsLoading = useSetRecoilState(state.loadingState.isLoading);
const setStatus = useSetRecoilState(state.status.commonMessages);
export const useMarcData = (setMarcPreviewData: (value: any) => void) => {
const { setIsLoading } = useLoadingState();
const { addStatusMessagesItem } = useStatusState();

const fetchMarcData = async (recordId?: string, endpointUrl?: string): Promise<MarcDTO | undefined> => {
if (!recordId) return undefined;
Expand All @@ -22,16 +19,13 @@ export const useMarcData = <T>(marcState: RecoilState<T>) => {

setMarcPreviewData(marcData);
} catch (error) {
setStatus(currentStatus => [
...currentStatus,
UserNotificationFactory.createMessage(StatusType.error, 'ld.cantLoadMarc'),
]);
addStatusMessagesItem?.(UserNotificationFactory.createMessage(StatusType.error, 'ld.cantLoadMarc'));
} finally {
setIsLoading(false);
}

return marcData;
};

return { fetchMarcData, clearMarcData };
return { fetchMarcData };
};
5 changes: 2 additions & 3 deletions src/common/hooks/useNavigateToEditPage.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { ROUTES, QueryParams } from '@common/constants/routes.constants';
import state from '@state';
import { useSearchState } from '@src/store';
import { useNavigate } from 'react-router-dom';
import { useRecoilValue } from 'recoil';

export const useNavigateToEditPage = () => {
const navigate = useNavigate();
const navigationState = useRecoilValue(state.search.navigationState);
const { navigationState } = useSearchState();

const navigateAsDuplicate = (duplicateId: string) => {
navigate(`${ROUTES.RESOURCE_CREATE.uri}?${QueryParams.CloneOf}=${duplicateId}`, { state: navigationState });
Expand Down
Loading

0 comments on commit a4c7a4c

Please sign in to comment.