tapjoy-react-native-sdk 13.1.2 → 13.2.0

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.
Files changed (65) hide show
  1. package/android/build.gradle +4 -1
  2. package/android/settings.gradle +1 -1
  3. package/android/src/main/java/com/tapjoyreactnativesdk/TapjoyReactNativeSdkModule.kt +281 -24
  4. package/example/android/app/build.gradle +3 -1
  5. package/example/android/app/proguard-rules.pro +19 -0
  6. package/example/android/app/src/main/AndroidManifest.xml +2 -1
  7. package/example/android/app/src/main/res/xml/network_security_config.xml +12 -0
  8. package/example/android/settings.gradle +1 -1
  9. package/example/ios/TapjoyReactNativeSdkExample.xcodeproj/project.pbxproj +16 -2
  10. package/example/metro.config.js +10 -2
  11. package/example/package.json +7 -3
  12. package/example/src/MainScreen.tsx +52 -46
  13. package/example/src/OfferwallScreen.tsx +263 -63
  14. package/example/src/SelectionMenu.tsx +70 -0
  15. package/example/src/Styles.ts +91 -5
  16. package/example/src/UserProperties.tsx +246 -8
  17. package/ios/TapjoyReactNativeSdk.m +17 -1
  18. package/ios/TapjoyReactNativeSdk.swift +276 -6
  19. package/lib/commonjs/TJEntryPoint.js +22 -0
  20. package/lib/commonjs/TJEntryPoint.js.map +1 -0
  21. package/lib/commonjs/TJPlacement.js +86 -2
  22. package/lib/commonjs/TJPlacement.js.map +1 -1
  23. package/lib/commonjs/TJPrivacyPolicy.js +52 -0
  24. package/lib/commonjs/TJPrivacyPolicy.js.map +1 -1
  25. package/lib/commonjs/TJSegment.js +16 -0
  26. package/lib/commonjs/TJSegment.js.map +1 -0
  27. package/lib/commonjs/TJStatus.js +15 -0
  28. package/lib/commonjs/TJStatus.js.map +1 -0
  29. package/lib/commonjs/TJVersion.js +2 -2
  30. package/lib/commonjs/index.js +14 -0
  31. package/lib/commonjs/index.js.map +1 -1
  32. package/lib/module/TJEntryPoint.js +15 -0
  33. package/lib/module/TJEntryPoint.js.map +1 -0
  34. package/lib/module/TJPlacement.js +86 -3
  35. package/lib/module/TJPlacement.js.map +1 -1
  36. package/lib/module/TJPrivacyPolicy.js +53 -1
  37. package/lib/module/TJPrivacyPolicy.js.map +1 -1
  38. package/lib/module/TJSegment.js +9 -0
  39. package/lib/module/TJSegment.js.map +1 -0
  40. package/lib/module/TJStatus.js +8 -0
  41. package/lib/module/TJStatus.js.map +1 -0
  42. package/lib/module/TJVersion.js +2 -2
  43. package/lib/module/index.js +3 -1
  44. package/lib/module/index.js.map +1 -1
  45. package/lib/typescript/TJEntryPoint.d.ts +14 -0
  46. package/lib/typescript/TJEntryPoint.d.ts.map +1 -0
  47. package/lib/typescript/TJPlacement.d.ts +59 -0
  48. package/lib/typescript/TJPlacement.d.ts.map +1 -1
  49. package/lib/typescript/TJPrivacyPolicy.d.ts +9 -0
  50. package/lib/typescript/TJPrivacyPolicy.d.ts.map +1 -1
  51. package/lib/typescript/TJSegment.d.ts +8 -0
  52. package/lib/typescript/TJSegment.d.ts.map +1 -0
  53. package/lib/typescript/TJStatus.d.ts +7 -0
  54. package/lib/typescript/TJStatus.d.ts.map +1 -0
  55. package/lib/typescript/index.d.ts +3 -1
  56. package/lib/typescript/index.d.ts.map +1 -1
  57. package/package.json +3 -2
  58. package/src/TJEntryPoint.ts +14 -0
  59. package/src/TJPlacement.ts +86 -3
  60. package/src/TJPrivacyPolicy.ts +62 -1
  61. package/src/TJSegment.ts +8 -0
  62. package/src/TJStatus.ts +7 -0
  63. package/src/TJVersion.ts +2 -2
  64. package/src/index.ts +3 -1
  65. package/tapjoy-react-native-sdk.podspec +1 -1
@@ -1,5 +1,12 @@
1
1
  import React, { useState, useEffect } from 'react';
2
- import { View, SafeAreaView, TextInput, Platform, Text } from 'react-native';
2
+ import {
3
+ View,
4
+ SafeAreaView,
5
+ TextInput,
6
+ Platform,
7
+ Text,
8
+ ScrollView,
9
+ } from 'react-native';
3
10
  import AsyncStorage from '@react-native-async-storage/async-storage';
4
11
  import {
5
12
  getTrackingStatus,
@@ -7,7 +14,7 @@ import {
7
14
  } from 'react-native-tracking-transparency';
8
15
  import styles from './Styles';
9
16
  import Button from './Button';
10
- import Tapjoy, { TJPrivacyPolicy, TJVersion } from 'tapjoy-react-native-sdk';
17
+ import Tapjoy, { TJVersion } from 'tapjoy-react-native-sdk';
11
18
 
12
19
  const MainScreen: React.FC = () => {
13
20
  const [sdkKey, setSdkKey] = useState<string>('');
@@ -37,13 +44,6 @@ const MainScreen: React.FC = () => {
37
44
 
38
45
  const handleConnect = async () => {
39
46
  try {
40
- //Privacy related flags
41
- let privacyPolicy = new TJPrivacyPolicy();
42
- privacyPolicy.setBelowConsentAge(false);
43
- privacyPolicy.setSubjectToGDPR(true);
44
- privacyPolicy.setUSPrivacy('1---');
45
- privacyPolicy.setUserConsent('1');
46
-
47
47
  setIsConnecting(true);
48
48
  await AsyncStorage.setItem('sdkKey', sdkKey);
49
49
 
@@ -63,8 +63,10 @@ const MainScreen: React.FC = () => {
63
63
  'Tapjoy SDK Connected' +
64
64
  (userId !== null ? `\nFlags: ${JSON.stringify(flags)}` : '')
65
65
  );
66
- } catch (error) {
67
- setStatusLabelText(`Tapjoy SDK failed to connect: ${error}`);
66
+ } catch (error: any) {
67
+ setStatusLabelText(
68
+ `Tapjoy SDK failed to connect. code: ${error.code}, message: ${error.message}`
69
+ );
68
70
  setIsConnecting(false);
69
71
  }
70
72
  };
@@ -108,44 +110,48 @@ const MainScreen: React.FC = () => {
108
110
  };
109
111
 
110
112
  return (
111
- <SafeAreaView style={styles.container}>
112
- <View style={styles.lineGap}>
113
- <Text style={styles.statusText}>{statusLabelText}</Text>
114
- </View>
115
- <View style={styles.inputContainer}>
116
- <TextInput
117
- style={styles.textInput}
118
- value={sdkKey}
119
- onChangeText={setSdkKey}
120
- placeholder="Enter SDK Key"
121
- />
122
- <Button
123
- title="Connect"
124
- style={styles.zeroFlex}
125
- onPress={handleConnect}
126
- disabled={isConnecting || Tapjoy.isConnected()}
127
- />
128
- </View>
129
- <View style={styles.currencyOuterContainer}>
130
- <Text style={styles.labelText}>{'Managed Currency:'}</Text>
131
- <View style={styles.currencyInnerContainer}>
132
- <Button
133
- style={styles.buttonGap}
134
- title="Get"
135
- onPress={getCurrencyBalance}
136
- />
137
- <Button
138
- style={styles.buttonGap}
139
- title="Spend"
140
- onPress={spendCurrency}
141
- />
142
- <Button title="Award" onPress={awardCurrency} />
143
- </View>
144
- </View>
113
+ <View style={styles.mainContainer}>
114
+ <ScrollView>
115
+ <SafeAreaView style={styles.container}>
116
+ <View style={styles.lineGap}>
117
+ <Text style={styles.statusText}>{statusLabelText}</Text>
118
+ </View>
119
+ <View style={styles.inputContainer}>
120
+ <TextInput
121
+ style={styles.textInput}
122
+ value={sdkKey}
123
+ onChangeText={setSdkKey}
124
+ placeholder="Enter SDK Key"
125
+ />
126
+ <Button
127
+ title="Connect"
128
+ style={styles.zeroFlex}
129
+ onPress={handleConnect}
130
+ disabled={isConnecting || Tapjoy.isConnected()}
131
+ />
132
+ </View>
133
+ <View style={styles.currencyOuterContainer}>
134
+ <Text style={styles.labelText}>{'Managed Currency:'}</Text>
135
+ <View style={styles.currencyInnerContainer}>
136
+ <Button
137
+ style={styles.buttonGap}
138
+ title="Get"
139
+ onPress={getCurrencyBalance}
140
+ />
141
+ <Button
142
+ style={styles.buttonGap}
143
+ title="Spend"
144
+ onPress={spendCurrency}
145
+ />
146
+ <Button title="Award" onPress={awardCurrency} />
147
+ </View>
148
+ </View>
149
+ </SafeAreaView>
150
+ </ScrollView>
145
151
  <Text style={styles.versionText}>
146
152
  Version: {TJVersion.getPluginVersion()}
147
153
  </Text>
148
- </SafeAreaView>
154
+ </View>
149
155
  );
150
156
  };
151
157
 
@@ -1,25 +1,35 @@
1
- import React, { useState, useEffect } from 'react';
1
+ import React, { useEffect, useState } from 'react';
2
2
  import { useFocusEffect } from '@react-navigation/native';
3
3
  import {
4
+ FlatList,
4
5
  SafeAreaView,
5
- View,
6
- TextInput,
6
+ ScrollView,
7
7
  Text,
8
- TouchableWithoutFeedback,
9
- Keyboard,
10
- FlatList,
8
+ TextInput,
9
+ View,
11
10
  } from 'react-native';
11
+ import dayjs from 'dayjs';
12
12
  import AsyncStorage from '@react-native-async-storage/async-storage';
13
13
  import Button from './Button';
14
- import styles from './Styles';
14
+ import styles, { pickerSelectStyles } from './Styles';
15
15
  import Tapjoy, { TJPlacement } from 'tapjoy-react-native-sdk';
16
+ import RNPickerSelect from 'react-native-picker-select';
17
+ import TJEntryPoint from '../../src/TJEntryPoint';
18
+
19
+ let offerwallPlacement: TJPlacement;
16
20
 
17
21
  const OfferwallScreen: React.FC = () => {
18
22
  const [offerwallPlacementName, _setOfferwallPlacementName] =
19
23
  useState<string>('offerwall_unit');
20
24
  const [isSdkConnected, setIsSdkConnected] = useState<boolean>(false);
21
- const [, setPlacementState] = useState<string>('');
25
+ const [placementState, setPlacementState] = useState<string>('');
22
26
  const [logData, setLogData] = useState<Array<string>>([]);
27
+ const [entryPoint, setEntryPoint] = useState<TJEntryPoint>(
28
+ TJEntryPoint.TJEntryPointUnknown
29
+ );
30
+ const [currencyId, _setCurrencyId] = useState<string>('');
31
+ const [currencyBalance, _setCurrencyBalance] = useState<string>('');
32
+ const [requiredAmount, _setRequiredAmount] = useState<string>('');
23
33
 
24
34
  useFocusEffect(
25
35
  React.useCallback(() => {
@@ -31,6 +41,18 @@ const OfferwallScreen: React.FC = () => {
31
41
  retrieveStoredPlacementName();
32
42
  });
33
43
 
44
+ useEffect(() => {
45
+ retrieveCurrencyId().then();
46
+ });
47
+
48
+ useEffect(() => {
49
+ retrieveCurrencyBalance().then();
50
+ });
51
+
52
+ useEffect(() => {
53
+ retrieveRequiredAmount().then();
54
+ });
55
+
34
56
  const retrieveStoredPlacementName = () => {
35
57
  AsyncStorage.getItem('placementName').then(async (value) => {
36
58
  if (value !== null) {
@@ -39,12 +61,117 @@ const OfferwallScreen: React.FC = () => {
39
61
  });
40
62
  };
41
63
 
64
+ const retrieveCurrencyId = async () => {
65
+ try {
66
+ const value = await AsyncStorage.getItem('currencyId');
67
+ if (value !== null) {
68
+ await setCurrencyId(value);
69
+ }
70
+ } catch (error) {
71
+ addLogItem(`Failed to retrieve currency ID: ${error}`);
72
+ }
73
+ };
74
+
75
+ const retrieveCurrencyBalance = async () => {
76
+ try {
77
+ const value = await AsyncStorage.getItem('currencyBalance');
78
+ if (value !== null) {
79
+ await setCurrencyBalance(value);
80
+ }
81
+ } catch (error) {
82
+ addLogItem(`Failed to retrieve currency balance: ${error}`);
83
+ }
84
+ };
85
+
86
+ const retrieveRequiredAmount = async () => {
87
+ try {
88
+ const value = await AsyncStorage.getItem('requiredAmount');
89
+ if (value !== null) {
90
+ await setRequiredAmount(value);
91
+ }
92
+ } catch (error) {
93
+ addLogItem(`Failed to retrieve currency requiredAmount: ${error}`);
94
+ }
95
+ };
96
+
97
+ const setCurrencyId = async (id: string) => {
98
+ _setCurrencyId(id);
99
+ let trimmedCurrencyId = id.trim();
100
+ await AsyncStorage.setItem('currencyId', trimmedCurrencyId);
101
+ };
102
+
103
+ const setCurrencyBalance = async (balance: string) => {
104
+ _setCurrencyBalance(balance);
105
+ let trimmedCurrencyBalance = balance.trim();
106
+ await AsyncStorage.setItem('currencyBalance', trimmedCurrencyBalance);
107
+ };
108
+
109
+ const setRequiredAmount = async (newValue: string) => {
110
+ _setRequiredAmount(newValue);
111
+ let trimmedValue = newValue.trim();
112
+ await AsyncStorage.setItem('requiredAmount', trimmedValue);
113
+ };
114
+
115
+ const handleClearCurrencyId = async () => {
116
+ await setCurrencyId('');
117
+ };
118
+
119
+ const handleClearCurrencyBalance = async () => {
120
+ await setCurrencyBalance('');
121
+ };
122
+
123
+ const handleClearRequiredAmount = async () => {
124
+ await setRequiredAmount('');
125
+ };
126
+
42
127
  const handleClearInput = async () => {
43
128
  await setOfferwallPlacementName('');
44
129
  };
45
130
 
46
- const loadPlacement = () => {
47
- let offerwallPlacement = new TJPlacement(offerwallPlacementName);
131
+ const loadPlacement = async () => {
132
+ offerwallPlacement = new TJPlacement(offerwallPlacementName);
133
+
134
+ if (currencyId !== '') {
135
+ if (currencyBalance !== '') {
136
+ try {
137
+ await offerwallPlacement?.setCurrencyBalance(
138
+ currencyId,
139
+ Number(currencyBalance)
140
+ );
141
+ addLogItem(
142
+ 'setCurrencyBalance: ' +
143
+ (await offerwallPlacement?.getCurrencyBalance(currencyId))
144
+ );
145
+ } catch (e: any) {
146
+ addLogItem(`currencyBalanceError: ${e.code} - ${e.message}`);
147
+ }
148
+ }
149
+
150
+ if (requiredAmount !== '') {
151
+ try {
152
+ await offerwallPlacement?.setRequiredAmount(
153
+ Number(requiredAmount),
154
+ currencyId
155
+ );
156
+ addLogItem(
157
+ 'setCurrencyRequiredAmount: ' +
158
+ JSON.stringify(
159
+ await offerwallPlacement?.getRequiredAmount(currencyId)
160
+ )
161
+ );
162
+ } catch (e: any) {
163
+ addLogItem(`requiredAmountError: ${e.code} - ${e.message}`);
164
+ }
165
+ }
166
+ }
167
+
168
+ if (entryPoint !== TJEntryPoint.TJEntryPointUnknown) {
169
+ offerwallPlacement.setEntryPoint(entryPoint);
170
+ addLogItem(
171
+ 'setEntryPoint: ' + (await offerwallPlacement?.getEntryPoint())
172
+ );
173
+ }
174
+
48
175
  offerwallPlacement.on(
49
176
  TJPlacement.REQUEST_DID_SUCCEED,
50
177
  (placement: TJPlacement) => {
@@ -78,8 +205,8 @@ const OfferwallScreen: React.FC = () => {
78
205
  };
79
206
 
80
207
  const showPlacement = () => {
81
- let offerwallPlacement = new TJPlacement(offerwallPlacementName);
82
- if (offerwallPlacement === undefined) {
208
+ addLogItem(offerwallPlacement.name);
209
+ if (placementState !== 'ready') {
83
210
  addLogItem(`"${offerwallPlacementName}" placement not loaded.`);
84
211
  setPlacementState('failed');
85
212
  return;
@@ -110,62 +237,135 @@ const OfferwallScreen: React.FC = () => {
110
237
  await AsyncStorage.setItem('placementName', placementName);
111
238
  };
112
239
 
113
- const handleDismissKeyboard = () => {
114
- Keyboard.dismiss();
115
- };
116
-
117
240
  const addLogItem = (item: string) => {
118
- const timestamp = new Date().toLocaleTimeString();
119
- logData.push(timestamp + ' ' + item);
241
+ logData.push(dayjs(new Date()).format('HH:mm:ss') + ' ' + item);
120
242
  setLogData(logData);
121
243
  };
122
244
 
245
+ const entryPointArray = [
246
+ { label: 'Other', value: TJEntryPoint.TJEntryPointOther },
247
+ { label: 'Main Menu', value: TJEntryPoint.TJEntryPointMainMenu },
248
+ { label: 'HUD', value: TJEntryPoint.TJEntryPointHud },
249
+ { label: 'Exit', value: TJEntryPoint.TJEntryPointExit },
250
+ { label: 'Fail', value: TJEntryPoint.TJEntryPointFail },
251
+ { label: 'Complete', value: TJEntryPoint.TJEntryPointComplete },
252
+ { label: 'Inbox', value: TJEntryPoint.TJEntryPointInbox },
253
+ { label: 'Initialisation', value: TJEntryPoint.TJEntryPointInit },
254
+ { label: 'Store', value: TJEntryPoint.TJEntryPointStore },
255
+ ];
256
+
123
257
  return (
124
- <TouchableWithoutFeedback onPress={handleDismissKeyboard}>
125
- <SafeAreaView style={styles.container}>
126
- <View style={styles.inputContainer}>
127
- <TextInput
128
- style={styles.textInput}
129
- value={offerwallPlacementName}
130
- onChangeText={setOfferwallPlacementName}
131
- autoCorrect={false}
132
- placeholder="Enter Placement Name"
133
- placeholderTextColor="#888"
134
- autoCapitalize="none"
135
- />
136
- <Button
137
- style={styles.clearButton}
138
- onPress={handleClearInput}
139
- title={'\u2573'}
140
- />
141
- </View>
142
- <View style={styles.buttonContainer}>
143
- <Button
144
- onPress={loadPlacement}
145
- disabled={!isSdkConnected}
146
- title={'Request'}
147
- />
148
- <View style={styles.buttonGap} />
149
- <Button
150
- onPress={showPlacement}
151
- disabled={!new TJPlacement(offerwallPlacementName).isContentReady()}
152
- title={'Display'}
153
- />
154
- </View>
155
- <View style={styles.owLogContainer}>
156
- <FlatList
157
- contentContainerStyle={styles.flexGrow}
158
- data={logData}
159
- renderItem={({ item }) => (
160
- <View>
161
- <Text style={styles.logText}>{item}</Text>
162
- </View>
163
- )}
164
- keyExtractor={(_item, index) => index.toString()}
165
- />
166
- </View>
167
- </SafeAreaView>
168
- </TouchableWithoutFeedback>
258
+ <View style={styles.mainContainer}>
259
+ <ScrollView style={styles.offerwallScrollContainer}>
260
+ <SafeAreaView style={styles.container}>
261
+ <View style={styles.inputContainer}>
262
+ <TextInput
263
+ style={styles.textInput}
264
+ value={offerwallPlacementName}
265
+ onChangeText={setOfferwallPlacementName}
266
+ autoCorrect={false}
267
+ placeholder="Enter Placement Name"
268
+ placeholderTextColor="#888"
269
+ autoCapitalize="none"
270
+ />
271
+ <Button
272
+ style={styles.clearButton}
273
+ onPress={handleClearInput}
274
+ title={'\u2573'}
275
+ />
276
+ </View>
277
+ <View style={styles.buttonContainer}>
278
+ <Button
279
+ onPress={loadPlacement}
280
+ disabled={!isSdkConnected}
281
+ title={'Request'}
282
+ />
283
+ <View style={styles.buttonGap} />
284
+ <Button
285
+ onPress={showPlacement}
286
+ disabled={!(placementState === 'ready')}
287
+ title={'Display'}
288
+ />
289
+ </View>
290
+ <View style={styles.inputContainer}>
291
+ <Text style={styles.userPropertiesLabel}>Entry Point: </Text>
292
+ <RNPickerSelect
293
+ placeholder={{
294
+ label: 'Select Entry Point...',
295
+ value: TJEntryPoint.TJEntryPointUnknown,
296
+ }}
297
+ onValueChange={async (value: any) => {
298
+ offerwallPlacement?.setEntryPoint(value);
299
+ setEntryPoint(value);
300
+ }}
301
+ items={entryPointArray}
302
+ style={pickerSelectStyles}
303
+ useNativeAndroidPickerStyle={false}
304
+ touchableWrapperProps={{ style: { flex: 1 } }}
305
+ />
306
+ </View>
307
+ <View style={styles.inputContainer}>
308
+ <Text style={styles.userPropertiesLabel}>Currency ID:</Text>
309
+ <TextInput
310
+ style={styles.textInput}
311
+ value={currencyId}
312
+ keyboardType={'default'}
313
+ onChangeText={setCurrencyId}
314
+ placeholder="Enter Currency ID."
315
+ placeholderTextColor="#888"
316
+ />
317
+ <Button
318
+ style={styles.clearButton}
319
+ onPress={handleClearCurrencyId}
320
+ title={'\u2573'}
321
+ />
322
+ </View>
323
+ <View style={styles.inputContainer}>
324
+ <Text style={styles.userPropertiesLabel}>Currency Balance:</Text>
325
+ <TextInput
326
+ style={styles.textInput}
327
+ value={currencyBalance}
328
+ keyboardType={'numeric'}
329
+ onChangeText={setCurrencyBalance}
330
+ placeholder="Enter Currency Balance."
331
+ placeholderTextColor="#888"
332
+ />
333
+ <Button
334
+ style={styles.clearButton}
335
+ onPress={handleClearCurrencyBalance}
336
+ title={'\u2573'}
337
+ />
338
+ </View>
339
+ <View style={styles.inputContainer}>
340
+ <Text style={styles.userPropertiesLabel}>Required Amount:</Text>
341
+ <TextInput
342
+ style={styles.textInput}
343
+ value={requiredAmount}
344
+ keyboardType={'numeric'}
345
+ onChangeText={setRequiredAmount}
346
+ placeholder="Enter Required Amount."
347
+ placeholderTextColor="#888"
348
+ />
349
+ <Button
350
+ style={styles.clearButton}
351
+ onPress={handleClearRequiredAmount}
352
+ title={'\u2573'}
353
+ />
354
+ </View>
355
+ </SafeAreaView>
356
+ </ScrollView>
357
+ <View style={styles.owLogContainer}>
358
+ <FlatList
359
+ data={logData}
360
+ renderItem={({ item }) => (
361
+ <View>
362
+ <Text style={styles.logText}>{item}</Text>
363
+ </View>
364
+ )}
365
+ keyExtractor={(_item, index) => index.toString()}
366
+ />
367
+ </View>
368
+ </View>
169
369
  );
170
370
  };
171
371
 
@@ -0,0 +1,70 @@
1
+ import React, { useState, useEffect } from 'react';
2
+ import { View, Text, TouchableOpacity, FlatList } from 'react-native';
3
+ import styles from './Styles';
4
+
5
+ interface Item {
6
+ value: any;
7
+ label: string;
8
+ }
9
+
10
+ interface Props {
11
+ data: Item[];
12
+ initialSelectedItem: Item | null;
13
+ onSelectItem: (item: Item) => void;
14
+ }
15
+
16
+ const SelectionMenu: React.FC<Props> = ({
17
+ data,
18
+ initialSelectedItem,
19
+ onSelectItem,
20
+ }) => {
21
+ const [selectedItem, setSelectedItem] = useState<Item | null>(
22
+ initialSelectedItem
23
+ );
24
+
25
+ const handleItemPress = (item: Item) => {
26
+ onSelectItem(item);
27
+ setSelectedItem(item);
28
+ };
29
+
30
+ useEffect(() => {
31
+ setSelectedItem(initialSelectedItem);
32
+ }, [initialSelectedItem]);
33
+
34
+ const renderItem = ({ item }: { item: Item }) => {
35
+ return (
36
+ <TouchableOpacity
37
+ style={[
38
+ { width: `${100 / data.length}%` },
39
+ styles.item,
40
+ selectedItem?.value === item.value && styles.selectedItem,
41
+ ]}
42
+ onPress={() => handleItemPress(item)}
43
+ >
44
+ <Text
45
+ style={[
46
+ styles.itemText,
47
+ selectedItem?.value === item.value && styles.selectionMenuItemText,
48
+ ]}
49
+ >
50
+ {item.label}
51
+ </Text>
52
+ </TouchableOpacity>
53
+ );
54
+ };
55
+
56
+ return (
57
+ <View style={styles.selectionMenuContainer}>
58
+ <FlatList
59
+ data={data}
60
+ renderItem={renderItem}
61
+ keyExtractor={(item) => item.value.toString()}
62
+ horizontal
63
+ showsHorizontalScrollIndicator={false}
64
+ contentContainerStyle={styles.flatListContent}
65
+ />
66
+ </View>
67
+ );
68
+ };
69
+
70
+ export default SelectionMenu;