bindingPhoneNumberPageStepTwo.tsx 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. import { View, Text, StyleSheet, Pressable, Alert } from 'react-native';
  2. import { useEffect, useState } from 'react';
  3. import { forgetPasswordFormData, HandleForgetPasswordFormDataChange } from '../../../../types/signup';
  4. import NumberInput from '../../../global/number_input';
  5. import NormalButton from '../../../global/normal_button';
  6. import NormalInput from '../../../global/normal_input';
  7. import { authenticationService } from '../../../../service/authService';
  8. import PhoneInput from '../../../global/phone_input';
  9. import * as SecureStore from 'expo-secure-store';
  10. import { usePushNotifications } from '../../../../app/hooks/usePushNotifications';
  11. import { useTranslation } from '../../../../util/hooks/useTranslation';
  12. const BindingPhoneNumberPageStepTwo = ({ bindingFormData, setBindingFormData, setScreen }: any) => {
  13. const { t } = useTranslation(); // 使用翻译钩子
  14. const [error, setError] = useState('');
  15. const [lockEmailInput, setLockEmailInput] = useState(false);
  16. const [isLoading2, setIsLoading2] = useState(false);
  17. const [countdown, setCountdown] = useState(0);
  18. const { expoPushToken } = usePushNotifications();
  19. useEffect(() => {
  20. let timer: NodeJS.Timeout;
  21. if (countdown > 0) {
  22. timer = setInterval(() => {
  23. setCountdown((prev) => prev - 1);
  24. }, 1000);
  25. } else {
  26. setLockEmailInput(false); // Add this line to unlock input when countdown reaches 0
  27. }
  28. return () => {
  29. if (timer) clearInterval(timer);
  30. };
  31. }, [countdown]);
  32. const handleConfirmBindingPhone = async () => {
  33. setIsLoading2(true);
  34. try {
  35. const result = await authenticationService.confirmBindingPhone(
  36. bindingFormData.phoneNumber,
  37. bindingFormData.otp,
  38. expoPushToken?.data ||
  39. `ExponentPushToken[TestToken${Math.random().toString(36).substring(2, 8).toUpperCase()}]`
  40. );
  41. if (result.status == 200) {
  42. setScreen(2);
  43. } else {
  44. setError(t('binding.two.phone_binding_failed'));
  45. }
  46. } catch (error) {
  47. Alert.alert(t('binding.two.phone_binding_failed'));
  48. } finally {
  49. setIsLoading2(false);
  50. }
  51. };
  52. const handleRequestOtp = async () => {
  53. try {
  54. //this check if phone same,
  55. const checkPhoneSame = await authenticationService.checkPhoneSame(bindingFormData.phoneNumber);
  56. if (checkPhoneSame?.status == 422) {
  57. //this means phone not same
  58. Alert.alert(t('binding.two.confirm_phone_number'), t('binding.two.phone_usage_notice'), [
  59. {
  60. text: t('binding.two.confirm_and_send_otp'),
  61. onPress: async () => {
  62. try {
  63. const token = await SecureStore.getItemAsync('accessToken');
  64. const changePhoneResult = await authenticationService.changePhone(
  65. bindingFormData.phoneNumber,
  66. token
  67. );
  68. if (changePhoneResult == true) {
  69. //this means change phone success
  70. try {
  71. const requestOtp = await authenticationService.checkPhoneSame(
  72. bindingFormData.phoneNumber
  73. );
  74. if (requestOtp.status == 200) {
  75. //this means request otp success
  76. setLockEmailInput(true);
  77. setCountdown(60);
  78. } else {
  79. setError(t('binding.two.send_otp_failed'));
  80. }
  81. } catch (error) {}
  82. } else {
  83. //this means change phone failed
  84. Alert.alert(t('binding.two.change_phone_failed'));
  85. }
  86. } catch (error) {}
  87. }
  88. }
  89. ]);
  90. } else {
  91. //this means phone same
  92. if (checkPhoneSame?.status == 200) {
  93. //this means request otp success
  94. setLockEmailInput(true);
  95. setCountdown(60); // Start 60 second countdown
  96. } else {
  97. setError(t('binding.two.send_otp_failed'));
  98. }
  99. }
  100. } catch (error) {}
  101. };
  102. return (
  103. <>
  104. <View style={styles.container}>
  105. <View style={styles.bottomContainer}>
  106. <Text style={styles.text}>{t('binding.two.enter_phone_for_login')}</Text>
  107. <PhoneInput
  108. value={bindingFormData?.phoneNumber || ''}
  109. onChangeText={(phoneNumber) => {
  110. setBindingFormData({
  111. ...bindingFormData,
  112. phoneNumber: phoneNumber
  113. });
  114. }}
  115. placeholder={t('binding.two.enter_phone_number')}
  116. editable={!lockEmailInput}
  117. extendedStyle={{ opacity: !lockEmailInput ? 1 : 0.5 }}
  118. />
  119. <View
  120. style={{
  121. display: 'flex',
  122. flexDirection: 'row',
  123. paddingVertical: 10,
  124. gap: 10
  125. }}
  126. >
  127. <NumberInput
  128. placeholder={t('binding.two.otp_verification_code')}
  129. onChangeText={(t) => setBindingFormData({ ...bindingFormData, otp: t })}
  130. extendedStyle={{
  131. flex: 1
  132. }}
  133. />
  134. <NormalButton
  135. title={
  136. <Text style={{ color: '#fff' }}>
  137. {lockEmailInput ? `${t('binding.two.sent')} (${countdown}s)` : t('binding.two.send')}
  138. </Text>
  139. }
  140. onPress={handleRequestOtp}
  141. extendedStyle={{ flex: 1 / 2, opacity: lockEmailInput ? 0.5 : 1 }}
  142. disabled={lockEmailInput}
  143. />
  144. </View>
  145. <NormalButton
  146. title={<Text style={{ color: '#fff' }}>{isLoading2 ? t('binding.two.processing') : t('binding.two.confirm')}</Text>}
  147. onPress={handleConfirmBindingPhone}
  148. />
  149. {error && <Text style={styles.errorMessage}>{error}</Text>}
  150. </View>
  151. </View>
  152. </>
  153. );
  154. };
  155. const styles = StyleSheet.create({
  156. container: {
  157. flex: 1,
  158. marginHorizontal: 20
  159. },
  160. titleText: {
  161. fontSize: 24,
  162. fontWeight: '300'
  163. },
  164. bottomContainer: {
  165. flex: 3,
  166. paddingBottom: 100
  167. },
  168. breakline: {
  169. width: 24,
  170. height: 1,
  171. backgroundColor: '#000000',
  172. marginVertical: 17
  173. },
  174. text: {
  175. fontSize: 18,
  176. paddingBottom: 10
  177. },
  178. hiddenPasswordFields: {
  179. gap: 10,
  180. paddingTop: 10
  181. },
  182. opacityZero: {
  183. opacity: 0
  184. },
  185. opacityFull: {
  186. opacity: 1
  187. },
  188. errorMessage: {
  189. fontSize: 14,
  190. color: '#ff0033',
  191. fontWeight: '400',
  192. marginLeft: 10,
  193. marginTop: 10
  194. },
  195. footer: { color: '#02677D', fontSize: 16, paddingVertical: 10 }
  196. });
  197. export default BindingPhoneNumberPageStepTwo;