@propel-nsl/propel-react-native-sdk 1.1.7 → 1.2.1

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@propel-nsl/propel-react-native-sdk",
3
- "version": "1.1.7",
3
+ "version": "1.2.1",
4
4
  "description": "Propel Mobile SDK - React Native Core",
5
5
  "files": [
6
6
  "src/",
@@ -85,6 +85,10 @@ const OrderDetails: React.FC<Props> = ({ navigation, route }) => {
85
85
  return (
86
86
  <CustomImage source={Images?.pendingIcon} imgStyle={[styles.icon]} />
87
87
  );
88
+ case 'cancelled':
89
+ return (
90
+ <CustomImage source={Images?.redCrossIcon} imgStyle={[styles.icon]} />
91
+ );
88
92
  default:
89
93
  return null;
90
94
  }
@@ -106,6 +110,8 @@ const OrderDetails: React.FC<Props> = ({ navigation, route }) => {
106
110
  case 'complete':
107
111
  case 'Complete':
108
112
  return colors.green;
113
+ case 'cancelled':
114
+ return colors.red;
109
115
  default:
110
116
  return colors.orderDetailsText;
111
117
  }
@@ -128,7 +128,11 @@ const wasPhoneAlreadyVerified = useAppSelector(
128
128
  getDeviceId();
129
129
  }, []);
130
130
 
131
+ const isSubmitting = useRef(false);
132
+
131
133
  const handleVerify = async () => {
134
+ if (isSubmitting.current || verifyOtpLoading) return;
135
+ isSubmitting.current = true;
132
136
  dispatch(
133
137
  verifyMobileOtpRequest({
134
138
  client_key: "mobile_app",
@@ -143,6 +147,8 @@ const wasPhoneAlreadyVerified = useAppSelector(
143
147
  is_hppl_login: true,
144
148
  })
145
149
  );
150
+ // Reset guard after a short delay to allow retry on error
151
+ setTimeout(() => { isSubmitting.current = false; }, 1500);
146
152
  };
147
153
 
148
154
  const handleResendOTP = () => {
@@ -257,6 +263,7 @@ const wasPhoneAlreadyVerified = useAppSelector(
257
263
  title="Verify"
258
264
  onPress={handleVerify}
259
265
  disabled={otpInput.length < 4}
266
+ loading={verifyOtpLoading}
260
267
  customButtonContainerStyle={styles.buttonContainer}
261
268
  />
262
269
 
@@ -84,6 +84,14 @@ const PaymentMethod: React.FC<{
84
84
  }
85
85
  }, [cartId, dispatch]);
86
86
 
87
+ // Reset Apply button state when screen gains focus
88
+ useFocusEffect(
89
+ useCallback(() => {
90
+ setShowPointsApply(false);
91
+ return () => {};
92
+ }, [])
93
+ );
94
+
87
95
 
88
96
  return (
89
97
  <View style={styles.container}>
@@ -484,21 +484,23 @@ const ProductDetail: React.FC = () => {
484
484
 
485
485
  return (
486
486
  <SafeAreaView style={styles.container}>
487
- <View style={styles.header}>
488
- <View style={styles.headerContent}>
487
+ <View style={styles.headerSection}>
488
+ <View style={styles.userInfo}>
489
489
  <TouchableOpacity
490
490
  onPress={() => handleGoBack()}
491
491
  >
492
492
  <BackIcon />
493
493
  </TouchableOpacity>
494
+ </View>
495
+ <View style={styles.headerIcons}>
494
496
  <TouchableOpacity
495
497
  activeOpacity={0.7}
496
- style={styles.cartBadge}
498
+ style={styles.cartButton}
497
499
  onPress={() => navigateToCart()}
498
500
  >
499
501
  <View style={styles.cartCountContainer}>
500
502
  <Text style={styles.cartCountText}>
501
- {viewMyCartData?.items?.length}
503
+ {viewMyCartData?.items?.length || 0}
502
504
  </Text>
503
505
  </View>
504
506
  <CustomImage source={Images.cart} imgStyle={styles.cartIcon} />
@@ -9,11 +9,12 @@ const styles = StyleSheet.create({
9
9
  flex: 1,
10
10
  backgroundColor: colors.white,
11
11
  },
12
- header: {
13
- backgroundColor: colors.white,
14
- paddingHorizontal: 20,
15
- paddingTop: 20,
16
- paddingBottom: 20,
12
+ headerSection: {
13
+ flexDirection: 'row',
14
+ justifyContent: 'space-between',
15
+ alignItems: 'center',
16
+ paddingHorizontal: SCALE(20),
17
+ paddingBottom: VSCALE(16),
17
18
  },
18
19
  statusBar: {
19
20
  flexDirection: 'row',
@@ -41,23 +42,25 @@ const styles = StyleSheet.create({
41
42
  justifyContent: 'space-between',
42
43
  alignItems: 'center',
43
44
  },
44
- cartButton: {
45
- width: 42,
46
- height: 42,
47
- borderRadius: 100,
48
- backgroundColor: colors.white,
49
- justifyContent: 'center',
45
+ userInfo: {
46
+ flexDirection: 'row',
47
+ alignItems: 'center',
48
+ gap: SCALE(12),
49
+ },
50
+ headerIcons: {
51
+ flexDirection: 'row',
50
52
  alignItems: 'center',
51
- position: 'relative',
53
+ },
54
+ cartButton: {
55
+ padding: SCALE(8),
52
56
  },
53
57
  cartBadge: {
54
- position: 'absolute',
55
- top: 0,
56
- right: 9,
58
+ padding: SCALE(8),
57
59
  width: 11,
58
60
  height: 12,
59
61
  justifyContent: 'center',
60
62
  alignItems: 'center',
63
+ overflow: 'visible',
61
64
  },
62
65
  cartBadgeText: {
63
66
  fontFamily: FontFamily.LEXEND_REGULAR,
@@ -281,8 +284,8 @@ const styles = StyleSheet.create({
281
284
  color: colors.white,
282
285
  },
283
286
  cartIcon: {
284
- width: 24,
285
- height: 26,
287
+ width: SCALE(20),
288
+ height: SCALE(20),
286
289
  resizeMode: 'contain',
287
290
  },
288
291
  variantTitle: {
@@ -311,12 +314,14 @@ const styles = StyleSheet.create({
311
314
  },
312
315
  cartCountContainer: {
313
316
  position: 'absolute',
314
- right: SCALE(-4),
317
+ top: VSCALE(2),
318
+ right: SCALE(8),
319
+ backgroundColor: colors.error,
320
+ borderRadius: SCALE(10),
315
321
  width: SCALE(16),
316
- height: VSCALE(14),
322
+ height: SCALE(16),
317
323
  justifyContent: 'center',
318
324
  alignItems: 'center',
319
- top: VSCALE(-8),
320
325
  },
321
326
  cartCountText: {
322
327
  fontFamily: FontFamily.LEXEND_REGULAR,
@@ -261,20 +261,24 @@ const Redeem: React.FC = () => {
261
261
 
262
262
  return (
263
263
  <SafeAreaView style={styles.container}>
264
- <View style={styles.headerContent}>
265
- <Text style={styles.headerTitle}>{ROUTES.REDEEM}</Text>
266
- <TouchableOpacity
267
- activeOpacity={0.7}
268
- style={styles.cartBadge}
269
- onPress={navigateToCart}
270
- >
271
- <View style={styles.cartCountContainer}>
272
- <Text style={styles.cartCountText}>
273
- {viewMyCartData?.items?.length}
274
- </Text>
275
- </View>
276
- <CustomImage source={Images.cart} imgStyle={styles.cartIcon} />
277
- </TouchableOpacity>
264
+ <View style={styles.headerSection}>
265
+ <View style={styles.userInfo}>
266
+ <Text style={styles.headerTitle}>{ROUTES.REDEEM}</Text>
267
+ </View>
268
+ <View style={styles.headerIcons}>
269
+ <TouchableOpacity
270
+ activeOpacity={0.7}
271
+ style={styles.cartButton}
272
+ onPress={navigateToCart}
273
+ >
274
+ <View style={styles.cartCountContainer}>
275
+ <Text style={styles.cartCountText}>
276
+ {viewMyCartData?.items?.length || 0}
277
+ </Text>
278
+ </View>
279
+ <CustomImage source={Images.cart} imgStyle={styles.cartIcon} />
280
+ </TouchableOpacity>
281
+ </View>
278
282
  </View>
279
283
  <View style={styles.searchSection}>
280
284
  <View style={styles.searchBar}>
@@ -8,11 +8,12 @@ const styles = StyleSheet.create({
8
8
  flex: 1,
9
9
  backgroundColor: colors.background,
10
10
  },
11
- header: {
12
- backgroundColor: colors.background,
11
+ headerSection: {
12
+ flexDirection: 'row',
13
+ justifyContent: 'space-between',
14
+ alignItems: 'center',
13
15
  paddingHorizontal: SCALE(20),
14
- paddingTop: VSCALE(20),
15
- paddingBottom: VSCALE(28),
16
+ paddingBottom: VSCALE(16),
16
17
  },
17
18
  statusBar: {
18
19
  flexDirection: 'row',
@@ -35,8 +36,14 @@ const styles = StyleSheet.create({
35
36
  width: SCALE(77),
36
37
  height: VSCALE(13),
37
38
  },
38
- headerContent: {
39
- marginTop: VSCALE(30),
39
+ userInfo: {
40
+ flexDirection: 'row',
41
+ alignItems: 'center',
42
+ gap: SCALE(12),
43
+ },
44
+ headerIcons: {
45
+ flexDirection: 'row',
46
+ alignItems: 'center',
40
47
  },
41
48
  headerTitle: {
42
49
  fontFamily: FontFamily.LEXEND_REGULAR,
@@ -46,14 +53,11 @@ const styles = StyleSheet.create({
46
53
  textTransform: 'capitalize',
47
54
  textAlign: 'center',
48
55
  },
56
+ headerContent: {
57
+ marginTop: VSCALE(30),
58
+ },
49
59
  cartButton: {
50
- width: SCALE(42),
51
- height: SCALE(42),
52
- borderRadius: SCALE(100),
53
- backgroundColor: 'rgba(255, 255, 255, 0.45)',
54
- justifyContent: 'center',
55
- alignItems: 'center',
56
- position: 'relative',
60
+ padding: SCALE(8),
57
61
  },
58
62
  cartBadge: {
59
63
  position: 'absolute',
@@ -63,6 +67,7 @@ const styles = StyleSheet.create({
63
67
  height: VSCALE(20),
64
68
  justifyContent: 'center',
65
69
  alignItems: 'center',
70
+ overflow: 'visible',
66
71
  },
67
72
  cartBadgeText: {
68
73
  fontFamily: FontFamily.LEXEND_REGULAR,
@@ -234,8 +239,8 @@ const styles = StyleSheet.create({
234
239
  alignItems: 'center',
235
240
  },
236
241
  cartIcon: {
237
- width: SCALE(24),
238
- height: VSCALE(26),
242
+ width: SCALE(20),
243
+ height: SCALE(20),
239
244
  resizeMode: 'contain',
240
245
  },
241
246
  emptyText: {
@@ -246,12 +251,14 @@ const styles = StyleSheet.create({
246
251
  },
247
252
  cartCountContainer: {
248
253
  position: 'absolute',
249
- right: SCALE(0),
254
+ top: VSCALE(2),
255
+ right: SCALE(8),
256
+ backgroundColor: colors.error,
257
+ borderRadius: SCALE(10),
250
258
  width: SCALE(16),
251
- height: VSCALE(14),
259
+ height: SCALE(16),
252
260
  justifyContent: 'center',
253
261
  alignItems: 'center',
254
- top: VSCALE(-5),
255
262
  },
256
263
  cartCountText: {
257
264
  fontFamily: FontFamily.LEXEND_REGULAR,
@@ -45,7 +45,7 @@ const CustomButton: React.FC<CustomButtonProps> = ({
45
45
  buttonStyle,
46
46
  ]}
47
47
  onPress={onPress}
48
- disabled={disabled}
48
+ disabled={disabled || loading}
49
49
  >
50
50
  <View style={styles.row}>
51
51
  {loading ? (
@@ -70,7 +70,7 @@ const getStatusIcon = (status: string) => {
70
70
  );
71
71
  case 'cancelled':
72
72
  return (
73
- <CustomImage source={Images?.crossIcon} imgStyle={[styles.icon]} />
73
+ <CustomImage source={Images?.redCrossIcon} imgStyle={[styles.icon]} />
74
74
  );
75
75
  default:
76
76
  return null;
@@ -1,4 +1,4 @@
1
- import React, { useState, useEffect } from 'react';
1
+ import React, { useState, useEffect, useRef } from 'react';
2
2
  import {
3
3
  View,
4
4
  Text,
@@ -79,6 +79,7 @@ const OTPModal: React.FC<OTPModalProps> = ({
79
79
  if (visible) {
80
80
  setCountdown(60);
81
81
  setNewOtp('');
82
+ isSubmitting.current = false;
82
83
  }
83
84
  }, [visible]);
84
85
 
@@ -90,8 +91,14 @@ const OTPModal: React.FC<OTPModalProps> = ({
90
91
  return () => clearTimeout(timer);
91
92
  }, [visible, countdown]);
92
93
 
94
+ const isSubmitting = useRef(false);
95
+
93
96
  const handleVerify = () => {
97
+ if (isSubmitting.current || isVerifying) return;
98
+ isSubmitting.current = true;
94
99
  onVerify(newOtp);
100
+ // Reset guard after a short delay to allow retry on error
101
+ setTimeout(() => { isSubmitting.current = false; }, 1500);
95
102
  };
96
103
 
97
104
  const handleResendOTP = () => {