diff --git a/src/altinn-app-frontend/src/features/form/data/fetch/fetchFormDataSagas.ts b/src/altinn-app-frontend/src/features/form/data/fetch/fetchFormDataSagas.ts index 515438f635..602e1ce166 100644 --- a/src/altinn-app-frontend/src/features/form/data/fetch/fetchFormDataSagas.ts +++ b/src/altinn-app-frontend/src/features/form/data/fetch/fetchFormDataSagas.ts @@ -28,9 +28,10 @@ import { } from 'src/utils/appUrlHelper'; import { convertModelToDataBinding } from 'src/utils/databindings'; import { putWithoutConfig } from 'src/utils/networking'; +import { waitFor } from 'src/utils/sagas'; import type { IApplicationMetadata } from 'src/shared/resources/applicationMetadata'; import type { IProcessState } from 'src/shared/resources/process'; -import type { ILayoutSets, IRuntimeState } from 'src/types'; +import type { ILayoutSets } from 'src/types'; import { get } from 'altinn-shared/utils'; import type { IInstance } from 'altinn-shared/types'; @@ -135,18 +136,6 @@ function* fetchFormDataStateless(applicationMetadata: IApplicationMetadata) { } } -function* waitFor(selector) { - if (yield select(selector)) { - return; - } - while (true) { - yield take('*'); - if (yield select(selector)) { - return; - } - } -} - export function* watchFetchFormDataInitialSaga(): SagaIterator { while (true) { yield take(FormDataActions.fetchInitial); @@ -157,10 +146,8 @@ export function* watchFetchFormDataInitialSaga(): SagaIterator { yield take(DataModelActions.fetchJsonSchemaFulfilled); const allowAnonymous = yield select(makeGetAllowAnonymousSelector()); if (!allowAnonymous) { - call( - waitFor, - (state: IRuntimeState) => - currentSelectedPartyIdSelector(state) !== undefined, + yield waitFor( + (state) => currentSelectedPartyIdSelector(state) !== undefined, ); } } else if ( diff --git a/src/altinn-app-frontend/src/shared/resources/language/fetch/fetchLanguageSagas.test.ts b/src/altinn-app-frontend/src/shared/resources/language/fetch/fetchLanguageSagas.test.ts index 959e5fd52e..47595f3400 100644 --- a/src/altinn-app-frontend/src/shared/resources/language/fetch/fetchLanguageSagas.test.ts +++ b/src/altinn-app-frontend/src/shared/resources/language/fetch/fetchLanguageSagas.test.ts @@ -10,7 +10,7 @@ import { watchFetchLanguageSaga, } from 'src/shared/resources/language/fetch/fetchLanguageSagas'; import { LanguageActions } from 'src/shared/resources/language/languageSlice'; -import { ProfileActions } from 'src/shared/resources/profile/profileSlice'; +import { waitForFunc } from 'src/utils/sagas'; import { getLanguageFromCode } from 'altinn-shared/language'; import * as language from 'altinn-shared/language'; @@ -60,7 +60,9 @@ describe('fetchLanguageSagas', () => { expect(generator.next().value).toEqual( select(makeGetAllowAnonymousSelector()), ); - expect(generator.next().value).toEqual(take(ProfileActions.fetchFulfilled)); + expect(generator.next().value).toEqual( + call(waitForFunc, expect.anything()), + ); expect(generator.next().value).toEqual(call(fetchLanguageSaga)); expect(generator.next().value).toEqual( takeLatest(LanguageActions.updateSelectedAppLanguage, fetchLanguageSaga), diff --git a/src/altinn-app-frontend/src/shared/resources/language/fetch/fetchLanguageSagas.ts b/src/altinn-app-frontend/src/shared/resources/language/fetch/fetchLanguageSagas.ts index a3a4374bc0..ac12628997 100644 --- a/src/altinn-app-frontend/src/shared/resources/language/fetch/fetchLanguageSagas.ts +++ b/src/altinn-app-frontend/src/shared/resources/language/fetch/fetchLanguageSagas.ts @@ -6,8 +6,8 @@ import { appLanguageStateSelector } from 'src/selectors/appLanguageStateSelector import { makeGetAllowAnonymousSelector } from 'src/selectors/getAllowAnonymous'; import { ApplicationMetadataActions } from 'src/shared/resources/applicationMetadata/applicationMetadataSlice'; import { LanguageActions } from 'src/shared/resources/language/languageSlice'; -import { ProfileActions } from 'src/shared/resources/profile/profileSlice'; import { QueueActions } from 'src/shared/resources/queue/queueSlice'; +import { waitFor } from 'src/utils/sagas'; import { getLanguageFromCode } from 'altinn-shared/language'; @@ -32,7 +32,7 @@ export function* watchFetchLanguageSaga(): SagaIterator { const allowAnonymous = yield select(makeGetAllowAnonymousSelector()); if (!allowAnonymous) { - yield take(ProfileActions.fetchFulfilled); + yield waitFor((state) => !!state.profile.profile); } yield call(fetchLanguageSaga); diff --git a/src/altinn-app-frontend/src/shared/resources/textResources/fetch/fetchTextResourcesSagas.test.ts b/src/altinn-app-frontend/src/shared/resources/textResources/fetch/fetchTextResourcesSagas.test.ts index 84e9910f6a..2f2aca598a 100644 --- a/src/altinn-app-frontend/src/shared/resources/textResources/fetch/fetchTextResourcesSagas.test.ts +++ b/src/altinn-app-frontend/src/shared/resources/textResources/fetch/fetchTextResourcesSagas.test.ts @@ -7,7 +7,6 @@ import { makeGetAllowAnonymousSelector } from 'src/selectors/getAllowAnonymous'; import { profileStateSelector } from 'src/selectors/simpleSelectors'; import { ApplicationMetadataActions } from 'src/shared/resources/applicationMetadata/applicationMetadataSlice'; import { LanguageActions } from 'src/shared/resources/language/languageSlice'; -import { ProfileActions } from 'src/shared/resources/profile/profileSlice'; import { fetchTextResources, watchFetchTextResourcesSaga, @@ -15,6 +14,7 @@ import { import { TextResourcesActions } from 'src/shared/resources/textResources/textResourcesSlice'; import { textResourcesUrl } from 'src/utils/appUrlHelper'; import { get } from 'src/utils/networking'; +import { waitForFunc } from 'src/utils/sagas'; import type { IProfile } from 'altinn-shared/types'; @@ -31,7 +31,9 @@ describe('fetchTextResourcesSagas', () => { expect(generator.next().value).toEqual( select(makeGetAllowAnonymousSelector()), ); - expect(generator.next().value).toEqual(take(ProfileActions.fetchFulfilled)); + expect(generator.next().value).toEqual( + call(waitForFunc, expect.anything()), + ); expect(generator.next().value).toEqual(call(fetchTextResources)); expect(generator.next().value).toEqual( takeLatest(TextResourcesActions.fetch, fetchTextResources), diff --git a/src/altinn-app-frontend/src/shared/resources/textResources/fetch/fetchTextResourcesSagas.ts b/src/altinn-app-frontend/src/shared/resources/textResources/fetch/fetchTextResourcesSagas.ts index 059e7bc57c..ed6ce06438 100644 --- a/src/altinn-app-frontend/src/shared/resources/textResources/fetch/fetchTextResourcesSagas.ts +++ b/src/altinn-app-frontend/src/shared/resources/textResources/fetch/fetchTextResourcesSagas.ts @@ -6,11 +6,11 @@ import { appLanguageStateSelector } from 'src/selectors/appLanguageStateSelector import { makeGetAllowAnonymousSelector } from 'src/selectors/getAllowAnonymous'; import { ApplicationMetadataActions } from 'src/shared/resources/applicationMetadata/applicationMetadataSlice'; import { LanguageActions } from 'src/shared/resources/language/languageSlice'; -import { ProfileActions } from 'src/shared/resources/profile/profileSlice'; import { QueueActions } from 'src/shared/resources/queue/queueSlice'; import { TextResourcesActions } from 'src/shared/resources/textResources/textResourcesSlice'; import { oldTextResourcesUrl, textResourcesUrl } from 'src/utils/appUrlHelper'; import { get } from 'src/utils/networking'; +import { waitFor } from 'src/utils/sagas'; export function* fetchTextResources(): SagaIterator { try { @@ -49,10 +49,10 @@ export function* watchFetchTextResourcesSaga(): SagaIterator { ]); const allowAnonymous = yield select(makeGetAllowAnonymousSelector()); - if (!allowAnonymous) { - yield take(ProfileActions.fetchFulfilled); + yield waitFor((state) => !!state.profile.profile); } + yield call(fetchTextResources); yield takeLatest(TextResourcesActions.fetch, fetchTextResources); yield takeLatest( diff --git a/src/altinn-app-frontend/src/utils/sagas.ts b/src/altinn-app-frontend/src/utils/sagas.ts new file mode 100644 index 0000000000..0a3d93dfbe --- /dev/null +++ b/src/altinn-app-frontend/src/utils/sagas.ts @@ -0,0 +1,27 @@ +import { call, select, take } from 'redux-saga/effects'; +import type { SagaIterator } from 'redux-saga'; + +import type { IRuntimeState } from 'src/types'; + +export function* waitForFunc( + selector: (state: IRuntimeState) => boolean, +): SagaIterator { + if (yield select(selector)) { + return; + } + while (true) { + yield take('*'); + if (yield select(selector)) { + return; + } + } +} + +/** + * This saga effect allows you to wait for a specific state to change. It will wait for new actions to be dispatched + * until your selector returns true, and it might be a safer way to wait than running yield take(...) on the action + * you wanted to wait for (as this will return immediately if the state already is as expected, instead of waiting + * for the event in question). + */ +export const waitFor = (selector: (state: IRuntimeState) => boolean) => + call(waitForFunc, selector);