verification.tsx 6.7 KB

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