@applicaster/quick-brick-core 12.0.0-alpha.5040434238 → 12.0.0-alpha.5050333009

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.
@@ -64,6 +64,9 @@ import { ZappPipesEntryContext } from "@applicaster/zapp-react-native-ui-compone
64
64
  import { PlayNextState } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/OverlayObserver/OverlaysObserver";
65
65
  import { inflateUrl } from "@applicaster/zapp-react-native-ui-components/Components/LinkHandler/LinkHandler";
66
66
  import { useModalStore } from "@applicaster/zapp-react-native-utils/modalState";
67
+ import { useSubscriberFor } from "@applicaster/zapp-react-native-utils/reactHooks/useSubscriberFor";
68
+ import { QBUIComponentEvents } from "@applicaster/zapp-react-native-ui-components/events";
69
+ import { Hook } from "@applicaster/zapp-react-native-utils/appUtils/HooksManager/Hook";
67
70
 
68
71
  const logger = coreAppLogger.addSubsystem("Navigator");
69
72
 
@@ -73,17 +76,6 @@ type Props = {
73
76
  plugins?: QuickBrickPlugin[];
74
77
  };
75
78
 
76
- type EntryWithParent = ZappEntry & { parent?: EntryWithParent };
77
-
78
- type SingleEntry = {
79
- data: EntryWithParent;
80
- route: string;
81
- id: string;
82
- parentId?: string;
83
- };
84
-
85
- type EntryContextType = { [K in string]: SingleEntry };
86
-
87
79
  const navigationActions = {
88
80
  [ACTIONS.PUSH]: push,
89
81
  [ACTIONS.REPLACE]: replace,
@@ -120,9 +112,7 @@ export function NavigationProvider({ children }: Props) {
120
112
  const pathname = state?.location?.pathname;
121
113
  const pathnameRef = React.useRef(pathname);
122
114
 
123
- const { context }: EntryContextType = React.useContext(
124
- ZappPipesEntryContext.Context
125
- );
115
+ const { context } = React.useContext(ZappPipesEntryContext.Context);
126
116
 
127
117
  const { openModal, dismissModal } = useModalStore();
128
118
 
@@ -130,6 +120,10 @@ export function NavigationProvider({ children }: Props) {
130
120
 
131
121
  const online = useConnectionInfo(true);
132
122
 
123
+ const replaceEvent = useSubscriberFor(
124
+ QBUIComponentEvents.navigatorReplaceItem
125
+ );
126
+
133
127
  React.useEffect(() => {
134
128
  stateRef.current = state;
135
129
  pathnameRef.current = pathname;
@@ -259,6 +253,7 @@ export function NavigationProvider({ children }: Props) {
259
253
  item?.id !==
260
254
  legacyScreenData(state?.location?.state as NavigationScreenData)?.id
261
255
  ) {
256
+ replaceEvent();
262
257
  navigateTo(item, ACTIONS.REPLACE, options);
263
258
  }
264
259
  };
@@ -275,7 +270,7 @@ export function NavigationProvider({ children }: Props) {
275
270
  route.includes(pathname)
276
271
  );
277
272
 
278
- return pathnameStackIndex > 1;
273
+ return pathnameStackIndex >= 1;
279
274
  }
280
275
 
281
276
  if (!Number.isNaN(filteredStack?.length)) {
@@ -373,7 +368,18 @@ export function NavigationProvider({ children }: Props) {
373
368
  }
374
369
  };
375
370
 
376
- const handleHookPresent = ({ hookPlugin, route, payload }, dispose) => {
371
+ const handleHookPresent = (
372
+ {
373
+ hookPlugin,
374
+ route,
375
+ payload,
376
+ }: {
377
+ hookPlugin: Hook;
378
+ route: string;
379
+ payload: object;
380
+ },
381
+ dispose
382
+ ) => {
377
383
  if (hookPlugin?.lastHook) {
378
384
  dispose();
379
385
  }
@@ -407,9 +413,12 @@ export function NavigationProvider({ children }: Props) {
407
413
  }
408
414
  };
409
415
 
410
- const handleHookCancel = ({ hookPlugin }, dispose) => {
411
- if (hookPlugin?.lastHook) {
412
- dispose();
416
+ const handleHookCancel = ({ hookPlugin, callback }, dispose) => {
417
+ dispose();
418
+ setStartUpHooks(false);
419
+
420
+ if (callback && typeof callback === "function") {
421
+ callback();
413
422
  }
414
423
 
415
424
  if (hookPlugin.isModalHook()) {
@@ -475,7 +484,13 @@ export function NavigationProvider({ children }: Props) {
475
484
  return false;
476
485
  }, [pluginConfigurations, plugins, rivers]);
477
486
 
478
- const [startUpHooks, setStartUpHooks] = React.useState(checkStartUpHooks);
487
+ const [startUpHooks, _setStartUpHooks] = React.useState(checkStartUpHooks);
488
+ const currentStartUpHooks = React.useRef(checkStartUpHooks);
489
+
490
+ const setStartUpHooks = (value) => {
491
+ _setStartUpHooks(value);
492
+ currentStartUpHooks.current = value;
493
+ };
479
494
 
480
495
  const handleHookComplete =
481
496
  (navigationAction, targetRoute, { screen, options }) =>
@@ -483,7 +498,7 @@ export function NavigationProvider({ children }: Props) {
483
498
  if (hookPlugin?.lastHook) {
484
499
  dispose({ disposeAll: true });
485
500
 
486
- startUpHooks && setStartUpHooks(false);
501
+ startUpHooks.current && setStartUpHooks(false);
487
502
  }
488
503
 
489
504
  dispatch(
@@ -592,10 +607,15 @@ export function NavigationProvider({ children }: Props) {
592
607
  targetScreen: screen,
593
608
  rivers,
594
609
  plugins,
595
- startUpHooksData: { startUpHooks, setStartUpHooks },
610
+ startUpHooksData: {
611
+ startUpHooks: currentStartUpHooks.current,
612
+ setStartUpHooks,
613
+ },
596
614
  };
597
615
 
598
- HooksManager(hooksOptions)
616
+ const hooksManager = HooksManager(hooksOptions);
617
+
618
+ hooksManager.subscriber
599
619
  .on(HOOKS_EVENTS.PRESENT_SCREEN_HOOK, handleHookPresent)
600
620
  .on(HOOKS_EVENTS.ERROR, handleHookError)
601
621
  .on(HOOKS_EVENTS.CANCEL, handleHookCancel)
@@ -606,8 +626,9 @@ export function NavigationProvider({ children }: Props) {
606
626
  screen,
607
627
  options,
608
628
  })
609
- )
610
- .handleHooks(legacyScreenData({ entry, screen }));
629
+ );
630
+
631
+ hooksManager.handleHooks(legacyScreenData({ entry, screen }));
611
632
  } else {
612
633
  dispatch(navigationAction(targetRoute, { screen, entry, options }));
613
634
  }
@@ -665,15 +686,15 @@ export function NavigationProvider({ children }: Props) {
665
686
 
666
687
  // It will only work for the regular stack and pathname, It won't work for modals
667
688
  // TODO: integrate video/hook and regular modal into stack.
668
- const getStackForPathname = React.useCallback((pathname: string):
669
- | NavigationScreenState
670
- | undefined => {
671
- const stack = [...stateRef?.current?.stack?.mainStack];
689
+ const getStackForPathname = (
690
+ pathname: string
691
+ ): NavigationScreenState | undefined => {
692
+ const stack = [...state?.stack?.mainStack];
672
693
 
673
694
  const currentStack = stack.find(({ route }) => route === pathname);
674
695
 
675
696
  return currentStack;
676
- }, []);
697
+ };
677
698
 
678
699
  const navigator: QuickBrickAppNavigator = React.useMemo(
679
700
  () => ({
@@ -717,6 +738,7 @@ export function NavigationProvider({ children }: Props) {
717
738
  replaceTop,
718
739
  getStack,
719
740
  getStackForPathname,
741
+ mainStack: state.stack.mainStack,
720
742
  }),
721
743
  [rivers, plugins, JSON.stringify(state), appLaunched, startUpHooks]
722
744
  );
@@ -5,6 +5,9 @@ import { createStore } from "redux";
5
5
  import { Provider } from "react-redux";
6
6
 
7
7
  import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks/navigation";
8
+ import { getByTestId } from "@applicaster/zapp-react-native-utils/testUtils/getByTestId";
9
+ // @TODO @szhigunov to complete the migration to @testing-library/react-native
10
+ // import { act, waitFor } from "@testing-library/react-native";
8
11
 
9
12
  const rivers = {
10
13
  A1234: {
@@ -151,37 +154,58 @@ const failingHook = {
151
154
  name: "failing hook",
152
155
  };
153
156
 
157
+ // const store = {
158
+ // rivers,
159
+ // plugins: [hookPlugin, hookPlugin2, failingHook],
160
+ // };
161
+
162
+ const store = createStore(() => ({
163
+ appData: { layoutVersion: "v1" },
164
+ contentTypes: null,
165
+ rivers,
166
+ plugins: [hookPlugin, hookPlugin2, failingHook],
167
+ appState: { appLaunched: true },
168
+ }));
169
+
154
170
  const ContextConsumer = () => {
155
171
  const { state, ...navigator } = useNavigation();
156
172
 
157
- const renderHook = () => {
158
- if (navigator.currentRoute.includes("/hooks/")) {
159
- const { hookPlugin, payload, callback } = navigator.screenData;
160
- const Component = hookPlugin.module.Component;
173
+ let renderHook;
161
174
 
162
- return <Component payload={payload} callback={callback} />;
163
- }
175
+ if (navigator.currentRoute.includes("/hooks/")) {
176
+ const { hookPlugin, payload, callback } = navigator.screenData;
177
+ const Component = hookPlugin.module.Component;
164
178
 
165
- return null;
166
- };
179
+ renderHook = <Component payload={payload} callback={callback} />;
180
+ }
181
+
182
+ renderHook = null;
183
+
184
+ const WrapperView: any = "View";
167
185
 
168
186
  return (
169
- <View navigator={navigator} state={state}>
170
- {renderHook()}
171
- </View>
187
+ <WrapperView testID="WrapperView" navigator={navigator} state={state}>
188
+ {renderHook}
189
+ </WrapperView>
172
190
  );
173
191
  };
174
192
 
175
- const store = createStore(() => ({
176
- appData: { layoutVersion: "v1" },
177
- contentTypes: null,
178
- rivers,
179
- plugins: [hookPlugin, hookPlugin2, failingHook],
180
- appState: { appLaunched: true },
181
- }));
182
-
183
193
  const consoleSpy = jest.spyOn(console, "error").mockImplementation(() => {});
184
194
 
195
+ // const renderContextConsumer = (_store = store) => {
196
+ // return renderWithProviders(<ContextConsumer />, _store);
197
+ // };
198
+
199
+ const renderContextConsumer = (_store = store) => {
200
+ return create(
201
+ <Provider store={store}>
202
+ <NavigationProvider>
203
+ <ContextConsumer />
204
+ </NavigationProvider>
205
+ </Provider>
206
+ );
207
+ };
208
+
185
209
  afterAll(() => {
186
210
  consoleSpy.mockReset();
187
211
  });
@@ -189,86 +213,39 @@ afterAll(() => {
189
213
  describe("<NavigationProvider />", () => {
190
214
  let wrapper;
191
215
 
192
- it("renders correctly", () => {
216
+ it("navigator contains expected properties", () => {
193
217
  act(() => {
194
- wrapper = create(
195
- <Provider store={store}>
196
- <NavigationProvider>
197
- <ContextConsumer />
198
- </NavigationProvider>
199
- </Provider>
200
- );
218
+ wrapper = renderContextConsumer();
201
219
  });
202
220
 
203
- expect(wrapper.toJSON()).toMatchSnapshot();
204
- });
221
+ const view = getByTestId(wrapper, "WrapperView");
205
222
 
206
- describe("navigator Properties", () => {
207
- act(() => {
208
- wrapper = create(
209
- <Provider store={store}>
210
- <NavigationProvider>
211
- <ContextConsumer />
212
- </NavigationProvider>
213
- </Provider>
214
- );
215
- });
216
-
217
- const view = wrapper.root.findByType(View);
218
223
  const { navigator } = view.props;
224
+ expect(navigator.activeRiver).toEqual(rivers.B4567);
225
+ expect(navigator.currentRoute).toEqual("/river/B4567");
226
+ expect(navigator.previousAction).toEqual("REPLACE");
219
227
 
220
- it("exposes the active river", () => {
221
- expect(navigator.activeRiver).toEqual(rivers.B4567);
222
- });
223
-
224
- it("exposes the currentRoute", () => {
225
- expect(navigator.currentRoute).toEqual("/river/B4567");
228
+ expect(navigator.screenData).toEqual({
229
+ ...rivers.B4567,
230
+ targetScreen: rivers.B4567,
226
231
  });
227
232
 
228
- it("exposes the previous action", () => {
229
- expect(navigator.previousAction).toEqual("REPLACE");
230
- });
231
-
232
- it("exposes the screen data", () => {
233
- expect(navigator.screenData).toEqual(rivers.B4567);
234
- });
235
-
236
- it("exposes a routeData function", () => {
237
- const consoleSpy = jest
238
- .spyOn(console, "warn")
239
- .mockImplementation(jest.fn());
240
-
241
- expect(navigator.routeData()).toEqual(rivers.B4567);
242
- consoleSpy.mockRestore();
243
- });
244
-
245
- it("warns in the console when calling navigator.routeData()", () => {
246
- const consoleSpy = jest
247
- .spyOn(console, "warn")
248
- .mockImplementation(jest.fn());
249
-
250
- navigator.routeData();
251
- expect(consoleSpy.mock.calls).toMatchSnapshot();
252
-
253
- consoleSpy.mockRestore();
233
+ expect(navigator.routeData()).toEqual({
234
+ ...rivers.B4567,
235
+ targetScreen: rivers.B4567,
254
236
  });
255
237
  });
256
238
 
257
239
  describe("pushing a new route", () => {
258
240
  act(() => {
259
- wrapper = create(
260
- <Provider store={store}>
261
- <NavigationProvider>
262
- <ContextConsumer />
263
- </NavigationProvider>
264
- </Provider>
265
- );
241
+ wrapper = renderContextConsumer();
266
242
  });
267
243
 
268
- const view = wrapper.root.findByType(View);
244
+ it("sets the data to that route", async () => {
245
+ const view = getByTestId(wrapper, "WrapperView");
269
246
 
270
- it("sets the data to that route", () => {
271
247
  act(() => view.props.navigator.push(rivers.A1234));
248
+
272
249
  expect(view.props.navigator).toHaveProperty("activeRiver", rivers.A1234);
273
250
 
274
251
  expect(view.props.navigator).toHaveProperty(
@@ -276,23 +253,21 @@ describe("<NavigationProvider />", () => {
276
253
  "/river/B4567/river/A1234"
277
254
  );
278
255
 
279
- expect(view.props.navigator.screenData).toEqual(rivers.A1234);
280
- expect(view.props.state.stack.mainStack).toBeArrayOfSize(2);
256
+ expect(view.props.navigator.screenData).toEqual({
257
+ ...rivers.A1234,
258
+ targetScreen: rivers.A1234,
259
+ });
260
+
261
+ expect(view.props.state.stack.mainStack).toHaveLength(2);
281
262
  });
282
263
  });
283
264
 
284
265
  describe("replacing a current route", () => {
285
266
  act(() => {
286
- wrapper = create(
287
- <Provider store={store}>
288
- <NavigationProvider>
289
- <ContextConsumer />
290
- </NavigationProvider>
291
- </Provider>
292
- );
267
+ wrapper = renderContextConsumer();
293
268
  });
294
269
 
295
- const view = wrapper.root.findByType(View);
270
+ const view = getByTestId(wrapper, "WrapperView");
296
271
 
297
272
  it("sets the data to that route", () => {
298
273
  act(() => view.props.navigator.replace(rivers.A1234));
@@ -303,24 +278,22 @@ describe("<NavigationProvider />", () => {
303
278
  "/river/A1234"
304
279
  );
305
280
 
306
- expect(view.props.navigator.screenData).toEqual(rivers.A1234);
307
- expect(view.props.state.stack.mainStack).toBeArrayOfSize(1);
281
+ expect(view.props.navigator.screenData).toEqual({
282
+ ...rivers.A1234,
283
+ targetScreen: rivers.A1234,
284
+ });
285
+
286
+ expect(view.props.state.stack.mainStack).toHaveLength(1);
308
287
  });
309
288
  });
310
289
 
311
290
  describe("going back", () => {
312
291
  describe("when there is no previous route", () => {
313
292
  act(() => {
314
- wrapper = create(
315
- <Provider store={store}>
316
- <NavigationProvider>
317
- <ContextConsumer />
318
- </NavigationProvider>
319
- </Provider>
320
- );
293
+ wrapper = renderContextConsumer();
321
294
  });
322
295
 
323
- const view = wrapper.root.findByType(View);
296
+ const view = getByTestId(wrapper, "WrapperView");
324
297
 
325
298
  it("returns false when calling canGoBack", () => {
326
299
  let result;
@@ -345,23 +318,21 @@ describe("<NavigationProvider />", () => {
345
318
  "/river/B4567"
346
319
  );
347
320
 
348
- expect(view.props.navigator.screenData).toEqual(rivers.B4567);
349
- expect(view.props.state.stack.mainStack).toBeArrayOfSize(1);
321
+ expect(view.props.navigator.screenData).toEqual({
322
+ ...rivers.B4567,
323
+ targetScreen: rivers.B4567,
324
+ });
325
+
326
+ expect(view.props.state.stack.mainStack).toHaveLength(1);
350
327
  });
351
328
  });
352
329
 
353
330
  describe("when there is one route and we're going in a hook", () => {
354
331
  act(() => {
355
- wrapper = create(
356
- <Provider store={store}>
357
- <NavigationProvider>
358
- <ContextConsumer />
359
- </NavigationProvider>
360
- </Provider>
361
- );
332
+ wrapper = renderContextConsumer();
362
333
  });
363
334
 
364
- const view = wrapper.root.findByType(View);
335
+ const view = getByTestId(wrapper, "WrapperView");
365
336
  act(() => view.props.navigator.replace(rivers.A1234));
366
337
 
367
338
  it("returns true when calling goBack()", () => {
@@ -387,25 +358,20 @@ describe("<NavigationProvider />", () => {
387
358
  );
388
359
 
389
360
  expect(view.props.navigator.screenData).toEqual(rivers.A1234);
390
- expect(view.props.state.stack.mainStack).toBeArrayOfSize(1);
361
+ expect(view.props.state.stack.mainStack).toHaveLength(1);
391
362
  });
392
363
  });
393
364
 
394
365
  describe("when there is a previous route", () => {
395
366
  act(() => {
396
- wrapper = create(
397
- <Provider store={store}>
398
- <NavigationProvider>
399
- <ContextConsumer />
400
- </NavigationProvider>
401
- </Provider>
402
- );
367
+ wrapper = renderContextConsumer();
403
368
  });
404
369
 
405
- const view = wrapper.root.findByType(View);
370
+ const view = getByTestId(wrapper, "WrapperView");
406
371
 
407
372
  act(() => view.props.navigator.push(rivers.A1234));
408
- act(() => view.props.navigator.push(rivers.B4567));
373
+
374
+ act(() => view.props.navigator.push({ ...rivers.B4567, id: "B4567-1" }));
409
375
 
410
376
  it("returns true when calling canGoBack", () => {
411
377
  let result;
@@ -414,11 +380,27 @@ describe("<NavigationProvider />", () => {
414
380
  result = view.props.navigator.canGoBack();
415
381
  });
416
382
 
417
- expect(result).toBe(true);
383
+ expect(result).toBeTruthy();
384
+ });
385
+
386
+ it("returns true when calling canGoBack(false, pathname)", () => {
387
+ let result;
388
+
389
+ act(() => {
390
+ result = view.props.navigator.canGoBack(false, "B4567-1");
391
+ });
392
+
393
+ expect(result).toBeTruthy();
394
+
395
+ act(() => {
396
+ result = view.props.navigator.canGoBack(false, "A1234");
397
+ });
398
+
399
+ expect(result).toBeTruthy();
418
400
  });
419
401
 
420
402
  it("returns to the previous route", () => {
421
- expect(view.props.state.stack.mainStack).toBeArrayOfSize(3);
403
+ expect(view.props.state.stack.mainStack).toHaveLength(3);
422
404
 
423
405
  act(() => view.props.navigator.goBack());
424
406
 
@@ -432,141 +414,71 @@ describe("<NavigationProvider />", () => {
432
414
  "/river/B4567/river/A1234"
433
415
  );
434
416
 
435
- expect(view.props.navigator.screenData).toEqual(rivers.A1234);
436
- expect(view.props.state.stack.mainStack).toBeArrayOfSize(2);
417
+ expect(view.props.navigator.screenData).toEqual({
418
+ ...rivers.A1234,
419
+ targetScreen: rivers.A1234,
420
+ });
421
+
422
+ expect(view.props.state.stack.mainStack).toHaveLength(2);
437
423
  });
438
424
  });
439
425
 
440
426
  describe("when there is a previous route and there are hooks", () => {
441
427
  act(() => {
442
- wrapper = create(
443
- <Provider store={store}>
444
- <NavigationProvider>
445
- <ContextConsumer />
446
- </NavigationProvider>
447
- </Provider>
448
- );
428
+ wrapper = renderContextConsumer();
449
429
  });
450
430
 
451
- const view = wrapper.root.findByType(View);
431
+ const view = getByTestId(wrapper, "WrapperView");
452
432
  act(() => view.props.navigator.push(rivers.A1234));
453
433
  act(() => view.props.navigator.push(rivers.C0987));
454
434
 
455
435
  it("returns to the previous entry in the stack which is not a hook", () => {
456
- expect(view.props.state.stack.mainStack).toBeArrayOfSize(5);
436
+ expect(view.props.state.stack.mainStack).toHaveLength(3);
457
437
 
458
438
  expect(view.props.navigator).toHaveProperty(
459
439
  "currentRoute",
460
440
  "/river/B4567/river/A1234/river/C0987"
461
441
  );
462
442
 
463
- expect(view.props.navigator.screenData).toEqual(rivers.C0987);
443
+ expect(view.props.navigator.screenData).toMatchObject({
444
+ ...rivers.C0987,
445
+ targetScreen: rivers.C0987,
446
+ });
464
447
 
465
448
  act(() => view.props.navigator.goBack());
466
449
 
467
- expect(view.props.state.stack.mainStack).toBeArrayOfSize(2);
450
+ expect(view.props.state.stack.mainStack).toHaveLength(2);
468
451
 
469
452
  expect(view.props.navigator).toHaveProperty(
470
453
  "currentRoute",
471
454
  "/river/B4567/river/A1234"
472
455
  );
473
456
 
474
- expect(view.props.navigator.screenData).toEqual(rivers.A1234);
457
+ expect(view.props.navigator.screenData).toMatchObject({
458
+ ...rivers.A1234,
459
+ targetScreen: rivers.A1234,
460
+ });
475
461
  });
476
462
  });
477
463
  });
478
464
 
479
- describe("when changing navBar visibility", () => {
480
- act(() => {
481
- wrapper = create(
482
- <Provider store={store}>
483
- <NavigationProvider>
484
- <ContextConsumer />
485
- </NavigationProvider>
486
- </Provider>
487
- );
488
- });
489
-
490
- const view = wrapper.root.findByType(View);
491
-
492
- it("updates the navbar visibility attribute", () => {
493
- act(() => view.props.navigator.hideNavBar());
494
- expect(view.props.state.options.navBar.visible).toBe(false);
495
- expect(view.props.navigator.isNavBarVisible).toBe(false);
496
- });
497
- });
498
-
499
- describe("set the navbar title", () => {
500
- act(() => {
501
- wrapper = create(
502
- <Provider store={store}>
503
- <NavigationProvider>
504
- <ContextConsumer />
505
- </NavigationProvider>
506
- </Provider>
507
- );
508
- });
509
-
510
- const view = wrapper.root.findByType(View);
511
-
512
- it("updates the navbar title attribute", () => {
513
- const screenTitle = "Screen Title";
514
- act(() => view.props.navigator.setScreenTitle(screenTitle));
515
- expect(view.props.state.options.navBar.title).toBe(screenTitle);
516
- expect(view.props.navigator.screenTitle).toBe(screenTitle);
517
- });
518
- });
519
-
520
- describe("set the navbar summary", () => {
521
- act(() => {
522
- wrapper = create(
523
- <Provider store={store}>
524
- <NavigationProvider>
525
- <ContextConsumer />
526
- </NavigationProvider>
527
- </Provider>
528
- );
529
- });
530
-
531
- const view = wrapper.root.findByType(View);
532
-
533
- it("updates the navbar summary attribute", () => {
534
- const screenSummary = "Screen Summary";
535
- act(() => view.props.navigator.setScreenSummary(screenSummary));
536
- expect(view.props.state.options.navBar.summary).toBe(screenSummary);
537
- expect(view.props.navigator.screenSummary).toBe(screenSummary);
538
- });
539
- });
540
-
541
- describe.only("modal feature", () => {
465
+ describe("modal feature", () => {
542
466
  it("sets the modalState when opening a modal", () => {
543
467
  act(() => {
544
- wrapper = create(
545
- <Provider store={store}>
546
- <NavigationProvider>
547
- <ContextConsumer />
548
- </NavigationProvider>
549
- </Provider>
550
- );
468
+ wrapper = renderContextConsumer();
551
469
  });
552
470
 
553
- const view = wrapper.root.findByType(View);
471
+ const view = getByTestId(wrapper, "WrapperView");
554
472
  act(() => view.props.navigator.openModal({ item: rivers.A1234 }));
555
473
  expect(view.props.navigator.get).toMatchSnapshot();
556
474
  });
557
475
 
558
476
  it("removes the visible flag when dismissing a modal", () => {
559
477
  act(() => {
560
- wrapper = create(
561
- <Provider store={store}>
562
- <NavigationProvider>
563
- <ContextConsumer />
564
- </NavigationProvider>
565
- </Provider>
566
- );
478
+ wrapper = renderContextConsumer();
567
479
  });
568
480
 
569
- const view = wrapper.root.findByType(View);
481
+ const view = getByTestId(wrapper, "WrapperView");
570
482
  act(() => view.props.navigator.openModal({ item: rivers.A1234 }));
571
483
  expect(view.props.navigator.getModalState()).toMatchSnapshot();
572
484
  act(() => view.props.navigator.dismissModal());
@@ -576,16 +488,10 @@ describe("<NavigationProvider />", () => {
576
488
 
577
489
  it("should reset state to initial when dismissing a modal ( closeModalBottomSheet ) opened by openModalBottomSheet", () => {
578
490
  act(() => {
579
- wrapper = create(
580
- <Provider store={store}>
581
- <NavigationProvider>
582
- <ContextConsumer />
583
- </NavigationProvider>
584
- </Provider>
585
- );
491
+ wrapper = renderContextConsumer();
586
492
  });
587
493
 
588
- const view = wrapper.root.findByType(View);
494
+ const view = getByTestId(wrapper, "WrapperView");
589
495
 
590
496
  act(() =>
591
497
  view.props.navigator.openModalBottomSheet({
@@ -3,7 +3,10 @@ import * as R from "ramda";
3
3
 
4
4
  import { NetInfoState } from "@react-native-community/netinfo";
5
5
  import { NETWORK_HOOKS_KEYS } from "./const";
6
- import { platformSelect } from "@applicaster/zapp-react-native-utils/reactUtils";
6
+ import {
7
+ isVizioPlatform,
8
+ platformSelect,
9
+ } from "@applicaster/zapp-react-native-utils/reactUtils";
7
10
  import { Platform } from "react-native";
8
11
 
9
12
  type ConnectionStatus = boolean;
@@ -203,6 +206,18 @@ export const subscribeToDeviceNetworkChanges = (callback: NetCb) => {
203
206
  registeredListener = webapis.network.addNetworkStateChangeListener(
204
207
  samsungNetworkChangeHandler(callback)
205
208
  );
209
+
210
+ return;
211
+ }
212
+
213
+ if (isVizioPlatform()) {
214
+ window.addEventListener("online", function () {
215
+ callback({ online: true });
216
+ });
217
+
218
+ window.addEventListener("offline", function () {
219
+ callback({ online: false });
220
+ });
206
221
  }
207
222
  };
208
223
 
@@ -214,5 +229,12 @@ export const subscribeToDeviceNetworkChanges = (callback: NetCb) => {
214
229
  export const unsubscribeToDeviceNetworkChanges = (id = registeredListener) => {
215
230
  if (hasTizenAPIs()) {
216
231
  webapis.network.removeNetworkStateChangeListener(id);
232
+
233
+ return;
234
+ }
235
+
236
+ if (isVizioPlatform()) {
237
+ window.removeEventListener("online", function () {});
238
+ window.removeEventListener("offline", function () {});
217
239
  }
218
240
  };
@@ -13,7 +13,6 @@ exports[`<RouteManager /> renders correctly 1`] = `
13
13
  }
14
14
  >
15
15
  <View
16
- comp="river"
17
16
  testID="river"
18
17
  />
19
18
  </RNCSafeAreaProvider>
package/App/index.tsx CHANGED
@@ -1,8 +1,8 @@
1
1
  import * as React from "react";
2
2
  import * as R from "ramda";
3
3
  import {
4
- SafeAreaProvider,
5
4
  initialWindowMetrics,
5
+ SafeAreaProvider,
6
6
  } from "react-native-safe-area-context";
7
7
 
8
8
  import { ErrorBoundary } from "./ErrorBoundary";
@@ -27,6 +27,7 @@ import {
27
27
  import { withURLSchemeContextProvider } from "./DeepLinking/URLSchemeListener/URLSchemeContextProvider";
28
28
  import { appRemoteDataLoader } from "./appRemoteDataLoader";
29
29
  import { withActionExecutor } from "@applicaster/zapp-react-native-utils/actionsExecutor/ActionExecutorContext";
30
+ import { withScreenDataContextProvider } from "@applicaster/zapp-react-native-ui-components/Contexts/ScreenDataContext";
30
31
 
31
32
  /**
32
33
  * @typedef {Object} AppOptions
@@ -99,6 +100,7 @@ export function createQuickBrickApp(options): ZappApp {
99
100
  withURLSchemeContextProvider,
100
101
  withNetworkStatusProvider,
101
102
  withNavigationProvider,
103
+ withScreenDataContextProvider,
102
104
  ZappPipesSearchContext.withProvider,
103
105
  InteractionManager,
104
106
  withActionExecutor,
package/const/index.ts CHANGED
@@ -34,3 +34,7 @@ export const requiredSessionKeys = [
34
34
  "userAgent",
35
35
  "version_name",
36
36
  ];
37
+
38
+ export const QUICK_BRICK_NAVBAR = "quick-brick-navbar";
39
+
40
+ export const QUICK_BRICK_CONTENT = "quick-brick-content";
@@ -7,6 +7,10 @@
7
7
  import * as React from "react";
8
8
  import * as R from "ramda";
9
9
  import { Dimensions } from "react-native";
10
+ import {
11
+ isNotEmpty,
12
+ isNotNil,
13
+ } from "@applicaster/zapp-react-native-utils/reactUtils/helpers";
10
14
 
11
15
  import {
12
16
  createZappReduxStore,
@@ -27,6 +31,9 @@ import { remoteDataLoader } from "../App/appRemoteDataLoader/remoteDataLoader";
27
31
  import * as QuickBrickManager from "@applicaster/zapp-react-native-bridge/QuickBrick";
28
32
  import { isAndroidPlatform } from "@applicaster/zapp-react-native-utils/reactUtils";
29
33
 
34
+ const isNotEmptyObject = (value: unknown) =>
35
+ isNotNil(value) && R.is(Object, value) && isNotEmpty(value);
36
+
30
37
  /**
31
38
  * Creates a Zapp App with the provided options
32
39
  * @export
@@ -55,8 +62,8 @@ export function createZappApp(zappAppConfig: ZappAppConfig) {
55
62
 
56
63
  const useTabletLayout =
57
64
  isTablet({ width, height }, width > height ? "landscape" : "portrait") &&
58
- tabletLayout &&
59
- tabletCellStyles;
65
+ isNotEmptyObject(tabletLayout) &&
66
+ isNotEmptyObject(tabletCellStyles);
60
67
 
61
68
  function fetchPluginConfiguration(plugin) {
62
69
  const configuration = R.compose(
package/defaults/index.js CHANGED
@@ -1,5 +1,3 @@
1
- // @flow
2
-
3
1
  /**
4
2
  * quick-brick-core module
5
3
  * @module @applicaster/quick-brick-core/defaults
package/package.json CHANGED
@@ -1,12 +1,11 @@
1
1
  {
2
2
  "name": "@applicaster/quick-brick-core",
3
- "version": "12.0.0-alpha.5040434238",
3
+ "version": "12.0.0-alpha.5050333009",
4
4
  "description": "Core package for Applicaster's Quick Brick App",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
7
7
  "scripts": {
8
8
  "test": "jest -w=2",
9
- "flow-types": "node_modules/.bin/flow-copy-source -v -i '**/__tests__**' . .",
10
9
  "build": "echo 'skipping ts build for core packages'"
11
10
  },
12
11
  "repository": {
@@ -30,13 +29,13 @@
30
29
  },
31
30
  "homepage": "https://github.com/applicaster/quickbrick#readme",
32
31
  "dependencies": {
33
- "@applicaster/applicaster-types": "12.0.0-alpha.5040434238",
34
- "@applicaster/quick-brick-core-plugins": "12.0.0-alpha.5040434238",
35
- "@applicaster/zapp-pipes-v2-client": "12.0.0-alpha.5040434238",
36
- "@applicaster/zapp-react-native-bridge": "12.0.0-alpha.5040434238",
37
- "@applicaster/zapp-react-native-redux": "12.0.0-alpha.5040434238",
38
- "@applicaster/zapp-react-native-ui-components": "12.0.0-alpha.5040434238",
39
- "@applicaster/zapp-react-native-utils": "12.0.0-alpha.5040434238",
32
+ "@applicaster/applicaster-types": "12.0.0-alpha.5050333009",
33
+ "@applicaster/quick-brick-core-plugins": "12.0.0-alpha.5050333009",
34
+ "@applicaster/zapp-pipes-v2-client": "12.0.0-alpha.5050333009",
35
+ "@applicaster/zapp-react-native-bridge": "12.0.0-alpha.5050333009",
36
+ "@applicaster/zapp-react-native-redux": "12.0.0-alpha.5050333009",
37
+ "@applicaster/zapp-react-native-ui-components": "12.0.0-alpha.5050333009",
38
+ "@applicaster/zapp-react-native-utils": "12.0.0-alpha.5050333009",
40
39
  "atob": "^2.1.2",
41
40
  "axios": "^0.28.0",
42
41
  "btoa": "^1.2.1",