verification.tsx 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. import { View, Text, StyleSheet, TextInput, Pressable } from 'react-native';
  2. import { useEffect, useState } from 'react';
  3. import PhoneInput from '../../../global/phone_input';
  4. import NumberInput from '../../../global/number_input';
  5. import NormalButton from '../../../global/normal_button';
  6. import useSignUpStore from '../../../../providers/signup_form_store';
  7. import { authenticationService } from '../../../../service/authService';
  8. import { usePushNotifications } from '../../../../app/hooks/usePushNotifications';
  9. type VerificationProps = {
  10. setScreen: React.Dispatch<React.SetStateAction<number>>;
  11. };
  12. const Verification: React.FC<VerificationProps> = ({ setScreen }) => {
  13. const { signUpFormData, setSignUpFormData } = useSignUpStore();
  14. const [error, setError] = useState('');
  15. const [otp, setOtp] = useState('');
  16. const [canSendOtp, setCanSendOtp] = useState(true);
  17. const [lockPhoneInput, setLockPhoneInput] = useState(false);
  18. const [countdown, setCountdown] = useState(0);
  19. const [loading, setLoading] = useState(false);
  20. const { expoPushToken } = usePushNotifications();
  21. const notify_session_id = expoPushToken?.data || '';
  22. const handleVerification = async () => {
  23. setLoading(true);
  24. if (signUpFormData.phone === '' || otp === '') {
  25. setError('請確保所有資料都已填寫。');
  26. } else {
  27. setError('');
  28. console.log('signUpFormData.phone', signUpFormData.phone);
  29. console.log('otp', otp);
  30. console.log('notifysession id in handleVerification', expoPushToken?.data);
  31. try {
  32. const result = await authenticationService.verifyPhoneOtp(
  33. signUpFormData.phone,
  34. otp,
  35. expoPushToken?.data
  36. );
  37. if (result.status === 200) {
  38. setScreen(2);
  39. } else {
  40. setError('OTP驗證失敗,請重新輸入');
  41. }
  42. } catch (error) {
  43. console.log('error', error);
  44. setError('OTP驗證失敗,請重新輸入');
  45. } finally {
  46. setLoading(false);
  47. }
  48. }
  49. };
  50. useEffect(() => {
  51. let timer: NodeJS.Timeout;
  52. if (countdown > 0) {
  53. timer = setInterval(() => {
  54. setCountdown((prev) => prev - 1);
  55. }, 1000);
  56. } else {
  57. setLockPhoneInput(false); // Add this line to unlock input when countdown reaches 0
  58. }
  59. return () => {
  60. if (timer) clearInterval(timer);
  61. };
  62. }, [countdown]);
  63. const handleSubmitOtp = async () => {
  64. if (signUpFormData.phone) {
  65. if (canSendOtp) {
  66. setCanSendOtp(false);
  67. setLockPhoneInput(true);
  68. setCountdown(60);
  69. try {
  70. await authenticationService.sendOtpToSignUpPhone(signUpFormData.phone);
  71. setError('');
  72. } catch (error) {
  73. console.log(error);
  74. setError('發送OTP失敗,請聯絡工作人員');
  75. setCanSendOtp(true); // Reset canSendOtp if there's an error
  76. setLockPhoneInput(false); // Unlock phone input if there's an error
  77. }
  78. setTimeout(() => {
  79. setCanSendOtp(true);
  80. setLockPhoneInput(false);
  81. }, 60000);
  82. // setError('');
  83. } else {
  84. setError('請等待一分鐘後再重新發送。');
  85. }
  86. } else {
  87. setError('請確保所有資料都已填寫。');
  88. }
  89. };
  90. const handleChangePhoneNumber = () => {
  91. setLockPhoneInput(false);
  92. };
  93. const otpButtonText = lockPhoneInput ? (
  94. <Text style={{ color: '#fff' }}>已發送 ({countdown}s)</Text>
  95. ) : (
  96. <Text style={{ color: '#fff' }}>發送</Text>
  97. );
  98. return (
  99. <>
  100. <View style={styles.container}>
  101. <Text style={styles.text}>請驗證您的手機號碼</Text>
  102. <PhoneInput
  103. value={signUpFormData?.phone || ''}
  104. onChangeText={(phone: any) =>
  105. setSignUpFormData({
  106. ...signUpFormData,
  107. phone: phone
  108. })
  109. }
  110. placeholder="請輸入手機號碼"
  111. editable={!lockPhoneInput}
  112. extendedStyle={{ opacity: !lockPhoneInput ? 1 : 0.5 }}
  113. />
  114. {/* <NormalInput
  115. placeholder="請填寫您的手機號碼"
  116. onChangeText={(phone) =>
  117. setSignUpFormData({
  118. ...signUpFormData,
  119. phone: phone
  120. })
  121. }
  122. editable={!lockPhoneInput}
  123. extendedStyle={{ opacity: !lockPhoneInput ? 1 : 0.5 }}
  124. autoCapitalize="none"
  125. /> */}
  126. <View
  127. style={{
  128. display: 'flex',
  129. flexDirection: 'row',
  130. paddingVertical: 10,
  131. gap: 10
  132. }}
  133. >
  134. <NumberInput placeholder="OTP驗證碼" onChangeText={setOtp} extendedStyle={{ flex: 1 }} />
  135. <NormalButton
  136. title={otpButtonText}
  137. onPress={handleSubmitOtp}
  138. extendedStyle={{ flex: 1 / 2, opacity: !lockPhoneInput ? 1 : 0.5 }}
  139. />
  140. </View>
  141. <NormalButton
  142. title={<Text style={{ color: '#fff' }}>{loading ? '驗證中...' : '驗證'}</Text>}
  143. onPress={() => {
  144. handleVerification();
  145. }}
  146. extendedStyle={{}}
  147. />
  148. {error && <Text style={styles.errorMessage}>{error}</Text>}
  149. {/* <Pressable onPress={handleChangePhoneNumber}>
  150. <Text style={[styles.footer, { opacity: lockPhoneInput ? 1 : 0 }]}>修改手機號碼</Text>
  151. </Pressable> */}
  152. </View>
  153. </>
  154. );
  155. };
  156. const styles = StyleSheet.create({
  157. container: {
  158. flex: 1,
  159. marginHorizontal: 20
  160. },
  161. text: {
  162. fontSize: 20,
  163. paddingBottom: 10
  164. },
  165. errorMessage: {
  166. fontSize: 16,
  167. color: '#ff0033',
  168. fontWeight: '400',
  169. paddingVertical: 10
  170. },
  171. footer: { color: '#02677D', fontSize: 16, paddingVertical: 10 }
  172. });
  173. export default Verification;