@teamnhz/rn-ui-toolkit 1.0.6 → 1.0.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.
|
@@ -8,20 +8,16 @@ interface DateTimePickerProps {
|
|
|
8
8
|
intlType?: string;
|
|
9
9
|
mode?: "date" | "time" | "datetime";
|
|
10
10
|
disabled?: boolean;
|
|
11
|
-
/** raw DatePicker props */
|
|
12
11
|
minimumDate?: Date;
|
|
13
12
|
maximumDate?: Date;
|
|
14
|
-
modal?: boolean;
|
|
15
13
|
confirmText?: string;
|
|
16
14
|
cancelText?: string;
|
|
17
|
-
/** style overrides */
|
|
18
15
|
containerStyle?: StyleProp<ViewStyle>;
|
|
19
16
|
pickerContainerStyle?: StyleProp<ViewStyle>;
|
|
20
17
|
labelStyle?: StyleProp<TextStyle>;
|
|
21
18
|
textStyle?: StyleProp<TextStyle>;
|
|
22
19
|
leftImageStyle?: StyleProp<ImageStyle>;
|
|
23
20
|
rightImageStyle?: StyleProp<ImageStyle>;
|
|
24
|
-
/** icons */
|
|
25
21
|
leftIcon?: ImageSourcePropType;
|
|
26
22
|
rightIcon?: ImageSourcePropType;
|
|
27
23
|
leftIconShow?: boolean;
|
|
@@ -1,93 +1,197 @@
|
|
|
1
|
-
import React, { useState } from "react";
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
1
|
+
// import React, { useState } from "react";
|
|
2
|
+
// import {
|
|
3
|
+
// View,
|
|
4
|
+
// TouchableOpacity,
|
|
5
|
+
// Text,
|
|
6
|
+
// StyleSheet,
|
|
7
|
+
// Image,
|
|
8
|
+
// ImageSourcePropType,
|
|
9
|
+
// StyleProp,
|
|
10
|
+
// TextStyle,
|
|
11
|
+
// ViewStyle,
|
|
12
|
+
// ImageStyle,
|
|
13
|
+
// } from "react-native";
|
|
14
|
+
// import DatePicker from "react-native-date-picker";
|
|
15
|
+
// import { useTranslation } from "react-i18next";
|
|
16
|
+
// import { Colors, Scale, Typography, Images } from "../../styles";
|
|
17
|
+
// interface DateTimePickerProps {
|
|
18
|
+
// value: Date | null;
|
|
19
|
+
// onChange: (date: Date) => void;
|
|
20
|
+
// label?: string;
|
|
21
|
+
// placeholder?: string;
|
|
22
|
+
// intlType?: string;
|
|
23
|
+
// mode?: "date" | "time" | "datetime";
|
|
24
|
+
// disabled?: boolean;
|
|
25
|
+
// /** raw DatePicker props */
|
|
26
|
+
// minimumDate?: Date;
|
|
27
|
+
// maximumDate?: Date;
|
|
28
|
+
// modal?: boolean;
|
|
29
|
+
// confirmText?: string;
|
|
30
|
+
// cancelText?: string;
|
|
31
|
+
// /** style overrides */
|
|
32
|
+
// containerStyle?: StyleProp<ViewStyle>;
|
|
33
|
+
// pickerContainerStyle?: StyleProp<ViewStyle>;
|
|
34
|
+
// labelStyle?: StyleProp<TextStyle>;
|
|
35
|
+
// textStyle?: StyleProp<TextStyle>;
|
|
36
|
+
// leftImageStyle?: StyleProp<ImageStyle>;
|
|
37
|
+
// rightImageStyle?: StyleProp<ImageStyle>;
|
|
38
|
+
// /** icons */
|
|
39
|
+
// leftIcon?: ImageSourcePropType;
|
|
40
|
+
// rightIcon?: ImageSourcePropType;
|
|
41
|
+
// leftIconShow?: boolean;
|
|
42
|
+
// onCancel?: () => void;
|
|
43
|
+
// error?: string | boolean;
|
|
44
|
+
// errorTextStyle?: StyleProp<TextStyle>;
|
|
45
|
+
// }
|
|
46
|
+
// const DateTimePicker: React.FC<DateTimePickerProps> = ({
|
|
47
|
+
// value,
|
|
48
|
+
// onChange,
|
|
49
|
+
// label,
|
|
50
|
+
// placeholder,
|
|
51
|
+
// intlType,
|
|
52
|
+
// mode = "date",
|
|
53
|
+
// disabled = false,
|
|
54
|
+
// minimumDate,
|
|
55
|
+
// maximumDate,
|
|
56
|
+
// modal = true,
|
|
57
|
+
// confirmText,
|
|
58
|
+
// cancelText,
|
|
59
|
+
// containerStyle,
|
|
60
|
+
// pickerContainerStyle,
|
|
61
|
+
// labelStyle,
|
|
62
|
+
// textStyle,
|
|
63
|
+
// leftImageStyle,
|
|
64
|
+
// rightImageStyle,
|
|
65
|
+
// leftIcon,
|
|
66
|
+
// rightIcon,
|
|
67
|
+
// leftIconShow,
|
|
68
|
+
// onCancel,
|
|
69
|
+
// error,
|
|
70
|
+
// errorTextStyle,
|
|
71
|
+
// }) => {
|
|
72
|
+
// const { t } = useTranslation(["common", "validation", "address", "sell"]);
|
|
73
|
+
// const [open, setOpen] = useState(false);
|
|
74
|
+
// /** default icons based on mode */
|
|
75
|
+
// const defaultLeftIcon =
|
|
76
|
+
// mode === "time"
|
|
77
|
+
// ? Images.ic_time // ⏰ your clock asset
|
|
78
|
+
// : Images.ic_calendar; // 📅 your calendar asset
|
|
79
|
+
// const getTranslatedLabel = () => {
|
|
80
|
+
// if (intlType) {
|
|
81
|
+
// const translated = t(label, { ns: intlType });
|
|
82
|
+
// if (translated !== label) return translated;
|
|
83
|
+
// }
|
|
84
|
+
// return label;
|
|
85
|
+
// };
|
|
86
|
+
// return (
|
|
87
|
+
// <View style={containerStyle}>
|
|
88
|
+
// {/* Top label */}
|
|
89
|
+
// {label ? (
|
|
90
|
+
// <Text style={[styles.label, labelStyle]}>{getTranslatedLabel()}</Text>
|
|
91
|
+
// ) : null}
|
|
92
|
+
// <TouchableOpacity
|
|
93
|
+
// style={[
|
|
94
|
+
// styles.button,
|
|
95
|
+
// pickerContainerStyle,
|
|
96
|
+
// disabled && { backgroundColor: Colors.disabledGrey, borderWidth: 0 },
|
|
97
|
+
// ]}
|
|
98
|
+
// disabled={disabled}
|
|
99
|
+
// onPress={() => setOpen(true)}
|
|
100
|
+
// >
|
|
101
|
+
// {/* Left icon */}
|
|
102
|
+
// {leftIconShow && (
|
|
103
|
+
// <Image
|
|
104
|
+
// source={leftIcon || defaultLeftIcon}
|
|
105
|
+
// style={[styles.icon, leftImageStyle]}
|
|
106
|
+
// />
|
|
107
|
+
// )}
|
|
108
|
+
// {/* Text / Placeholder */}
|
|
109
|
+
// <Text
|
|
110
|
+
// style={[styles.text, textStyle, !value && { color: Colors.textGrey }]}
|
|
111
|
+
// numberOfLines={1}
|
|
112
|
+
// >
|
|
113
|
+
// {value ? formatValue(value, mode) : placeholder || "Select"}
|
|
114
|
+
// </Text>
|
|
115
|
+
// {/* Right icon (mandatory) */}
|
|
116
|
+
// {rightIcon && (
|
|
117
|
+
// <Image source={rightIcon} style={[styles.icon, rightImageStyle]} />
|
|
118
|
+
// )}
|
|
119
|
+
// </TouchableOpacity>
|
|
120
|
+
// {/* Error text */}
|
|
121
|
+
// {typeof error === "string" && error.length > 0 && (
|
|
122
|
+
// <Text style={[styles.errorText, errorTextStyle]}>{error}</Text>
|
|
123
|
+
// )}
|
|
124
|
+
// <DatePicker
|
|
125
|
+
// modal={modal}
|
|
126
|
+
// open={open}
|
|
127
|
+
// date={value || new Date()}
|
|
128
|
+
// mode={mode}
|
|
129
|
+
// minimumDate={minimumDate}
|
|
130
|
+
// maximumDate={maximumDate}
|
|
131
|
+
// confirmText={confirmText}
|
|
132
|
+
// cancelText={cancelText}
|
|
133
|
+
// onConfirm={(val) => {
|
|
134
|
+
// setOpen(false);
|
|
135
|
+
// onChange(val);
|
|
136
|
+
// }}
|
|
137
|
+
// onCancel={() => {
|
|
138
|
+
// setOpen(false);
|
|
139
|
+
// onCancel && onCancel();
|
|
140
|
+
// }}
|
|
141
|
+
// />
|
|
142
|
+
// </View>
|
|
143
|
+
// );
|
|
144
|
+
// };
|
|
145
|
+
// const formatValue = (date: Date, mode: "date" | "time" | "datetime") => {
|
|
146
|
+
// try {
|
|
147
|
+
// switch (mode) {
|
|
148
|
+
// case "time":
|
|
149
|
+
// return date.toLocaleTimeString([], {
|
|
150
|
+
// hour: "2-digit",
|
|
151
|
+
// minute: "2-digit",
|
|
152
|
+
// });
|
|
153
|
+
// case "datetime":
|
|
154
|
+
// return date.toLocaleString();
|
|
155
|
+
// default:
|
|
156
|
+
// return date.toLocaleDateString();
|
|
157
|
+
// }
|
|
158
|
+
// } catch {
|
|
159
|
+
// return "";
|
|
160
|
+
// }
|
|
161
|
+
// };
|
|
162
|
+
// const styles = StyleSheet.create({
|
|
163
|
+
// label: {
|
|
164
|
+
// ...Typography.style.standardU(),
|
|
165
|
+
// color: Colors.textColor,
|
|
166
|
+
// marginBottom: Scale.moderateScale(8),
|
|
167
|
+
// },
|
|
168
|
+
// button: {
|
|
169
|
+
// borderWidth: 1,
|
|
170
|
+
// borderColor: Colors.primaryColor,
|
|
171
|
+
// borderRadius: Scale.moderateScale(6),
|
|
172
|
+
// paddingVertical: Scale.moderateScale(12),
|
|
173
|
+
// paddingHorizontal: Scale.moderateScale(10),
|
|
174
|
+
// flexDirection: "row",
|
|
175
|
+
// alignItems: "center",
|
|
176
|
+
// },
|
|
177
|
+
// text: {
|
|
178
|
+
// flex: 1,
|
|
179
|
+
// ...Typography.style.standardU(),
|
|
180
|
+
// color: Colors.textColor,
|
|
181
|
+
// textTransform: "none",
|
|
182
|
+
// },
|
|
183
|
+
// icon: {
|
|
184
|
+
// width: Scale.moderateScale(20),
|
|
185
|
+
// height: Scale.moderateScale(20),
|
|
186
|
+
// resizeMode: "contain",
|
|
187
|
+
// },
|
|
188
|
+
// errorText: {
|
|
189
|
+
// color: Colors.dangerRed,
|
|
190
|
+
// fontSize: Scale.moderateScale(12),
|
|
191
|
+
// marginTop: 3,
|
|
192
|
+
// },
|
|
193
|
+
// });
|
|
194
|
+
// export default DateTimePicker;
|
|
91
195
|
// import React, { useState } from 'react';
|
|
92
196
|
// import {
|
|
93
197
|
// View,
|
|
@@ -274,3 +378,89 @@ export default DateTimePicker;
|
|
|
274
378
|
// },
|
|
275
379
|
// });
|
|
276
380
|
// export default DateTimePicker;
|
|
381
|
+
import React, { useState } from "react";
|
|
382
|
+
import { View, TouchableOpacity, Text, StyleSheet, Image, } from "react-native";
|
|
383
|
+
import DateTimePickerModal from "react-native-modal-datetime-picker";
|
|
384
|
+
import { useTranslation } from "react-i18next";
|
|
385
|
+
import { Colors, Scale, Typography, Images } from "../../styles";
|
|
386
|
+
const DateTimePicker = ({ value, onChange, label, placeholder, intlType, mode = "date", disabled = false, minimumDate, maximumDate, confirmText = "Confirm", cancelText = "Cancel", containerStyle, pickerContainerStyle, labelStyle, textStyle, leftImageStyle, rightImageStyle, leftIcon, rightIcon, leftIconShow, onCancel, error, errorTextStyle, }) => {
|
|
387
|
+
const { t } = useTranslation(["common", "validation", "address", "sell"]);
|
|
388
|
+
const [isVisible, setIsVisible] = useState(false);
|
|
389
|
+
const defaultLeftIcon = mode === "time" ? Images.ic_time : Images.ic_calendar;
|
|
390
|
+
const getTranslatedLabel = () => {
|
|
391
|
+
if (intlType) {
|
|
392
|
+
const translated = t(label, { ns: intlType });
|
|
393
|
+
if (translated !== label)
|
|
394
|
+
return translated;
|
|
395
|
+
}
|
|
396
|
+
return label;
|
|
397
|
+
};
|
|
398
|
+
const handleConfirm = (date) => {
|
|
399
|
+
setIsVisible(false);
|
|
400
|
+
onChange(date);
|
|
401
|
+
};
|
|
402
|
+
const handleCancel = () => {
|
|
403
|
+
setIsVisible(false);
|
|
404
|
+
onCancel?.();
|
|
405
|
+
};
|
|
406
|
+
return (React.createElement(View, { style: containerStyle },
|
|
407
|
+
label ? (React.createElement(Text, { style: [styles.label, labelStyle] }, getTranslatedLabel())) : null,
|
|
408
|
+
React.createElement(TouchableOpacity, { style: [
|
|
409
|
+
styles.button,
|
|
410
|
+
pickerContainerStyle,
|
|
411
|
+
disabled && { backgroundColor: Colors.disabledGrey, borderWidth: 0 },
|
|
412
|
+
], onPress: () => !disabled && setIsVisible(true), disabled: disabled },
|
|
413
|
+
leftIconShow && (React.createElement(Image, { source: leftIcon || defaultLeftIcon, style: [styles.icon, leftImageStyle] })),
|
|
414
|
+
React.createElement(Text, { style: [styles.text, textStyle, !value && { color: Colors.textGrey }], numberOfLines: 1 }, value ? formatValue(value, mode) : placeholder || "Select"),
|
|
415
|
+
rightIcon && (React.createElement(Image, { source: rightIcon, style: [styles.icon, rightImageStyle] }))),
|
|
416
|
+
typeof error === "string" && error.length > 0 && (React.createElement(Text, { style: [styles.errorText, errorTextStyle] }, error)),
|
|
417
|
+
React.createElement(DateTimePickerModal, { isVisible: isVisible, mode: mode, date: value || new Date(), minimumDate: minimumDate, maximumDate: maximumDate, onConfirm: handleConfirm, onCancel: handleCancel, confirmTextIOS: confirmText, cancelTextIOS: cancelText, is24Hour: true })));
|
|
418
|
+
};
|
|
419
|
+
const formatValue = (date, mode) => {
|
|
420
|
+
try {
|
|
421
|
+
switch (mode) {
|
|
422
|
+
case "time":
|
|
423
|
+
return date.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" });
|
|
424
|
+
case "datetime":
|
|
425
|
+
return date.toLocaleString();
|
|
426
|
+
default:
|
|
427
|
+
return date.toLocaleDateString();
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
catch {
|
|
431
|
+
return "";
|
|
432
|
+
}
|
|
433
|
+
};
|
|
434
|
+
const styles = StyleSheet.create({
|
|
435
|
+
label: {
|
|
436
|
+
...Typography.style.standardU(),
|
|
437
|
+
color: Colors.textColor,
|
|
438
|
+
marginBottom: Scale.moderateScale(8),
|
|
439
|
+
},
|
|
440
|
+
button: {
|
|
441
|
+
borderWidth: 1,
|
|
442
|
+
borderColor: Colors.primaryColor,
|
|
443
|
+
borderRadius: Scale.moderateScale(6),
|
|
444
|
+
paddingVertical: Scale.moderateScale(12),
|
|
445
|
+
paddingHorizontal: Scale.moderateScale(10),
|
|
446
|
+
flexDirection: "row",
|
|
447
|
+
alignItems: "center",
|
|
448
|
+
},
|
|
449
|
+
text: {
|
|
450
|
+
flex: 1,
|
|
451
|
+
...Typography.style.standardU(),
|
|
452
|
+
color: Colors.textColor,
|
|
453
|
+
textTransform: "none",
|
|
454
|
+
},
|
|
455
|
+
icon: {
|
|
456
|
+
width: Scale.moderateScale(20),
|
|
457
|
+
height: Scale.moderateScale(20),
|
|
458
|
+
resizeMode: "contain",
|
|
459
|
+
},
|
|
460
|
+
errorText: {
|
|
461
|
+
color: Colors.dangerRed,
|
|
462
|
+
fontSize: Scale.moderateScale(12),
|
|
463
|
+
marginTop: 3,
|
|
464
|
+
},
|
|
465
|
+
});
|
|
466
|
+
export default DateTimePicker;
|
|
@@ -4,15 +4,18 @@
|
|
|
4
4
|
*/
|
|
5
5
|
export declare const requestDocumentPermission: () => Promise<boolean>;
|
|
6
6
|
/**
|
|
7
|
-
*
|
|
7
|
+
* 📸 CAMERA PERMISSION
|
|
8
8
|
*/
|
|
9
9
|
export declare const cameraPermissions: (callback: (status: boolean) => void) => Promise<void>;
|
|
10
10
|
/**
|
|
11
|
-
* 🎤
|
|
11
|
+
* 🎤 MICROPHONE PERMISSION
|
|
12
12
|
*/
|
|
13
13
|
export declare const checkMicroPhonePermission: () => Promise<boolean>;
|
|
14
14
|
/**
|
|
15
|
-
* 🖼️
|
|
16
|
-
* ✅ Handles Android < 13 and >= 13
|
|
15
|
+
* 🖼️ GALLERY / STORAGE PERMISSION
|
|
17
16
|
*/
|
|
18
17
|
export declare const galleryPermissions: (callback: (status: boolean) => void) => Promise<void>;
|
|
18
|
+
/**
|
|
19
|
+
* 🔔 Show alert and open Settings if user accepts
|
|
20
|
+
*/
|
|
21
|
+
export declare const settingAlert: (message?: string) => void;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Platform, PermissionsAndroid } from 'react-native';
|
|
1
|
+
import { Platform, PermissionsAndroid, Alert, Linking } from 'react-native';
|
|
2
2
|
import { request, PERMISSIONS, RESULTS } from 'react-native-permissions';
|
|
3
3
|
/**
|
|
4
4
|
* Request storage/doc access permissions cross-platform.
|
|
@@ -36,71 +36,108 @@ export const requestDocumentPermission = async () => {
|
|
|
36
36
|
}
|
|
37
37
|
};
|
|
38
38
|
/**
|
|
39
|
-
*
|
|
39
|
+
* 📸 CAMERA PERMISSION
|
|
40
40
|
*/
|
|
41
41
|
export const cameraPermissions = async (callback) => {
|
|
42
42
|
try {
|
|
43
|
-
if (Platform.OS ===
|
|
43
|
+
if (Platform.OS === "ios") {
|
|
44
44
|
const result = await request(PERMISSIONS.IOS.CAMERA);
|
|
45
|
-
|
|
45
|
+
if (result === RESULTS.GRANTED)
|
|
46
|
+
return callback(true);
|
|
47
|
+
if (result === RESULTS.BLOCKED)
|
|
48
|
+
settingAlert("Camera access is blocked");
|
|
49
|
+
callback(false);
|
|
46
50
|
}
|
|
47
51
|
else {
|
|
48
52
|
const result = await PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.CAMERA);
|
|
49
|
-
|
|
53
|
+
if (result === PermissionsAndroid.RESULTS.GRANTED) {
|
|
54
|
+
callback(true);
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
settingAlert("Camera permission is required to take photos");
|
|
58
|
+
callback(false);
|
|
59
|
+
}
|
|
50
60
|
}
|
|
51
61
|
}
|
|
52
62
|
catch (error) {
|
|
53
|
-
console.log(
|
|
63
|
+
console.log("Camera Permission Error:", error);
|
|
54
64
|
callback(false);
|
|
55
65
|
}
|
|
56
66
|
};
|
|
57
67
|
/**
|
|
58
|
-
* 🎤
|
|
68
|
+
* 🎤 MICROPHONE PERMISSION
|
|
59
69
|
*/
|
|
60
70
|
export const checkMicroPhonePermission = async () => {
|
|
61
71
|
try {
|
|
62
|
-
if (Platform.OS ===
|
|
72
|
+
if (Platform.OS === "ios") {
|
|
63
73
|
const result = await request(PERMISSIONS.IOS.MICROPHONE);
|
|
74
|
+
if (result === RESULTS.BLOCKED)
|
|
75
|
+
settingAlert("Microphone is blocked");
|
|
64
76
|
return result === RESULTS.GRANTED;
|
|
65
77
|
}
|
|
66
78
|
else {
|
|
67
79
|
const result = await PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.RECORD_AUDIO);
|
|
80
|
+
if (result !== PermissionsAndroid.RESULTS.GRANTED)
|
|
81
|
+
settingAlert("Microphone permission is required for video recording");
|
|
68
82
|
return result === PermissionsAndroid.RESULTS.GRANTED;
|
|
69
83
|
}
|
|
70
84
|
}
|
|
71
85
|
catch (error) {
|
|
72
|
-
console.log(
|
|
86
|
+
console.log("Microphone Permission Error:", error);
|
|
73
87
|
return false;
|
|
74
88
|
}
|
|
75
89
|
};
|
|
76
90
|
/**
|
|
77
|
-
* 🖼️
|
|
78
|
-
* ✅ Handles Android < 13 and >= 13
|
|
91
|
+
* 🖼️ GALLERY / STORAGE PERMISSION
|
|
79
92
|
*/
|
|
80
93
|
export const galleryPermissions = async (callback) => {
|
|
81
94
|
try {
|
|
82
|
-
if (Platform.OS ===
|
|
95
|
+
if (Platform.OS === "ios") {
|
|
83
96
|
const result = await request(PERMISSIONS.IOS.PHOTO_LIBRARY);
|
|
84
|
-
|
|
97
|
+
if (result === RESULTS.GRANTED)
|
|
98
|
+
return callback(true);
|
|
99
|
+
if (result === RESULTS.BLOCKED)
|
|
100
|
+
settingAlert("Photo library access is blocked");
|
|
101
|
+
callback(false);
|
|
85
102
|
}
|
|
86
103
|
else {
|
|
87
104
|
const androidVersion = Platform.Version;
|
|
88
105
|
if (androidVersion >= 33) {
|
|
89
|
-
// 👉 Android 13+ requires READ_MEDIA permissions
|
|
90
106
|
const imagePermission = await PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.READ_MEDIA_IMAGES);
|
|
91
107
|
const videoPermission = await PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.READ_MEDIA_VIDEO);
|
|
92
|
-
|
|
93
|
-
videoPermission === PermissionsAndroid.RESULTS.GRANTED
|
|
108
|
+
const granted = imagePermission === PermissionsAndroid.RESULTS.GRANTED ||
|
|
109
|
+
videoPermission === PermissionsAndroid.RESULTS.GRANTED;
|
|
110
|
+
if (!granted)
|
|
111
|
+
settingAlert("Storage permission is required to select images");
|
|
112
|
+
callback(granted);
|
|
94
113
|
}
|
|
95
114
|
else {
|
|
96
|
-
// 👉 Below Android 13 needs old storage permission
|
|
97
115
|
const storagePermission = await PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.READ_EXTERNAL_STORAGE);
|
|
98
|
-
|
|
116
|
+
const granted = storagePermission === PermissionsAndroid.RESULTS.GRANTED;
|
|
117
|
+
if (!granted)
|
|
118
|
+
settingAlert("Storage permission is required to select images");
|
|
119
|
+
callback(granted);
|
|
99
120
|
}
|
|
100
121
|
}
|
|
101
122
|
}
|
|
102
123
|
catch (error) {
|
|
103
|
-
console.log(
|
|
124
|
+
console.log("Gallery Permission Error:", error);
|
|
104
125
|
callback(false);
|
|
105
126
|
}
|
|
106
127
|
};
|
|
128
|
+
/**
|
|
129
|
+
* 🔔 Show alert and open Settings if user accepts
|
|
130
|
+
*/
|
|
131
|
+
export const settingAlert = (message = "Permission is required") => {
|
|
132
|
+
Alert.alert("Permission Required", message + "\nPlease enable it from settings to continue.", [
|
|
133
|
+
{ text: "Cancel", style: "cancel" },
|
|
134
|
+
{
|
|
135
|
+
text: "Go to Settings",
|
|
136
|
+
onPress: () => {
|
|
137
|
+
Linking.openSettings().catch(() => {
|
|
138
|
+
Alert.alert("Error", "Unable to open settings");
|
|
139
|
+
});
|
|
140
|
+
},
|
|
141
|
+
},
|
|
142
|
+
]);
|
|
143
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@teamnhz/rn-ui-toolkit",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.8",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"files": [
|
|
@@ -38,5 +38,9 @@
|
|
|
38
38
|
"cpx": "^1.5.0",
|
|
39
39
|
"react-native-keyboard-aware-scroll-view": "^0.9.5",
|
|
40
40
|
"typescript": "^5.9.2"
|
|
41
|
+
},
|
|
42
|
+
"dependencies": {
|
|
43
|
+
"@react-native-community/datetimepicker": "^8.5.0",
|
|
44
|
+
"react-native-modal-datetime-picker": "^18.0.0"
|
|
41
45
|
}
|
|
42
46
|
}
|