@propel-nsl/propel-react-native-sdk 1.0.2 → 1.0.5
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/package.json +26 -7
- package/src/PropelSDKScreen.tsx +3 -0
- package/src/SDKApp.tsx +25 -0
- package/src/components/SDKBackHandler.tsx +14 -3
- package/src/contexts/SDKContext.tsx +12 -0
- package/src/screens/Dashboard/index.tsx +41 -10
- package/src/screens/Profile/index.tsx +1 -20
- package/src/screens/RedemptionHistory/index.tsx +12 -2
- package/src-app/hooks/useAppSelector.ts +2 -2
- package/src-app/services/index.ts +37 -4
package/package.json
CHANGED
|
@@ -1,8 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@propel-nsl/propel-react-native-sdk",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.5",
|
|
4
4
|
"description": "Propel Mobile SDK - React Native Core",
|
|
5
|
-
"files": [
|
|
5
|
+
"files": [
|
|
6
|
+
"src/",
|
|
7
|
+
"src-app/",
|
|
8
|
+
"lib/",
|
|
9
|
+
"assets/",
|
|
10
|
+
"index.ts",
|
|
11
|
+
"CLIENT_INTEGRATION_GUIDE.md",
|
|
12
|
+
"RN_HOST_INTEGRATION.md",
|
|
13
|
+
"README.md"
|
|
14
|
+
],
|
|
6
15
|
"main": "index.ts",
|
|
7
16
|
"react-native": "lib/index.ts",
|
|
8
17
|
"types": "lib/index.ts",
|
|
@@ -53,11 +62,21 @@
|
|
|
53
62
|
"redux-saga": ">=1.0.0"
|
|
54
63
|
},
|
|
55
64
|
"peerDependenciesMeta": {
|
|
56
|
-
"@react-native-clipboard/clipboard": {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
"react-native-
|
|
60
|
-
|
|
65
|
+
"@react-native-clipboard/clipboard": {
|
|
66
|
+
"optional": true
|
|
67
|
+
},
|
|
68
|
+
"@react-native-community/masked-view": {
|
|
69
|
+
"optional": true
|
|
70
|
+
},
|
|
71
|
+
"react-native-image-picker": {
|
|
72
|
+
"optional": true
|
|
73
|
+
},
|
|
74
|
+
"react-native-permissions": {
|
|
75
|
+
"optional": true
|
|
76
|
+
},
|
|
77
|
+
"react-native-fast-image": {
|
|
78
|
+
"optional": true
|
|
79
|
+
}
|
|
61
80
|
},
|
|
62
81
|
"devDependencies": {
|
|
63
82
|
"@babel/core": "^7.25.2",
|
package/src/PropelSDKScreen.tsx
CHANGED
|
@@ -80,6 +80,9 @@ const PropelSDKScreen: React.FC<PropelSDKScreenProps> = (props) => {
|
|
|
80
80
|
},
|
|
81
81
|
// Flag so SDKApp knows it's running inside a RN host (no native bridge)
|
|
82
82
|
__rnHostMode: true,
|
|
83
|
+
// Pass navigation and onClose for proper back navigation
|
|
84
|
+
hostNavigation: props.navigation,
|
|
85
|
+
onClose: props.onClose,
|
|
83
86
|
};
|
|
84
87
|
|
|
85
88
|
return (
|
package/src/SDKApp.tsx
CHANGED
|
@@ -253,6 +253,8 @@ const SDKApp: React.FC<any> = (props) => {
|
|
|
253
253
|
navigateToTransactionHistory(from);
|
|
254
254
|
} else if (target === 'Redeem') {
|
|
255
255
|
navigateToRedeem(from);
|
|
256
|
+
} else if (target === 'Dashboard') {
|
|
257
|
+
console.log('🚀 Dashboard navigation after auth - no special navigation needed, using default flow');
|
|
256
258
|
}
|
|
257
259
|
},
|
|
258
260
|
[authenticateSDK, navigateToTransactionHistory, navigateToRedeem]
|
|
@@ -309,6 +311,14 @@ const SDKApp: React.FC<any> = (props) => {
|
|
|
309
311
|
lastSegment === 'redeem_screen' ||
|
|
310
312
|
lastSegment === 'redeemscreen';
|
|
311
313
|
|
|
314
|
+
const isDashboard =
|
|
315
|
+
normalized === 'dashboard' ||
|
|
316
|
+
normalized === 'dash' ||
|
|
317
|
+
normalized === 'home' ||
|
|
318
|
+
lastSegment === 'dashboard' ||
|
|
319
|
+
lastSegment === 'dash' ||
|
|
320
|
+
lastSegment === 'home';
|
|
321
|
+
|
|
312
322
|
if (isRedemptionHistory || isTransactionHistory) {
|
|
313
323
|
// Prevent duplicate handling
|
|
314
324
|
if (deepLinkHandledRef.current) {
|
|
@@ -330,6 +340,16 @@ const SDKApp: React.FC<any> = (props) => {
|
|
|
330
340
|
console.log('🚀 Intent matched! Will authenticate then navigate to Redeem...');
|
|
331
341
|
pendingDeepLinkRef.current = { target: 'Redeem', from: 'HostApp' };
|
|
332
342
|
authenticateAndNavigate('Redeem', 'HostApp');
|
|
343
|
+
} else if (isDashboard) {
|
|
344
|
+
// Prevent duplicate handling
|
|
345
|
+
if (deepLinkHandledRef.current) {
|
|
346
|
+
console.log('🚀 Deep link already handled, skipping duplicate call');
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
349
|
+
deepLinkHandledRef.current = true;
|
|
350
|
+
console.log('🚀 Intent matched! Will authenticate then navigate to Dashboard...');
|
|
351
|
+
pendingDeepLinkRef.current = { target: 'Dashboard', from: 'HostApp' };
|
|
352
|
+
authenticateAndNavigate('Dashboard', 'HostApp');
|
|
333
353
|
}
|
|
334
354
|
},
|
|
335
355
|
[authenticateAndNavigate]
|
|
@@ -488,8 +508,11 @@ const SDKApp: React.FC<any> = (props) => {
|
|
|
488
508
|
const isDeepLinkEntryValue = deepLinkToRedemptionHistory || deepLinkToRedeem;
|
|
489
509
|
const deepLinkTargetValue = deepLinkToRedemptionHistory ? 'RedemptionHistory' : (deepLinkToRedeem ? 'Redeem' : undefined);
|
|
490
510
|
const isRNHostMode = !!(initialParams as any)?.__rnHostMode;
|
|
511
|
+
const hostNavigation = (initialParams as any)?.hostNavigation;
|
|
512
|
+
const onClose = (initialParams as any)?.onClose;
|
|
491
513
|
|
|
492
514
|
console.log('🔍 SDKApp render: deepLinkToRedemptionHistory=', deepLinkToRedemptionHistory, 'deepLinkToRedeem=', deepLinkToRedeem, 'deepLinkTargetValue=', deepLinkTargetValue);
|
|
515
|
+
console.log('🔍 SDKApp render: isRNHostMode=', isRNHostMode, 'hasHostNavigation=', !!hostNavigation, 'hasOnClose=', !!onClose);
|
|
493
516
|
|
|
494
517
|
return (
|
|
495
518
|
<GestureHandlerRootView style={{ flex: 1 }}>
|
|
@@ -498,6 +521,8 @@ const SDKApp: React.FC<any> = (props) => {
|
|
|
498
521
|
isSDK={true}
|
|
499
522
|
initialDeepLinkEntry={isDeepLinkEntryValue}
|
|
500
523
|
initialDeepLinkTarget={deepLinkTargetValue}
|
|
524
|
+
hostNavigation={hostNavigation}
|
|
525
|
+
onClose={onClose}
|
|
501
526
|
>
|
|
502
527
|
<SafeAreaProvider>
|
|
503
528
|
<NavigationContainer
|
|
@@ -17,17 +17,28 @@ const HIDDEN_TABS = [
|
|
|
17
17
|
|
|
18
18
|
const SDKBackHandler: React.FC<{ children: React.ReactNode }> = ({ children }) => {
|
|
19
19
|
const navigation = useNavigation();
|
|
20
|
-
const { isDeepLinkEntry } = useSDKContext();
|
|
20
|
+
const { isDeepLinkEntry, hostNavigation, onClose } = useSDKContext();
|
|
21
21
|
const dispatch = useAppDispatch();
|
|
22
22
|
|
|
23
23
|
// Helper to exit SDK and clear auth state
|
|
24
24
|
const exitSDK = React.useCallback(() => {
|
|
25
25
|
console.log('🚀 Exiting SDK - clearing auth state');
|
|
26
26
|
dispatch(clearAllAuthState());
|
|
27
|
-
|
|
27
|
+
|
|
28
|
+
// Check if we're in RN host mode (hostNavigation or onClose available)
|
|
29
|
+
if (hostNavigation) {
|
|
30
|
+
console.log('🚀 RN Host Mode: Using hostNavigation.goBack()');
|
|
31
|
+
hostNavigation.goBack();
|
|
32
|
+
} else if (onClose) {
|
|
33
|
+
console.log('🚀 RN Host Mode: Using onClose callback');
|
|
34
|
+
onClose();
|
|
35
|
+
} else if (NativeModules.PropelSDKBridge?.closeSDK) {
|
|
36
|
+
console.log('🚀 Native Mode: Using PropelSDKBridge.closeSDK()');
|
|
28
37
|
NativeModules.PropelSDKBridge.closeSDK();
|
|
38
|
+
} else {
|
|
39
|
+
console.log('⚠️ No exit method available - SDK may not close properly');
|
|
29
40
|
}
|
|
30
|
-
}, [dispatch]);
|
|
41
|
+
}, [dispatch, hostNavigation, onClose]);
|
|
31
42
|
|
|
32
43
|
// Shared back handler logic
|
|
33
44
|
const handleBackPress = React.useCallback(() => {
|
|
@@ -19,6 +19,10 @@ interface SDKContextType {
|
|
|
19
19
|
deepLinkTarget?: string;
|
|
20
20
|
/** Set the deep link entry state */
|
|
21
21
|
setDeepLinkEntry: (isDeepLink: boolean, target?: string) => void;
|
|
22
|
+
/** Host app navigation (for RN host mode) */
|
|
23
|
+
hostNavigation?: any;
|
|
24
|
+
/** Callback to close SDK (for RN host mode) */
|
|
25
|
+
onClose?: () => void;
|
|
22
26
|
}
|
|
23
27
|
|
|
24
28
|
const SDKContext = createContext<SDKContextType>({
|
|
@@ -26,6 +30,8 @@ const SDKContext = createContext<SDKContextType>({
|
|
|
26
30
|
isDeepLinkEntry: false,
|
|
27
31
|
deepLinkTarget: undefined,
|
|
28
32
|
setDeepLinkEntry: () => {},
|
|
33
|
+
hostNavigation: undefined,
|
|
34
|
+
onClose: undefined,
|
|
29
35
|
});
|
|
30
36
|
|
|
31
37
|
export const useSDKContext = () => useContext(SDKContext);
|
|
@@ -36,6 +42,8 @@ interface SDKProviderProps {
|
|
|
36
42
|
sdkNavigation?: any;
|
|
37
43
|
initialDeepLinkEntry?: boolean;
|
|
38
44
|
initialDeepLinkTarget?: string;
|
|
45
|
+
hostNavigation?: any;
|
|
46
|
+
onClose?: () => void;
|
|
39
47
|
}
|
|
40
48
|
|
|
41
49
|
export const SDKProvider: React.FC<SDKProviderProps> = ({
|
|
@@ -44,6 +52,8 @@ export const SDKProvider: React.FC<SDKProviderProps> = ({
|
|
|
44
52
|
sdkNavigation,
|
|
45
53
|
initialDeepLinkEntry = false,
|
|
46
54
|
initialDeepLinkTarget,
|
|
55
|
+
hostNavigation,
|
|
56
|
+
onClose,
|
|
47
57
|
}) => {
|
|
48
58
|
const [isDeepLinkEntry, setIsDeepLinkEntry] = useState(initialDeepLinkEntry);
|
|
49
59
|
const [deepLinkTarget, setDeepLinkTarget] = useState<string | undefined>(initialDeepLinkTarget);
|
|
@@ -60,6 +70,8 @@ export const SDKProvider: React.FC<SDKProviderProps> = ({
|
|
|
60
70
|
isDeepLinkEntry,
|
|
61
71
|
deepLinkTarget,
|
|
62
72
|
setDeepLinkEntry,
|
|
73
|
+
hostNavigation,
|
|
74
|
+
onClose,
|
|
63
75
|
};
|
|
64
76
|
|
|
65
77
|
return (
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
ImageBackground,
|
|
10
10
|
Dimensions,
|
|
11
11
|
NativeModules,
|
|
12
|
+
BackHandler,
|
|
12
13
|
} from "react-native";
|
|
13
14
|
import { StackNavigationProp } from "@react-navigation/stack";
|
|
14
15
|
import { AppStackParamList } from "../../../src-app/types/navigation";
|
|
@@ -36,6 +37,7 @@ import { useFocusEffect } from "@react-navigation/native";
|
|
|
36
37
|
import { pointsFromCentsFixed } from "../../../src-app/constants/Formatter";
|
|
37
38
|
import CustomLoader from "../../../src-app/components/CustomLoader";
|
|
38
39
|
import { ROUTES } from "../../../src-app/constants/Routes";
|
|
40
|
+
import { useSDKContext } from "../../contexts/SDKContext";
|
|
39
41
|
|
|
40
42
|
type DashboardNavigationProp = StackNavigationProp<
|
|
41
43
|
AppStackParamList,
|
|
@@ -53,6 +55,7 @@ const Dashboard: React.FC<Props> = ({ navigation }) => {
|
|
|
53
55
|
const [resetOtpTrigger, setResetOtpTrigger] = useState(0);
|
|
54
56
|
const [messagepopUpVisible, setMessagepopUpVisible] = useState(false);
|
|
55
57
|
const [screen, setScreen] = useState("");
|
|
58
|
+
const { hostNavigation, onClose } = useSDKContext();
|
|
56
59
|
|
|
57
60
|
// Debug screen state changes
|
|
58
61
|
useEffect(() => {
|
|
@@ -196,6 +199,44 @@ const Dashboard: React.FC<Props> = ({ navigation }) => {
|
|
|
196
199
|
dispatch(viewMyCartRequest({ id: cartId }));
|
|
197
200
|
}, [cartId, dispatch]);
|
|
198
201
|
|
|
202
|
+
const handleBackToHost = () => {
|
|
203
|
+
console.log('🔙 Dashboard: handleBackToHost called');
|
|
204
|
+
// Clear all auth state before exiting SDK to prevent stale data on next launch
|
|
205
|
+
dispatch(clearAllAuthState());
|
|
206
|
+
|
|
207
|
+
// Check if we're in RN host mode (hostNavigation or onClose available)
|
|
208
|
+
if (hostNavigation) {
|
|
209
|
+
console.log('🚀 Dashboard: RN Host Mode - Using hostNavigation.goBack()');
|
|
210
|
+
hostNavigation.goBack();
|
|
211
|
+
} else if (onClose) {
|
|
212
|
+
console.log('🚀 Dashboard: RN Host Mode - Using onClose callback');
|
|
213
|
+
onClose();
|
|
214
|
+
} else if (NativeModules.PropelSDKBridge?.closeSDK) {
|
|
215
|
+
console.log('🚀 Dashboard: Native Mode - Using NativeModules.PropelSDKBridge.closeSDK()');
|
|
216
|
+
NativeModules.PropelSDKBridge.closeSDK();
|
|
217
|
+
} else if (NativeModules.PropelSDKBridge?.dismiss) {
|
|
218
|
+
console.log('🚀 Dashboard: Native Mode - Using NativeModules.PropelSDKBridge.dismiss()');
|
|
219
|
+
NativeModules.PropelSDKBridge.dismiss();
|
|
220
|
+
} else {
|
|
221
|
+
console.log('⚠️ Dashboard: No closeSDK method available');
|
|
222
|
+
}
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
// Add hardware back handler as fallback for Dashboard
|
|
226
|
+
useFocusEffect(
|
|
227
|
+
useCallback(() => {
|
|
228
|
+
const onBackPress = () => {
|
|
229
|
+
console.log('🔙 Dashboard: Hardware back pressed - calling handleBackToHost');
|
|
230
|
+
handleBackToHost();
|
|
231
|
+
return true; // Prevent default back behavior
|
|
232
|
+
};
|
|
233
|
+
|
|
234
|
+
const subscription = BackHandler.addEventListener('hardwareBackPress', onBackPress);
|
|
235
|
+
|
|
236
|
+
return () => subscription.remove();
|
|
237
|
+
}, [handleBackToHost])
|
|
238
|
+
);
|
|
239
|
+
|
|
199
240
|
const navigateToDashboardScreen = (screenName: string, params?: any) => {
|
|
200
241
|
// Navigate within DashboardStack for screens that are part of the stack
|
|
201
242
|
// For screens like MyCart, we need to navigate within the stack
|
|
@@ -280,16 +321,6 @@ const Dashboard: React.FC<Props> = ({ navigation }) => {
|
|
|
280
321
|
navigateToDashboardScreen("MyCart", { from: "Dashboard" });
|
|
281
322
|
};
|
|
282
323
|
|
|
283
|
-
const handleBackToHost = () => {
|
|
284
|
-
// Clear all auth state before exiting SDK to prevent stale data on next launch
|
|
285
|
-
dispatch(clearAllAuthState());
|
|
286
|
-
if (NativeModules.PropelSDKBridge?.closeSDK) {
|
|
287
|
-
NativeModules.PropelSDKBridge.closeSDK();
|
|
288
|
-
} else if (NativeModules.PropelSDKBridge?.dismiss) {
|
|
289
|
-
NativeModules.PropelSDKBridge.dismiss();
|
|
290
|
-
}
|
|
291
|
-
};
|
|
292
|
-
|
|
293
324
|
// Categories data with actual images
|
|
294
325
|
const categoriesData = [
|
|
295
326
|
{ id: "1", name: "Apparel", image: Images.categoryApparel },
|
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
resetAuthState,
|
|
20
20
|
uploadProfileImageRequest,
|
|
21
21
|
} from "../../../src-app/redux/authSlice";
|
|
22
|
-
import { CustomImage
|
|
22
|
+
import { CustomImage } from "../../../src-app/components";
|
|
23
23
|
import Images from "../../../src-app/constants/Images";
|
|
24
24
|
import { useAppSelector } from "../../../src-app/hooks/useAppSelector";
|
|
25
25
|
import { RootState } from "../../../src-app/redux/store";
|
|
@@ -79,7 +79,6 @@ const Profile: React.FC<ProfileProps> = ({ navigation }) => {
|
|
|
79
79
|
uploadProfileImageLoading,
|
|
80
80
|
uploadProfileImageError
|
|
81
81
|
} = useAppSelector((state: RootState) => state.auth);
|
|
82
|
-
const [logoutModalVisible, setLogoutModalVisible] = useState(false);
|
|
83
82
|
const myProfileLoading = useAppSelector((state: RootState) => state.auth.myProfileLoading);
|
|
84
83
|
const { myOrdersValidateOtpSuccessMessage } = useAppSelector(
|
|
85
84
|
(state: RootState) => state.auth
|
|
@@ -119,9 +118,6 @@ const Profile: React.FC<ProfileProps> = ({ navigation }) => {
|
|
|
119
118
|
}, [otpModalVisible, myOrdersValidateOtpSuccessMessage, screen, navigation, dispatch]);
|
|
120
119
|
|
|
121
120
|
|
|
122
|
-
const handleLogout = () => {
|
|
123
|
-
setLogoutModalVisible(true);
|
|
124
|
-
};
|
|
125
121
|
|
|
126
122
|
const handleMenuPress = (screen: string) => {
|
|
127
123
|
console.log('🚀 Profile handleMenuPress called with screen:', screen);
|
|
@@ -314,11 +310,6 @@ const Profile: React.FC<ProfileProps> = ({ navigation }) => {
|
|
|
314
310
|
/>
|
|
315
311
|
</View>
|
|
316
312
|
|
|
317
|
-
{/* Logout Button */}
|
|
318
|
-
<TouchableOpacity style={styles.logoutButton} onPress={handleLogout}>
|
|
319
|
-
<CustomImage source={Images.logout} imgStyle={styles.logoutIcon} />
|
|
320
|
-
<Text style={styles.logoutButtonText}>Logout</Text>
|
|
321
|
-
</TouchableOpacity>
|
|
322
313
|
</ScrollView>
|
|
323
314
|
</TouchableWithoutFeedback>
|
|
324
315
|
<OTPModal
|
|
@@ -344,16 +335,6 @@ const Profile: React.FC<ProfileProps> = ({ navigation }) => {
|
|
|
344
335
|
otpLength={4}
|
|
345
336
|
screen={screen}
|
|
346
337
|
/>
|
|
347
|
-
<Logout
|
|
348
|
-
visible={logoutModalVisible}
|
|
349
|
-
onClose={() => setLogoutModalVisible(false)}
|
|
350
|
-
onPress={() => {
|
|
351
|
-
setLogoutModalVisible(false);
|
|
352
|
-
navigation.reset({ index: 0, routes: [{ name: 'Login' }], });
|
|
353
|
-
dispatch(resetAuthState("verifyOtpSuccessMessage"));
|
|
354
|
-
dispatch(resetAuthState("otpSuccessMessage"));
|
|
355
|
-
}}
|
|
356
|
-
/>
|
|
357
338
|
<CustomLoader loading={!!myProfileLoading} text="Loading profile..." fullScreen />
|
|
358
339
|
</SafeAreaView>
|
|
359
340
|
);
|
|
@@ -47,7 +47,7 @@ const RedemptionHistory: React.FC<Props> = ({ navigation }) => {
|
|
|
47
47
|
const from = route.params?.from;
|
|
48
48
|
const exitToHost = (route.params as any)?.exitToHost;
|
|
49
49
|
const insets = useSafeAreaInsets();
|
|
50
|
-
const { isDeepLinkEntry } = useSDKContext();
|
|
50
|
+
const { isDeepLinkEntry, hostNavigation, onClose } = useSDKContext();
|
|
51
51
|
const dispatch = useAppDispatch();
|
|
52
52
|
|
|
53
53
|
// OTP modal state for deep link entry or direct access without prior OTP verification
|
|
@@ -72,9 +72,19 @@ const RedemptionHistory: React.FC<Props> = ({ navigation }) => {
|
|
|
72
72
|
if (exitToHost || (isDeepLinkEntry && (!from || from === 'DeepLink' || from === 'HostApp'))) {
|
|
73
73
|
console.log('🚀 RedemptionHistory: Deep link entry - exiting SDK to host app');
|
|
74
74
|
dispatch(clearAllAuthState());
|
|
75
|
-
|
|
75
|
+
|
|
76
|
+
// Check if we're in RN host mode (hostNavigation or onClose available)
|
|
77
|
+
if (hostNavigation) {
|
|
78
|
+
console.log('🚀 RedemptionHistory: RN Host Mode - Using hostNavigation.goBack()');
|
|
79
|
+
hostNavigation.goBack();
|
|
80
|
+
} else if (onClose) {
|
|
81
|
+
console.log('🚀 RedemptionHistory: RN Host Mode - Using onClose callback');
|
|
82
|
+
onClose();
|
|
83
|
+
} else if (NativeModules.PropelSDKBridge?.closeSDK) {
|
|
84
|
+
console.log('🚀 RedemptionHistory: Native Mode - Using closeSDK');
|
|
76
85
|
NativeModules.PropelSDKBridge.closeSDK();
|
|
77
86
|
} else if (NativeModules.PropelSDKBridge?.dismiss) {
|
|
87
|
+
console.log('🚀 RedemptionHistory: Native Mode - Using dismiss');
|
|
78
88
|
NativeModules.PropelSDKBridge.dismiss();
|
|
79
89
|
}
|
|
80
90
|
return true;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useSelector } from 'react-redux';
|
|
1
|
+
import { TypedUseSelectorHook, useSelector } from 'react-redux';
|
|
2
2
|
import type { RootState } from '../redux/store';
|
|
3
3
|
|
|
4
|
-
export const useAppSelector = useSelector
|
|
4
|
+
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;
|
|
@@ -33,8 +33,11 @@ const getDeviceId = async (): Promise<string> => {
|
|
|
33
33
|
|
|
34
34
|
|
|
35
35
|
const createAuthHeader = async (token: string): Promise<string> => {
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
// Try to get device ID from SDK credentials first (from host app), then fallback to device info
|
|
37
|
+
const creds = getSDKCredentials();
|
|
38
|
+
const deviceId = creds?.deviceId || await getDeviceId();
|
|
39
|
+
console.log('createAuthHeader: Using device ID:', deviceId, '(from host:', !!creds?.deviceId, ')');
|
|
40
|
+
return `Token token=${token};client_key=mobile_app;device_id=${deviceId};client_id=7b170ef2-c0a0-4968-a832-d308d54a8419;user_type=end_user;language_code=en;`;
|
|
38
41
|
};
|
|
39
42
|
|
|
40
43
|
|
|
@@ -67,8 +70,12 @@ export const sdkAuthApi = async () => {
|
|
|
67
70
|
|
|
68
71
|
const environment = creds.environment?.toUpperCase?.() || "PRODUCTION";
|
|
69
72
|
|
|
73
|
+
const resolvedDeviceId = creds.deviceId && typeof creds.deviceId === 'object' && typeof (creds.deviceId as any).then === 'function'
|
|
74
|
+
? await (creds.deviceId as Promise<string>)
|
|
75
|
+
: creds.deviceId;
|
|
76
|
+
|
|
70
77
|
const payload = {
|
|
71
|
-
device_id:
|
|
78
|
+
device_id: resolvedDeviceId || await getDeviceId(),
|
|
72
79
|
client_name: creds.clientName || "AndroidApp",
|
|
73
80
|
client_version: creds.clientVersion || "1.0.0",
|
|
74
81
|
environment,
|
|
@@ -83,7 +90,33 @@ export const sdkAuthApi = async () => {
|
|
|
83
90
|
"Content-Type": "application/json",
|
|
84
91
|
};
|
|
85
92
|
|
|
86
|
-
|
|
93
|
+
// Log complete authentication request
|
|
94
|
+
console.log('=== SDK AUTH API REQUEST ===');
|
|
95
|
+
console.log('URL:', ENDPOINTS.SDK_AUTH_INIT);
|
|
96
|
+
console.log('Headers:', {
|
|
97
|
+
"X-Auth-Token": creds.authToken.substring(0, 20) + '...',
|
|
98
|
+
"X-Auth-Id": creds.authId,
|
|
99
|
+
"Content-Type": "application/json",
|
|
100
|
+
});
|
|
101
|
+
console.log('Payload:', JSON.stringify(payload, null, 2));
|
|
102
|
+
console.log('=============================');
|
|
103
|
+
|
|
104
|
+
try {
|
|
105
|
+
const response = await api1.post(ENDPOINTS.SDK_AUTH_INIT, payload, { headers });
|
|
106
|
+
|
|
107
|
+
console.log('=== SDK AUTH API RESPONSE ===');
|
|
108
|
+
console.log('Status:', response.status);
|
|
109
|
+
console.log('Response Data:', JSON.stringify(response.data, null, 2));
|
|
110
|
+
console.log('==============================');
|
|
111
|
+
|
|
112
|
+
return response;
|
|
113
|
+
} catch (error: any) {
|
|
114
|
+
console.log('=== SDK AUTH API ERROR ===');
|
|
115
|
+
console.log('Error:', error?.response?.data || error?.message);
|
|
116
|
+
console.log('Status:', error?.response?.status);
|
|
117
|
+
console.log('==========================');
|
|
118
|
+
throw error;
|
|
119
|
+
}
|
|
87
120
|
};
|
|
88
121
|
export const myOrdersApi = async () => {
|
|
89
122
|
try {
|