From 8c5e56d9113460ce2c2be4c8e7e255fece577255 Mon Sep 17 00:00:00 2001 From: Jacques Date: Tue, 22 Jun 2021 17:19:58 +0200 Subject: [PATCH] feat: include loading state for reaction and action hooks --- package.json | 2 +- .../use-trixta-action-reaction/index.test.tsx | 6 ++-- .../use-trixta-action-reaction.ts | 11 +++---- src/React/hooks/use-trixta-action/types.ts | 6 +++- .../use-trixta-action/use-trixta-action.ts | 29 ++++++++++++++----- .../hooks/use-trixta-reaction/index.test.tsx | 6 ++-- .../use-trixta-reaction.ts | 28 ++++++++++++++---- .../selectors/tests/actions/selectors.test.js | 25 ++++++++++++++++ .../tests/reactions/selectors.test.js | 25 ++++++++++++++++ src/React/selectors/trixtaActions.ts | 16 ++++++++++ src/React/selectors/trixtaReactions.ts | 16 ++++++++++ 11 files changed, 145 insertions(+), 25 deletions(-) diff --git a/package.json b/package.json index 05f70c6b..3d234bbb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@trixta/trixta-js", - "version": "4.0.5", + "version": "4.0.6", "description": "Javascript library to integrate Trixta", "source": "src/index.ts", "main": "dist/@trixta/trixta-js.cjs.js", diff --git a/src/React/hooks/use-trixta-action-reaction/index.test.tsx b/src/React/hooks/use-trixta-action-reaction/index.test.tsx index e22ce999..7cbc9c22 100644 --- a/src/React/hooks/use-trixta-action-reaction/index.test.tsx +++ b/src/React/hooks/use-trixta-action-reaction/index.test.tsx @@ -19,7 +19,9 @@ describe('useTrixtaActionReaction', () => { }, ); - expect(result.error).toEqual(Error('Please provide actionName parameter.')); + expect(result.error).toEqual( + Error('Please provide reactionName parameter.'), + ); }); it('should throw error if no reactionName parameter', () => { @@ -249,7 +251,7 @@ describe('useTrixtaActionReaction', () => { expect(result.current.actionResponse).toBeUndefined(); expect(result.current.hasResponse).toBe(false); - expect(result.current.isInProgress).toBe(false); + expect(result.current.loading).toBe(true); act(() => { result.current.submitTrixtaActionResponse({ data: {} }); diff --git a/src/React/hooks/use-trixta-action-reaction/use-trixta-action-reaction.ts b/src/React/hooks/use-trixta-action-reaction/use-trixta-action-reaction.ts index b34ce58f..fa59b1c7 100644 --- a/src/React/hooks/use-trixta-action-reaction/use-trixta-action-reaction.ts +++ b/src/React/hooks/use-trixta-action-reaction/use-trixta-action-reaction.ts @@ -40,10 +40,6 @@ export const useTrixtaActionReaction = < TReactionResponseType, TReactionErrorType > => { - const { submitTrixtaAction, ...action } = useTrixtaAction< - TActionResponseType, - TActionErrorType - >({ ...actionProps, options: { autoSubmit }, actionParameters }); const reaction = useTrixtaReaction< TInitialData, TReactionResponseType, @@ -56,6 +52,11 @@ export const useTrixtaActionReaction = < requestForEffect: reactionProps.requestForEffect, }); + const { submitTrixtaAction, ...action } = useTrixtaAction< + TActionResponseType, + TActionErrorType + >({ ...actionProps, options: { autoSubmit }, actionParameters }); + const hasActionResponse = action.hasResponse; const hasReactionResponse = reaction.hasResponse; @@ -63,7 +64,7 @@ export const useTrixtaActionReaction = < initialData: reaction.initialData, hasRoleAccess: reaction.hasRoleAccess, isInProgress: action.isInProgress || reaction.isInProgress, - loading: reaction.loading, + loading: reaction.loading || action.loading, actionResponse: action.response, hasActionResponse, hasReactionResponse, diff --git a/src/React/hooks/use-trixta-action/types.ts b/src/React/hooks/use-trixta-action/types.ts index 946a1564..d9e8dac3 100644 --- a/src/React/hooks/use-trixta-action/types.ts +++ b/src/React/hooks/use-trixta-action/types.ts @@ -1,9 +1,9 @@ import { TrixtaActionBaseProps } from '../../../React/types/actions'; import { DefaultUnknownType, + submitTrixtaFunctionParameters, TrixtaInstance, TrixtaInstanceResponse, - submitTrixtaFunctionParameters, } from '../../types/common'; export interface UseTrixtaActionProps extends TrixtaActionBaseProps { options?: { @@ -59,4 +59,8 @@ export interface UseTrixtaActionHookReturn< * If 'true', there is a Trixta action instance response */ hasResponse: boolean; + /** + * If 'true',Trixta action is waiting to be loaded + */ + loading: boolean; } diff --git a/src/React/hooks/use-trixta-action/use-trixta-action.ts b/src/React/hooks/use-trixta-action/use-trixta-action.ts index d7437be9..57b38f40 100644 --- a/src/React/hooks/use-trixta-action/use-trixta-action.ts +++ b/src/React/hooks/use-trixta-action/use-trixta-action.ts @@ -7,11 +7,12 @@ import { clearTrixtaActionResponse, submitTrixtaActionResponse, } from '../../reduxActions/trixtaActions'; +import { makeSelectHasTrixtaRoleAccess } from '../../selectors/common'; import { - makeSelectHasTrixtaRoleAccess, + makeSelectIsTrixtaActionReadyForRole, makeSelectTrixtaActionRequestStatus, makeSelectTrixtaActionResponseInstancesForRole, -} from '../../selectors'; +} from '../../selectors/trixtaActions'; import { trixtaDebugger, TrixtaDebugType, @@ -70,6 +71,14 @@ export const useTrixtaAction = < selectHasRoleAccess(state, { roleName }), ); const roleActionProps = { roleName, actionName } as TrixtaActionBaseProps; + + const selectIsTrixtaActionReady = useMemo( + makeSelectIsTrixtaActionReadyForRole, + [], + ); + const isTrixtaActionReady = useSelector<{ trixta: TrixtaState }, boolean>( + (state) => selectIsTrixtaActionReady(state, roleActionProps), + ); // eslint-disable-next-line @typescript-eslint/no-explicit-any const selectActionResponses: any = useMemo( makeSelectTrixtaActionResponseInstancesForRole, @@ -119,7 +128,7 @@ export const useTrixtaAction = < requestEvent, errorEvent, }: submitTrixtaFunctionParameters) => { - if (!hasRoleAccess) return; + if (!hasRoleAccess || !isTrixtaActionReady) return; dispatch( submitTrixtaActionResponse({ @@ -132,11 +141,11 @@ export const useTrixtaAction = < }), ); }, - [dispatch, roleName, actionName, hasRoleAccess], + [dispatch, isTrixtaActionReady, roleName, actionName, hasRoleAccess], ); useEffect(() => { - if (options.autoSubmit) { + if (options.autoSubmit && isTrixtaActionReady) { if ( !deequal(actionParamatersRef.current, actionParameters) || actionParamatersRef.current === undefined @@ -145,7 +154,12 @@ export const useTrixtaAction = < submitTrixtaAction(actionParameters ?? { data: {} }); } } - }, [options.autoSubmit, submitTrixtaAction, actionParameters]); + }, [ + options.autoSubmit, + submitTrixtaAction, + isTrixtaActionReady, + actionParameters, + ]); const success = latestInstance ? latestInstance.response.success : false; const error = latestInstance ? latestInstance.response.error : false; @@ -162,7 +176,8 @@ export const useTrixtaAction = < return { latestInstance, hasRoleAccess, - isInProgress, + isInProgress: isTrixtaActionReady ? isInProgress : true, + loading: !isTrixtaActionReady, hasResponse: !!latestInstance, clearActionResponses, response: latestInstance?.response, diff --git a/src/React/hooks/use-trixta-reaction/index.test.tsx b/src/React/hooks/use-trixta-reaction/index.test.tsx index b64f390e..612a6e57 100644 --- a/src/React/hooks/use-trixta-reaction/index.test.tsx +++ b/src/React/hooks/use-trixta-reaction/index.test.tsx @@ -196,7 +196,7 @@ describe('useTrixtaReaction', () => { expect(result.current.latestResponse).toBeUndefined(); expect(result.current.latestInstance).toBeUndefined(); expect(result.current.hasResponse).toBe(false); - expect(result.current.isInProgress).toBe(false); + expect(result.current.isInProgress).toBe(true); act(() => { store.dispatch( @@ -230,7 +230,7 @@ describe('useTrixtaReaction', () => { expect(result.current.latestResponse).toBeUndefined(); expect(result.current.latestInstance).toBeUndefined(); expect(result.current.hasResponse).toBe(false); - expect(result.current.isInProgress).toBe(false); + expect(result.current.isInProgress).toBe(true); act(() => { store.dispatch( @@ -281,7 +281,7 @@ describe('useTrixtaReaction', () => { expect(result.current.latestResponse).toBeUndefined(); expect(result.current.latestInstance).toBeUndefined(); expect(result.current.hasResponse).toBe(false); - expect(result.current.isInProgress).toBe(false); + expect(result.current.isInProgress).toBe(true); act(() => { store.dispatch( diff --git a/src/React/hooks/use-trixta-reaction/use-trixta-reaction.ts b/src/React/hooks/use-trixta-reaction/use-trixta-reaction.ts index b38ce462..8613f951 100644 --- a/src/React/hooks/use-trixta-reaction/use-trixta-reaction.ts +++ b/src/React/hooks/use-trixta-reaction/use-trixta-reaction.ts @@ -5,12 +5,13 @@ import { clearTrixtaReactionResponse, submitTrixtaReactionResponse, } from '../../reduxActions/trixtaReactions'; +import { makeSelectHasTrixtaRoleAccess } from '../../selectors/common'; import { - makeSelectHasTrixtaRoleAccess, makeSelectIsTrixtaReactionLoading, makeSelectTrixtaReactionRequestStatus, makeSelectTrixtaReactionResponseInstancesForRole, -} from '../../selectors'; + makesSelectIsTrixtaReactionReadyForRole, +} from '../../selectors/trixtaReactions'; import { trixtaDebugger, TrixtaDebugType, @@ -75,6 +76,14 @@ export const useTrixtaReaction = < reactionName, } as TrixtaReactionBaseProps; // eslint-disable-next-line @typescript-eslint/no-explicit-any + + const selectIsTrixtaReactionReadyForRole: any = useMemo( + makesSelectIsTrixtaReactionReadyForRole, + [], + ); + const isTrixtaReactionReady = useSelector<{ trixta: TrixtaState }, boolean>( + (state) => selectIsTrixtaReactionReadyForRole(state, reactionRoleProps), + ); const selectReactionResponses: any = useMemo( makeSelectTrixtaReactionResponseInstancesForRole, [], @@ -124,7 +133,7 @@ export const useTrixtaReaction = < ref, requestEvent, }: submitTrixtaFunctionParameters) => { - if (!hasRoleAccess) return; + if (!hasRoleAccess || !isTrixtaReactionReady) return; dispatch( submitTrixtaReactionResponse({ @@ -138,7 +147,14 @@ export const useTrixtaReaction = < }), ); }, - [dispatch, roleName, reactionName, hasRoleAccess, latestInstance], + [ + dispatch, + roleName, + reactionName, + isTrixtaReactionReady, + hasRoleAccess, + latestInstance, + ], ); const success = latestInstance ? latestInstance.response.success : false; @@ -177,8 +193,8 @@ export const useTrixtaReaction = < hasRoleAccess, hasResponse: !!latestInstance, instances, - isInProgress, - loading, + isInProgress: isTrixtaReactionReady ? isInProgress : true, + loading: isTrixtaReactionReady ? loading : true, clearReactionResponses, submitTrixtaReaction, }; diff --git a/src/React/selectors/tests/actions/selectors.test.js b/src/React/selectors/tests/actions/selectors.test.js index 23d1dd2d..132199e6 100644 --- a/src/React/selectors/tests/actions/selectors.test.js +++ b/src/React/selectors/tests/actions/selectors.test.js @@ -146,6 +146,31 @@ describe('Trixta Selectors', () => { expect(selector(mockedState, props)).toEqual(expectedResult); }); + describe('makeSelectIsTrixtaActionReadyForRole', () => { + it('makeSelectIsTrixtaActionReadyForRole should return true if exists', () => { + const selector = trixtaActionSelectors.makeSelectIsTrixtaActionReadyForRole(); + const selectedAction = trixtaActionSelectors.selectTrixtActionStateSelector( + mockedState, + props, + ); + const expectedResult = selectedAction !== undefined; + expect(selector(mockedState, props)).toEqual(expectedResult); + expect(expectedResult).toEqual(true); + }); + + it('makeSelectIsTrixtaActionReadyForRole should return false if does not exist', () => { + const selector = trixtaActionSelectors.makeSelectIsTrixtaActionReadyForRole(); + props.actionName = 'nonense'; + const selectedAction = trixtaActionSelectors.selectTrixtActionStateSelector( + mockedState, + props, + ); + const expectedResult = selectedAction !== undefined; + expect(selector(mockedState, props)).toEqual(expectedResult); + expect(expectedResult).toEqual(false); + }); + }); + describe('selectors for TrixtaAction loading status For Role', () => { it('makeSelectIsTrixtaActionInProgress for existing role', () => { const selector = trixtaActionSelectors.makeSelectIsTrixtaActionInProgress(); diff --git a/src/React/selectors/tests/reactions/selectors.test.js b/src/React/selectors/tests/reactions/selectors.test.js index badea36e..4215d17d 100644 --- a/src/React/selectors/tests/reactions/selectors.test.js +++ b/src/React/selectors/tests/reactions/selectors.test.js @@ -105,6 +105,31 @@ describe('Trixta Selectors', () => { expect(selector(mockedState, props)).toEqual(expectedResult); }); + describe('makesSelectIsTrixtaReactionReadyForRole', () => { + it('makesSelectIsTrixtaReactionReadyForRole should return true if exists', () => { + const selector = trixtaReactionSelectors.makesSelectIsTrixtaReactionReadyForRole(); + const selectedReaction = trixtaReactionSelectors.selectTrixtReactionStateSelector( + mockedState, + props, + ); + const expectedResult = selectedReaction !== undefined; + expect(selector(mockedState, props)).toEqual(expectedResult); + expect(expectedResult).toEqual(true); + }); + + it('makesSelectIsTrixtaReactionReadyForRole should return false if does not exist', () => { + const selector = trixtaReactionSelectors.makesSelectIsTrixtaReactionReadyForRole(); + props.reactionName = 'nonense'; + const selectedReaction = trixtaReactionSelectors.selectTrixtReactionStateSelector( + mockedState, + props, + ); + const expectedResult = selectedReaction !== undefined; + expect(selector(mockedState, props)).toEqual(expectedResult); + expect(expectedResult).toEqual(false); + }); + }); + it('makeSelectTrixtaReactionCommonForRole', () => { const selector = trixtaReactionSelectors.makeSelectTrixtaReactionCommonForRole(); const selectedReaction = trixtaReactionSelectors.selectTrixtReactionStateSelector( diff --git a/src/React/selectors/trixtaActions.ts b/src/React/selectors/trixtaActions.ts index 113db0fe..9d052c5c 100644 --- a/src/React/selectors/trixtaActions.ts +++ b/src/React/selectors/trixtaActions.ts @@ -140,6 +140,22 @@ export const makeSelectTrixtaActionCommonForRole = (): OutputParametricSelector< return get(selectedAction, `common`, undefined); }); +/** + * Selects the actions[props.roleName:props.actionName] + * for the given props.roleName, props.actionName and returns true or false if it exists + */ +export const makeSelectIsTrixtaActionReadyForRole = (): OutputParametricSelector< + { + trixta: TrixtaState; + }, + TrixtaActionBaseProps, + boolean, + (res: TrixtaAction | undefined) => boolean +> => + createSelector([selectTrixtActionStateSelector], (selectedAction) => { + return selectedAction !== undefined; + }); + /** * Selects the actions[props.roleName:props.actionName].instances for the given props.roleName,props.actionName and returns the action instances */ diff --git a/src/React/selectors/trixtaReactions.ts b/src/React/selectors/trixtaReactions.ts index ff88db31..3b2d17a1 100644 --- a/src/React/selectors/trixtaReactions.ts +++ b/src/React/selectors/trixtaReactions.ts @@ -253,6 +253,22 @@ export const makesSelectTrixtaReactionForRole = (): OutputParametricSelector< return selectedReaction; }); +/** + * Selects the reactions[props.roleName:props.actionName] + * for the given props.roleName , props.reactionName and returns true or false if it exists + */ +export const makesSelectIsTrixtaReactionReadyForRole = (): OutputParametricSelector< + { + trixta: TrixtaState; + }, + TrixtaReactionBaseProps, + boolean, + (res: TrixtaReaction | undefined) => boolean +> => + createSelector([selectTrixtReactionStateSelector], (selectedReaction) => { + return selectedReaction !== undefined; + }); + /** * Returns the common for the props.reactionName */