bindingPhoneNumberPageStepTwo.tsx 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381
  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. const BindingPhoneNumberPageStepTwo = ({ bindingFormData, setBindingFormData, setScreen }: any) => {
  12. const [authError, setAuthError] = useState('');
  13. const [error, setError] = useState('');
  14. const [canSendOtp, setCanSendOtp] = useState(true);
  15. const [lockEmailInput, setLockEmailInput] = useState(false);
  16. const [data, setData] = useState('');
  17. const [isLoading, setIsLoading] = useState(false);
  18. const [isLoading2, setIsLoading2] = useState(false);
  19. const [countdown, setCountdown] = useState(0);
  20. const { expoPushToken } = usePushNotifications();
  21. useEffect(() => {
  22. let timer: NodeJS.Timeout;
  23. if (countdown > 0) {
  24. timer = setInterval(() => {
  25. setCountdown((prev) => prev - 1);
  26. }, 1000);
  27. } else {
  28. setLockEmailInput(false); // Add this line to unlock input when countdown reaches 0
  29. }
  30. return () => {
  31. if (timer) clearInterval(timer);
  32. };
  33. }, [countdown]);
  34. // const handleVerification = async () => {
  35. // setIsLoading(true);
  36. // if (!forgetPasswordFormData.otp && !forgetPasswordFormData.email) {
  37. // setAuthError('請確保所有資料都已填寫');
  38. // } else if (!forgetPasswordFormData.otp) {
  39. // setAuthError('請輸入OTP驗證碼');
  40. // } else {
  41. // setAuthError('');
  42. // try {
  43. // const result =
  44. // await authenticationService.verifyingOtpForgetPassword(
  45. // forgetPasswordFormData.email.toLowerCase(),
  46. // forgetPasswordFormData.otp,
  47. // setForgetPasswordFormData,
  48. // setData
  49. // );
  50. // if (result === false) {
  51. // setAuthError('驗證OTP時發生錯誤,請稍後再試');
  52. // }
  53. // } catch (error) {
  54. // console.error('Error verifying OTP:', error);
  55. // setAuthError('驗證OTP時發生錯誤,請稍後再試');
  56. // }
  57. // }
  58. // setIsLoading(false);
  59. // };
  60. // const handleFormDataChange: HandleForgetPasswordFormDataChange = (
  61. // field,
  62. // value
  63. // ) => {
  64. // setForgetPasswordFormData((prevFormData) => ({
  65. // ...prevFormData,
  66. // [field]: value
  67. // }));
  68. // };
  69. // const handleSubmitOtp = () => {
  70. // if (forgetPasswordFormData.email) {
  71. // if (canSendOtp) {
  72. // const lowerCaseEmail =
  73. // forgetPasswordFormData.email.toLowerCase();
  74. // setCanSendOtp(false);
  75. // setLockEmailInput(true);
  76. // authenticationService.sendForgetPasswordOtp(lowerCaseEmail);
  77. // //can only request otp every 60 seconds
  78. // setTimeout(() => {
  79. // setCanSendOtp(true);
  80. // setLockEmailInput(false);
  81. // }, 60000);
  82. // setAuthError('');
  83. // } else {
  84. // setAuthError('請等待一分鐘後再重新發送。');
  85. // }
  86. // } else {
  87. // setAuthError('請確保所有資料都已填寫。');
  88. // }
  89. // };
  90. // const handleFinishResetPassword = async () => {
  91. // if (
  92. // forgetPasswordFormData.newPassword !==
  93. // forgetPasswordFormData.confirmedNewPassword
  94. // ) {
  95. // setError('請確保新密碼和確認密碼相同');
  96. // } else {
  97. // setError('');
  98. // setIsLoading2(true);
  99. // try {
  100. // const success = await authenticationService.changePassword(
  101. // forgetPasswordFormData.confirmedNewPassword,
  102. // data
  103. // );
  104. // if (success) {
  105. // setScreen(1);
  106. // } else {
  107. // setError('密碼重置失敗,請稍後再試');
  108. // }
  109. // } catch (error) {
  110. // console.error('Error changing password:', error);
  111. // setError('發生錯誤,請稍後再試');
  112. // } finally {
  113. // setIsLoading2(false);
  114. // }
  115. // }
  116. // };
  117. const handleConfirmBindingPhone = async () => {
  118. setIsLoading2(true);
  119. try {
  120. const result = await authenticationService.confirmBindingPhone(
  121. bindingFormData.phoneNumber,
  122. bindingFormData.otp,
  123. expoPushToken?.data ||
  124. `ExponentPushToken[TestToken${Math.random().toString(36).substring(2, 8).toUpperCase()}]`
  125. );
  126. if (result.status == 200) {
  127. setScreen(2);
  128. } else {
  129. setError('綁定手機號碼失敗,請檢查您輸入的OTP並再試一次');
  130. }
  131. } catch (error) {
  132. Alert.alert('綁定手機號碼失敗,請檢查您輸入的OTP並再試一次');
  133. } finally {
  134. setIsLoading2(false);
  135. }
  136. };
  137. const handleRequestOtp = async () => {
  138. try {
  139. //this check if phone same,
  140. const checkPhoneSame = await authenticationService.checkPhoneSame(bindingFormData.phoneNumber);
  141. console.log('checkPhoneSame', checkPhoneSame);
  142. if (checkPhoneSame?.status == 422) {
  143. //this means phone not same
  144. Alert.alert('確認您的手機號碼', '您以後將使用現在輸入的號碼進行登入。請按下確認表示您已知悉。', [
  145. {
  146. text: '確認並發出驗證碼',
  147. onPress: async () => {
  148. try {
  149. const token = await SecureStore.getItemAsync('accessToken');
  150. const changePhoneResult = await authenticationService.changePhone(
  151. bindingFormData.phoneNumber,
  152. token
  153. );
  154. if (changePhoneResult == true) {
  155. //this means change phone success
  156. try {
  157. const requestOtp = await authenticationService.checkPhoneSame(
  158. bindingFormData.phoneNumber
  159. );
  160. if (requestOtp.status == 200) {
  161. //this means request otp success
  162. setLockEmailInput(true);
  163. setCountdown(60);
  164. } else {
  165. setError('發送OTP失敗,請聯絡工作人員');
  166. }
  167. } catch (error) {
  168. console.log(error);
  169. }
  170. } else {
  171. //this means change phone failed
  172. Alert.alert('修改手機號碼失敗,請稍後再試');
  173. }
  174. } catch (error) {
  175. console.log(error);
  176. }
  177. }
  178. }
  179. ]);
  180. } else {
  181. //this means phone same
  182. if (checkPhoneSame?.status == 200) {
  183. //this means request otp success
  184. setLockEmailInput(true);
  185. setCountdown(60); // Start 60 second countdown
  186. } else {
  187. setError('發送OTP失敗,請稍後再試');
  188. }
  189. }
  190. } catch (error) {
  191. console.log(error);
  192. }
  193. };
  194. return (
  195. <>
  196. <View style={styles.container}>
  197. <View style={styles.bottomContainer}>
  198. <Text style={styles.text}>請輸入手機號碼,此手機號碼將用作登入用途</Text>
  199. <PhoneInput
  200. value={bindingFormData?.phoneNumber || ''}
  201. onChangeText={(phoneNumber) => {
  202. setBindingFormData({
  203. ...bindingFormData,
  204. phoneNumber: phoneNumber
  205. });
  206. }}
  207. placeholder="請輸入手機號碼"
  208. editable={!lockEmailInput}
  209. extendedStyle={{ opacity: !lockEmailInput ? 1 : 0.5 }}
  210. />
  211. {/* <NormalInput
  212. placeholder="請輸入手機號碼"
  213. onChangeText={(phoneNumber) =>
  214. setBindingFormData({
  215. ...bindingFormData,
  216. phoneNumber: phoneNumber
  217. })
  218. }
  219. // editable={!lockEmailInput}
  220. // extendedStyle={{ opacity: !lockEmailInput ? 1 : 0.5 }}
  221. /> */}
  222. <View
  223. style={{
  224. display: 'flex',
  225. flexDirection: 'row',
  226. paddingVertical: 10,
  227. gap: 10
  228. }}
  229. >
  230. <NumberInput
  231. placeholder="OTP驗證碼"
  232. onChangeText={(t) => setBindingFormData({ ...bindingFormData, otp: t })}
  233. // editable={!forgetPasswordFormData.otpAuthCompleted}
  234. extendedStyle={{
  235. flex: 1
  236. // opacity: !forgetPasswordFormData.otpAuthCompleted ? 1 : 0.5
  237. }}
  238. />
  239. <NormalButton
  240. title={
  241. <Text style={{ color: '#fff' }}>
  242. {lockEmailInput ? `已發送 (${countdown}s)` : '發送'}
  243. </Text>
  244. }
  245. onPress={handleRequestOtp}
  246. extendedStyle={{ flex: 1 / 2, opacity: lockEmailInput ? 0.5 : 1 }}
  247. disabled={lockEmailInput}
  248. />
  249. </View>
  250. <NormalButton
  251. title={<Text style={{ color: '#fff' }}>{isLoading2 ? '處理中...' : '確認'}</Text>}
  252. onPress={handleConfirmBindingPhone}
  253. // extendedStyle={
  254. // forgetPasswordFormData.otpAuthCompleted == true ? { backgroundColor: '#70787C' } : {}
  255. // }
  256. />
  257. {/* {lockEmailInput && (
  258. <Pressable
  259. // disabled={forgetPasswordFormData.otpAuthCompleted}
  260. onPress={() => setLockEmailInput(false)}
  261. >
  262. <Text
  263. style={[
  264. styles.footer
  265. // forgetPasswordFormData.otpAuthCompleted && {
  266. // opacity: 0.5
  267. // }
  268. ]}
  269. >
  270. 重新整理
  271. </Text>
  272. </Pressable>
  273. )} */}
  274. {/* {authError && <Text style={styles.errorMessage}>{authError}</Text>}
  275. {lockEmailInput && (
  276. <Pressable
  277. disabled={forgetPasswordFormData.otpAuthCompleted}
  278. onPress={() => setLockEmailInput(false)}
  279. >
  280. <Text
  281. style={[
  282. styles.footer,
  283. forgetPasswordFormData.otpAuthCompleted && {
  284. opacity: 0.5
  285. }
  286. ]}
  287. >
  288. 修改電子郵件
  289. </Text>
  290. </Pressable>
  291. )}
  292. {forgetPasswordFormData.otpAuthCompleted && (
  293. <View
  294. style={[
  295. styles.hiddenPasswordFields,
  296. forgetPasswordFormData.otpAuthCompleted ? styles.opacityFull : styles.opacityZero
  297. ]}
  298. >
  299. <NormalInput
  300. placeholder="新密碼"
  301. onChangeText={(t) => handleFormDataChange('newPassword', t)}
  302. secureTextEntry={true}
  303. textContentType={'oneTimeCode'}
  304. />
  305. <NormalInput
  306. placeholder="確認密碼"
  307. onChangeText={(t) => handleFormDataChange('confirmedNewPassword', t)}
  308. secureTextEntry={true}
  309. textContentType={'oneTimeCode'}
  310. />
  311. <NormalButton
  312. title={<Text style={{ color: '#fff' }}>{isLoading ? '重置中...' : '重置'}</Text>}
  313. onPress={handleFinishResetPassword}
  314. extendedStyle={{}}
  315. />
  316. </View>
  317. )} */}
  318. {error && <Text style={styles.errorMessage}>{error}</Text>}
  319. </View>
  320. </View>
  321. </>
  322. );
  323. };
  324. const styles = StyleSheet.create({
  325. container: {
  326. flex: 1,
  327. marginHorizontal: 20
  328. },
  329. titleText: {
  330. fontSize: 24,
  331. fontWeight: '300'
  332. },
  333. bottomContainer: {
  334. flex: 3,
  335. paddingBottom: 100
  336. },
  337. breakline: {
  338. width: 24,
  339. height: 1,
  340. backgroundColor: '#000000',
  341. marginVertical: 17
  342. },
  343. text: {
  344. fontSize: 18,
  345. paddingBottom: 10
  346. },
  347. hiddenPasswordFields: {
  348. gap: 10,
  349. paddingTop: 10
  350. },
  351. opacityZero: {
  352. opacity: 0
  353. },
  354. opacityFull: {
  355. opacity: 1
  356. },
  357. errorMessage: {
  358. fontSize: 14,
  359. color: '#ff0033',
  360. fontWeight: '400',
  361. marginLeft: 10,
  362. marginTop: 10
  363. },
  364. footer: { color: '#02677D', fontSize: 16, paddingVertical: 10 }
  365. });
  366. export default BindingPhoneNumberPageStepTwo;