@finspringinnovations/fdsdk 0.0.4 → 0.0.6
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/lib/api/baseApi.js +17 -6
- package/lib/api/masterDataApi.js +21 -1
- package/lib/api/workflowApi.js +46 -1
- package/lib/config/appDataConfig.d.ts +5 -0
- package/lib/hooks/usePaymentSSE.d.ts +7 -1
- package/lib/hooks/usePaymentSSE.js +287 -63
- package/lib/navigation/RootNavigator.js +10 -2
- package/lib/screens/AadhaarVerification.js +2 -2
- package/lib/screens/FDCalculator.js +6 -2
- package/lib/screens/FDList.js +37 -64
- package/lib/screens/Payment.js +159 -27
- package/lib/screens/PaymentStatus.js +139 -25
- package/lib/screens/ReviewKYC.js +45 -97
- package/lib/utils/sseParser.js +19 -3
- package/package.json +1 -1
- package/src/api/baseApi.ts +19 -6
- package/src/api/masterDataApi.ts +21 -3
- package/src/api/workflowApi.ts +50 -1
- package/src/config/appDataConfig.ts +5 -0
- package/src/hooks/usePaymentSSE.ts +307 -66
- package/src/navigation/RootNavigator.tsx +8 -2
- package/src/screens/AadhaarVerification.tsx +2 -2
- package/src/screens/FDCalculator.tsx +7 -2
- package/src/screens/FDList.tsx +37 -76
- package/src/screens/Payment.tsx +181 -38
- package/src/screens/PaymentStatus.tsx +158 -43
- package/src/screens/ReviewKYC.tsx +94 -170
- package/src/utils/sseParser.ts +20 -4
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React, { useState, useEffect, useRef } from 'react';
|
|
2
2
|
import { useRoute } from '@react-navigation/native';
|
|
3
|
-
import { View, Text, StyleSheet, ScrollView, TouchableOpacity, Alert, Image, TouchableWithoutFeedback, Keyboard, TextInput
|
|
3
|
+
import { View, Text, StyleSheet, ScrollView, TouchableOpacity, Alert, Image, TouchableWithoutFeedback, Keyboard, TextInput } from 'react-native';
|
|
4
4
|
import Icon from 'react-native-vector-icons/Ionicons';
|
|
5
5
|
import SafeAreaWrapper from '../components/SafeAreaWrapper';
|
|
6
6
|
import { Header, DropdownSelector } from '../components';
|
|
@@ -209,7 +209,6 @@ const ReviewKYC: React.FC<ReviewKYCProps> = ({
|
|
|
209
209
|
|
|
210
210
|
// State to track marital status dropdown visibility
|
|
211
211
|
const [showMaritalStatusMenu, setShowMaritalStatusMenu] = useState(false);
|
|
212
|
-
const [isGoingBack, setIsGoingBack] = useState(false);
|
|
213
212
|
|
|
214
213
|
// Ref to track currently focused text input
|
|
215
214
|
const focusedTextInputRef = useRef<TextInput | null>(null);
|
|
@@ -287,10 +286,6 @@ const ReviewKYC: React.FC<ReviewKYCProps> = ({
|
|
|
287
286
|
// Validate individual field and set error
|
|
288
287
|
const validateField = (field: keyof KYCData, value: string): string => {
|
|
289
288
|
if (!value || value.trim().length === 0) {
|
|
290
|
-
// Use "District" for area field
|
|
291
|
-
if (field === 'area') {
|
|
292
|
-
return 'District is required';
|
|
293
|
-
}
|
|
294
289
|
return `${field.charAt(0).toUpperCase() + field.slice(1)} is required`;
|
|
295
290
|
}
|
|
296
291
|
|
|
@@ -298,12 +293,6 @@ const ReviewKYC: React.FC<ReviewKYCProps> = ({
|
|
|
298
293
|
const textFields = ['area', 'city', 'addressLine1', 'addressLine2', 'state', 'country'];
|
|
299
294
|
if (textFields.includes(field)) {
|
|
300
295
|
if (value.trim().length < 2) {
|
|
301
|
-
// Use "Address" for addressLine1 and addressLine2
|
|
302
|
-
if (field === 'addressLine1' || field === 'addressLine2') {
|
|
303
|
-
return 'Address must be at least 2 characters';
|
|
304
|
-
} else if (field === 'area') {
|
|
305
|
-
return 'District must be at least 2 characters';
|
|
306
|
-
}
|
|
307
296
|
return `${field.charAt(0).toUpperCase() + field.slice(1)} must be at least 2 characters`;
|
|
308
297
|
}
|
|
309
298
|
}
|
|
@@ -334,9 +323,7 @@ const ReviewKYC: React.FC<ReviewKYCProps> = ({
|
|
|
334
323
|
|
|
335
324
|
return (
|
|
336
325
|
<View style={styles.errorContainer}>
|
|
337
|
-
{
|
|
338
|
-
<Icon name="warning" size={16} color={colors.error || '#FF0000'} style={styles.errorIcon} />
|
|
339
|
-
)}
|
|
326
|
+
<Icon name="warning" size={16} color={colors.error || '#FF0000'} style={styles.errorIcon} />
|
|
340
327
|
<Text style={styles.errorText}>{error}</Text>
|
|
341
328
|
</View>
|
|
342
329
|
);
|
|
@@ -550,6 +537,8 @@ const ReviewKYC: React.FC<ReviewKYCProps> = ({
|
|
|
550
537
|
return;
|
|
551
538
|
}
|
|
552
539
|
const data = getGlobalData();
|
|
540
|
+
|
|
541
|
+
console.log('panRapidNumber global data check', data, panRapidNumber);
|
|
553
542
|
// Decide next screen based on panrapidnumber existence
|
|
554
543
|
if (panRapidNumber && data.completeFDData) {
|
|
555
544
|
navigate('PayNow', { fdData: fdDataFromRoute });
|
|
@@ -597,13 +586,6 @@ const ReviewKYC: React.FC<ReviewKYCProps> = ({
|
|
|
597
586
|
autoCapitalize={variant === 'email' ? 'none' : 'words'}
|
|
598
587
|
onFocus={() => textInputRef && handleFieldFocus(textInputRef)}
|
|
599
588
|
textInputRef={textInputRef}
|
|
600
|
-
returnKeyType="done"
|
|
601
|
-
onSubmitEditing={() => {
|
|
602
|
-
if (textInputRef?.current) {
|
|
603
|
-
textInputRef.current.blur();
|
|
604
|
-
}
|
|
605
|
-
Keyboard.dismiss();
|
|
606
|
-
}}
|
|
607
589
|
/>
|
|
608
590
|
{renderFieldError(field)}
|
|
609
591
|
</View>
|
|
@@ -674,163 +656,119 @@ const ReviewKYC: React.FC<ReviewKYCProps> = ({
|
|
|
674
656
|
onDatePress={() => {
|
|
675
657
|
// TODO: Implement date picker if needed
|
|
676
658
|
}}
|
|
677
|
-
returnKeyType="done"
|
|
678
|
-
onSubmitEditing={() => {
|
|
679
|
-
if (textInputRef?.current) {
|
|
680
|
-
textInputRef.current.blur();
|
|
681
|
-
}
|
|
682
|
-
Keyboard.dismiss();
|
|
683
|
-
}}
|
|
684
659
|
/>
|
|
685
660
|
{renderFieldError(field)}
|
|
686
661
|
</View>
|
|
687
662
|
);
|
|
688
663
|
|
|
689
|
-
// Handler for back button (used by both header and hardware back button)
|
|
690
|
-
const handleBackPress = async () => {
|
|
691
|
-
setIsGoingBack(true);
|
|
692
|
-
try {
|
|
693
|
-
const userInfo = getUserInfoForAPI();
|
|
694
|
-
await previousState({
|
|
695
|
-
providerId: defaultProviderId,
|
|
696
|
-
workflowInstanceId,
|
|
697
|
-
userreferenceid: userInfo.userReferenceId,
|
|
698
|
-
applicationid: applicationId,
|
|
699
|
-
entityid: entityId,
|
|
700
|
-
});
|
|
701
|
-
} catch (e) {
|
|
702
|
-
// Handle error silently
|
|
703
|
-
} finally {
|
|
704
|
-
setIsGoingBack(false);
|
|
705
|
-
//onGoBack?.();
|
|
706
|
-
navigate('FDCalculator');
|
|
707
|
-
}
|
|
708
|
-
};
|
|
709
|
-
|
|
710
|
-
// Handle Android hardware back button
|
|
711
|
-
useEffect(() => {
|
|
712
|
-
if (Platform.OS !== 'android') return;
|
|
713
|
-
|
|
714
|
-
const onHardwareBackPress = () => {
|
|
715
|
-
handleBackPress();
|
|
716
|
-
return true; // Prevent default behavior
|
|
717
|
-
};
|
|
718
|
-
|
|
719
|
-
const backHandler = BackHandler.addEventListener(
|
|
720
|
-
'hardwareBackPress',
|
|
721
|
-
onHardwareBackPress
|
|
722
|
-
);
|
|
723
|
-
|
|
724
|
-
return () => backHandler.remove();
|
|
725
|
-
}, [defaultProviderId, workflowInstanceId, applicationId, entityId]);
|
|
726
|
-
|
|
727
664
|
return (
|
|
728
665
|
<SafeAreaWrapper
|
|
729
666
|
includeTop={false}
|
|
730
667
|
bottomPadding={25}
|
|
731
|
-
statusBarColor="#
|
|
732
|
-
statusBarStyle="
|
|
668
|
+
statusBarColor="#f8f9fa"
|
|
669
|
+
statusBarStyle="dark-content"
|
|
733
670
|
>
|
|
734
671
|
<Header
|
|
735
672
|
title="Review KYC"
|
|
736
|
-
onBackPress={
|
|
673
|
+
onBackPress={async () => {
|
|
674
|
+
try {
|
|
675
|
+
const userInfo = getUserInfoForAPI();
|
|
676
|
+
await previousState({
|
|
677
|
+
providerId: defaultProviderId,
|
|
678
|
+
workflowInstanceId,
|
|
679
|
+
userreferenceid: userInfo.userReferenceId,
|
|
680
|
+
applicationid: applicationId,
|
|
681
|
+
entityid: entityId,
|
|
682
|
+
});
|
|
683
|
+
} catch (e) {
|
|
684
|
+
// Handle error silently
|
|
685
|
+
} finally {
|
|
686
|
+
//onGoBack?.();
|
|
687
|
+
navigate('FDCalculator');
|
|
688
|
+
}
|
|
689
|
+
}}
|
|
737
690
|
backgroundColor={colors.primary}
|
|
738
691
|
/>
|
|
739
692
|
|
|
740
|
-
<
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
693
|
+
<ScrollView
|
|
694
|
+
style={styles.container}
|
|
695
|
+
showsVerticalScrollIndicator={false}
|
|
696
|
+
scrollEnabled={!isLoadingPanRapid}
|
|
744
697
|
>
|
|
745
|
-
<
|
|
746
|
-
|
|
747
|
-
showsVerticalScrollIndicator={false}
|
|
748
|
-
scrollEnabled={!isLoadingPanRapid}
|
|
749
|
-
keyboardShouldPersistTaps="handled"
|
|
750
|
-
contentContainerStyle={styles.scrollContent}
|
|
751
|
-
>
|
|
752
|
-
<TouchableWithoutFeedback onPress={isLoadingPanRapid ? undefined : closeDropdown}>
|
|
698
|
+
<TouchableWithoutFeedback onPress={isLoadingPanRapid ? undefined : closeDropdown}>
|
|
699
|
+
<View>
|
|
753
700
|
<View>
|
|
754
|
-
<
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
701
|
+
<TextFieldWithLabel
|
|
702
|
+
label="Pan Card"
|
|
703
|
+
value={kycData.panCard}
|
|
704
|
+
onChangeText={(text) => updateField('panCard', text)}
|
|
705
|
+
placeholder="Enter PAN Card"
|
|
706
|
+
editable={false}
|
|
707
|
+
variant="text"
|
|
708
|
+
maxLength={10}
|
|
709
|
+
keyboardType="default"
|
|
710
|
+
autoCapitalize="characters"
|
|
711
|
+
onFocus={() => handleFieldFocus(panCardRef)}
|
|
712
|
+
textInputRef={panCardRef}
|
|
713
|
+
/>
|
|
714
|
+
{renderFieldError('panCard')}
|
|
715
|
+
</View>
|
|
716
|
+
|
|
717
|
+
{renderDateField('Date of Birth', kycData.dateOfBirth, 'dateOfBirth', false, dateOfBirthRef)}
|
|
718
|
+
|
|
719
|
+
{renderMaritalStatusDropdown()}
|
|
720
|
+
|
|
721
|
+
{renderInputField('Area', kycData.area, 'area', 'Enter Area', true, 'text', 50, areaRef)}
|
|
722
|
+
|
|
723
|
+
{renderInputField('City', kycData.city, 'city', 'Enter City', true, 'text', 30, cityRef)}
|
|
724
|
+
|
|
725
|
+
{renderInputField('Address line 1', kycData.addressLine1, 'addressLine1', 'Enter Address Line 1', true, 'text', 100, addressLine1Ref)}
|
|
726
|
+
|
|
727
|
+
{renderInputField('Address line 2', kycData.addressLine2, 'addressLine2', 'Enter Address Line 2', true, 'text', 100, addressLine2Ref)}
|
|
728
|
+
|
|
729
|
+
{renderInputField('Pincode', kycData.pincode, 'pincode', 'Enter Pincode', true, 'numeric', 6, pincodeRef)}
|
|
730
|
+
|
|
731
|
+
{renderInputField('State', kycData.state, 'state', 'Enter State', true, 'text', undefined, stateRef)}
|
|
732
|
+
|
|
733
|
+
{renderInputField('Country', kycData.country, 'country', 'Enter Country', true, 'text', undefined, countryRef)}
|
|
734
|
+
|
|
735
|
+
<View style={styles.checkboxContainer}>
|
|
736
|
+
<TouchableOpacity
|
|
737
|
+
style={styles.checkbox}
|
|
738
|
+
onPress={() => updateField('useExistingAddress', !kycData.useExistingAddress)}
|
|
739
|
+
>
|
|
740
|
+
<View style={[
|
|
741
|
+
styles.checkboxBox,
|
|
742
|
+
kycData.useExistingAddress && styles.checkboxChecked
|
|
743
|
+
]}>
|
|
744
|
+
{kycData.useExistingAddress ? (
|
|
745
|
+
<Image
|
|
746
|
+
source={{ uri: (themeName === 'dark') ? base64Images.checkBoxDark : base64Images.filledCheckBox }}
|
|
747
|
+
resizeMode="cover"
|
|
748
|
+
width={20}
|
|
749
|
+
height={20}
|
|
750
|
+
/>
|
|
751
|
+
) : (
|
|
752
|
+
(themeName === 'dark') ? (
|
|
806
753
|
<Image
|
|
807
|
-
source={{ uri:
|
|
754
|
+
source={{ uri: base64Images.unCheckBoxDark }}
|
|
808
755
|
resizeMode="cover"
|
|
809
756
|
width={20}
|
|
810
757
|
height={20}
|
|
811
758
|
/>
|
|
812
|
-
) :
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
) : null
|
|
821
|
-
)}
|
|
822
|
-
</View>
|
|
823
|
-
</TouchableOpacity>
|
|
824
|
-
<Text style={styles.checkboxText}>
|
|
825
|
-
For existing customers, we'll use the address from our records. For new customers, the address from your Aadhar card will be used. To update, please raise a service request with valid address proof.
|
|
826
|
-
</Text>
|
|
827
|
-
</View>
|
|
759
|
+
) : null
|
|
760
|
+
)}
|
|
761
|
+
</View>
|
|
762
|
+
</TouchableOpacity>
|
|
763
|
+
<Text style={styles.checkboxText}>
|
|
764
|
+
For existing customers, we'll use the address from our records. For new customers, the address from your Aadhar card will be used. To update, please raise a service request with valid address proof.
|
|
765
|
+
</Text>
|
|
766
|
+
</View>
|
|
828
767
|
|
|
829
768
|
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
</KeyboardAvoidingView>
|
|
769
|
+
</View>
|
|
770
|
+
</TouchableWithoutFeedback>
|
|
771
|
+
</ScrollView>
|
|
834
772
|
<ActionButton
|
|
835
773
|
title="Continue"
|
|
836
774
|
onPress={handleContinue}
|
|
@@ -842,28 +780,16 @@ const ReviewKYC: React.FC<ReviewKYCProps> = ({
|
|
|
842
780
|
<View style={styles.loadingOverlay} pointerEvents="auto">
|
|
843
781
|
</View>
|
|
844
782
|
)}
|
|
845
|
-
{/* Loading overlay for back navigation */}
|
|
846
|
-
{isGoingBack && (
|
|
847
|
-
<View style={styles.loadingOverlay} pointerEvents="auto">
|
|
848
|
-
<ActivityIndicator size="large" color={colors.primary} />
|
|
849
|
-
</View>
|
|
850
|
-
)}
|
|
851
783
|
</SafeAreaWrapper>
|
|
852
784
|
);
|
|
853
785
|
};
|
|
854
786
|
|
|
855
787
|
const createStyles = (colors: any, typography: any, themeName?: string) => StyleSheet.create({
|
|
856
|
-
keyboardAvoidingView: {
|
|
857
|
-
flex: 1,
|
|
858
|
-
},
|
|
859
788
|
container: {
|
|
860
789
|
flex: 1,
|
|
861
790
|
paddingHorizontal: 16,
|
|
862
791
|
paddingTop: 20,
|
|
863
792
|
},
|
|
864
|
-
scrollContent: {
|
|
865
|
-
flexGrow: 1,
|
|
866
|
-
},
|
|
867
793
|
checkboxContainer: {
|
|
868
794
|
flexDirection: 'row',
|
|
869
795
|
alignItems: 'flex-start',
|
|
@@ -947,10 +873,8 @@ const createStyles = (colors: any, typography: any, themeName?: string) => Style
|
|
|
947
873
|
right: 0,
|
|
948
874
|
bottom: 0,
|
|
949
875
|
backgroundColor: 'rgba(0, 0, 0, 0.3)',
|
|
950
|
-
justifyContent: 'center',
|
|
951
|
-
alignItems: 'center',
|
|
952
876
|
zIndex: 1000,
|
|
953
877
|
},
|
|
954
878
|
});
|
|
955
879
|
|
|
956
|
-
export default ReviewKYC;
|
|
880
|
+
export default ReviewKYC;
|
package/src/utils/sseParser.ts
CHANGED
|
@@ -11,13 +11,29 @@ export function parseSSEBuffer(
|
|
|
11
11
|
|
|
12
12
|
buffer.value += chunk;
|
|
13
13
|
|
|
14
|
-
let idx
|
|
14
|
+
let idx = -1;
|
|
15
|
+
let delimiterLength = 0;
|
|
16
|
+
const findDelimiter = () => {
|
|
17
|
+
const unixIdx = buffer.value.indexOf('\n\n');
|
|
18
|
+
const windowsIdx = buffer.value.indexOf('\r\n\r\n');
|
|
19
|
+
if (windowsIdx >= 0 && (unixIdx < 0 || windowsIdx < unixIdx)) {
|
|
20
|
+
idx = windowsIdx;
|
|
21
|
+
delimiterLength = 4;
|
|
22
|
+
return true;
|
|
23
|
+
}
|
|
24
|
+
if (unixIdx >= 0) {
|
|
25
|
+
idx = unixIdx;
|
|
26
|
+
delimiterLength = 2;
|
|
27
|
+
return true;
|
|
28
|
+
}
|
|
29
|
+
return false;
|
|
30
|
+
};
|
|
15
31
|
|
|
16
|
-
while ((
|
|
32
|
+
while (findDelimiter()) {
|
|
17
33
|
|
|
18
34
|
const block = buffer.value.slice(0, idx);
|
|
19
35
|
|
|
20
|
-
buffer.value = buffer.value.slice(idx +
|
|
36
|
+
buffer.value = buffer.value.slice(idx + delimiterLength);
|
|
21
37
|
|
|
22
38
|
let eventType = 'message';
|
|
23
39
|
|
|
@@ -37,4 +53,4 @@ export function parseSSEBuffer(
|
|
|
37
53
|
}
|
|
38
54
|
}
|
|
39
55
|
return results;
|
|
40
|
-
}
|
|
56
|
+
}
|