@jescon-technologies/react-native-ui-kit 0.0.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.
@@ -0,0 +1,346 @@
1
+ import React, { useState, useEffect } from 'react'
2
+ import {
3
+ View,
4
+ Text,
5
+ StatusBar,
6
+ Dimensions,
7
+ ImageBackground,
8
+ TouchableOpacity,
9
+ TouchableHighlight,
10
+ TextInput
11
+ } from 'react-native'
12
+
13
+ import Icons from '../Common/Icons'
14
+ import { normalize } from '../CommonStyle/componentStyle'
15
+ import { getLoading, notifyMessage, ValueCheck } from '../CommonStyle/ComponentFunctions'
16
+ import NetworkServiceCall from '../Common/NetworkServiceCall'
17
+ import { APIURL } from '../Common/apiConstants'
18
+ import Loader from '../Custom/Loader'
19
+ import { Global } from '../Common/Global'
20
+ import axios from 'axios'
21
+
22
+ const image = {
23
+ uri: 'https://t4.ftcdn.net/jpg/05/19/65/81/360_F_519658132_FkvYwAjuJ8q67PGQUgYLrumVymaJtlZj.jpg'
24
+ }
25
+
26
+ /* ---------------- CUSTOM INPUT ---------------- */
27
+ const CustomInput = ({
28
+ value,
29
+ onChangeText,
30
+ placeholder,
31
+ secureTextEntry,
32
+ keyboardType,
33
+ autoFocus,
34
+ leftIcon,
35
+ rightIcon,
36
+ onRightIconPress,
37
+ onEndEditing,
38
+ style
39
+ }) => {
40
+ return (
41
+ <View
42
+ style={[
43
+ {
44
+ width: Dimensions.get('screen').width * 0.9,
45
+ borderWidth: 1,
46
+ borderColor: '#aaa',
47
+ borderRadius: 6,
48
+ flexDirection: 'row',
49
+ alignItems: 'center',
50
+ paddingHorizontal: 10,
51
+ backgroundColor: '#fff',
52
+ height: normalize(45)
53
+ },
54
+ style
55
+ ]}
56
+ >
57
+ {leftIcon && <View style={{ marginRight: 8 }}>{leftIcon}</View>}
58
+
59
+ <TextInput
60
+ style={{ flex: 1, color: '#000' }}
61
+ placeholder={placeholder}
62
+ placeholderTextColor="#777"
63
+ value={value}
64
+ onChangeText={onChangeText}
65
+ secureTextEntry={secureTextEntry}
66
+ keyboardType={keyboardType}
67
+ autoFocus={autoFocus}
68
+ onEndEditing={onEndEditing}
69
+ />
70
+
71
+ {rightIcon && (
72
+ <TouchableOpacity onPress={onRightIconPress}>
73
+ {rightIcon}
74
+ </TouchableOpacity>
75
+ )}
76
+ </View>
77
+ )
78
+ }
79
+
80
+ /* ---------------- MAIN COMPONENT ---------------- */
81
+ export default function ForgotPassword({ navigation }) {
82
+ const [stage, setStage] = useState(1)
83
+ const [text, setText] = useState('')
84
+ const [msg, setMsg] = useState('')
85
+ const [isLoading, setIsLoading] = useState(false)
86
+
87
+ const [password, setPassword] = useState({
88
+ oldpass: '',
89
+ newpass: '',
90
+ confirmpass: ''
91
+ })
92
+
93
+ const [isPasswordSecure, setIsPasswordSecure] = useState(true)
94
+ const [isPasswordSecureTwo, setIsPasswordSecureTwo] = useState(true)
95
+
96
+ useEffect(() => {
97
+ setPassword({ oldpass: '', newpass: '', confirmpass: '' })
98
+ setMsg('')
99
+ }, [stage])
100
+
101
+ /* ---------------- AUTH JWT ---------------- */
102
+ function actionJWT() {
103
+ if (password.oldpass && text) {
104
+ let buttonapi = APIURL + 'auth/authenticate'
105
+ let PostArr = {
106
+ username: text,
107
+ password: password.oldpass
108
+ }
109
+
110
+ axios
111
+ .post(buttonapi, PostArr)
112
+ .then(res => {
113
+ if (res.status === 200) {
114
+ Global.JWTToken = res.data
115
+ } else {
116
+ notifyMessage('Please check old password', 2)
117
+ }
118
+ })
119
+ .catch(() => notifyMessage('Authentication failed', 3))
120
+ }
121
+ }
122
+
123
+ /* ---------------- UPDATE PASSWORD ---------------- */
124
+ function getUpdate() {
125
+ if (!password.newpass || !password.confirmpass) {
126
+ notifyMessage('Please fill out passwords', 3)
127
+ return
128
+ }
129
+
130
+ if (password.newpass !== password.confirmpass) {
131
+ notifyMessage('Passwords do not match', 4)
132
+ return
133
+ }
134
+
135
+ const ReqJson = {
136
+ groups: {
137
+ procedurename: 'suuserforgetpassword1',
138
+ userid: text,
139
+ ...password
140
+ }
141
+ }
142
+
143
+ let buttonapi = APIURL + 'commontemplatesave/RnCommonTemplateSave'
144
+ setIsLoading(true)
145
+
146
+ NetworkServiceCall('post', buttonapi, ReqJson, Global.JWTToken).then(res => {
147
+ if (res?.httpstatus === 200 && res?.data?.code > 0) {
148
+ notifyMessage('Password Updated !!!', 1)
149
+ setStage(3)
150
+ } else {
151
+ notifyMessage('Password Not Updated', 2)
152
+ }
153
+ setIsLoading(false)
154
+ })
155
+
156
+ getLoading(() => setIsLoading(false))
157
+ }
158
+
159
+ /* ---------------- PASSWORD STRENGTH ---------------- */
160
+ function checkPasswordStrength(pass) {
161
+ let strength = 0
162
+ let tips = ''
163
+
164
+ if (pass.length >= 8) strength++
165
+ else tips += 'Minimum 8 characters. '
166
+
167
+ if (/[a-z]/.test(pass) && /[A-Z]/.test(pass)) strength++
168
+ else tips += 'Use upper & lower case. '
169
+
170
+ if (/\d/.test(pass)) strength++
171
+ else tips += 'Add a number. '
172
+
173
+ if (/[^a-zA-Z\d]/.test(pass)) strength++
174
+ else tips += 'Add a special character. '
175
+
176
+ if (strength < 2) setMsg('Easy')
177
+ else if (strength === 2) setMsg('Medium')
178
+ else if (strength === 3) setMsg('Strong')
179
+ else setMsg('Very Strong')
180
+
181
+ tips && notifyMessage(tips, 5)
182
+ }
183
+
184
+ /* ---------------- UI ---------------- */
185
+ return (
186
+ <View style={{ flex: 1, marginTop: StatusBar.currentHeight }}>
187
+ <StatusBar translucent backgroundColor="transparent" barStyle="dark-content" />
188
+
189
+ <ImageBackground source={image} style={{ flex: 1 }}>
190
+ <TouchableOpacity
191
+ style={{ padding: 20 }}
192
+ onPress={() => (stage === 1 ? navigation.goBack() : setStage(stage - 1))}
193
+ >
194
+ <Icons.FontAwesome5 name="arrow-left" size={normalize(20)} />
195
+ </TouchableOpacity>
196
+
197
+ {/* -------- STAGE 1 -------- */}
198
+ {stage === 1 && (
199
+ <View style={{ alignItems: 'center' }}>
200
+ <Icons.FontAwesome5 name="lock" size={normalize(50)} />
201
+ <Text style={{ fontSize: normalize(24), fontWeight: 'bold' }}>
202
+ CHANGE PASSWORD
203
+ </Text>
204
+
205
+ <CustomInput
206
+ placeholder="Enter User ID"
207
+ keyboardType="numeric"
208
+ value={text}
209
+ autoFocus
210
+ onChangeText={setText}
211
+ leftIcon={
212
+ <Icons.MaterialCommunityIcons
213
+ name="clock-time-five-outline"
214
+ size={normalize(20)}
215
+ color="purple"
216
+ />
217
+ }
218
+ style={{ marginTop: normalize(20) }}
219
+ />
220
+
221
+ <TouchableHighlight
222
+ onPress={() =>
223
+ ValueCheck(text)
224
+ ? setStage(2)
225
+ : notifyMessage('Enter User ID', 3)
226
+ }
227
+ style={{
228
+ marginTop: normalize(15),
229
+ width: Dimensions.get('screen').width * 0.9,
230
+ height: normalize(40),
231
+ backgroundColor: '#FADF00',
232
+ alignItems: 'center',
233
+ justifyContent: 'center'
234
+ }}
235
+ >
236
+ <Text style={{ fontWeight: 'bold' }}>NEXT</Text>
237
+ </TouchableHighlight>
238
+ </View>
239
+ )}
240
+
241
+ {/* -------- STAGE 2 -------- */}
242
+ {stage === 2 && (
243
+ <View style={{ alignItems: 'center' }}>
244
+ <Text style={{ fontWeight: 'bold', fontSize: normalize(18) }}>
245
+ New Credentials
246
+ </Text>
247
+
248
+ <CustomInput
249
+ placeholder="Old Password"
250
+ secureTextEntry={isPasswordSecure}
251
+ value={password.oldpass}
252
+ onChangeText={t => setPassword({ ...password, oldpass: t })}
253
+ onEndEditing={actionJWT}
254
+ leftIcon={<Icons.FontAwesome5 name="lock" size={18} />}
255
+ rightIcon={
256
+ <Icons.FontAwesome5
257
+ name={isPasswordSecure ? 'eye-slash' : 'eye'}
258
+ size={18}
259
+ />
260
+ }
261
+ onRightIconPress={() => setIsPasswordSecure(!isPasswordSecure)}
262
+ style={{ marginTop: normalize(15) }}
263
+ />
264
+
265
+ <Text style={{ alignSelf: 'flex-end', color: 'red' }}>{msg}</Text>
266
+
267
+ <CustomInput
268
+ placeholder="New Password"
269
+ secureTextEntry={isPasswordSecure}
270
+ value={password.newpass}
271
+ onChangeText={t => setPassword({ ...password, newpass: t })}
272
+ onEndEditing={() => checkPasswordStrength(password.newpass)}
273
+ leftIcon={<Icons.FontAwesome5 name="lock" size={18} />}
274
+ rightIcon={
275
+ <Icons.FontAwesome5
276
+ name={isPasswordSecure ? 'eye-slash' : 'eye'}
277
+ size={18}
278
+ />
279
+ }
280
+ onRightIconPress={() => setIsPasswordSecure(!isPasswordSecure)}
281
+ style={{ marginTop: normalize(15) }}
282
+ />
283
+
284
+ <CustomInput
285
+ placeholder="Confirm Password"
286
+ secureTextEntry={isPasswordSecureTwo}
287
+ value={password.confirmpass}
288
+ onChangeText={t => setPassword({ ...password, confirmpass: t })}
289
+ leftIcon={<Icons.FontAwesome5 name="lock" size={18} />}
290
+ rightIcon={
291
+ <Icons.FontAwesome5
292
+ name={isPasswordSecureTwo ? 'eye-slash' : 'eye'}
293
+ size={18}
294
+ />
295
+ }
296
+ onRightIconPress={() =>
297
+ setIsPasswordSecureTwo(!isPasswordSecureTwo)
298
+ }
299
+ style={{ marginTop: normalize(15) }}
300
+ />
301
+
302
+ <TouchableHighlight
303
+ onPress={getUpdate}
304
+ style={{
305
+ marginTop: normalize(15),
306
+ width: Dimensions.get('screen').width * 0.9,
307
+ height: normalize(40),
308
+ backgroundColor: '#FADF00',
309
+ alignItems: 'center',
310
+ justifyContent: 'center'
311
+ }}
312
+ >
313
+ <Text style={{ fontWeight: 'bold' }}>UPDATE</Text>
314
+ </TouchableHighlight>
315
+ </View>
316
+ )}
317
+
318
+ {/* -------- STAGE 3 -------- */}
319
+ {stage === 3 && (
320
+ <View style={{ alignItems: 'center' }}>
321
+ <Icons.EvilIcons name="check" size={normalize(100)} color="green" />
322
+ <Text style={{ color: 'green', fontWeight: 'bold' }}>
323
+ Password Updated
324
+ </Text>
325
+
326
+ <TouchableHighlight
327
+ onPress={() => navigation.goBack()}
328
+ style={{
329
+ marginTop: normalize(15),
330
+ width: Dimensions.get('screen').width * 0.9,
331
+ height: normalize(40),
332
+ backgroundColor: '#FADF00',
333
+ alignItems: 'center',
334
+ justifyContent: 'center'
335
+ }}
336
+ >
337
+ <Text style={{ fontWeight: 'bold' }}>LOGIN</Text>
338
+ </TouchableHighlight>
339
+ </View>
340
+ )}
341
+ </ImageBackground>
342
+
343
+ {isLoading && <Loader displaytext />}
344
+ </View>
345
+ )
346
+ }
@@ -0,0 +1,328 @@
1
+ import React, { useState, useEffect } from 'react';
2
+ import {
3
+ View,
4
+ StatusBar,
5
+ Text,
6
+ Image,
7
+ Platform,
8
+ TouchableOpacity,
9
+ Dimensions,
10
+ StyleSheet,
11
+ ScrollView,
12
+ TouchableWithoutFeedback,
13
+ Keyboard,
14
+ SafeAreaView,
15
+ Linking,
16
+ BackHandler,
17
+ } from 'react-native';
18
+ import { normalize } from '../CommonStyle/componentStyle';
19
+ import Icon from '../Common/Icons';
20
+ import Loader from '../Custom/Loader';
21
+ import { useIsFocused } from '../Navigation/useIsFocused';
22
+ import { useNavigation } from '../Navigation/useNavigation';
23
+ import RNFetchBlob from 'react-native-blob-util';
24
+ import { Global } from '../Common/Global';
25
+ import { isNU } from '../CommonStyle/ComponentFunctions';
26
+ import RNExitApp from 'react-native-exit-app';
27
+ import HView from '../HOC/HView';
28
+ import { APIURL } from '../Common/apiConstants';
29
+
30
+ /**
31
+ * Login Component
32
+ *
33
+ * Handles the main login screen functionality of the application
34
+ *
35
+ * @param {Object} props - Component props passed from parent
36
+ * @returns {React.ReactElement} Rendered login screen
37
+ */
38
+ function Login(props) {
39
+ // State variables
40
+ const [data, setData] = useState(props.route.params.data);
41
+ const [isLoading, setIsLoading] = useState(false);
42
+
43
+ // Hooks and dimensions
44
+ const { width, height } = Dimensions.get('screen');
45
+ const isFocused = useIsFocused();
46
+ const navigation = useNavigation();
47
+
48
+ // Handle back button press to exit app
49
+ useEffect(() => {
50
+ const backAction = () => {
51
+ if (!navigation.isFocused()) {
52
+ return false;
53
+ }
54
+
55
+ RNExitApp.exitApp();
56
+ return true;
57
+ };
58
+
59
+ const backHandler = BackHandler.addEventListener(
60
+ 'hardwareBackPress',
61
+ backAction,
62
+ );
63
+
64
+ return () => backHandler.remove();
65
+ }, [navigation]);
66
+
67
+ /**
68
+ * Get file extension from filename
69
+ * @param {string} filename - The file name to extract extension from
70
+ * @returns {string|undefined} - The file extension
71
+ */
72
+ const getExtention = filename => {
73
+ return /[.]/.exec(filename) ? /[^.]+$/.exec(filename) : undefined;
74
+ };
75
+
76
+ /**
77
+ * Downloads an image from URL to device storage
78
+ */
79
+ const downloadImage = () => {
80
+ let date = new Date();
81
+ let image_URL = 'https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png';
82
+ let ext = getExtention(image_URL);
83
+ ext = '.' + ext[0];
84
+
85
+ const { config, fs } = RNFetchBlob;
86
+ let PictureDir = fs.dirs.PictureDir;
87
+
88
+ let options = {
89
+ fileCache: true,
90
+ addAndroidDownloads: {
91
+ useDownloadManager: true,
92
+ notification: true,
93
+ path: PictureDir + '/image_' + Math.floor(date.getTime() + date.getSeconds() / 2) + ext,
94
+ description: 'Image',
95
+ },
96
+ };
97
+
98
+ config(options)
99
+ .fetch('GET', image_URL)
100
+ .then(res => {
101
+ console.log('res -> ', JSON.stringify(res));
102
+ alert('Image Downloaded Successfully.');
103
+ });
104
+ };
105
+
106
+ const hospitalBgImage = Global.HospitalData?.bgimage || 'https://i.ibb.co/jvj0wdH/Adams-Neilson.jpg';
107
+
108
+ return (
109
+ <SafeAreaView style={styles.container}>
110
+ <StatusBar
111
+ translucent
112
+ backgroundColor="transparent"
113
+ barStyle={Platform.OS === 'ios' ? 'light-content' : 'dark-content'} />
114
+
115
+ <TouchableWithoutFeedback>
116
+ <View style={styles.container}>
117
+ {/* App Title */}
118
+ <Text
119
+ style={[
120
+ styles.titleText,
121
+ {
122
+ paddingHorizontal: 30,
123
+ textShadowColor: Global.AppTheme.primary_color,
124
+ textShadowOffset: { width: normalize(5), height: normalize(5) },
125
+ textShadowRadius: normalize(15),
126
+ textAlign: 'center',
127
+ },
128
+ ]}
129
+ >
130
+ {'HOMES'}
131
+ </Text>
132
+
133
+ <ScrollView keyboardShouldPersistTaps="handled">
134
+ <View style={styles.contentContainer}>
135
+ {/* Header Image */}
136
+ <View>
137
+ <Image
138
+ style={styles.headerImage}
139
+ source={{ uri: hospitalBgImage }}
140
+ />
141
+
142
+ {/* Customer Service Button */}
143
+ <TouchableOpacity
144
+ style={styles.customerServiceButton}
145
+ onPress={() => Linking.openURL(`tel:${Global.HospitalData.customercare}`)}
146
+ >
147
+ <Icon.AntDesign
148
+ name="customerservice"
149
+ color="#fff"
150
+ size={normalize(17)}
151
+ />
152
+ </TouchableOpacity>
153
+ </View>
154
+
155
+ {/* Login Form */}
156
+ <View style={styles.bottomView}>
157
+ <HView
158
+ component={'InsureLoginLayout'}
159
+ loader={val => (val === undefined ? null : setIsLoading(val))}
160
+ />
161
+ </View>
162
+ </View>
163
+
164
+ {/* Company Logo Section */}
165
+ <View style={styles.companyLogoSection}>
166
+ <TouchableOpacity
167
+ onPress={() => Linking.openURL('http://jescontechnologies.com/')}
168
+ style={styles.footer_container}
169
+ >
170
+ <View style={styles.companyinfo_container}>
171
+ <Image
172
+ style={styles.companyLogo}
173
+ source={{ uri: 'https://i.ibb.co/dkNbcDN/jesconnewlogo.jpg' }}
174
+ />
175
+ <Image
176
+ style={styles.company_icon}
177
+ source={{ uri: `${APIURL}insurancefile/getCommonFile/image/companyaddress_transparent.png` }}
178
+ />
179
+ </View>
180
+ </TouchableOpacity>
181
+ </View>
182
+ </ScrollView>
183
+
184
+ {/* App Version Display */}
185
+ <View style={styles.versionContainer}>
186
+ {Platform.OS !== 'ios' && (
187
+ <Text style={styles.versionText}>
188
+ {Global.CodePushVersion}
189
+ </Text>
190
+ )}
191
+ <Text style={styles.versionText}>
192
+ {isNU(Global.version) ? `V ${Global.version}` : null}
193
+ </Text>
194
+ </View>
195
+
196
+ {/* Footer Icons */}
197
+ {/* <View style={styles.footerIconsContainer}>
198
+ <View style={styles.footerIconsRow}>
199
+ {data?.loginfootericons?.map((item, i) => (
200
+ <CVectorIcon
201
+ key={i}
202
+ data={{
203
+ disabled: false,
204
+ displaytext: item.displaytext,
205
+ fontcolor: item.color,
206
+ fontWeight: 'bold',
207
+ size: 12,
208
+ iconname: item.iconname,
209
+ iconcolor: item.color,
210
+ iconsize: 22,
211
+ functionid: 'DF01',
212
+ }}
213
+ callBack={val =>
214
+ val === undefined
215
+ ? null
216
+ : props.navigation.navigate('WebPage', { data: item })
217
+ }
218
+ />
219
+ ))}
220
+ </View>
221
+ </View> */}
222
+
223
+ {/* Loading Indicator */}
224
+ {isLoading && <Loader displaytext={true} />}
225
+ </View>
226
+ </TouchableWithoutFeedback>
227
+ </SafeAreaView>
228
+ );
229
+ }
230
+
231
+ export default Login;
232
+
233
+ const styles = StyleSheet.create({
234
+ container: {
235
+ flex: 1,
236
+ },
237
+ contentContainer: {
238
+ flex: 1,
239
+ marginBottom: Platform.OS !== 'web' ? normalize(100) : normalize(50),
240
+ },
241
+ titleText: {
242
+ position: 'absolute',
243
+ top: Dimensions.get('screen').height * 0.05,
244
+ alignSelf: 'center',
245
+ color: '#fff',
246
+ zIndex: 1,
247
+ elevation: 5,
248
+ fontWeight: 'bold',
249
+ fontSize: normalize(40),
250
+ },
251
+ headerImage: {
252
+ height: Dimensions.get('screen').height * 0.25,
253
+ width: '100%',
254
+ opacity: 0.7,
255
+ },
256
+ customerServiceButton: {
257
+ position: 'absolute',
258
+ top: normalize(60),
259
+ right: normalize(20),
260
+ backgroundColor: Global.AppTheme.primary_color,
261
+ padding: normalize(5),
262
+ borderRadius: 1000,
263
+ },
264
+ bottomView: {
265
+ backgroundColor: '#fff',
266
+ opacity: 0.95,
267
+ marginTop: normalize(-50),
268
+ borderRadius: normalize(20),
269
+ marginHorizontal: normalize(7),
270
+ paddingHorizontal: normalize(15),
271
+ },
272
+ companyLogoSection: {
273
+ position: Platform.OS !== 'web' && 'absolute',
274
+ bottom: normalize(50),
275
+ backgroundColor: '#fff',
276
+ },
277
+ footer_container: {
278
+ marginBottom: '1%',
279
+ alignItems: 'center',
280
+ width: '100%',
281
+ },
282
+ companyinfo_container: {
283
+ flexDirection: 'row',
284
+ height: normalize(45),
285
+ width: '100%',
286
+ justifyContent: 'flex-start',
287
+ alignItems: 'flex-start',
288
+ },
289
+ companyLogo: {
290
+ width: '47%',
291
+ height: '100%',
292
+ borderRadius: 0,
293
+ margin: 5,
294
+ resizeMode: 'cover',
295
+ },
296
+ company_icon: {
297
+ width: '47%',
298
+ height: '100%',
299
+ borderRadius: 0,
300
+ margin: 5,
301
+ resizeMode: 'contain',
302
+ },
303
+ versionContainer: {
304
+ position: 'absolute',
305
+ bottom: 0,
306
+ zIndex: 1,
307
+ alignSelf: 'center',
308
+ },
309
+ versionText: {
310
+ color: Global.AppTheme.secondary_color,
311
+ fontSize: normalize(10),
312
+ alignSelf: 'center',
313
+ fontWeight: 'bold',
314
+ },
315
+ footerIconsContainer: {
316
+ position: 'absolute',
317
+ bottom: 0,
318
+ backgroundColor: '#fff',
319
+ width: '100%',
320
+ height: normalize(45),
321
+ justifyContent: 'center',
322
+ },
323
+ footerIconsRow: {
324
+ flexDirection: 'row',
325
+ justifyContent: 'space-between',
326
+ paddingHorizontal: normalize(15),
327
+ },
328
+ });