@teamnhz/rn-ui-toolkit 1.1.7 → 1.1.8
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/dist/components/AppHeader/index.d.ts +1 -16
- package/dist/components/AppHeader/index.js +39 -18
- package/dist/components/ImagePicker/index.d.ts +1 -8
- package/dist/components/ImagePicker/index.js +235 -358
- package/dist/components/Input/index.d.ts +1 -0
- package/dist/components/Input/index.js +2 -238
- package/package.json +1 -1
|
@@ -1,17 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
navigation: any;
|
|
3
|
-
headerTitle?: string;
|
|
4
|
-
titleStyle?: object;
|
|
5
|
-
leftImage?: any;
|
|
6
|
-
onPressLeft?: () => void;
|
|
7
|
-
leftIconStyle?: object;
|
|
8
|
-
rightImageOne?: any;
|
|
9
|
-
onPressRightOne?: () => void;
|
|
10
|
-
rightImageOneStyle?: object;
|
|
11
|
-
rightImageTwo?: any;
|
|
12
|
-
onPressRightTwo?: () => void;
|
|
13
|
-
rightImageTwoStyle?: object;
|
|
14
|
-
headerStyle?: object;
|
|
15
|
-
};
|
|
16
|
-
declare const AppHeader: (props: AppHeaderProps) => void;
|
|
1
|
+
declare const AppHeader: (props: any) => any;
|
|
17
2
|
export default AppHeader;
|
|
@@ -1,45 +1,66 @@
|
|
|
1
|
-
import { View, TouchableOpacity, StyleSheet } from "react-native";
|
|
2
1
|
import React from "react";
|
|
2
|
+
import { View, TouchableOpacity, StyleSheet, Platform, StatusBar, } from "react-native";
|
|
3
3
|
import { Colors } from "../../styles";
|
|
4
4
|
import { Image, T } from "../index";
|
|
5
|
+
const getSafeAreaTop = () => {
|
|
6
|
+
if (Platform.OS === "android") {
|
|
7
|
+
return StatusBar.currentHeight || 0;
|
|
8
|
+
}
|
|
9
|
+
return 20; // iOS safe area fallback
|
|
10
|
+
};
|
|
5
11
|
const AppHeader = (props) => {
|
|
6
12
|
const { navigation, headerTitle, titleStyle, leftImage, onPressLeft, leftIconStyle, rightImageOne, onPressRightOne, rightImageOneStyle, rightImageTwo, onPressRightTwo, rightImageTwoStyle, headerStyle, } = props;
|
|
13
|
+
const safeTop = getSafeAreaTop();
|
|
7
14
|
navigation.setOptions({
|
|
15
|
+
headerLeftContainerStyle: {
|
|
16
|
+
paddingLeft: 12,
|
|
17
|
+
paddingBottom: Platform.OS === "ios" ? 4 : 0,
|
|
18
|
+
},
|
|
19
|
+
headerRightContainerStyle: {
|
|
20
|
+
paddingRight: 12,
|
|
21
|
+
paddingBottom: Platform.OS === "ios" ? 4 : 0,
|
|
22
|
+
},
|
|
23
|
+
headerTitleContainerStyle: {
|
|
24
|
+
paddingBottom: Platform.OS === "ios" ? 4 : 0,
|
|
25
|
+
},
|
|
26
|
+
headerStyle: [
|
|
27
|
+
styles.headerBase,
|
|
28
|
+
{ paddingTop: safeTop },
|
|
29
|
+
headerStyle,
|
|
30
|
+
],
|
|
8
31
|
headerLeft: () => leftImage ? (React.createElement(TouchableOpacity, { onPress: onPressLeft, activeOpacity: 0.8 },
|
|
9
|
-
React.createElement(Image, { source: leftImage, resizeMode: "contain", style: [styles.
|
|
32
|
+
React.createElement(Image, { source: leftImage, resizeMode: "contain", style: [styles.icon, leftIconStyle] }))) : null,
|
|
10
33
|
headerTitle: () => headerTitle ? (React.createElement(T, { title: headerTitle, style: [styles.headerTitleText, titleStyle] })) : null,
|
|
11
34
|
headerRight: () => (React.createElement(View, { style: styles.headerRightWrapper },
|
|
12
35
|
rightImageOne ? (React.createElement(TouchableOpacity, { onPress: onPressRightOne, activeOpacity: 0.8 },
|
|
13
|
-
React.createElement(Image, { source: rightImageOne, resizeMode: "contain", style: [
|
|
14
|
-
styles.rightImage,
|
|
15
|
-
rightImageOneStyle,
|
|
16
|
-
{ marginRight: 10 },
|
|
17
|
-
] }))) : null,
|
|
36
|
+
React.createElement(Image, { source: rightImageOne, resizeMode: "contain", style: [styles.icon, rightImageOneStyle] }))) : null,
|
|
18
37
|
rightImageTwo ? (React.createElement(TouchableOpacity, { onPress: onPressRightTwo, activeOpacity: 0.8 },
|
|
19
|
-
React.createElement(Image, { source: rightImageTwo, resizeMode: "contain", style: [styles.
|
|
20
|
-
headerStyle: [styles.headerBase, headerStyle],
|
|
38
|
+
React.createElement(Image, { source: rightImageTwo, resizeMode: "contain", style: [styles.icon, rightImageTwoStyle] }))) : null)),
|
|
21
39
|
});
|
|
40
|
+
return null;
|
|
22
41
|
};
|
|
23
42
|
export default AppHeader;
|
|
24
43
|
const styles = StyleSheet.create({
|
|
25
44
|
headerBase: {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
width: 44,
|
|
45
|
+
backgroundColor: Colors.white,
|
|
46
|
+
borderBottomWidth: 1,
|
|
47
|
+
borderBottomColor: Colors.lightGrey,
|
|
48
|
+
height: Platform.OS === "ios" ? 90 : 70,
|
|
49
|
+
justifyContent: "center",
|
|
32
50
|
},
|
|
33
|
-
|
|
34
|
-
height:
|
|
35
|
-
width:
|
|
51
|
+
icon: {
|
|
52
|
+
height: 28,
|
|
53
|
+
width: 28,
|
|
36
54
|
},
|
|
37
55
|
headerRightWrapper: {
|
|
38
56
|
flexDirection: "row",
|
|
39
57
|
alignItems: "center",
|
|
58
|
+
gap: 12,
|
|
40
59
|
},
|
|
41
60
|
headerTitleText: {
|
|
42
61
|
color: Colors.black,
|
|
43
62
|
textAlign: "center",
|
|
63
|
+
fontSize: 18,
|
|
64
|
+
fontWeight: "600",
|
|
44
65
|
},
|
|
45
66
|
});
|
|
@@ -2,17 +2,10 @@ import React from "react";
|
|
|
2
2
|
type Props = {
|
|
3
3
|
mediaType: "photo" | "video";
|
|
4
4
|
isMultiSelect?: boolean;
|
|
5
|
-
onSuccess: (
|
|
5
|
+
onSuccess: (response: any) => void;
|
|
6
6
|
visible: boolean;
|
|
7
7
|
onClose: () => void;
|
|
8
8
|
enableCompression?: boolean;
|
|
9
|
-
imageCompressionOptions?: {
|
|
10
|
-
maxWidth?: number;
|
|
11
|
-
quality?: number;
|
|
12
|
-
};
|
|
13
|
-
videoCompressionOptions?: {
|
|
14
|
-
compressionMethod?: "auto" | "manual";
|
|
15
|
-
};
|
|
16
9
|
};
|
|
17
10
|
declare const ImagePicker: React.FC<Props>;
|
|
18
11
|
export default ImagePicker;
|
|
@@ -1,162 +1,3 @@
|
|
|
1
|
-
// // import React, { useCallback } from "react";
|
|
2
|
-
// // import {
|
|
3
|
-
// // View,
|
|
4
|
-
// // Text,
|
|
5
|
-
// // TouchableOpacity,
|
|
6
|
-
// // StyleSheet,
|
|
7
|
-
// // Image,
|
|
8
|
-
// // Alert,
|
|
9
|
-
// // ViewStyle,
|
|
10
|
-
// // TextStyle,
|
|
11
|
-
// // ImageStyle,
|
|
12
|
-
// // } from "react-native";
|
|
13
|
-
// // import { BottomSheet, Dividers } from "../index";
|
|
14
|
-
// // import { launchCamera, launchImageLibrary } from "react-native-image-picker";
|
|
15
|
-
// // import ImageCropPicker from "react-native-image-crop-picker";
|
|
16
|
-
// // import { Colors, Images, Scale, Typography } from "../../styles";
|
|
17
|
-
// // type StyleProps = {
|
|
18
|
-
// // containerStyle?: ViewStyle;
|
|
19
|
-
// // rowStyle?: ViewStyle;
|
|
20
|
-
// // textStyle?: TextStyle;
|
|
21
|
-
// // iconStyle?: ImageStyle;
|
|
22
|
-
// // };
|
|
23
|
-
// // type Props = {
|
|
24
|
-
// // mediaType: "photo" | "video";
|
|
25
|
-
// // isMultiSelect?: boolean;
|
|
26
|
-
// // onSuccess: (data: any) => void;
|
|
27
|
-
// // visible: boolean;
|
|
28
|
-
// // onClose: () => void;
|
|
29
|
-
// // } & StyleProps;
|
|
30
|
-
// // const ImagePicker: React.FC<Props> = ({
|
|
31
|
-
// // mediaType,
|
|
32
|
-
// // isMultiSelect = false,
|
|
33
|
-
// // onSuccess,
|
|
34
|
-
// // visible,
|
|
35
|
-
// // onClose,
|
|
36
|
-
// // containerStyle,
|
|
37
|
-
// // rowStyle,
|
|
38
|
-
// // textStyle,
|
|
39
|
-
// // iconStyle,
|
|
40
|
-
// // }) => {
|
|
41
|
-
// // const onComplete = useCallback(
|
|
42
|
-
// // (data: any) => {
|
|
43
|
-
// // onSuccess(data);
|
|
44
|
-
// // onClose();
|
|
45
|
-
// // },
|
|
46
|
-
// // [onSuccess, onClose]
|
|
47
|
-
// // );
|
|
48
|
-
// // const onCamera = () => {
|
|
49
|
-
// // if (mediaType === "photo") {
|
|
50
|
-
// // if (isMultiSelect) {
|
|
51
|
-
// // ImageCropPicker.openCamera({ mediaType: "photo" })
|
|
52
|
-
// // .then((response) => onComplete([response]))
|
|
53
|
-
// // .catch(() => {});
|
|
54
|
-
// // } else {
|
|
55
|
-
// // ImageCropPicker.openCamera({ mediaType: "photo" })
|
|
56
|
-
// // .then((response) =>
|
|
57
|
-
// // ImageCropPicker.openCropper({
|
|
58
|
-
// // path: response?.path,
|
|
59
|
-
// // width: response?.width,
|
|
60
|
-
// // height: response?.height,
|
|
61
|
-
// // mediaType: "photo",
|
|
62
|
-
// // freeStyleCropEnabled: true,
|
|
63
|
-
// // }).then(onComplete)
|
|
64
|
-
// // )
|
|
65
|
-
// // .catch(() => {});
|
|
66
|
-
// // }
|
|
67
|
-
// // } else {
|
|
68
|
-
// // launchCamera({ mediaType: "video" }, (response) => {
|
|
69
|
-
// // if (response?.assets) {
|
|
70
|
-
// // onComplete({
|
|
71
|
-
// // path: response.assets[0]?.uri,
|
|
72
|
-
// // duration: response.assets[0]?.duration,
|
|
73
|
-
// // });
|
|
74
|
-
// // }
|
|
75
|
-
// // });
|
|
76
|
-
// // }
|
|
77
|
-
// // };
|
|
78
|
-
// // const onGallery = () => {
|
|
79
|
-
// // if (mediaType === "photo") {
|
|
80
|
-
// // if (isMultiSelect) {
|
|
81
|
-
// // ImageCropPicker.openPicker({
|
|
82
|
-
// // mediaType: "photo",
|
|
83
|
-
// // multiple: true,
|
|
84
|
-
// // maxFiles: 5,
|
|
85
|
-
// // })
|
|
86
|
-
// // .then((images) => {
|
|
87
|
-
// // if (images.length > 5) {
|
|
88
|
-
// // Alert.alert(
|
|
89
|
-
// // "Limit Exceeded",
|
|
90
|
-
// // "You can only select up to 5 images."
|
|
91
|
-
// // );
|
|
92
|
-
// // } else {
|
|
93
|
-
// // onComplete(images);
|
|
94
|
-
// // }
|
|
95
|
-
// // })
|
|
96
|
-
// // .catch(() => {});
|
|
97
|
-
// // } else {
|
|
98
|
-
// // ImageCropPicker.openPicker({ mediaType: "photo" })
|
|
99
|
-
// // .then((response) =>
|
|
100
|
-
// // ImageCropPicker.openCropper({
|
|
101
|
-
// // path: response?.path,
|
|
102
|
-
// // width: response?.width,
|
|
103
|
-
// // height: response?.height,
|
|
104
|
-
// // mediaType: "photo",
|
|
105
|
-
// // freeStyleCropEnabled: true,
|
|
106
|
-
// // }).then(onComplete)
|
|
107
|
-
// // )
|
|
108
|
-
// // .catch(() => {});
|
|
109
|
-
// // }
|
|
110
|
-
// // } else {
|
|
111
|
-
// // launchImageLibrary({ mediaType: "video" }, (result) => {
|
|
112
|
-
// // if (result?.assets) {
|
|
113
|
-
// // onComplete({
|
|
114
|
-
// // path: result.assets[0]?.uri,
|
|
115
|
-
// // duration: result.assets[0]?.duration,
|
|
116
|
-
// // });
|
|
117
|
-
// // }
|
|
118
|
-
// // });
|
|
119
|
-
// // }
|
|
120
|
-
// // };
|
|
121
|
-
// // return (
|
|
122
|
-
// // <BottomSheet visible={visible} onClose={onClose} height={230}>
|
|
123
|
-
// // <View style={[styles.container, containerStyle]}>
|
|
124
|
-
// // {/* Camera */}
|
|
125
|
-
// // <TouchableOpacity style={[styles.row, rowStyle]} onPress={onCamera}>
|
|
126
|
-
// // <Image source={Images.video_icon} style={[styles.icon, iconStyle]} />
|
|
127
|
-
// // <Text style={[styles.text, textStyle]}>Camera</Text>
|
|
128
|
-
// // </TouchableOpacity>
|
|
129
|
-
// // <Dividers small />
|
|
130
|
-
// // {/* Gallery */}
|
|
131
|
-
// // <TouchableOpacity style={[styles.row, rowStyle]} onPress={onGallery}>
|
|
132
|
-
// // <Image source={Images.image_icon} style={[styles.icon, iconStyle]} />
|
|
133
|
-
// // <Text style={[styles.text, textStyle]}>Gallery</Text>
|
|
134
|
-
// // </TouchableOpacity>
|
|
135
|
-
// // <Dividers small />
|
|
136
|
-
// // {/* Cancel */}
|
|
137
|
-
// // <TouchableOpacity style={[styles.row, rowStyle]} onPress={onClose}>
|
|
138
|
-
// // <Image source={Images.cancel} style={[styles.icon, iconStyle]} />
|
|
139
|
-
// // <Text style={[styles.text, textStyle]}>Cancel</Text>
|
|
140
|
-
// // </TouchableOpacity>
|
|
141
|
-
// // </View>
|
|
142
|
-
// // </BottomSheet>
|
|
143
|
-
// // );
|
|
144
|
-
// // };
|
|
145
|
-
// // export default ImagePicker;
|
|
146
|
-
// // const styles = StyleSheet.create({
|
|
147
|
-
// // container: { flex: 1, padding: 16 },
|
|
148
|
-
// // row: {
|
|
149
|
-
// // flexDirection: "row",
|
|
150
|
-
// // alignItems: "center",
|
|
151
|
-
// // },
|
|
152
|
-
// // text: { ...Typography.style.standardU(), color: Colors.white },
|
|
153
|
-
// // icon: {
|
|
154
|
-
// // width: Scale.moderateScale(20),
|
|
155
|
-
// // height: Scale.moderateScale(20),
|
|
156
|
-
// // marginRight: 10,
|
|
157
|
-
// // tintColor: Colors.white,
|
|
158
|
-
// // },
|
|
159
|
-
// // });
|
|
160
1
|
// import React, { useCallback } from "react";
|
|
161
2
|
// import {
|
|
162
3
|
// View,
|
|
@@ -169,18 +10,33 @@
|
|
|
169
10
|
// import { BottomSheet, Dividers } from "../index";
|
|
170
11
|
// import { launchCamera, launchImageLibrary } from "react-native-image-picker";
|
|
171
12
|
// import ImageCropPicker from "react-native-image-crop-picker";
|
|
13
|
+
// import {
|
|
14
|
+
// Image as ImageCompressor,
|
|
15
|
+
// Video as VideoCompressor,
|
|
16
|
+
// } from "react-native-compressor";
|
|
17
|
+
// import RNFS from "react-native-fs";
|
|
172
18
|
// import { Colors, Images, Scale, Typography } from "../../styles";
|
|
173
|
-
// //
|
|
19
|
+
// // Import your permission utilities
|
|
174
20
|
// import {
|
|
175
21
|
// cameraPermissions,
|
|
176
22
|
// galleryPermissions,
|
|
177
|
-
//
|
|
23
|
+
// checkMicroPhonePermission,
|
|
24
|
+
// } from "../../utils/permissions";
|
|
178
25
|
// type Props = {
|
|
179
26
|
// mediaType: "photo" | "video";
|
|
180
27
|
// isMultiSelect?: boolean;
|
|
181
28
|
// onSuccess: (data: any) => void;
|
|
182
29
|
// visible: boolean;
|
|
183
30
|
// onClose: () => void;
|
|
31
|
+
// // Compression options
|
|
32
|
+
// enableCompression?: boolean;
|
|
33
|
+
// imageCompressionOptions?: {
|
|
34
|
+
// maxWidth?: number;
|
|
35
|
+
// quality?: number;
|
|
36
|
+
// };
|
|
37
|
+
// videoCompressionOptions?: {
|
|
38
|
+
// compressionMethod?: "auto" | "manual";
|
|
39
|
+
// };
|
|
184
40
|
// };
|
|
185
41
|
// const ImagePicker: React.FC<Props> = ({
|
|
186
42
|
// mediaType,
|
|
@@ -188,8 +44,11 @@
|
|
|
188
44
|
// onSuccess,
|
|
189
45
|
// visible,
|
|
190
46
|
// onClose,
|
|
47
|
+
// enableCompression = true,
|
|
48
|
+
// imageCompressionOptions = { maxWidth: 1080, quality: 0.7 },
|
|
49
|
+
// videoCompressionOptions = { compressionMethod: "auto" },
|
|
191
50
|
// }) => {
|
|
192
|
-
// //
|
|
51
|
+
// // Success handler
|
|
193
52
|
// const onComplete = useCallback(
|
|
194
53
|
// (data: any) => {
|
|
195
54
|
// onSuccess(data);
|
|
@@ -197,106 +56,181 @@
|
|
|
197
56
|
// },
|
|
198
57
|
// [onSuccess, onClose]
|
|
199
58
|
// );
|
|
200
|
-
// //
|
|
59
|
+
// // Helper: Compress Image
|
|
60
|
+
// const compressImage = async (imagePath: string) => {
|
|
61
|
+
// if (!enableCompression) return imagePath;
|
|
62
|
+
// try {
|
|
63
|
+
// const compressedImage = await ImageCompressor.compress(imagePath, {
|
|
64
|
+
// maxWidth: imageCompressionOptions.maxWidth,
|
|
65
|
+
// quality: imageCompressionOptions.quality,
|
|
66
|
+
// });
|
|
67
|
+
// // Log compressed size (optional)
|
|
68
|
+
// const stats = await RNFS.stat(compressedImage.replace("file://", ""));
|
|
69
|
+
// const sizeInMB = stats.size / (1024 * 1024);
|
|
70
|
+
// console.log("Compressed Image Size (MB):", sizeInMB);
|
|
71
|
+
// return compressedImage;
|
|
72
|
+
// } catch (error) {
|
|
73
|
+
// console.error("Image compression error:", error);
|
|
74
|
+
// return imagePath; // Return original if compression fails
|
|
75
|
+
// }
|
|
76
|
+
// };
|
|
77
|
+
// // Helper: Compress Video
|
|
78
|
+
// const compressVideo = async (videoUri: string) => {
|
|
79
|
+
// if (!enableCompression) return videoUri;
|
|
80
|
+
// try {
|
|
81
|
+
// const compressedVideo = await VideoCompressor.compress(videoUri, {
|
|
82
|
+
// compressionMethod: videoCompressionOptions.compressionMethod,
|
|
83
|
+
// });
|
|
84
|
+
// // Log compressed size (optional)
|
|
85
|
+
// const stats = await RNFS.stat(compressedVideo.replace("file://", ""));
|
|
86
|
+
// const sizeInMB = stats.size / (1024 * 1024);
|
|
87
|
+
// console.log("Compressed Video Size (MB):", sizeInMB);
|
|
88
|
+
// return compressedVideo;
|
|
89
|
+
// } catch (error) {
|
|
90
|
+
// console.error("Video compression error:", error);
|
|
91
|
+
// return videoUri; // Return original if compression fails
|
|
92
|
+
// }
|
|
93
|
+
// };
|
|
94
|
+
// // CAMERA HANDLER with permission check and compression
|
|
201
95
|
// const handleCamera = async () => {
|
|
202
96
|
// await cameraPermissions(async (granted: boolean) => {
|
|
203
|
-
// if (!granted) return;
|
|
97
|
+
// if (!granted) return;
|
|
204
98
|
// if (mediaType === "photo") {
|
|
205
|
-
//
|
|
206
|
-
//
|
|
207
|
-
//
|
|
208
|
-
//
|
|
209
|
-
//
|
|
210
|
-
//
|
|
211
|
-
//
|
|
212
|
-
//
|
|
213
|
-
//
|
|
214
|
-
//
|
|
215
|
-
//
|
|
216
|
-
//
|
|
217
|
-
//
|
|
218
|
-
//
|
|
219
|
-
//
|
|
220
|
-
//
|
|
221
|
-
//
|
|
99
|
+
// try {
|
|
100
|
+
// const response = await ImageCropPicker.openCamera({
|
|
101
|
+
// mediaType: "photo",
|
|
102
|
+
// });
|
|
103
|
+
// if (isMultiSelect) {
|
|
104
|
+
// // Single capture for multi-select mode
|
|
105
|
+
// const compressedPath = await compressImage(response.path);
|
|
106
|
+
// onComplete([{ ...response, path: compressedPath }]);
|
|
107
|
+
// } else {
|
|
108
|
+
// // Crop and compress single image
|
|
109
|
+
// const cropped = await ImageCropPicker.openCropper({
|
|
110
|
+
// path: response?.path,
|
|
111
|
+
// width: response?.width,
|
|
112
|
+
// height: response?.height,
|
|
113
|
+
// mediaType: "photo",
|
|
114
|
+
// freeStyleCropEnabled: true,
|
|
115
|
+
// });
|
|
116
|
+
// const compressedPath = await compressImage(cropped.path);
|
|
117
|
+
// onComplete({ ...cropped, path: compressedPath });
|
|
118
|
+
// }
|
|
119
|
+
// } catch (error) {
|
|
120
|
+
// console.log("Camera cancelled or error:", error);
|
|
222
121
|
// }
|
|
223
122
|
// } else {
|
|
224
|
-
// //
|
|
225
|
-
//
|
|
226
|
-
//
|
|
227
|
-
//
|
|
228
|
-
//
|
|
229
|
-
//
|
|
230
|
-
//
|
|
123
|
+
// // VIDEO CAPTURE - check microphone permission first
|
|
124
|
+
// const micPermission = await checkMicroPhonePermission();
|
|
125
|
+
// if (!micPermission) {
|
|
126
|
+
// Alert.alert(
|
|
127
|
+
// "Microphone Permission Required",
|
|
128
|
+
// "Please enable microphone access to record videos."
|
|
129
|
+
// );
|
|
130
|
+
// return;
|
|
131
|
+
// }
|
|
132
|
+
// launchCamera(
|
|
133
|
+
// {
|
|
134
|
+
// mediaType: "video",
|
|
135
|
+
// durationLimit: 60,
|
|
136
|
+
// videoQuality: "high",
|
|
137
|
+
// },
|
|
138
|
+
// async (response) => {
|
|
139
|
+
// if (response?.assets?.length) {
|
|
140
|
+
// const videoUri = response.assets[0]?.uri;
|
|
141
|
+
// const compressedPath = await compressVideo(videoUri);
|
|
142
|
+
// onComplete({
|
|
143
|
+
// path: compressedPath,
|
|
144
|
+
// duration: response.assets[0]?.duration,
|
|
145
|
+
// });
|
|
146
|
+
// }
|
|
231
147
|
// }
|
|
232
|
-
//
|
|
148
|
+
// );
|
|
233
149
|
// }
|
|
234
150
|
// });
|
|
235
151
|
// };
|
|
236
|
-
// //
|
|
152
|
+
// // GALLERY HANDLER with permission check and compression
|
|
237
153
|
// const handleGallery = async () => {
|
|
238
154
|
// await galleryPermissions(async (granted: boolean) => {
|
|
239
|
-
// if (!granted) return;
|
|
155
|
+
// if (!granted) return;
|
|
240
156
|
// if (mediaType === "photo") {
|
|
241
|
-
//
|
|
242
|
-
//
|
|
243
|
-
//
|
|
244
|
-
//
|
|
245
|
-
//
|
|
246
|
-
//
|
|
247
|
-
//
|
|
248
|
-
//
|
|
249
|
-
//
|
|
250
|
-
//
|
|
251
|
-
//
|
|
252
|
-
//
|
|
253
|
-
//
|
|
254
|
-
//
|
|
255
|
-
//
|
|
256
|
-
//
|
|
257
|
-
//
|
|
258
|
-
//
|
|
259
|
-
//
|
|
260
|
-
//
|
|
261
|
-
//
|
|
262
|
-
//
|
|
263
|
-
//
|
|
264
|
-
//
|
|
265
|
-
//
|
|
266
|
-
//
|
|
267
|
-
//
|
|
268
|
-
//
|
|
269
|
-
//
|
|
157
|
+
// try {
|
|
158
|
+
// if (isMultiSelect) {
|
|
159
|
+
// const images = await ImageCropPicker.openPicker({
|
|
160
|
+
// mediaType: "photo",
|
|
161
|
+
// multiple: true,
|
|
162
|
+
// maxFiles: 5,
|
|
163
|
+
// });
|
|
164
|
+
// if (images.length > 5) {
|
|
165
|
+
// Alert.alert(
|
|
166
|
+
// "Limit Exceeded",
|
|
167
|
+
// "You can only select up to 5 images."
|
|
168
|
+
// );
|
|
169
|
+
// return;
|
|
170
|
+
// }
|
|
171
|
+
// // Compress multiple images
|
|
172
|
+
// const compressedImages = await Promise.all(
|
|
173
|
+
// images.map(async (img) => ({
|
|
174
|
+
// ...img,
|
|
175
|
+
// path: await compressImage(img.path),
|
|
176
|
+
// }))
|
|
177
|
+
// );
|
|
178
|
+
// onComplete(compressedImages);
|
|
179
|
+
// } else {
|
|
180
|
+
// // Single image with crop
|
|
181
|
+
// const response = await ImageCropPicker.openPicker({
|
|
182
|
+
// mediaType: "photo",
|
|
183
|
+
// });
|
|
184
|
+
// const cropped = await ImageCropPicker.openCropper({
|
|
185
|
+
// path: response?.path,
|
|
186
|
+
// width: response?.width,
|
|
187
|
+
// height: response?.height,
|
|
188
|
+
// mediaType: "photo",
|
|
189
|
+
// freeStyleCropEnabled: true,
|
|
190
|
+
// });
|
|
191
|
+
// const compressedPath = await compressImage(cropped.path);
|
|
192
|
+
// onComplete({ ...cropped, path: compressedPath });
|
|
193
|
+
// }
|
|
194
|
+
// } catch (error) {
|
|
195
|
+
// console.log("Gallery cancelled or error:", error);
|
|
270
196
|
// }
|
|
271
197
|
// } else {
|
|
272
|
-
// //
|
|
273
|
-
// launchImageLibrary(
|
|
274
|
-
//
|
|
275
|
-
//
|
|
276
|
-
//
|
|
277
|
-
//
|
|
278
|
-
//
|
|
198
|
+
// // VIDEO FROM GALLERY
|
|
199
|
+
// launchImageLibrary(
|
|
200
|
+
// {
|
|
201
|
+
// mediaType: "video",
|
|
202
|
+
// assetRepresentationMode: "current",
|
|
203
|
+
// },
|
|
204
|
+
// async (result) => {
|
|
205
|
+
// if (result?.assets?.length) {
|
|
206
|
+
// const videoUri = result.assets[0]?.uri;
|
|
207
|
+
// const compressedPath = await compressVideo(videoUri);
|
|
208
|
+
// onComplete({
|
|
209
|
+
// path: compressedPath,
|
|
210
|
+
// duration: result.assets[0]?.duration,
|
|
211
|
+
// });
|
|
212
|
+
// }
|
|
279
213
|
// }
|
|
280
|
-
//
|
|
214
|
+
// );
|
|
281
215
|
// }
|
|
282
216
|
// });
|
|
283
217
|
// };
|
|
284
218
|
// return (
|
|
285
219
|
// <BottomSheet visible={visible} onClose={onClose} height={230}>
|
|
286
220
|
// <View style={styles.container}>
|
|
287
|
-
// {/*
|
|
221
|
+
// {/* Camera */}
|
|
288
222
|
// <TouchableOpacity style={styles.row} onPress={handleCamera}>
|
|
289
223
|
// <Image source={Images.video_icon} style={styles.icon} />
|
|
290
224
|
// <Text style={styles.text}>Camera</Text>
|
|
291
225
|
// </TouchableOpacity>
|
|
292
226
|
// <Dividers small />
|
|
293
|
-
// {/*
|
|
227
|
+
// {/* Gallery */}
|
|
294
228
|
// <TouchableOpacity style={styles.row} onPress={handleGallery}>
|
|
295
229
|
// <Image source={Images.image_icon} style={styles.icon} />
|
|
296
230
|
// <Text style={styles.text}>Gallery</Text>
|
|
297
231
|
// </TouchableOpacity>
|
|
298
232
|
// <Dividers small />
|
|
299
|
-
// {/*
|
|
233
|
+
// {/* Cancel */}
|
|
300
234
|
// <TouchableOpacity style={styles.row} onPress={onClose}>
|
|
301
235
|
// <Image source={Images.cancel} style={styles.icon} />
|
|
302
236
|
// <Text style={styles.text}>Cancel</Text>
|
|
@@ -320,175 +254,121 @@
|
|
|
320
254
|
// tintColor: Colors.white,
|
|
321
255
|
// },
|
|
322
256
|
// });
|
|
323
|
-
import React
|
|
324
|
-
import { View, Text, TouchableOpacity, StyleSheet, Image,
|
|
257
|
+
import React from "react";
|
|
258
|
+
import { View, Text, TouchableOpacity, StyleSheet, Image, } from "react-native";
|
|
325
259
|
import { BottomSheet, Dividers } from "../index";
|
|
326
260
|
import { launchCamera, launchImageLibrary } from "react-native-image-picker";
|
|
327
261
|
import ImageCropPicker from "react-native-image-crop-picker";
|
|
328
262
|
import { Image as ImageCompressor, Video as VideoCompressor, } from "react-native-compressor";
|
|
329
|
-
import RNFS from "react-native-fs";
|
|
330
263
|
import { Colors, Images, Scale, Typography } from "../../styles";
|
|
331
|
-
// Import your permission utilities
|
|
332
264
|
import { cameraPermissions, galleryPermissions, checkMicroPhonePermission, } from "../../utils/permissions";
|
|
333
|
-
const ImagePicker = ({ mediaType, isMultiSelect = false, onSuccess, visible, onClose, enableCompression = true,
|
|
334
|
-
//
|
|
335
|
-
const
|
|
336
|
-
onSuccess(data);
|
|
265
|
+
const ImagePicker = ({ mediaType, isMultiSelect = false, onSuccess, visible, onClose, enableCompression = true, }) => {
|
|
266
|
+
// Close modal + start loader in parent
|
|
267
|
+
const sendRawAndClose = (rawData) => {
|
|
337
268
|
onClose();
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
269
|
+
onSuccess({ loading: true, data: rawData });
|
|
270
|
+
};
|
|
271
|
+
// After compression finished
|
|
272
|
+
const sendFinalCompressed = (compressed) => {
|
|
273
|
+
onSuccess({ loading: false, data: compressed });
|
|
274
|
+
};
|
|
275
|
+
const compressImage = async (path) => {
|
|
343
276
|
try {
|
|
344
|
-
const
|
|
345
|
-
maxWidth:
|
|
346
|
-
quality:
|
|
277
|
+
const compressed = await ImageCompressor.compress(path, {
|
|
278
|
+
maxWidth: 1080,
|
|
279
|
+
quality: 0.7,
|
|
347
280
|
});
|
|
348
|
-
|
|
349
|
-
const stats = await RNFS.stat(compressedImage.replace("file://", ""));
|
|
350
|
-
const sizeInMB = stats.size / (1024 * 1024);
|
|
351
|
-
console.log("Compressed Image Size (MB):", sizeInMB);
|
|
352
|
-
return compressedImage;
|
|
281
|
+
return compressed;
|
|
353
282
|
}
|
|
354
|
-
catch (
|
|
355
|
-
|
|
356
|
-
return imagePath; // Return original if compression fails
|
|
283
|
+
catch (e) {
|
|
284
|
+
return path;
|
|
357
285
|
}
|
|
358
286
|
};
|
|
359
|
-
|
|
360
|
-
const compressVideo = async (videoUri) => {
|
|
361
|
-
if (!enableCompression)
|
|
362
|
-
return videoUri;
|
|
287
|
+
const compressVideo = async (uri) => {
|
|
363
288
|
try {
|
|
364
|
-
const
|
|
365
|
-
compressionMethod:
|
|
289
|
+
const compressed = await VideoCompressor.compress(uri, {
|
|
290
|
+
compressionMethod: "auto",
|
|
366
291
|
});
|
|
367
|
-
|
|
368
|
-
const stats = await RNFS.stat(compressedVideo.replace("file://", ""));
|
|
369
|
-
const sizeInMB = stats.size / (1024 * 1024);
|
|
370
|
-
console.log("Compressed Video Size (MB):", sizeInMB);
|
|
371
|
-
return compressedVideo;
|
|
292
|
+
return compressed;
|
|
372
293
|
}
|
|
373
|
-
catch (
|
|
374
|
-
|
|
375
|
-
return videoUri; // Return original if compression fails
|
|
294
|
+
catch (e) {
|
|
295
|
+
return uri;
|
|
376
296
|
}
|
|
377
297
|
};
|
|
378
|
-
// CAMERA
|
|
298
|
+
// ---------- CAMERA ----------
|
|
379
299
|
const handleCamera = async () => {
|
|
380
300
|
await cameraPermissions(async (granted) => {
|
|
381
301
|
if (!granted)
|
|
382
302
|
return;
|
|
383
303
|
if (mediaType === "photo") {
|
|
384
304
|
try {
|
|
385
|
-
const
|
|
305
|
+
const picked = await ImageCropPicker.openCamera({
|
|
386
306
|
mediaType: "photo",
|
|
387
307
|
});
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
const compressedPath = await compressImage(
|
|
391
|
-
|
|
392
|
-
}
|
|
393
|
-
else {
|
|
394
|
-
// Crop and compress single image
|
|
395
|
-
const cropped = await ImageCropPicker.openCropper({
|
|
396
|
-
path: response?.path,
|
|
397
|
-
width: response?.width,
|
|
398
|
-
height: response?.height,
|
|
399
|
-
mediaType: "photo",
|
|
400
|
-
freeStyleCropEnabled: true,
|
|
401
|
-
});
|
|
402
|
-
const compressedPath = await compressImage(cropped.path);
|
|
403
|
-
onComplete({ ...cropped, path: compressedPath });
|
|
404
|
-
}
|
|
308
|
+
sendRawAndClose(picked); // CLOSE MODAL + START LOADER
|
|
309
|
+
setTimeout(async () => {
|
|
310
|
+
const compressedPath = await compressImage(picked.path);
|
|
311
|
+
sendFinalCompressed({ ...picked, path: compressedPath });
|
|
312
|
+
}, 10);
|
|
405
313
|
}
|
|
406
|
-
catch (
|
|
407
|
-
console.log(
|
|
314
|
+
catch (err) {
|
|
315
|
+
console.log(err);
|
|
408
316
|
}
|
|
409
317
|
}
|
|
410
318
|
else {
|
|
411
|
-
// VIDEO
|
|
412
|
-
const
|
|
413
|
-
if (!
|
|
414
|
-
Alert.alert("Microphone Permission Required", "Please enable microphone access to record videos.");
|
|
319
|
+
// VIDEO
|
|
320
|
+
const mic = await checkMicroPhonePermission();
|
|
321
|
+
if (!mic)
|
|
415
322
|
return;
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
path: compressedPath,
|
|
427
|
-
duration: response.assets[0]?.duration,
|
|
323
|
+
launchCamera({ mediaType: "video", durationLimit: 60, videoQuality: "high" }, (res) => {
|
|
324
|
+
if (!res?.assets?.length)
|
|
325
|
+
return;
|
|
326
|
+
const raw = res.assets[0];
|
|
327
|
+
sendRawAndClose(raw);
|
|
328
|
+
setTimeout(async () => {
|
|
329
|
+
const compressed = await compressVideo(raw.uri);
|
|
330
|
+
sendFinalCompressed({
|
|
331
|
+
path: compressed,
|
|
332
|
+
duration: raw.duration,
|
|
428
333
|
});
|
|
429
|
-
}
|
|
334
|
+
}, 10);
|
|
430
335
|
});
|
|
431
336
|
}
|
|
432
337
|
});
|
|
433
338
|
};
|
|
434
|
-
// GALLERY
|
|
339
|
+
// ---------- GALLERY ----------
|
|
435
340
|
const handleGallery = async () => {
|
|
436
341
|
await galleryPermissions(async (granted) => {
|
|
437
342
|
if (!granted)
|
|
438
343
|
return;
|
|
439
344
|
if (mediaType === "photo") {
|
|
440
345
|
try {
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
return;
|
|
450
|
-
}
|
|
451
|
-
// Compress multiple images
|
|
452
|
-
const compressedImages = await Promise.all(images.map(async (img) => ({
|
|
453
|
-
...img,
|
|
454
|
-
path: await compressImage(img.path),
|
|
455
|
-
})));
|
|
456
|
-
onComplete(compressedImages);
|
|
457
|
-
}
|
|
458
|
-
else {
|
|
459
|
-
// Single image with crop
|
|
460
|
-
const response = await ImageCropPicker.openPicker({
|
|
461
|
-
mediaType: "photo",
|
|
462
|
-
});
|
|
463
|
-
const cropped = await ImageCropPicker.openCropper({
|
|
464
|
-
path: response?.path,
|
|
465
|
-
width: response?.width,
|
|
466
|
-
height: response?.height,
|
|
467
|
-
mediaType: "photo",
|
|
468
|
-
freeStyleCropEnabled: true,
|
|
469
|
-
});
|
|
470
|
-
const compressedPath = await compressImage(cropped.path);
|
|
471
|
-
onComplete({ ...cropped, path: compressedPath });
|
|
472
|
-
}
|
|
346
|
+
const picked = await ImageCropPicker.openPicker({
|
|
347
|
+
mediaType: "photo",
|
|
348
|
+
});
|
|
349
|
+
sendRawAndClose(picked);
|
|
350
|
+
setTimeout(async () => {
|
|
351
|
+
const compressed = await compressImage(picked.path);
|
|
352
|
+
sendFinalCompressed({ ...picked, path: compressed });
|
|
353
|
+
}, 10);
|
|
473
354
|
}
|
|
474
|
-
catch (
|
|
475
|
-
console.log(
|
|
355
|
+
catch (e) {
|
|
356
|
+
console.log(e);
|
|
476
357
|
}
|
|
477
358
|
}
|
|
478
359
|
else {
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
const
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
duration: result.assets[0]?.duration,
|
|
360
|
+
launchImageLibrary({ mediaType: "video" }, (res) => {
|
|
361
|
+
if (!res?.assets?.length)
|
|
362
|
+
return;
|
|
363
|
+
const raw = res.assets[0];
|
|
364
|
+
sendRawAndClose(raw);
|
|
365
|
+
setTimeout(async () => {
|
|
366
|
+
const compressed = await compressVideo(raw.uri);
|
|
367
|
+
sendFinalCompressed({
|
|
368
|
+
path: compressed,
|
|
369
|
+
duration: raw.duration,
|
|
490
370
|
});
|
|
491
|
-
}
|
|
371
|
+
}, 10);
|
|
492
372
|
});
|
|
493
373
|
}
|
|
494
374
|
});
|
|
@@ -510,10 +390,7 @@ const ImagePicker = ({ mediaType, isMultiSelect = false, onSuccess, visible, onC
|
|
|
510
390
|
export default ImagePicker;
|
|
511
391
|
const styles = StyleSheet.create({
|
|
512
392
|
container: { flex: 1, padding: 16 },
|
|
513
|
-
row: {
|
|
514
|
-
flexDirection: "row",
|
|
515
|
-
alignItems: "center",
|
|
516
|
-
},
|
|
393
|
+
row: { flexDirection: "row", alignItems: "center" },
|
|
517
394
|
text: { ...Typography.style.standardU(), color: Colors.white },
|
|
518
395
|
icon: {
|
|
519
396
|
width: Scale.moderateScale(20),
|
|
@@ -4,7 +4,7 @@ import { useTranslation } from "react-i18next";
|
|
|
4
4
|
import { Colors, Typography, Scale, Images } from "../../styles";
|
|
5
5
|
import { defaultRegex } from "../../utils/regex";
|
|
6
6
|
import { messages } from "../../constants/messages";
|
|
7
|
-
const Input = ({ intlType, textKey, placeholder, inputPlaceholderTextColor, leftIcon, rightIcon, onLeftIconPress, onRightIconPress, style, containerStyle, inputStyle, errorTextStyle, leftIconStyle, rightIconStyle, leftIconWrapperStyle, rightIconWrapperStyle, type = "text", editable = true, error, value = "", customRegex, customErrorMessage, onChangeText, onValidation, onBlur: restOnBlur, onFocus: restOnFocus, multiline = false, maxLength, returnKeyType, countryCode, onPressCountryCode, countryCodeTextStyle, countryCodeWrapperStyle, ...rest }) => {
|
|
7
|
+
const Input = ({ intlType, textKey, placeholder, inputPlaceholderTextColor, leftIcon, rightIcon, onLeftIconPress, onRightIconPress, style, containerStyle, inputStyle, errorTextStyle, leftIconStyle, rightIconStyle, leftIconWrapperStyle, rightIconWrapperStyle, type = "text", editable = true, error, value = "", customRegex, customErrorMessage, onChangeText, onValidation, onBlur: restOnBlur, onFocus: restOnFocus, multiline = false, maxLength, returnKeyType, countryCode, onPressCountryCode, countryCodeTextStyle, countryCodeWrapperStyle, isError = true, ...rest }) => {
|
|
8
8
|
const { t } = useTranslation();
|
|
9
9
|
const [secureText, setSecureText] = useState(type === "password");
|
|
10
10
|
const [internalError, setInternalError] = useState(null);
|
|
@@ -97,7 +97,7 @@ const Input = ({ intlType, textKey, placeholder, inputPlaceholderTextColor, left
|
|
|
97
97
|
type === "password" ? (React.createElement(TouchableOpacity, { onPress: () => setSecureText(!secureText), style: [styles.iconWrapper, rightIconWrapperStyle] },
|
|
98
98
|
React.createElement(Image, { source: secureText ? Images.Eyeoff : Images.Eyeon, style: [styles.icon, rightIconStyle], resizeMode: "contain" }))) : (rightIcon && (React.createElement(TouchableOpacity, { onPress: onRightIconPress, disabled: !onRightIconPress, style: [styles.iconWrapper, rightIconWrapperStyle] },
|
|
99
99
|
React.createElement(Image, { source: rightIcon, style: [styles.icon, rightIconStyle], resizeMode: "contain" }))))),
|
|
100
|
-
showError && (React.createElement(Text, { style: [styles.errorText, errorTextStyle] }, showError))));
|
|
100
|
+
showError && isError && (React.createElement(Text, { style: [styles.errorText, errorTextStyle] }, showError))));
|
|
101
101
|
};
|
|
102
102
|
export default Input;
|
|
103
103
|
const styles = StyleSheet.create({
|
|
@@ -167,239 +167,3 @@ const styles = StyleSheet.create({
|
|
|
167
167
|
color: Colors.textColor,
|
|
168
168
|
},
|
|
169
169
|
});
|
|
170
|
-
// import React, { useState, useCallback, useEffect } from "react";
|
|
171
|
-
// import {
|
|
172
|
-
// View,
|
|
173
|
-
// TextInput,
|
|
174
|
-
// TextInputProps,
|
|
175
|
-
// StyleSheet,
|
|
176
|
-
// Image,
|
|
177
|
-
// ImageSourcePropType,
|
|
178
|
-
// TouchableOpacity,
|
|
179
|
-
// Text,
|
|
180
|
-
// NativeSyntheticEvent,
|
|
181
|
-
// TextInputFocusEventData,
|
|
182
|
-
// } from "react-native";
|
|
183
|
-
// import { useTranslation } from "react-i18next";
|
|
184
|
-
// import { Colors, Typography, Scale, Images } from "../../styles";
|
|
185
|
-
// import { defaultRegex, InputType } from "../../utils/regex";
|
|
186
|
-
// import { messages } from "../../constants/messages";
|
|
187
|
-
// interface InputProps extends TextInputProps {
|
|
188
|
-
// intlType?: string;
|
|
189
|
-
// textKey?: string;
|
|
190
|
-
// leftIcon?: ImageSourcePropType;
|
|
191
|
-
// rightIcon?: ImageSourcePropType;
|
|
192
|
-
// onLeftIconPress?: () => void;
|
|
193
|
-
// onRightIconPress?: () => void;
|
|
194
|
-
// type?: InputType;
|
|
195
|
-
// editable?: boolean;
|
|
196
|
-
// error?: string | boolean;
|
|
197
|
-
// value?: string;
|
|
198
|
-
// customRegex?: RegExp;
|
|
199
|
-
// customErrorMessage?: string;
|
|
200
|
-
// onChangeText?: (text: string) => void;
|
|
201
|
-
// onValidation?: (errorObj: { type: InputType; hasError: boolean; message?: string }) => void;
|
|
202
|
-
// containerStyle?: object;
|
|
203
|
-
// inputStyle?: object;
|
|
204
|
-
// errorTextStyle?: object;
|
|
205
|
-
// leftIconStyle?: object;
|
|
206
|
-
// rightIconStyle?: object;
|
|
207
|
-
// }
|
|
208
|
-
// const Input: React.FC<InputProps> = ({
|
|
209
|
-
// intlType,
|
|
210
|
-
// textKey,
|
|
211
|
-
// placeholder,
|
|
212
|
-
// leftIcon,
|
|
213
|
-
// rightIcon,
|
|
214
|
-
// onLeftIconPress,
|
|
215
|
-
// onRightIconPress,
|
|
216
|
-
// style,
|
|
217
|
-
// containerStyle,
|
|
218
|
-
// inputStyle,
|
|
219
|
-
// errorTextStyle,
|
|
220
|
-
// leftIconStyle,
|
|
221
|
-
// rightIconStyle,
|
|
222
|
-
// type = "text",
|
|
223
|
-
// editable = true,
|
|
224
|
-
// error,
|
|
225
|
-
// value = "",
|
|
226
|
-
// customRegex,
|
|
227
|
-
// customErrorMessage,
|
|
228
|
-
// onChangeText,
|
|
229
|
-
// onValidation,
|
|
230
|
-
// onBlur: restOnBlur,
|
|
231
|
-
// onFocus: restOnFocus,
|
|
232
|
-
// multiline = false,
|
|
233
|
-
// ...rest
|
|
234
|
-
// }) => {
|
|
235
|
-
// const { t } = useTranslation();
|
|
236
|
-
// const [secureText, setSecureText] = useState(type === "password");
|
|
237
|
-
// const [internalError, setInternalError] = useState<string | null>(null);
|
|
238
|
-
// const [wasBlurred, setWasBlurred] = useState(false);
|
|
239
|
-
// const [isFocused, setIsFocused] = useState(false);
|
|
240
|
-
// const translatedPlaceholder =
|
|
241
|
-
// intlType && textKey ? String(t(textKey, { ns: intlType, value })) : placeholder;
|
|
242
|
-
// const keyboardType: TextInputProps["keyboardType"] =
|
|
243
|
-
// type === "email" ? "email-address" : type === "number" ? "numeric" : "default";
|
|
244
|
-
// const validateInternal = useCallback(
|
|
245
|
-
// (text: string) => {
|
|
246
|
-
// if (!wasBlurred || !editable) return;
|
|
247
|
-
// const regexToUse = customRegex ?? defaultRegex[type];
|
|
248
|
-
// const fallbackMsg = messages.invalid[type] || "Invalid input";
|
|
249
|
-
// const msg = customErrorMessage || fallbackMsg;
|
|
250
|
-
// if (text === "" || !regexToUse.test(text)) {
|
|
251
|
-
// setInternalError(msg);
|
|
252
|
-
// onValidation?.({ type, hasError: true, message: msg });
|
|
253
|
-
// } else {
|
|
254
|
-
// setInternalError(null);
|
|
255
|
-
// onValidation?.({ type, hasError: false });
|
|
256
|
-
// }
|
|
257
|
-
// },
|
|
258
|
-
// [wasBlurred, editable, type, customRegex, customErrorMessage, onValidation]
|
|
259
|
-
// );
|
|
260
|
-
// useEffect(() => {
|
|
261
|
-
// if (!customRegex) return;
|
|
262
|
-
// if (internalError && value && customRegex.test(value)) {
|
|
263
|
-
// setInternalError(null);
|
|
264
|
-
// onValidation?.({ type, hasError: false });
|
|
265
|
-
// }
|
|
266
|
-
// }, [value]);
|
|
267
|
-
// const handleChangeText = (text: string) => {
|
|
268
|
-
// onChangeText?.(text);
|
|
269
|
-
// if (wasBlurred) validateInternal(text);
|
|
270
|
-
// };
|
|
271
|
-
// const handleFocus = (e?: NativeSyntheticEvent<TextInputFocusEventData>) => {
|
|
272
|
-
// setIsFocused(true);
|
|
273
|
-
// restOnFocus?.(e as any);
|
|
274
|
-
// };
|
|
275
|
-
// const handleBlur = (e?: NativeSyntheticEvent<TextInputFocusEventData>) => {
|
|
276
|
-
// setIsFocused(false);
|
|
277
|
-
// if (!wasBlurred) setWasBlurred(true);
|
|
278
|
-
// if (editable) validateInternal(value || "");
|
|
279
|
-
// restOnBlur?.(e as any);
|
|
280
|
-
// };
|
|
281
|
-
// const rawError = (typeof error === "string" ? error : undefined) ?? internalError ?? null;
|
|
282
|
-
// const showError = (() => {
|
|
283
|
-
// if (!rawError || !editable) return null;
|
|
284
|
-
// return wasBlurred && !isFocused ? rawError : null;
|
|
285
|
-
// })();
|
|
286
|
-
// return (
|
|
287
|
-
// <View style={{ marginBottom: 10 }}>
|
|
288
|
-
// <View
|
|
289
|
-
// style={[
|
|
290
|
-
// styles.container,
|
|
291
|
-
// !editable && styles.disabled,
|
|
292
|
-
// !!showError && styles.errorBorder,
|
|
293
|
-
// isFocused && styles.focusedBorder,
|
|
294
|
-
// style,
|
|
295
|
-
// containerStyle,
|
|
296
|
-
// multiline && styles.multilineContainer,
|
|
297
|
-
// ]}
|
|
298
|
-
// >
|
|
299
|
-
// {leftIcon && (
|
|
300
|
-
// <TouchableOpacity
|
|
301
|
-
// onPress={onLeftIconPress}
|
|
302
|
-
// disabled={!onLeftIconPress}
|
|
303
|
-
// style={styles.iconWrapper}
|
|
304
|
-
// >
|
|
305
|
-
// <Image source={leftIcon} style={[styles.icon, leftIconStyle]} resizeMode="contain" />
|
|
306
|
-
// </TouchableOpacity>
|
|
307
|
-
// )}
|
|
308
|
-
// <TextInput
|
|
309
|
-
// style={[
|
|
310
|
-
// styles.input,
|
|
311
|
-
// !editable && styles.disabledText,
|
|
312
|
-
// multiline && styles.multilineInput,
|
|
313
|
-
// inputStyle,
|
|
314
|
-
// ]}
|
|
315
|
-
// placeholder={translatedPlaceholder}
|
|
316
|
-
// placeholderTextColor={Colors.textGrey}
|
|
317
|
-
// editable={editable}
|
|
318
|
-
// secureTextEntry={secureText}
|
|
319
|
-
// keyboardType={keyboardType}
|
|
320
|
-
// value={value}
|
|
321
|
-
// onChangeText={handleChangeText}
|
|
322
|
-
// onFocus={handleFocus}
|
|
323
|
-
// onBlur={handleBlur}
|
|
324
|
-
// multiline={multiline}
|
|
325
|
-
// {...rest}
|
|
326
|
-
// />
|
|
327
|
-
// {type === "password" ? (
|
|
328
|
-
// <TouchableOpacity onPress={() => setSecureText(!secureText)} style={styles.iconWrapper}>
|
|
329
|
-
// <Image
|
|
330
|
-
// source={secureText ? Images.Eyeoff : Images.Eyeon}
|
|
331
|
-
// style={[styles.icon, rightIconStyle]}
|
|
332
|
-
// resizeMode="contain"
|
|
333
|
-
// />
|
|
334
|
-
// </TouchableOpacity>
|
|
335
|
-
// ) : (
|
|
336
|
-
// rightIcon && (
|
|
337
|
-
// <TouchableOpacity
|
|
338
|
-
// onPress={onRightIconPress}
|
|
339
|
-
// disabled={!onRightIconPress}
|
|
340
|
-
// style={styles.iconWrapper}
|
|
341
|
-
// >
|
|
342
|
-
// <Image source={rightIcon} style={[styles.icon, rightIconStyle]} resizeMode="contain" />
|
|
343
|
-
// </TouchableOpacity>
|
|
344
|
-
// )
|
|
345
|
-
// )}
|
|
346
|
-
// </View>
|
|
347
|
-
// {showError && <Text style={[styles.errorText, errorTextStyle]}>{showError}</Text>}
|
|
348
|
-
// </View>
|
|
349
|
-
// );
|
|
350
|
-
// };
|
|
351
|
-
// export default Input;
|
|
352
|
-
// const styles = StyleSheet.create({
|
|
353
|
-
// container: {
|
|
354
|
-
// flexDirection: "row",
|
|
355
|
-
// alignItems: "center",
|
|
356
|
-
// borderRadius: 5,
|
|
357
|
-
// borderWidth: 1,
|
|
358
|
-
// borderColor: Colors.primaryColor,
|
|
359
|
-
// backgroundColor: Colors.white,
|
|
360
|
-
// height: Scale.moderateScale(50),
|
|
361
|
-
// paddingHorizontal: Scale.moderateScale(4),
|
|
362
|
-
// },
|
|
363
|
-
// multilineContainer: {
|
|
364
|
-
// height: "auto",
|
|
365
|
-
// minHeight: Scale.moderateScale(80),
|
|
366
|
-
// alignItems: "flex-start",
|
|
367
|
-
// paddingVertical: Scale.moderateScale(8),
|
|
368
|
-
// },
|
|
369
|
-
// focusedBorder: {
|
|
370
|
-
// borderColor: Colors.primaryColor,
|
|
371
|
-
// },
|
|
372
|
-
// input: {
|
|
373
|
-
// flex: 1,
|
|
374
|
-
// ...Typography.style.standardU(),
|
|
375
|
-
// textTransform: "none",
|
|
376
|
-
// color: Colors.textColor,
|
|
377
|
-
// },
|
|
378
|
-
// multilineInput: {
|
|
379
|
-
// textAlignVertical: "top",
|
|
380
|
-
// paddingTop: Scale.moderateScale(5),
|
|
381
|
-
// },
|
|
382
|
-
// iconWrapper: {
|
|
383
|
-
// padding: Scale.moderateScale(5),
|
|
384
|
-
// },
|
|
385
|
-
// icon: {
|
|
386
|
-
// width: Scale.moderateScale(20),
|
|
387
|
-
// height: Scale.moderateScale(20),
|
|
388
|
-
// tintColor: Colors.primaryColor,
|
|
389
|
-
// },
|
|
390
|
-
// disabled: {
|
|
391
|
-
// backgroundColor: Colors.lightGrey,
|
|
392
|
-
// borderColor: Colors.borderGrey,
|
|
393
|
-
// },
|
|
394
|
-
// disabledText: {
|
|
395
|
-
// color: Colors.disabledGrey,
|
|
396
|
-
// },
|
|
397
|
-
// errorBorder: {
|
|
398
|
-
// borderColor: Colors.dangerRed,
|
|
399
|
-
// },
|
|
400
|
-
// errorText: {
|
|
401
|
-
// color: Colors.dangerRed,
|
|
402
|
-
// fontSize: Scale.moderateScale(12),
|
|
403
|
-
// marginTop: 3,
|
|
404
|
-
// },
|
|
405
|
-
// });
|