create-gufran-expo-app 2.0.3 → 2.0.5
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/README.md +1 -2
- package/package.json +3 -3
- package/template/src/navigation/AuthStack.tsx +6 -25
- package/template/src/navigation/MainStack.tsx +0 -148
- package/template/src/navigation/RootNavigator.tsx +4 -26
- package/template/src/navigation/index.ts +0 -1
- package/template/src/navigation/navigationRef.ts +1 -1
- package/template/src/screens/HomeScreen.tsx +3 -215
- package/template/src/screens/auth/LoginScreen.tsx +13 -13
- package/template/src/screens/auth/index.ts +1 -6
- package/template/src/screens/index.ts +0 -35
- package/template/src/services/api.ts +5 -5
- package/template/src/services/authService.ts +3 -299
- package/template/src/services/mainServices.ts +19 -1914
- package/template/src/types/navigation.ts +5 -155
- package/template/src/utils/index.ts +5 -8
- package/template/src/navigation/MiddleStack.tsx +0 -35
- package/template/src/screens/auth/AddMamber.tsx +0 -428
- package/template/src/screens/auth/ForgotPasswordScreen.tsx +0 -176
- package/template/src/screens/auth/OTPVerifyScreen.tsx +0 -359
- package/template/src/screens/auth/RegisterScreen.tsx +0 -430
- package/template/src/screens/auth/SuccessScreen.tsx +0 -201
- package/template/src/screens/chat/ChatScreen.tsx +0 -1819
- package/template/src/screens/chat/ChatThreadsScreen.tsx +0 -360
- package/template/src/screens/chat/ReportMessageScreen.tsx +0 -238
- package/template/src/screens/clubs/Announcements.tsx +0 -426
- package/template/src/screens/clubs/BuyRaffleTicketsScreen.tsx +0 -568
- package/template/src/screens/clubs/ClubDeteils.tsx +0 -497
- package/template/src/screens/clubs/JoinClub.tsx +0 -841
- package/template/src/screens/events/EventScreen.tsx +0 -460
- package/template/src/screens/raffles/MyReferralMembersScreen.tsx +0 -758
- package/template/src/screens/raffles/RaffleDetailsScreen.tsx +0 -762
- package/template/src/screens/raffles/RafflesScreen.tsx +0 -495
- package/template/src/screens/raffles/SetRaffleReminderScreen.tsx +0 -390
- package/template/src/screens/teams/JoinTeamScreen.tsx +0 -464
- package/template/src/screens/teams/MyTeamDetailsScreen.tsx +0 -979
- package/template/src/screens/teams/MyTeamScreen.tsx +0 -568
- package/template/src/screens/teams/PendingRequestsScreen.tsx +0 -426
- package/template/src/screens/volunteerOpportunities/SetReminderScreen.tsx +0 -631
- package/template/src/screens/volunteerOpportunities/VolunteerOpportunitiesDetailsScreen.tsx +0 -1049
- package/template/src/screens/volunteerOpportunities/VolunteerOpportunitiesScreen.tsx +0 -608
- package/template/src/utils/ClubSearchManager.ts +0 -222
|
@@ -1,359 +0,0 @@
|
|
|
1
|
-
import React, { useState, useEffect, useRef } from 'react';
|
|
2
|
-
import {
|
|
3
|
-
View,
|
|
4
|
-
Text,
|
|
5
|
-
StyleSheet,
|
|
6
|
-
ImageBackground,
|
|
7
|
-
TouchableOpacity,
|
|
8
|
-
Platform
|
|
9
|
-
} from 'react-native';
|
|
10
|
-
import { Button, hideLoader, OTPInputComponent, OTPInputRef, showLoader } from '../../components/common';
|
|
11
|
-
import { theme } from '../../constants';
|
|
12
|
-
import { Strings } from '../../constants/strings';
|
|
13
|
-
import { getApiErrorInfo, useResendOTP, useVerifyOTP } from '../../services/authService';
|
|
14
|
-
import { moderateScale } from '../../utils/scaling';
|
|
15
|
-
import { Fonts } from '../../constants/Fonts';
|
|
16
|
-
import { SafeAreaView } from 'react-native-safe-area-context';
|
|
17
|
-
import { StatusBar } from 'react-native';
|
|
18
|
-
import { KeyboardAwareScrollView } from 'react-native-keyboard-aware-scroll-view';
|
|
19
|
-
import Images from '../../assets/images';
|
|
20
|
-
import SVG from '../../assets/icons';
|
|
21
|
-
import ToastManager from '../../components/common/ToastManager';
|
|
22
|
-
import { useAuthStore } from '../../stores/authStore';
|
|
23
|
-
|
|
24
|
-
interface OTPVerifyScreenProps {
|
|
25
|
-
navigation: any;
|
|
26
|
-
route?: {
|
|
27
|
-
params?: {
|
|
28
|
-
email?: string;
|
|
29
|
-
};
|
|
30
|
-
};
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export const OTPVerifyScreen: React.FC<OTPVerifyScreenProps> = ({ navigation, route }) => {
|
|
34
|
-
|
|
35
|
-
const [isLoading, setIsLoading] = useState(false);
|
|
36
|
-
const emailParam = route?.params?.email || 'your email';
|
|
37
|
-
const verifyOTPMutation = useVerifyOTP();
|
|
38
|
-
const resendOTPMutation = useResendOTP();
|
|
39
|
-
const [otp, setOtp] = useState('');
|
|
40
|
-
const [resendTimer, setResendTimer] = useState(60);
|
|
41
|
-
const [canResend, setCanResend] = useState(false);
|
|
42
|
-
const [startTime, setStartTime] = useState<number | null>(null);
|
|
43
|
-
const { login } = useAuthStore();
|
|
44
|
-
const otpInputRef = useRef<OTPInputRef>(null);
|
|
45
|
-
|
|
46
|
-
useEffect(() => {
|
|
47
|
-
// Initialize timer with start time
|
|
48
|
-
if (startTime === null) {
|
|
49
|
-
const initialStartTime = Date.now();
|
|
50
|
-
setStartTime(initialStartTime);
|
|
51
|
-
runTimer(initialStartTime);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
return () => {
|
|
55
|
-
// Cleanup will be handled in runTimer function
|
|
56
|
-
};
|
|
57
|
-
}, [startTime]);
|
|
58
|
-
|
|
59
|
-
const runTimer = (initialStartTime: number) => {
|
|
60
|
-
setResendTimer(60);
|
|
61
|
-
setCanResend(false);
|
|
62
|
-
|
|
63
|
-
const timerInterval = setInterval(() => {
|
|
64
|
-
const elapsedTime = (Date.now() - initialStartTime) / 1000; // Elapsed time in seconds
|
|
65
|
-
const remaining = Math.max(60 - elapsedTime, 0); // Calculate remaining time
|
|
66
|
-
|
|
67
|
-
setResendTimer(remaining);
|
|
68
|
-
|
|
69
|
-
if (remaining <= 0) {
|
|
70
|
-
setCanResend(true);
|
|
71
|
-
clearInterval(timerInterval);
|
|
72
|
-
}
|
|
73
|
-
}, 1000); // Update every second
|
|
74
|
-
|
|
75
|
-
// Store interval reference for cleanup
|
|
76
|
-
return timerInterval;
|
|
77
|
-
};
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
const validateOTP = () => {
|
|
81
|
-
if (!otp.trim()) {
|
|
82
|
-
ToastManager.error('OTP is required');
|
|
83
|
-
return false;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
if (otp.length !== 4) {
|
|
87
|
-
ToastManager.error('Please enter a complete 4-digit OTP');
|
|
88
|
-
return false;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
return true;
|
|
92
|
-
};
|
|
93
|
-
|
|
94
|
-
const handleVerify = async () => {
|
|
95
|
-
// navigation.navigate('AddMember');
|
|
96
|
-
// return
|
|
97
|
-
if (!validateOTP()) return;
|
|
98
|
-
showLoader();
|
|
99
|
-
await verifyOTPMutation.mutateAsync({
|
|
100
|
-
email: emailParam,
|
|
101
|
-
otp: otp,
|
|
102
|
-
deviceToken: "jhjhjghgj",
|
|
103
|
-
deviceType: Platform.OS === "ios" ? 2 : 1,
|
|
104
|
-
}, {
|
|
105
|
-
onSuccess: (response) => {
|
|
106
|
-
ToastManager.success(response?.data?.message || Strings.AUTH.OTP_VERIFIED_SUCCESS);
|
|
107
|
-
|
|
108
|
-
// Handle the response data based on the API structure you provided
|
|
109
|
-
if (response.data) {
|
|
110
|
-
const userData = {
|
|
111
|
-
userId: response.data.data.userId,
|
|
112
|
-
Name: response.data.data.Name,
|
|
113
|
-
email: response.data.data.email,
|
|
114
|
-
profileImage: response?.data?.data?.profileImage || "",
|
|
115
|
-
isProfileCompleted: response?.data?.data?.isProfileCompleted,
|
|
116
|
-
isAddMember: response?.data?.data?.isAddMember,
|
|
117
|
-
userType: response?.data?.data?.userType
|
|
118
|
-
};
|
|
119
|
-
|
|
120
|
-
// Save both tokens and user data
|
|
121
|
-
login(userData, response.data.data.accessToken, response.data.data.authorizationToken);
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
}
|
|
125
|
-
},
|
|
126
|
-
onError: (error) => {
|
|
127
|
-
const errorInfo = getApiErrorInfo(error);
|
|
128
|
-
ToastManager.error(errorInfo.message || Strings.AUTH.OTP_VERIFIED_FAILED);
|
|
129
|
-
console.error('Verify OTP error:', error);
|
|
130
|
-
},
|
|
131
|
-
onSettled: () => {
|
|
132
|
-
hideLoader();
|
|
133
|
-
console.log('Verify OTP settled');
|
|
134
|
-
}
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
};
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
const onOTPChange = (text: string) => {
|
|
142
|
-
setOtp(text);
|
|
143
|
-
};
|
|
144
|
-
|
|
145
|
-
const onOTPFilled = (text: string) => {
|
|
146
|
-
setOtp(text);
|
|
147
|
-
};
|
|
148
|
-
|
|
149
|
-
const onResendOTPClick = () => {
|
|
150
|
-
if (!canResend) return;
|
|
151
|
-
|
|
152
|
-
resendOTPMutation.mutate({
|
|
153
|
-
email: emailParam,
|
|
154
|
-
}, {
|
|
155
|
-
onSuccess: (response) => {
|
|
156
|
-
ToastManager.success(response?.data?.message || Strings.AUTH.OTP_SEND_SUCCESS);
|
|
157
|
-
|
|
158
|
-
// Reset timer by setting new start time
|
|
159
|
-
const newStartTime = Date.now();
|
|
160
|
-
setStartTime(newStartTime);
|
|
161
|
-
setOtp(''); // Clear current OTP
|
|
162
|
-
otpInputRef.current?.clear(); // Clear OTP input component
|
|
163
|
-
|
|
164
|
-
// Start new timer
|
|
165
|
-
runTimer(newStartTime);
|
|
166
|
-
},
|
|
167
|
-
onError: (error) => {
|
|
168
|
-
const errorInfo = getApiErrorInfo(error);
|
|
169
|
-
ToastManager.error(errorInfo.message || 'Failed to send OTP. Please try again.');
|
|
170
|
-
console.error('Resend OTP error:', error);
|
|
171
|
-
},
|
|
172
|
-
onSettled: () => {
|
|
173
|
-
console.log('Resend OTP settled');
|
|
174
|
-
}
|
|
175
|
-
});
|
|
176
|
-
};
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
const formatTimer = (seconds: number) => {
|
|
180
|
-
const mins = Math.floor(seconds / 60);
|
|
181
|
-
const secs = Math.floor(seconds % 60);
|
|
182
|
-
return `${mins}:${secs.toString().padStart(2, '0')}`;
|
|
183
|
-
};
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
return (
|
|
187
|
-
<ImageBackground
|
|
188
|
-
source={Images.backgroundImage}
|
|
189
|
-
style={styles.backgroundImage}
|
|
190
|
-
resizeMode="contain"
|
|
191
|
-
>
|
|
192
|
-
<SafeAreaView edges={['top']} style={{ flex: 1 }}>
|
|
193
|
-
<StatusBar barStyle="dark-content" />
|
|
194
|
-
<KeyboardAwareScrollView
|
|
195
|
-
enableOnAndroid={true}
|
|
196
|
-
contentContainerStyle={styles.container}
|
|
197
|
-
keyboardShouldPersistTaps="handled"
|
|
198
|
-
>
|
|
199
|
-
<TouchableOpacity style={{ marginLeft: theme.spacing.md, marginTop: theme.spacing.md }} onPress={() => navigation.goBack()}>
|
|
200
|
-
<SVG.arrowLeft height={moderateScale(30)} width={moderateScale(30)} style={styles.logoIcon} />
|
|
201
|
-
</TouchableOpacity>
|
|
202
|
-
<View style={styles.logoSection}>
|
|
203
|
-
<SVG.login_logo height={moderateScale(150)} width={moderateScale(150)} style={styles.logoIcon} />
|
|
204
|
-
</View>
|
|
205
|
-
|
|
206
|
-
{/* Login Form */}
|
|
207
|
-
<View style={styles.loginSection}>
|
|
208
|
-
<Text style={styles.loginTitle}>{Strings.AUTH.EMAIL_VERIFY_TITLE}</Text>
|
|
209
|
-
<Text style={styles.emailVerifySubTitle}>{Strings.AUTH.EMAIL_VERIFY_SUBTITLE}</Text>
|
|
210
|
-
|
|
211
|
-
<View style={styles.form}>
|
|
212
|
-
|
|
213
|
-
<OTPInputComponent
|
|
214
|
-
ref={otpInputRef}
|
|
215
|
-
onTextChange={onOTPChange}
|
|
216
|
-
onFilled={onOTPFilled}
|
|
217
|
-
numberOfDigits={4}
|
|
218
|
-
disabled={isLoading}
|
|
219
|
-
/>
|
|
220
|
-
|
|
221
|
-
{/* Resend Section */}
|
|
222
|
-
<View style={styles.resendSection}>
|
|
223
|
-
<Text style={styles.resendText}>Didn't receive OTP? </Text>
|
|
224
|
-
{canResend ? (
|
|
225
|
-
<TouchableOpacity
|
|
226
|
-
onPress={onResendOTPClick}
|
|
227
|
-
disabled={isLoading}
|
|
228
|
-
activeOpacity={0.7}
|
|
229
|
-
>
|
|
230
|
-
<Text style={[styles.resendButton, isLoading && styles.resendButtonDisabled]}>
|
|
231
|
-
Resend Code
|
|
232
|
-
</Text>
|
|
233
|
-
</TouchableOpacity>
|
|
234
|
-
) : (
|
|
235
|
-
<Text style={styles.timerText}>
|
|
236
|
-
Resend in {formatTimer(resendTimer)}
|
|
237
|
-
</Text>
|
|
238
|
-
)}
|
|
239
|
-
</View>
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
<Button
|
|
243
|
-
title={Strings.COMMON.VERIFY}
|
|
244
|
-
onPress={handleVerify}
|
|
245
|
-
variant="primary"
|
|
246
|
-
size="medium"
|
|
247
|
-
/>
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
</View>
|
|
252
|
-
</View>
|
|
253
|
-
</KeyboardAwareScrollView>
|
|
254
|
-
</SafeAreaView>
|
|
255
|
-
</ImageBackground>
|
|
256
|
-
);
|
|
257
|
-
};
|
|
258
|
-
|
|
259
|
-
const styles = StyleSheet.create({
|
|
260
|
-
backgroundImage: {
|
|
261
|
-
flex: 1,
|
|
262
|
-
width: '100%',
|
|
263
|
-
height: '100%',
|
|
264
|
-
},
|
|
265
|
-
container: {
|
|
266
|
-
flexGrow: 1,
|
|
267
|
-
},
|
|
268
|
-
// Logo Section
|
|
269
|
-
logoSection: {
|
|
270
|
-
justifyContent: 'center',
|
|
271
|
-
alignItems: 'center',
|
|
272
|
-
marginBottom: theme.spacing.xs,
|
|
273
|
-
},
|
|
274
|
-
logoIcon: {
|
|
275
|
-
marginBottom: theme.spacing.xs,
|
|
276
|
-
},
|
|
277
|
-
// Login Section
|
|
278
|
-
loginSection: {
|
|
279
|
-
flex: 1,
|
|
280
|
-
backgroundColor: theme.colors.background,
|
|
281
|
-
paddingHorizontal: theme.spacing.lg,
|
|
282
|
-
borderTopLeftRadius: moderateScale(30),
|
|
283
|
-
borderTopRightRadius: moderateScale(30),
|
|
284
|
-
paddingTop: moderateScale(20),
|
|
285
|
-
},
|
|
286
|
-
loginTitle: {
|
|
287
|
-
fontFamily: Fonts.outfitSemiBold,
|
|
288
|
-
fontSize: moderateScale(22),
|
|
289
|
-
color: theme.colors.black,
|
|
290
|
-
marginBottom: theme.spacing.xs,
|
|
291
|
-
},
|
|
292
|
-
emailVerifySubTitle: {
|
|
293
|
-
fontFamily: Fonts.outfitRegular,
|
|
294
|
-
fontSize: moderateScale(15),
|
|
295
|
-
color: theme.colors.black,
|
|
296
|
-
marginBottom: theme.spacing.md,
|
|
297
|
-
},
|
|
298
|
-
form: {
|
|
299
|
-
gap: theme.spacing.sm,
|
|
300
|
-
},
|
|
301
|
-
forgotPasswordContainer: {
|
|
302
|
-
alignItems: 'flex-end',
|
|
303
|
-
marginTop: -8,
|
|
304
|
-
},
|
|
305
|
-
forgotButton: {
|
|
306
|
-
backgroundColor: 'transparent',
|
|
307
|
-
borderColor: 'transparent',
|
|
308
|
-
shadowOpacity: 0,
|
|
309
|
-
elevation: 0,
|
|
310
|
-
paddingHorizontal: 0,
|
|
311
|
-
paddingVertical: 4,
|
|
312
|
-
minHeight: 'auto',
|
|
313
|
-
},
|
|
314
|
-
forgotButtonText: {
|
|
315
|
-
color: theme.colors.appleGreen,
|
|
316
|
-
fontSize: theme.typography.fontSize.sm,
|
|
317
|
-
fontFamily: Fonts.outfitRegular,
|
|
318
|
-
},
|
|
319
|
-
divider: {
|
|
320
|
-
flexDirection: 'row',
|
|
321
|
-
alignItems: 'center',
|
|
322
|
-
justifyContent: 'center',
|
|
323
|
-
marginVertical: theme.spacing.sm,
|
|
324
|
-
},
|
|
325
|
-
signUpButton: {
|
|
326
|
-
borderColor: theme.colors.appleGreen,
|
|
327
|
-
},
|
|
328
|
-
signUpButtonText: {
|
|
329
|
-
color: theme.colors.appleGreen,
|
|
330
|
-
fontWeight: theme.typography.fontWeight.semibold,
|
|
331
|
-
},
|
|
332
|
-
resendSection: {
|
|
333
|
-
flexDirection: 'row',
|
|
334
|
-
justifyContent: 'center',
|
|
335
|
-
alignItems: 'center',
|
|
336
|
-
marginVertical: theme.spacing.sm,
|
|
337
|
-
},
|
|
338
|
-
resendText: {
|
|
339
|
-
fontFamily: Fonts.outfitRegular,
|
|
340
|
-
fontSize: moderateScale(15),
|
|
341
|
-
color: theme.colors.black,
|
|
342
|
-
},
|
|
343
|
-
resendButton: {
|
|
344
|
-
fontFamily: Fonts.outfitSemiBold,
|
|
345
|
-
fontSize: moderateScale(15),
|
|
346
|
-
color: theme.colors.primary,
|
|
347
|
-
textDecorationLine: 'underline',
|
|
348
|
-
},
|
|
349
|
-
resendButtonDisabled: {
|
|
350
|
-
color: theme.colors.textSecondary,
|
|
351
|
-
textDecorationLine: 'none',
|
|
352
|
-
},
|
|
353
|
-
timerText: {
|
|
354
|
-
fontFamily: Fonts.outfitSemiBold,
|
|
355
|
-
fontSize: moderateScale(15),
|
|
356
|
-
color: theme.colors.warning,
|
|
357
|
-
},
|
|
358
|
-
});
|
|
359
|
-
|