@applicaster/zapp-react-native-ui-components 13.0.8 → 13.0.9-alpha.8843371874
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/Components/Cell/__tests__/CellWIthFocusable.test.js +3 -2
- package/Components/FeedLoader/FeedLoader.tsx +4 -14
- package/Components/FeedLoader/FeedLoaderHOC.tsx +19 -0
- package/Components/FeedLoader/index.js +2 -8
- package/Components/GeneralContentScreen/utils/useCurationAPI.ts +5 -6
- package/Components/MasterCell/DefaultComponents/ActionButton.tsx +2 -0
- package/Components/MasterCell/utils/behaviorProvider.ts +82 -14
- package/Components/MasterCell/utils/index.ts +11 -5
- package/Components/River/RefreshControl.tsx +11 -17
- package/Components/River/__tests__/river.test.js +12 -26
- package/Contexts/ScreenContext/index.tsx +46 -6
- package/Decorators/RiverFeedLoader/__tests__/__snapshots__/riverFeedLoader.test.tsx.snap +221 -209
- package/Decorators/RiverFeedLoader/__tests__/riverFeedLoader.test.tsx +14 -16
- package/Decorators/RiverFeedLoader/__tests__/utils.test.ts +0 -20
- package/Decorators/RiverFeedLoader/index.tsx +22 -4
- package/Decorators/RiverFeedLoader/utils/index.ts +0 -18
- package/Decorators/ZappPipesDataConnector/__tests__/UrlFeedResolver.test.tsx +368 -0
- package/Decorators/ZappPipesDataConnector/index.tsx +20 -5
- package/Decorators/ZappPipesDataConnector/resolvers/UrlFeedResolver.tsx +266 -0
- package/Decorators/ZappPipesDataConnector/utils/mongoFilter.ts +738 -0
- package/Decorators/ZappPipesDataConnector/utils/useFilter.tsx +159 -0
- package/package.json +5 -5
- package/Components/River/__tests__/__snapshots__/river.test.js.snap +0 -27
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { View } from "react-native";
|
|
2
2
|
import React from "react";
|
|
3
|
-
import { act
|
|
3
|
+
import { act } from "@testing-library/react-native";
|
|
4
4
|
import { CellWithFocusable } from "../CellWithFocusable.tsx";
|
|
5
5
|
|
|
6
6
|
import { focusManager } from "@applicaster/zapp-react-native-utils/appUtils/focusManager";
|
|
7
|
+
import { renderWithProviders } from "@applicaster/zapp-react-native-utils/testUtils/index.tsx";
|
|
7
8
|
|
|
8
9
|
const renderWith = (props) => {
|
|
9
|
-
return
|
|
10
|
+
return renderWithProviders(<CellWithFocusable {...props} />);
|
|
10
11
|
};
|
|
11
12
|
|
|
12
13
|
describe("CellWithFocusable", () => {
|
|
@@ -3,23 +3,13 @@ import * as R from "ramda";
|
|
|
3
3
|
|
|
4
4
|
type Props = {
|
|
5
5
|
zappPipes: ZappPipesData;
|
|
6
|
-
loadPipesData:
|
|
7
|
-
feed
|
|
8
|
-
|
|
9
|
-
clearCache: boolean;
|
|
10
|
-
meta: any;
|
|
11
|
-
loadLocalFavorites: boolean;
|
|
12
|
-
silentRefresh: boolean;
|
|
13
|
-
parentFeed: ZappFeed;
|
|
14
|
-
callback: () => void;
|
|
15
|
-
bodyParams: any;
|
|
16
|
-
riverId: string;
|
|
17
|
-
}>
|
|
18
|
-
) => void;
|
|
6
|
+
loadPipesData: ReturnType<
|
|
7
|
+
typeof import("@applicaster/zapp-react-native-utils/reactHooks/feed").useLoadPipesDataDispatch
|
|
8
|
+
>;
|
|
19
9
|
feedUrl: string;
|
|
20
10
|
children: (feed: ZappFeed) => React.ComponentType<any>;
|
|
21
11
|
onFeedLoaded: (feed: ZappFeed) => {};
|
|
22
|
-
onError: (
|
|
12
|
+
onError: (error: ZappPipesData["error"]) => {};
|
|
23
13
|
refreshing: boolean;
|
|
24
14
|
refreshCallback: () => void;
|
|
25
15
|
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
|
|
3
|
+
import { useLoadPipesDataDispatch } from "@applicaster/zapp-react-native-utils/reactHooks/feed";
|
|
4
|
+
import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
|
|
5
|
+
|
|
6
|
+
export const FeedLoaderHOC = (_Component: any) => {
|
|
7
|
+
return function FeedLoaderHOC(props: any) {
|
|
8
|
+
const { zappPipes } = usePickFromState(["zappPipes"]);
|
|
9
|
+
const loadPipesData = useLoadPipesDataDispatch();
|
|
10
|
+
|
|
11
|
+
return (
|
|
12
|
+
<_Component
|
|
13
|
+
{...props}
|
|
14
|
+
zappPipes={zappPipes}
|
|
15
|
+
loadPipesData={loadPipesData}
|
|
16
|
+
/>
|
|
17
|
+
);
|
|
18
|
+
};
|
|
19
|
+
};
|
|
@@ -1,10 +1,4 @@
|
|
|
1
|
-
import * as R from "ramda";
|
|
2
|
-
|
|
3
|
-
import { connectToStore } from "@applicaster/zapp-react-native-redux";
|
|
4
|
-
import { loadPipesData } from "@applicaster/zapp-react-native-redux/ZappPipes";
|
|
5
|
-
|
|
6
1
|
import { FeedLoaderComponent } from "./FeedLoader";
|
|
2
|
+
import { FeedLoaderHOC } from "./FeedLoaderHOC";
|
|
7
3
|
|
|
8
|
-
export const FeedLoader =
|
|
9
|
-
loadPipesData,
|
|
10
|
-
})(FeedLoaderComponent);
|
|
4
|
+
export const FeedLoader = FeedLoaderHOC(FeedLoaderComponent);
|
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
import { all, equals, path, prop, isEmpty, pluck, values } from "ramda";
|
|
2
2
|
|
|
3
3
|
import { useEffect, useMemo } from "react";
|
|
4
|
-
import { useDispatch } from "react-redux";
|
|
5
4
|
|
|
6
5
|
import {
|
|
7
6
|
useLayoutPresets,
|
|
8
7
|
useZappPipesFeeds,
|
|
9
8
|
} from "@applicaster/zapp-react-native-redux/hooks";
|
|
10
|
-
import { loadPipesData } from "@applicaster/zapp-react-native-redux/ZappPipes";
|
|
11
9
|
import { isEmptyOrNil } from "@applicaster/zapp-react-native-utils/cellUtils";
|
|
12
10
|
import { Categories } from "./logger";
|
|
13
11
|
import { createLogger } from "@applicaster/zapp-react-native-utils/logger";
|
|
@@ -24,6 +22,7 @@ import {
|
|
|
24
22
|
} from "@applicaster/zapp-react-native-utils/reactHooks/feed/useInflatedUrl";
|
|
25
23
|
|
|
26
24
|
import { produce } from "immer";
|
|
25
|
+
import { useLoadPipesDataDispatch } from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
27
26
|
// types reference
|
|
28
27
|
|
|
29
28
|
declare type CurationEntry = { preset_name: string; feed_url: string };
|
|
@@ -122,8 +121,6 @@ export const getFinalComponents = (
|
|
|
122
121
|
export const useCurationAPI = (
|
|
123
122
|
components: Array<ZappUIComponent>
|
|
124
123
|
): ZappUIComponent[] => {
|
|
125
|
-
const dispatch = useDispatch();
|
|
126
|
-
|
|
127
124
|
const smartComponents = useMemo(
|
|
128
125
|
() => components?.filter?.(isSmartComponent) ?? [],
|
|
129
126
|
[components]
|
|
@@ -159,17 +156,19 @@ export const useCurationAPI = (
|
|
|
159
156
|
|
|
160
157
|
const urls = useMemo<string[]>(() => Object.values(urlsMap), [urlsMap]);
|
|
161
158
|
|
|
159
|
+
const loadPipesDataDispatcher = useLoadPipesDataDispatch();
|
|
160
|
+
|
|
162
161
|
useEffect(() => {
|
|
163
162
|
urls.forEach((url, index) => {
|
|
164
163
|
if (url) {
|
|
165
|
-
|
|
164
|
+
loadPipesDataDispatcher(url, { clearCache: false });
|
|
166
165
|
} else {
|
|
167
166
|
logger.log_error("Curation url is empty", {
|
|
168
167
|
componentId: smartComponents?.[index]?.id,
|
|
169
168
|
});
|
|
170
169
|
}
|
|
171
170
|
});
|
|
172
|
-
}, [urls]);
|
|
171
|
+
}, [urls, loadPipesDataDispatcher]);
|
|
173
172
|
|
|
174
173
|
const feeds = useZappPipesFeeds(urls);
|
|
175
174
|
const layoutPresets = useLayoutPresets();
|
|
@@ -23,6 +23,7 @@ type Props = {
|
|
|
23
23
|
style: ViewStyle;
|
|
24
24
|
testID?: string;
|
|
25
25
|
accessibilityLabel?: string;
|
|
26
|
+
accessibilityHint?: string;
|
|
26
27
|
cellUUID?: string;
|
|
27
28
|
extraProps?: Record<string, any>;
|
|
28
29
|
};
|
|
@@ -98,6 +99,7 @@ export function ActionButton(props: Props) {
|
|
|
98
99
|
onPress={onPress}
|
|
99
100
|
testID={props?.testID || `${item?.id}`}
|
|
100
101
|
accessibilityLabel={props?.accessibilityLabel || `${item?.id}`}
|
|
102
|
+
accessibilityHint={props?.accessibilityHint}
|
|
101
103
|
accessible={!!(props?.testID || props?.accessibilityLabel)}
|
|
102
104
|
style={props?.style}
|
|
103
105
|
>
|
|
@@ -1,28 +1,58 @@
|
|
|
1
1
|
import { playerManager } from "@applicaster/zapp-react-native-utils/appUtils";
|
|
2
|
-
import { StorageSingleValueProvider } from "@applicaster/zapp-react-native-
|
|
2
|
+
import { StorageSingleValueProvider } from "@applicaster/zapp-react-native-utils/storage/StorageSingleSelectProvider";
|
|
3
3
|
import { PushTopicManager } from "@applicaster/zapp-react-native-bridge/PushNotifications/PushTopicManager";
|
|
4
|
-
import { StorageMultiSelectProvider } from "@applicaster/zapp-react-native-
|
|
4
|
+
import { StorageMultiSelectProvider } from "@applicaster/zapp-react-native-utils/storage/StorageMultiSelectProvider";
|
|
5
5
|
import React, { useEffect } from "react";
|
|
6
6
|
import { usePlayer } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/usePlayer";
|
|
7
7
|
import { BehaviorSubject } from "rxjs";
|
|
8
8
|
import { masterCellLogger } from "../logger";
|
|
9
9
|
import get from "lodash/get";
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
10
|
+
import { ScreenMultiSelectProvider } from "@applicaster/zapp-react-native-utils/storage/ScreenStateMultiSelectProvider";
|
|
11
|
+
import { ScreenSingleValueProvider } from "@applicaster/zapp-react-native-utils/storage/ScreenSingleValueProvider";
|
|
12
|
+
import { useRoute } from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
13
|
+
import { useScreenStateStore } from "@applicaster/zapp-react-native-utils/reactHooks/navigation/useScreenStateStore";
|
|
14
|
+
|
|
15
|
+
const parseContextKey = (
|
|
16
|
+
key: string,
|
|
17
|
+
context: string = "ctx"
|
|
18
|
+
): string | null => {
|
|
19
|
+
if (!key?.startsWith(`@{${context}/`)) return null;
|
|
20
|
+
|
|
21
|
+
return key.substring(`@{${context}/`.length, key.length - 1);
|
|
15
22
|
};
|
|
16
23
|
|
|
17
24
|
const getDataSourceProvider = (
|
|
18
|
-
behavior: Behavior
|
|
25
|
+
behavior: Behavior,
|
|
26
|
+
screenRoute: string,
|
|
27
|
+
screenStateStore: ReturnType<typeof useScreenStateStore>
|
|
19
28
|
): BehaviorSubject<string[] | string> | null => {
|
|
20
29
|
if (!behavior) return null;
|
|
21
30
|
|
|
22
31
|
const selection = String(behavior.current_selection);
|
|
32
|
+
const screenKey = parseContextKey(selection, "screen");
|
|
33
|
+
|
|
34
|
+
if (screenKey) {
|
|
35
|
+
if (behavior.select_mode === "multi") {
|
|
36
|
+
return ScreenMultiSelectProvider.getProvider(
|
|
37
|
+
screenKey,
|
|
38
|
+
screenRoute,
|
|
39
|
+
screenStateStore
|
|
40
|
+
).getObservable();
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (behavior.select_mode === "single") {
|
|
44
|
+
return ScreenSingleValueProvider.getProvider(
|
|
45
|
+
screenKey,
|
|
46
|
+
screenRoute,
|
|
47
|
+
screenStateStore
|
|
48
|
+
).getObservable();
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
23
52
|
const contextKey = parseContextKey(selection);
|
|
24
53
|
|
|
25
54
|
if (contextKey) {
|
|
55
|
+
// TODO: Add storage scope to behavior
|
|
26
56
|
if (behavior.select_mode === "multi") {
|
|
27
57
|
return StorageMultiSelectProvider.getProvider(contextKey).getObservable();
|
|
28
58
|
}
|
|
@@ -41,6 +71,8 @@ const getDataSourceProvider = (
|
|
|
41
71
|
|
|
42
72
|
export const useBehaviorUpdate = (behavior: Behavior) => {
|
|
43
73
|
const [lastUpdate, setLastUpdate] = React.useState<number | null>(null);
|
|
74
|
+
const screenRoute = useRoute()?.pathname || "";
|
|
75
|
+
const screenStateStore = useScreenStateStore();
|
|
44
76
|
const player = usePlayer();
|
|
45
77
|
|
|
46
78
|
const triggerUpdate = () => setLastUpdate(Date.now());
|
|
@@ -48,7 +80,11 @@ export const useBehaviorUpdate = (behavior: Behavior) => {
|
|
|
48
80
|
useEffect(() => {
|
|
49
81
|
if (!behavior) return;
|
|
50
82
|
|
|
51
|
-
const dataSource = getDataSourceProvider(
|
|
83
|
+
const dataSource = getDataSourceProvider(
|
|
84
|
+
behavior,
|
|
85
|
+
screenRoute,
|
|
86
|
+
screenStateStore
|
|
87
|
+
);
|
|
52
88
|
|
|
53
89
|
if (dataSource) {
|
|
54
90
|
const subscription = dataSource.subscribe(triggerUpdate);
|
|
@@ -72,10 +108,17 @@ export const useBehaviorUpdate = (behavior: Behavior) => {
|
|
|
72
108
|
|
|
73
109
|
// We cant use async in this function (its inside render),
|
|
74
110
|
// so we rely on useBehaviorUpdate to update current value and trigger re-render
|
|
75
|
-
export const isCellSelected = (
|
|
76
|
-
item
|
|
77
|
-
|
|
78
|
-
|
|
111
|
+
export const isCellSelected = ({
|
|
112
|
+
item,
|
|
113
|
+
screenRoute,
|
|
114
|
+
screenStateStore,
|
|
115
|
+
behavior,
|
|
116
|
+
}: {
|
|
117
|
+
item: ZappEntry;
|
|
118
|
+
screenRoute: string;
|
|
119
|
+
screenStateStore: ReturnType<typeof useScreenStateStore>;
|
|
120
|
+
behavior?: Behavior;
|
|
121
|
+
}): boolean => {
|
|
79
122
|
if (!behavior) return false;
|
|
80
123
|
|
|
81
124
|
const id = behavior.selector ? get(item, behavior.selector) : item.id;
|
|
@@ -99,7 +142,32 @@ export const isCellSelected = (
|
|
|
99
142
|
}
|
|
100
143
|
|
|
101
144
|
const selection = String(behavior.current_selection);
|
|
102
|
-
|
|
145
|
+
|
|
146
|
+
const screenKey = parseContextKey(selection, "screen");
|
|
147
|
+
|
|
148
|
+
if (screenKey) {
|
|
149
|
+
if (behavior.select_mode === "single") {
|
|
150
|
+
const selectedItem = ScreenSingleValueProvider.getProvider(
|
|
151
|
+
screenKey,
|
|
152
|
+
screenRoute,
|
|
153
|
+
screenStateStore
|
|
154
|
+
).getValue();
|
|
155
|
+
|
|
156
|
+
return selectedItem === String(id);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
if (behavior.select_mode === "multi") {
|
|
160
|
+
const selectedItems = ScreenMultiSelectProvider.getProvider(
|
|
161
|
+
screenKey,
|
|
162
|
+
screenRoute,
|
|
163
|
+
screenStateStore
|
|
164
|
+
).getSelectedItems();
|
|
165
|
+
|
|
166
|
+
return selectedItems?.includes(String(id));
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const contextKey = parseContextKey(selection, "ctx");
|
|
103
171
|
|
|
104
172
|
if (contextKey) {
|
|
105
173
|
if (behavior.select_mode === "single") {
|
|
@@ -8,6 +8,8 @@ import { masterCellLogger } from "../logger";
|
|
|
8
8
|
import { getCellState } from "../../Cell/utils";
|
|
9
9
|
import { getColorFromData } from "@applicaster/zapp-react-native-utils/cellUtils";
|
|
10
10
|
import { isCellSelected, useBehaviorUpdate } from "./behaviorProvider";
|
|
11
|
+
import { useRoute } from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
12
|
+
import { useScreenStateStore } from "@applicaster/zapp-react-native-utils/reactHooks/navigation/useScreenStateStore";
|
|
11
13
|
|
|
12
14
|
const hasElementSpecificViewType = (viewType) => (element) => {
|
|
13
15
|
if (R.isNil(element)) {
|
|
@@ -190,10 +192,6 @@ export const getFocusedButtonId = (focusable) => {
|
|
|
190
192
|
});
|
|
191
193
|
};
|
|
192
194
|
|
|
193
|
-
export const isSelected = (item: ZappEntry, behavior?: Behavior) => {
|
|
194
|
-
return isCellSelected(item, behavior);
|
|
195
|
-
};
|
|
196
|
-
|
|
197
195
|
export const useCellState = ({
|
|
198
196
|
item,
|
|
199
197
|
behavior,
|
|
@@ -204,9 +202,17 @@ export const useCellState = ({
|
|
|
204
202
|
focused: boolean;
|
|
205
203
|
}): CellState => {
|
|
206
204
|
const lastUpdate = useBehaviorUpdate(behavior);
|
|
205
|
+
const router = useRoute();
|
|
206
|
+
const screenStateStore = useScreenStateStore();
|
|
207
207
|
|
|
208
208
|
const _isSelected = useMemo(
|
|
209
|
-
() =>
|
|
209
|
+
() =>
|
|
210
|
+
isCellSelected({
|
|
211
|
+
item,
|
|
212
|
+
screenRoute: router?.pathname,
|
|
213
|
+
screenStateStore,
|
|
214
|
+
behavior,
|
|
215
|
+
}),
|
|
210
216
|
[behavior, item, lastUpdate]
|
|
211
217
|
);
|
|
212
218
|
|
|
@@ -10,11 +10,10 @@ import { useLocalizedStrings } from "@applicaster/zapp-react-native-utils/locali
|
|
|
10
10
|
import { useAnalytics } from "@applicaster/zapp-react-native-utils/analyticsUtils";
|
|
11
11
|
import { useSendAnalyticsEventWithFunction } from "@applicaster/zapp-react-native-utils/analyticsUtils/helpers/hooks";
|
|
12
12
|
import { useCurrentScreenData } from "@applicaster/zapp-react-native-utils/reactHooks/screen/useCurrentScreenData";
|
|
13
|
-
import { loadPipesData } from "@applicaster/zapp-react-native-redux/ZappPipes";
|
|
14
|
-
import { useDispatch } from "react-redux";
|
|
15
13
|
import { useShallow } from "zustand/react/shallow";
|
|
16
14
|
import { useScreenContextV2 } from "@applicaster/zapp-react-native-utils/reactHooks/screen/useScreenContext";
|
|
17
15
|
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
|
16
|
+
import { useLoadPipesDataDispatch } from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
18
17
|
|
|
19
18
|
const BRIGHTNESS_THRESHOLD = 160;
|
|
20
19
|
const ABOVE_DEFAULT_COLOR = "gray";
|
|
@@ -61,38 +60,33 @@ export const usePullToRefresh = (
|
|
|
61
60
|
) => {
|
|
62
61
|
const isPipesV1 = !!pullToRefreshPipesV1RefreshingStateUpdater;
|
|
63
62
|
|
|
64
|
-
const dispatch = useDispatch();
|
|
65
|
-
|
|
66
63
|
const [refreshing, setRefreshing] = React.useState(false);
|
|
67
64
|
|
|
68
65
|
const feeds: string[] =
|
|
69
66
|
riverComponents?.map(R.path(["data", "source"])).filter((feed) => !!feed) ??
|
|
70
67
|
[];
|
|
71
68
|
|
|
72
|
-
const screenData = useCurrentScreenData();
|
|
73
|
-
|
|
74
69
|
const feedsLength = feeds.length;
|
|
75
70
|
|
|
76
71
|
const [requestsCompletedCounter, setRequestsCompletedCounter] =
|
|
77
72
|
React.useState(0);
|
|
78
73
|
|
|
74
|
+
const loadPipesDataDispatcher = useLoadPipesDataDispatch();
|
|
75
|
+
|
|
79
76
|
React.useEffect(() => {
|
|
80
77
|
// will not work for pipes v1 on 1st level screens
|
|
81
78
|
if (refreshing && !isPipesV1) {
|
|
82
79
|
feeds.forEach((feed) => {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
riverId: screenData.id,
|
|
91
|
-
})
|
|
92
|
-
);
|
|
80
|
+
loadPipesDataDispatcher(feed, {
|
|
81
|
+
silentRefresh: true,
|
|
82
|
+
clearCache: true,
|
|
83
|
+
callback: () => {
|
|
84
|
+
setRequestsCompletedCounter(R.inc);
|
|
85
|
+
},
|
|
86
|
+
});
|
|
93
87
|
});
|
|
94
88
|
}
|
|
95
|
-
}, [refreshing, isPipesV1]);
|
|
89
|
+
}, [refreshing, isPipesV1, feeds, loadPipesDataDispatcher]);
|
|
96
90
|
|
|
97
91
|
React.useEffect(() => {
|
|
98
92
|
if (requestsCompletedCounter === feedsLength) {
|
|
@@ -1,20 +1,10 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import {
|
|
3
|
-
import configureStore from "redux-mock-store";
|
|
2
|
+
import { screen } from "@testing-library/react-native";
|
|
4
3
|
import { renderWithProviders } from "@applicaster/zapp-react-native-utils/testUtils";
|
|
5
|
-
import { Provider } from "react-redux";
|
|
6
4
|
|
|
7
|
-
import { River } from "../";
|
|
8
5
|
import { ScreenResolver } from "../../ScreenResolver";
|
|
9
6
|
import { RiverComponent } from "../River";
|
|
10
7
|
|
|
11
|
-
jest.mock(
|
|
12
|
-
"@applicaster/zapp-react-native-utils/reactHooks/navigation/useIsScreenActive",
|
|
13
|
-
() => ({
|
|
14
|
-
useIsScreenActive: jest.fn(() => true),
|
|
15
|
-
})
|
|
16
|
-
);
|
|
17
|
-
|
|
18
8
|
jest.mock(
|
|
19
9
|
"@applicaster/zapp-react-native-ui-components/Components/GeneralContentScreen",
|
|
20
10
|
() => {
|
|
@@ -46,6 +36,13 @@ jest.mock(
|
|
|
46
36
|
})
|
|
47
37
|
);
|
|
48
38
|
|
|
39
|
+
jest.mock(
|
|
40
|
+
"@applicaster/zapp-react-native-utils/reactHooks/navigation/useIsScreenActive",
|
|
41
|
+
() => ({
|
|
42
|
+
useIsScreenActive: jest.fn(() => true),
|
|
43
|
+
})
|
|
44
|
+
);
|
|
45
|
+
|
|
49
46
|
const river = {
|
|
50
47
|
home: true,
|
|
51
48
|
id: "A1234",
|
|
@@ -89,28 +86,17 @@ const riverProps = {
|
|
|
89
86
|
|
|
90
87
|
const appData = { layoutVersion: "v1" };
|
|
91
88
|
|
|
92
|
-
const store =
|
|
89
|
+
const store = { rivers, appData };
|
|
93
90
|
|
|
94
91
|
describe("When River has a general_content type", () => {
|
|
95
92
|
it("renders GeneralContentScreen correctly", () => {
|
|
96
|
-
const { getByTestId } =
|
|
97
|
-
<
|
|
98
|
-
|
|
99
|
-
</Provider>
|
|
93
|
+
const { getByTestId } = renderWithProviders(
|
|
94
|
+
<RiverComponent {...riverProps} />,
|
|
95
|
+
store
|
|
100
96
|
);
|
|
101
97
|
|
|
102
98
|
expect(getByTestId("general-content-screen")).toBeTruthy();
|
|
103
99
|
});
|
|
104
|
-
|
|
105
|
-
it("renders River component correctly", () => {
|
|
106
|
-
const wrapper = render(
|
|
107
|
-
<Provider store={store}>
|
|
108
|
-
<River screenId="A1234" />
|
|
109
|
-
</Provider>
|
|
110
|
-
);
|
|
111
|
-
|
|
112
|
-
expect(wrapper.toJSON()).toMatchSnapshot();
|
|
113
|
-
});
|
|
114
100
|
});
|
|
115
101
|
|
|
116
102
|
describe("When River has any other type other than general_content", () => {
|
|
@@ -13,7 +13,8 @@ import {
|
|
|
13
13
|
} from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
14
14
|
import { useModalNavigationContext } from "@applicaster/zapp-react-native-ui-components/Contexts/ModalNavigationContext";
|
|
15
15
|
import { useNestedNavigationContext } from "@applicaster/zapp-react-native-ui-components/Contexts/NestedNavigationContext";
|
|
16
|
-
import { create
|
|
16
|
+
import { create } from "zustand";
|
|
17
|
+
import { subscribeWithSelector } from "zustand/middleware";
|
|
17
18
|
import { useShallow } from "zustand/react/shallow";
|
|
18
19
|
import { Animated } from "react-native";
|
|
19
20
|
|
|
@@ -39,11 +40,26 @@ interface NavBarState {
|
|
|
39
40
|
setSummary: (subtitle: string) => void;
|
|
40
41
|
}
|
|
41
42
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
43
|
+
const createStateStore = () =>
|
|
44
|
+
create(
|
|
45
|
+
subscribeWithSelector<ScreenStateStore>((set) => ({
|
|
46
|
+
data: {},
|
|
47
|
+
setValue: (key, value) =>
|
|
48
|
+
set((state) => ({
|
|
49
|
+
data: {
|
|
50
|
+
...state.data,
|
|
51
|
+
[key]: value,
|
|
52
|
+
},
|
|
53
|
+
})),
|
|
54
|
+
removeValue: (key) =>
|
|
55
|
+
set((state) => {
|
|
56
|
+
const newData = { ...state.data };
|
|
57
|
+
delete newData[key];
|
|
58
|
+
|
|
59
|
+
return { data: newData };
|
|
60
|
+
}),
|
|
61
|
+
}))
|
|
62
|
+
);
|
|
47
63
|
|
|
48
64
|
const createStore = () =>
|
|
49
65
|
create<NavBarStoreState>((set) => ({
|
|
@@ -65,7 +81,15 @@ const createStore = () =>
|
|
|
65
81
|
},
|
|
66
82
|
}));
|
|
67
83
|
|
|
84
|
+
type ScreenContextType = {
|
|
85
|
+
_navBarStore: ReturnType<typeof createStore>;
|
|
86
|
+
_stateStore: ReturnType<typeof createStateStore>;
|
|
87
|
+
navBar: NavBarState;
|
|
88
|
+
legacyFormatScreenData: LegacyNavigationScreenData | null;
|
|
89
|
+
};
|
|
90
|
+
|
|
68
91
|
export const ScreenContext = createContext<ScreenContextType>({
|
|
92
|
+
_stateStore: createStateStore(),
|
|
69
93
|
_navBarStore: createStore(),
|
|
70
94
|
navBar: {
|
|
71
95
|
visible: true,
|
|
@@ -103,6 +127,21 @@ export function ScreenContextProvider({
|
|
|
103
127
|
null
|
|
104
128
|
);
|
|
105
129
|
|
|
130
|
+
const screenStateRef = useRef<null | ReturnType<typeof createStateStore>>(
|
|
131
|
+
null
|
|
132
|
+
);
|
|
133
|
+
|
|
134
|
+
const getScreenState = useCallback(() => {
|
|
135
|
+
if (screenStateRef.current !== null) {
|
|
136
|
+
return screenStateRef.current;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const stateStore = createStateStore();
|
|
140
|
+
screenStateRef.current = stateStore;
|
|
141
|
+
|
|
142
|
+
return stateStore;
|
|
143
|
+
}, []);
|
|
144
|
+
|
|
106
145
|
const getScreenNavBarState = useCallback(() => {
|
|
107
146
|
if (screenNavBarStateRef.current !== null) {
|
|
108
147
|
return screenNavBarStateRef.current;
|
|
@@ -163,6 +202,7 @@ export function ScreenContextProvider({
|
|
|
163
202
|
value={useMemo(
|
|
164
203
|
() => ({
|
|
165
204
|
_navBarStore: getScreenNavBarState(),
|
|
205
|
+
_stateStore: getScreenState(),
|
|
166
206
|
navBar: navBarState,
|
|
167
207
|
legacyFormatScreenData: routeScreenData,
|
|
168
208
|
}),
|