@applicaster/zapp-react-native-utils 14.0.0-rc.51 → 14.0.0-rc.52
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/actionsExecutor/ActionExecutorContext.tsx +60 -84
- package/actionsExecutor/ScreenActions.ts +164 -0
- package/actionsExecutor/StorageActions.ts +110 -0
- package/actionsExecutor/feedDecorator.ts +171 -0
- package/actionsExecutor/screenResolver.ts +11 -0
- package/analyticsUtils/AnalyticsEvents/helper.ts +1 -1
- package/analyticsUtils/__tests__/analyticsUtils.test.js +0 -11
- package/appUtils/contextKeysManager/contextResolver.ts +42 -1
- package/package.json +2 -2
- package/reactHooks/cell-click/__tests__/index.test.js +3 -0
- package/reactHooks/cell-click/index.ts +8 -1
- package/reactHooks/feed/__tests__/useBatchLoading.test.tsx +8 -2
- package/reactHooks/feed/__tests__/useFeedLoader.test.tsx +71 -31
- package/reactHooks/feed/index.ts +2 -0
- package/reactHooks/feed/useBatchLoading.ts +14 -9
- package/reactHooks/feed/useFeedLoader.tsx +36 -38
- package/reactHooks/feed/useLoadPipesDataDispatch.ts +57 -0
- package/reactHooks/navigation/useRoute.ts +7 -2
- package/reactHooks/navigation/useScreenStateStore.ts +8 -0
- package/storage/ScreenSingleValueProvider.ts +204 -0
- package/storage/ScreenStateMultiSelectProvider.ts +293 -0
- package/storage/StorageMultiSelectProvider.ts +192 -0
- package/storage/StorageSingleSelectProvider.ts +108 -0
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import { ContextKeysManager } from "./index";
|
|
2
2
|
import * as R from "ramda";
|
|
3
|
+
import * as _ from "lodash";
|
|
4
|
+
import { useScreenStateStore } from "../../reactHooks/navigation/useScreenStateStore";
|
|
3
5
|
|
|
4
|
-
interface IResolver {
|
|
6
|
+
export interface IResolver {
|
|
5
7
|
resolve: (string) => Promise<string | number | object>;
|
|
6
8
|
}
|
|
7
9
|
|
|
10
|
+
// TODO: Rename to ObjectKeyResolver or similar
|
|
8
11
|
export class EntryResolver implements IResolver {
|
|
9
12
|
entry: ZappEntry;
|
|
10
13
|
|
|
@@ -21,6 +24,28 @@ export class EntryResolver implements IResolver {
|
|
|
21
24
|
}
|
|
22
25
|
}
|
|
23
26
|
|
|
27
|
+
// TODO: Move to proper place
|
|
28
|
+
|
|
29
|
+
export class ScreenStateResolver implements IResolver {
|
|
30
|
+
constructor(
|
|
31
|
+
private screenStateStore: ReturnType<typeof useScreenStateStore>
|
|
32
|
+
) {}
|
|
33
|
+
|
|
34
|
+
async resolve(key: string) {
|
|
35
|
+
const screenState = this.screenStateStore.getState().data;
|
|
36
|
+
|
|
37
|
+
if (!key || key.length === 0) {
|
|
38
|
+
return screenState;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (key.includes(".")) {
|
|
42
|
+
return R.view(R.lensPath(key.split(".")), screenState);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return screenState?.[key];
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
24
49
|
export class ContextResolver implements IResolver {
|
|
25
50
|
resolve = async (compositeKey: string) =>
|
|
26
51
|
ContextKeysManager.instance.getKey(compositeKey);
|
|
@@ -64,3 +89,19 @@ export const resolveObjectValues = async (
|
|
|
64
89
|
|
|
65
90
|
return Object.fromEntries(resolvedEntries);
|
|
66
91
|
};
|
|
92
|
+
|
|
93
|
+
export const extractAtValues = _.memoize((input: any): string[] => {
|
|
94
|
+
return _.flatMapDeep(input, (value: any) => {
|
|
95
|
+
if (_.isString(value)) {
|
|
96
|
+
const matches = value.match(/@\{([^}]*)\}/g);
|
|
97
|
+
|
|
98
|
+
return matches ? matches.map((match) => match.slice(2, -1)) : [];
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (_.isObject(value)) {
|
|
102
|
+
return extractAtValues(_.values(value));
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return [];
|
|
106
|
+
});
|
|
107
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@applicaster/zapp-react-native-utils",
|
|
3
|
-
"version": "14.0.0-rc.
|
|
3
|
+
"version": "14.0.0-rc.52",
|
|
4
4
|
"description": "Applicaster Zapp React Native utilities package",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
},
|
|
28
28
|
"homepage": "https://github.com/applicaster/quickbrick#readme",
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@applicaster/applicaster-types": "14.0.0-rc.
|
|
30
|
+
"@applicaster/applicaster-types": "14.0.0-rc.52",
|
|
31
31
|
"buffer": "^5.2.1",
|
|
32
32
|
"camelize": "^1.0.0",
|
|
33
33
|
"dayjs": "^1.11.10",
|
|
@@ -26,6 +26,9 @@ jest.mock("@applicaster/zapp-react-native-utils/analyticsUtils/", () => ({
|
|
|
26
26
|
}));
|
|
27
27
|
|
|
28
28
|
jest.mock("@applicaster/zapp-react-native-utils/reactHooks/screen", () => ({
|
|
29
|
+
...jest.requireActual(
|
|
30
|
+
"@applicaster/zapp-react-native-utils/reactHooks/screen"
|
|
31
|
+
),
|
|
29
32
|
useTargetScreenData: jest.fn(() => ({})),
|
|
30
33
|
useCurrentScreenData: jest.fn(() => ({})),
|
|
31
34
|
}));
|
|
@@ -16,7 +16,8 @@ import { ActionExecutorContext } from "@applicaster/zapp-react-native-utils/acti
|
|
|
16
16
|
import { isFunction, noop } from "../../functionUtils";
|
|
17
17
|
import { useSendAnalyticsOnPress } from "../analytics";
|
|
18
18
|
import { logOnPress, warnEmptyContentType } from "./helpers";
|
|
19
|
-
import { useCurrentScreenData } from "../screen";
|
|
19
|
+
import { useCurrentScreenData, useScreenContext } from "../screen";
|
|
20
|
+
import { useScreenStateStore } from "../navigation/useScreenStateStore";
|
|
20
21
|
|
|
21
22
|
/**
|
|
22
23
|
* If onCellTap is defined execute the function and
|
|
@@ -42,10 +43,12 @@ export const useCellClick = ({
|
|
|
42
43
|
}: Props): onPressReturnFn => {
|
|
43
44
|
const { push, currentRoute } = useNavigation();
|
|
44
45
|
const { pathname } = useRoute();
|
|
46
|
+
const screenStateStore = useScreenStateStore();
|
|
45
47
|
|
|
46
48
|
const onCellTap: Option<Function> = React.useContext(CellTapContext);
|
|
47
49
|
const actionExecutor = React.useContext(ActionExecutorContext);
|
|
48
50
|
const screenData = useCurrentScreenData();
|
|
51
|
+
const screenState = useScreenContext()?.options;
|
|
49
52
|
|
|
50
53
|
const cellSelectable = toBooleanWithDefaultTrue(
|
|
51
54
|
component?.rules?.component_cells_selectable
|
|
@@ -83,6 +86,9 @@ export const useCellClick = ({
|
|
|
83
86
|
await actionExecutor?.handleEntryActions(selectedItem, {
|
|
84
87
|
component,
|
|
85
88
|
screenData,
|
|
89
|
+
screenState,
|
|
90
|
+
screenRoute: pathname,
|
|
91
|
+
screenStateStore,
|
|
86
92
|
});
|
|
87
93
|
}
|
|
88
94
|
|
|
@@ -117,6 +123,7 @@ export const useCellClick = ({
|
|
|
117
123
|
push,
|
|
118
124
|
sendAnalyticsOnPress,
|
|
119
125
|
screenData,
|
|
126
|
+
screenState,
|
|
120
127
|
]
|
|
121
128
|
);
|
|
122
129
|
|
|
@@ -2,12 +2,16 @@ import { renderHook } from "@testing-library/react-hooks";
|
|
|
2
2
|
import { allFeedsIsReady, useBatchLoading } from "../useBatchLoading";
|
|
3
3
|
import { WrappedWithProviders } from "@applicaster/zapp-react-native-utils/testUtils";
|
|
4
4
|
import { appStore } from "@applicaster/zapp-react-native-redux/AppStore";
|
|
5
|
+
import { waitFor } from "@testing-library/react-native";
|
|
5
6
|
|
|
6
7
|
jest.mock("../../navigation");
|
|
7
8
|
|
|
8
9
|
jest.mock(
|
|
9
10
|
"@applicaster/zapp-react-native-utils/reactHooks/screen/useScreenContext",
|
|
10
11
|
() => ({
|
|
12
|
+
...jest.requireActual(
|
|
13
|
+
"@applicaster/zapp-react-native-utils/reactHooks/screen/useScreenContext"
|
|
14
|
+
),
|
|
11
15
|
useScreenContext: jest.fn().mockReturnValue({ screen: {}, entry: {} }),
|
|
12
16
|
})
|
|
13
17
|
);
|
|
@@ -33,7 +37,7 @@ describe("useBatchLoading", () => {
|
|
|
33
37
|
jest.clearAllMocks();
|
|
34
38
|
});
|
|
35
39
|
|
|
36
|
-
it("loadPipesData start loading not started requests", () => {
|
|
40
|
+
it("loadPipesData start loading not started requests", async () => {
|
|
37
41
|
const store = {
|
|
38
42
|
zappPipes: {
|
|
39
43
|
url1: {
|
|
@@ -65,7 +69,9 @@ describe("useBatchLoading", () => {
|
|
|
65
69
|
|
|
66
70
|
const actions = (appStore.getStore() as any).getActions();
|
|
67
71
|
|
|
68
|
-
|
|
72
|
+
await waitFor(() => {
|
|
73
|
+
expect(actions).toHaveLength(2);
|
|
74
|
+
});
|
|
69
75
|
|
|
70
76
|
expect(actions[0]).toMatchObject({
|
|
71
77
|
type: "ZAPP_PIPES_REQUEST_START",
|
|
@@ -2,15 +2,12 @@ import { renderHook } from "@testing-library/react-hooks";
|
|
|
2
2
|
import * as R from "ramda";
|
|
3
3
|
import * as zappPipesModule from "@applicaster/zapp-react-native-redux/ZappPipes";
|
|
4
4
|
import * as reactReduxModules from "react-redux";
|
|
5
|
-
import { Provider } from "react-redux";
|
|
6
5
|
import * as React from "react";
|
|
7
|
-
import configureStore from "redux-mock-store";
|
|
8
|
-
import thunk from "redux-thunk";
|
|
9
6
|
import * as useRouteHook from "@applicaster/zapp-react-native-utils/reactHooks/navigation/useRoute";
|
|
10
7
|
import * as useNavigationHooks from "@applicaster/zapp-react-native-utils/reactHooks/navigation/useNavigation";
|
|
11
8
|
import { useFeedLoader } from "../useFeedLoader";
|
|
12
|
-
|
|
13
|
-
|
|
9
|
+
import { WrappedWithProviders } from "../../../testUtils";
|
|
10
|
+
import { ScreenStateResolver } from "../../../appUtils/contextKeysManager/contextResolver";
|
|
14
11
|
|
|
15
12
|
jest.useFakeTimers({ legacyFakeTimers: true });
|
|
16
13
|
|
|
@@ -55,13 +52,15 @@ const mockZappPipesData = {
|
|
|
55
52
|
|
|
56
53
|
describe("useFeedLoader", () => {
|
|
57
54
|
describe("with cached feed url", () => {
|
|
58
|
-
const store =
|
|
55
|
+
const store = {
|
|
59
56
|
plugins: [],
|
|
60
57
|
zappPipes: { "test://testfakeurl": mockZappPipesData },
|
|
61
|
-
}
|
|
58
|
+
};
|
|
62
59
|
|
|
63
|
-
const wrapper: React.FC<any> = ({ children }) => (
|
|
64
|
-
<
|
|
60
|
+
const wrapper: React.FC<any> = ({ children, ...props }) => (
|
|
61
|
+
<WrappedWithProviders store={props.store || store}>
|
|
62
|
+
{children}
|
|
63
|
+
</WrappedWithProviders>
|
|
65
64
|
);
|
|
66
65
|
|
|
67
66
|
it("returns cached feed", () => {
|
|
@@ -110,8 +109,10 @@ describe("useFeedLoader", () => {
|
|
|
110
109
|
describe("without cached feeds", () => {
|
|
111
110
|
const feedUrl = "test://testfakeurl2";
|
|
112
111
|
|
|
113
|
-
const wrapper: React.FC<any> = ({ children,
|
|
114
|
-
<
|
|
112
|
+
const wrapper: React.FC<any> = ({ children, ...props }) => (
|
|
113
|
+
<WrappedWithProviders store={props.store}>
|
|
114
|
+
{children}
|
|
115
|
+
</WrappedWithProviders>
|
|
115
116
|
);
|
|
116
117
|
|
|
117
118
|
it("It loads data for new url and returns it", () => {
|
|
@@ -123,10 +124,10 @@ describe("useFeedLoader", () => {
|
|
|
123
124
|
.spyOn(zappPipesModule, "loadPipesData")
|
|
124
125
|
.mockImplementation(jest.fn());
|
|
125
126
|
|
|
126
|
-
const initialStore =
|
|
127
|
+
const initialStore = {
|
|
127
128
|
plugins: [],
|
|
128
129
|
zappPipes: { "test://testfakeurl": "foobar" },
|
|
129
|
-
}
|
|
130
|
+
};
|
|
130
131
|
|
|
131
132
|
const { result, rerender } = renderHook(
|
|
132
133
|
() => useFeedLoader({ feedUrl: "test://testfakeurl2" }),
|
|
@@ -135,15 +136,19 @@ describe("useFeedLoader", () => {
|
|
|
135
136
|
|
|
136
137
|
expect(result.current.data).toBeNull();
|
|
137
138
|
|
|
138
|
-
expect(loadPipesDataSpy).
|
|
139
|
+
expect(loadPipesDataSpy).toHaveBeenCalledWith(feedUrl, {
|
|
139
140
|
clearCache: true,
|
|
140
141
|
riverId: undefined,
|
|
142
|
+
callback: expect.any(Function),
|
|
143
|
+
resolvers: {
|
|
144
|
+
screen: expect.any(ScreenStateResolver),
|
|
145
|
+
},
|
|
141
146
|
});
|
|
142
147
|
|
|
143
|
-
const store2 =
|
|
148
|
+
const store2 = {
|
|
144
149
|
plugins: [],
|
|
145
150
|
zappPipes: { "test://testfakeurl2": mockZappPipesData },
|
|
146
|
-
}
|
|
151
|
+
};
|
|
147
152
|
|
|
148
153
|
rerender({ store: store2 });
|
|
149
154
|
|
|
@@ -164,10 +169,10 @@ describe("useFeedLoader", () => {
|
|
|
164
169
|
.spyOn(reactReduxModules, "useDispatch")
|
|
165
170
|
.mockImplementation(() => jest.fn());
|
|
166
171
|
|
|
167
|
-
const initialStore =
|
|
172
|
+
const initialStore = {
|
|
168
173
|
plugins: [],
|
|
169
174
|
zappPipes: { "test://testfakeurl": "foobar" },
|
|
170
|
-
}
|
|
175
|
+
};
|
|
171
176
|
|
|
172
177
|
const { result, rerender } = renderHook(
|
|
173
178
|
() => useFeedLoader({ feedUrl: "test://testfakeurl2" }),
|
|
@@ -176,15 +181,22 @@ describe("useFeedLoader", () => {
|
|
|
176
181
|
|
|
177
182
|
expect(result.current.data).toBeNull();
|
|
178
183
|
|
|
179
|
-
expect(loadPipesDataSpy).
|
|
184
|
+
expect(loadPipesDataSpy.mock.calls[0][0]).toBe(feedUrl);
|
|
185
|
+
|
|
186
|
+
expect(loadPipesDataSpy.mock.calls[0][1]).toMatchObject({
|
|
180
187
|
clearCache: true,
|
|
181
188
|
riverId: undefined,
|
|
189
|
+
resolvers: {
|
|
190
|
+
screen: {
|
|
191
|
+
screenStateStore: expect.any(Function),
|
|
192
|
+
},
|
|
193
|
+
},
|
|
182
194
|
});
|
|
183
195
|
|
|
184
|
-
const store2 =
|
|
196
|
+
const store2 = {
|
|
185
197
|
plugins: [],
|
|
186
198
|
zappPipes: { "test://testfakeurl2": mockZappPipesData },
|
|
187
|
-
}
|
|
199
|
+
};
|
|
188
200
|
|
|
189
201
|
rerender({ store: store2 });
|
|
190
202
|
|
|
@@ -197,8 +209,10 @@ describe("useFeedLoader", () => {
|
|
|
197
209
|
const feedUrl = "test://testfakeurl";
|
|
198
210
|
const feedUrlWithNext = "test://withnexttestfakeurl";
|
|
199
211
|
|
|
200
|
-
const wrapper: React.FC<any> = ({ children,
|
|
201
|
-
<
|
|
212
|
+
const wrapper: React.FC<any> = ({ children, ...props }) => (
|
|
213
|
+
<WrappedWithProviders store={props.store || {}}>
|
|
214
|
+
{children}
|
|
215
|
+
</WrappedWithProviders>
|
|
202
216
|
);
|
|
203
217
|
|
|
204
218
|
describe("reloadData", () => {
|
|
@@ -211,10 +225,10 @@ describe("useFeedLoader", () => {
|
|
|
211
225
|
.spyOn(reactReduxModules, "useDispatch")
|
|
212
226
|
.mockImplementation(() => jest.fn());
|
|
213
227
|
|
|
214
|
-
const initialStore =
|
|
228
|
+
const initialStore = {
|
|
215
229
|
plugins: [],
|
|
216
230
|
zappPipes: { [feedUrl]: "foobar" },
|
|
217
|
-
}
|
|
231
|
+
};
|
|
218
232
|
|
|
219
233
|
const { result } = renderHook(() => useFeedLoader({ feedUrl }), {
|
|
220
234
|
wrapper,
|
|
@@ -223,11 +237,24 @@ describe("useFeedLoader", () => {
|
|
|
223
237
|
|
|
224
238
|
const { reloadData } = result.current;
|
|
225
239
|
|
|
226
|
-
reloadData();
|
|
240
|
+
reloadData?.();
|
|
241
|
+
|
|
242
|
+
expect(loadPipesDataSpy).toHaveBeenCalled();
|
|
243
|
+
|
|
244
|
+
expect(
|
|
245
|
+
loadPipesDataSpy.mock.calls[loadPipesDataSpy.mock.calls.length - 1][0]
|
|
246
|
+
).toBe(feedUrl);
|
|
227
247
|
|
|
228
|
-
expect(
|
|
248
|
+
expect(
|
|
249
|
+
loadPipesDataSpy.mock.calls[loadPipesDataSpy.mock.calls.length - 1][1]
|
|
250
|
+
).toMatchObject({
|
|
229
251
|
clearCache: true,
|
|
230
252
|
silentRefresh: true,
|
|
253
|
+
resolvers: {
|
|
254
|
+
screen: {
|
|
255
|
+
screenStateStore: expect.any(Function),
|
|
256
|
+
},
|
|
257
|
+
},
|
|
231
258
|
});
|
|
232
259
|
|
|
233
260
|
loadPipesDataSpy.mockRestore();
|
|
@@ -247,10 +274,10 @@ describe("useFeedLoader", () => {
|
|
|
247
274
|
.spyOn(reactReduxModules, "useDispatch")
|
|
248
275
|
.mockImplementation(() => jest.fn());
|
|
249
276
|
|
|
250
|
-
const initialStore =
|
|
277
|
+
const initialStore = {
|
|
251
278
|
plugins: [],
|
|
252
279
|
zappPipes: { [feedUrlWithNext]: { data: { next: nextUrl } } },
|
|
253
|
-
}
|
|
280
|
+
};
|
|
254
281
|
|
|
255
282
|
const { result } = renderHook(
|
|
256
283
|
() => useFeedLoader({ feedUrl: feedUrlWithNext }),
|
|
@@ -262,11 +289,24 @@ describe("useFeedLoader", () => {
|
|
|
262
289
|
|
|
263
290
|
const { loadNext } = result.current;
|
|
264
291
|
|
|
265
|
-
loadNext();
|
|
292
|
+
loadNext?.();
|
|
293
|
+
|
|
294
|
+
expect(loadPipesDataSpy).toHaveBeenCalled();
|
|
295
|
+
|
|
296
|
+
expect(
|
|
297
|
+
loadPipesDataSpy.mock.calls[loadPipesDataSpy.mock.calls.length - 1][0]
|
|
298
|
+
).toBe(nextUrl);
|
|
266
299
|
|
|
267
|
-
expect(
|
|
300
|
+
expect(
|
|
301
|
+
loadPipesDataSpy.mock.calls[loadPipesDataSpy.mock.calls.length - 1][1]
|
|
302
|
+
).toMatchObject({
|
|
268
303
|
parentFeed: feedUrlWithNext,
|
|
269
304
|
silentRefresh: true,
|
|
305
|
+
resolvers: {
|
|
306
|
+
screen: {
|
|
307
|
+
screenStateStore: expect.any(Function),
|
|
308
|
+
},
|
|
309
|
+
},
|
|
270
310
|
});
|
|
271
311
|
|
|
272
312
|
loadPipesDataSpy.mockRestore();
|
package/reactHooks/feed/index.ts
CHANGED
|
@@ -1,15 +1,12 @@
|
|
|
1
1
|
import { complement, compose, isNil, map, min, prop, take, uniq } from "ramda";
|
|
2
2
|
import * as React from "react";
|
|
3
|
-
import {
|
|
4
|
-
ZappPipes,
|
|
5
|
-
useAppDispatch,
|
|
6
|
-
useZappPipesFeed,
|
|
7
|
-
} from "@applicaster/zapp-react-native-redux";
|
|
3
|
+
import { useZappPipesFeed } from "@applicaster/zapp-react-native-redux";
|
|
8
4
|
import { isNilOrEmpty } from "../../reactUtils/helpers";
|
|
9
5
|
import { ZappPipesSearchContext } from "@applicaster/zapp-react-native-ui-components/Contexts";
|
|
10
6
|
import {
|
|
11
7
|
getInflatedDataSourceUrl,
|
|
12
8
|
getSearchContext,
|
|
9
|
+
useLoadPipesDataDispatch,
|
|
13
10
|
} from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
14
11
|
import { isGallery } from "@applicaster/zapp-react-native-utils/componentsUtils";
|
|
15
12
|
import { useScreenContext } from "../screen";
|
|
@@ -65,7 +62,6 @@ export const useBatchLoading = (
|
|
|
65
62
|
componentsToRender: { data?: ZappDataSource; component_type: string }[],
|
|
66
63
|
options: Options
|
|
67
64
|
) => {
|
|
68
|
-
const dispatch = useAppDispatch();
|
|
69
65
|
const { screen: screenContext, entry: entryContext } = useScreenContext();
|
|
70
66
|
const [searchContext] = ZappPipesSearchContext.useZappPipesContext();
|
|
71
67
|
const [hasEverBeenReady, setHasEverBeenReady] = React.useState(false);
|
|
@@ -122,6 +118,8 @@ export const useBatchLoading = (
|
|
|
122
118
|
|
|
123
119
|
const feeds = useZappPipesFeed(feedUrls);
|
|
124
120
|
|
|
121
|
+
const loadPipesDataDispatcher = useLoadPipesDataDispatch();
|
|
122
|
+
|
|
125
123
|
// dispatch loadPipesData for each feed that is not loaded
|
|
126
124
|
const runBatchLoading = React.useCallback(() => {
|
|
127
125
|
batchComponents.forEach((rawData: any) => {
|
|
@@ -140,13 +138,20 @@ export const useBatchLoading = (
|
|
|
140
138
|
|
|
141
139
|
if (mappedFeedUrl) {
|
|
142
140
|
// 4. load data
|
|
143
|
-
return
|
|
144
|
-
|
|
141
|
+
return loadPipesDataDispatcher(
|
|
142
|
+
mappedFeedUrl,
|
|
143
|
+
{
|
|
144
|
+
riverId: options.riverId,
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
withResolvers: true,
|
|
148
|
+
withScreenRouteMapping: true,
|
|
149
|
+
}
|
|
145
150
|
);
|
|
146
151
|
}
|
|
147
152
|
}
|
|
148
153
|
});
|
|
149
|
-
}, [feedUrls, feeds]);
|
|
154
|
+
}, [feedUrls, feeds, loadPipesDataDispatcher]);
|
|
150
155
|
|
|
151
156
|
React.useEffect(() => {
|
|
152
157
|
runBatchLoading();
|
|
@@ -1,15 +1,11 @@
|
|
|
1
1
|
import React, { useEffect } from "react";
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
ZappPipes,
|
|
5
|
-
useAppDispatch,
|
|
6
|
-
useZappPipesFeed,
|
|
7
|
-
} from "@applicaster/zapp-react-native-redux";
|
|
3
|
+
import { useZappPipesFeed } from "@applicaster/zapp-react-native-redux";
|
|
8
4
|
|
|
9
5
|
import { reactHooksLogger } from "../logger";
|
|
10
6
|
import { shouldDispatchData, useIsInitialRender } from "../utils";
|
|
11
7
|
import { useInflatedUrl } from "./useInflatedUrl";
|
|
12
|
-
import {
|
|
8
|
+
import { useLoadPipesDataDispatch } from "./useLoadPipesDataDispatch";
|
|
13
9
|
|
|
14
10
|
const logger = reactHooksLogger.addSubsystem("useFeedLoader");
|
|
15
11
|
|
|
@@ -51,29 +47,26 @@ export const useFeedLoader = ({
|
|
|
51
47
|
}, []);
|
|
52
48
|
|
|
53
49
|
const isInitialRender = useIsInitialRender();
|
|
54
|
-
const dispatch = useAppDispatch();
|
|
55
|
-
const { screenData } = useRoute();
|
|
56
50
|
|
|
57
51
|
const callableFeedUrl = useInflatedUrl({ feedUrl, mapping });
|
|
58
52
|
|
|
59
53
|
const currentFeed = useZappPipesFeed(callableFeedUrl);
|
|
60
54
|
|
|
61
|
-
const
|
|
62
|
-
(screenData as LegacyNavigationScreenData)?.targetScreen?.id ??
|
|
63
|
-
screenData?.id;
|
|
55
|
+
const loadPipesDataDispatcher = useLoadPipesDataDispatch();
|
|
64
56
|
|
|
65
57
|
const reloadData = React.useCallback<ReloadDataFunction>(
|
|
66
58
|
(silentRefresh = true, callback) => {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
59
|
+
loadPipesDataDispatcher(
|
|
60
|
+
callableFeedUrl,
|
|
61
|
+
{
|
|
62
|
+
clearCache: true,
|
|
63
|
+
silentRefresh,
|
|
64
|
+
callback,
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
withResolvers: true,
|
|
68
|
+
}
|
|
69
|
+
);
|
|
77
70
|
},
|
|
78
71
|
[callableFeedUrl]
|
|
79
72
|
);
|
|
@@ -82,15 +75,16 @@ export const useFeedLoader = ({
|
|
|
82
75
|
if (callableFeedUrl) {
|
|
83
76
|
const nextFeed = currentFeed?.data?.next;
|
|
84
77
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
78
|
+
loadPipesDataDispatcher(
|
|
79
|
+
nextFeed,
|
|
80
|
+
{
|
|
81
|
+
silentRefresh: true,
|
|
82
|
+
parentFeed: callableFeedUrl,
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
withResolvers: true,
|
|
86
|
+
}
|
|
87
|
+
);
|
|
94
88
|
}
|
|
95
89
|
}, [callableFeedUrl, currentFeed?.data?.next]);
|
|
96
90
|
|
|
@@ -99,12 +93,16 @@ export const useFeedLoader = ({
|
|
|
99
93
|
shouldDispatchData(callableFeedUrl, currentFeed, pipesOptions.clearCache)
|
|
100
94
|
) {
|
|
101
95
|
if (callableFeedUrl && !pipesOptions.skipLoading) {
|
|
102
|
-
|
|
103
|
-
|
|
96
|
+
loadPipesDataDispatcher(
|
|
97
|
+
callableFeedUrl,
|
|
98
|
+
{
|
|
104
99
|
...pipesOptions,
|
|
105
100
|
clearCache: true,
|
|
106
|
-
|
|
107
|
-
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
withResolvers: true,
|
|
104
|
+
withScreenRouteMapping: true,
|
|
105
|
+
}
|
|
108
106
|
);
|
|
109
107
|
} else if (!callableFeedUrl) {
|
|
110
108
|
logger.info({
|
|
@@ -133,11 +131,11 @@ export const useFeedLoader = ({
|
|
|
133
131
|
// Reload feed when feedUrl changes, unless skipLoading is true
|
|
134
132
|
useEffect(() => {
|
|
135
133
|
if (!isInitialRender && callableFeedUrl && !pipesOptions.skipLoading) {
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
);
|
|
134
|
+
loadPipesDataDispatcher(callableFeedUrl, pipesOptions, {
|
|
135
|
+
withResolvers: true,
|
|
136
|
+
});
|
|
139
137
|
}
|
|
140
|
-
}, [callableFeedUrl]);
|
|
138
|
+
}, [callableFeedUrl, isInitialRender, pipesOptions.skipLoading]);
|
|
141
139
|
|
|
142
140
|
return React.useMemo(() => {
|
|
143
141
|
if (!callableFeedUrl || !feedUrl) {
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import {
|
|
2
|
+
useAppDispatch,
|
|
3
|
+
ZappPipes,
|
|
4
|
+
} from "@applicaster/zapp-react-native-redux";
|
|
5
|
+
import { applyScreenRouteDefaults } from "@applicaster/zapp-react-native-redux/ZappPipes/feedProcessor";
|
|
6
|
+
import React from "react";
|
|
7
|
+
import { useScreenResolvers } from "../../actionsExecutor/screenResolver";
|
|
8
|
+
import { useRoute } from "../navigation";
|
|
9
|
+
import { useScreenStateStore } from "../navigation/useScreenStateStore";
|
|
10
|
+
|
|
11
|
+
export const useLoadPipesDataDispatch = () => {
|
|
12
|
+
const screenStateStore = useScreenStateStore();
|
|
13
|
+
const resolvers = useScreenResolvers();
|
|
14
|
+
const dispatch = useAppDispatch();
|
|
15
|
+
|
|
16
|
+
const { pathname, screenData } = useRoute();
|
|
17
|
+
|
|
18
|
+
const riverId =
|
|
19
|
+
(screenData as LegacyNavigationScreenData)?.targetScreen?.id ??
|
|
20
|
+
screenData?.id;
|
|
21
|
+
|
|
22
|
+
const onLoadCB = (options) => (data, _err) => {
|
|
23
|
+
options?.callback?.();
|
|
24
|
+
|
|
25
|
+
if (data) {
|
|
26
|
+
applyScreenRouteDefaults(data, screenStateStore, pathname);
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
return React.useCallback(
|
|
31
|
+
(
|
|
32
|
+
url: string,
|
|
33
|
+
options = {},
|
|
34
|
+
{
|
|
35
|
+
withResolvers = false,
|
|
36
|
+
withScreenRouteMapping = false,
|
|
37
|
+
}: {
|
|
38
|
+
withResolvers?: boolean;
|
|
39
|
+
withScreenRouteMapping?: boolean;
|
|
40
|
+
} = {}
|
|
41
|
+
) => {
|
|
42
|
+
if (url) {
|
|
43
|
+
dispatch(
|
|
44
|
+
ZappPipes.loadPipesData(url, {
|
|
45
|
+
riverId,
|
|
46
|
+
resolvers: withResolvers ? resolvers : undefined,
|
|
47
|
+
...options,
|
|
48
|
+
callback: withScreenRouteMapping
|
|
49
|
+
? onLoadCB(options)
|
|
50
|
+
: options?.callback,
|
|
51
|
+
})
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
[]
|
|
56
|
+
);
|
|
57
|
+
};
|
|
@@ -28,14 +28,19 @@ const isHookPathname = (pathname: string) => /^\/hooks\//.test(pathname);
|
|
|
28
28
|
|
|
29
29
|
type VariousScreenData = LegacyNavigationScreenData | ZappRiver | ZappEntry;
|
|
30
30
|
|
|
31
|
-
export const useRoute = (
|
|
31
|
+
export const useRoute = (
|
|
32
|
+
useLegacy = true
|
|
33
|
+
): {
|
|
32
34
|
screenData: VariousScreenData;
|
|
33
35
|
pathname: string;
|
|
34
36
|
} => {
|
|
35
37
|
const pathname = usePathname() || "";
|
|
36
38
|
const navigator = useNavigation();
|
|
39
|
+
const screenContext = useContext(ScreenDataContext);
|
|
37
40
|
|
|
38
|
-
const screenDataContext =
|
|
41
|
+
const screenDataContext = useLegacy
|
|
42
|
+
? legacyScreenData(screenContext)
|
|
43
|
+
: screenContext;
|
|
39
44
|
|
|
40
45
|
const { plugins, contentTypes, rivers } = usePickFromState([
|
|
41
46
|
"plugins",
|