changePasswordPageComponent.tsx 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. import { View, Text, ScrollView, StyleSheet, Pressable } from 'react-native';
  2. import { useContext, useEffect, useState } from 'react';
  3. import { SafeAreaView } from 'react-native-safe-area-context';
  4. import { router } from 'expo-router';
  5. import { CrossLogoSvg } from '../global/SVG';
  6. import { AuthContext } from '../../context/AuthProvider';
  7. import NormalInput from '../global/normal_input';
  8. import NormalButton from '../global/normal_button';
  9. import * as SecureStore from 'expo-secure-store';
  10. import { authenticationService } from '../../service/authService';
  11. const changePasswordPageComponent = () => {
  12. const { user, setUser } = useContext(AuthContext);
  13. const [token, setToken] = useState<string | null>(null);
  14. const [currentPassword, setCurrentPassword] = useState<string | null>(null);
  15. const [newPassword, setNewPassword] = useState<string | null>(null);
  16. const [newConfirmPassword, setNewConfirmPassword] = useState<string | null>(
  17. null
  18. );
  19. const [isPasswordVerified, setIsPasswordVerified] =
  20. useState<boolean>(false);
  21. const [error, setError] = useState<string | null>(null);
  22. const [isLoading, setIsLoading] = useState(false);
  23. const [isLoading2, setIsLoading2] = useState(false);
  24. useEffect(() => {
  25. const getToken = async () => {
  26. const storedToken = await SecureStore.getItemAsync('accessToken');
  27. setToken(storedToken);
  28. };
  29. getToken();
  30. }, []);
  31. const handleVerifyPassword = async (currentPassword: string) => {
  32. try {
  33. setIsLoading(true);
  34. if (!currentPassword) {
  35. setError('請輸入密碼');
  36. return;
  37. }
  38. if (!user || !user.email) {
  39. setError('無法驗證用戶,請重新登錄');
  40. return;
  41. }
  42. const success = await authenticationService.login(
  43. user.email,
  44. currentPassword
  45. );
  46. if (success) {
  47. setIsPasswordVerified(true);
  48. setError('');
  49. return true;
  50. } else {
  51. setError('密碼錯誤,請稍後再試');
  52. }
  53. } catch (error) {
  54. console.error('Error verifying password:', error);
  55. setError('密碼錯誤,請稍後再試');
  56. return false;
  57. } finally {
  58. setIsLoading(false);
  59. }
  60. };
  61. const handlePasswordChange = async () => {
  62. try {
  63. setIsLoading2(true);
  64. if (newPassword !== newConfirmPassword) {
  65. setError('新密碼不相符');
  66. return;
  67. }
  68. if (!newConfirmPassword || !token) {
  69. setError('請輸入新密碼');
  70. return;
  71. }
  72. const success = await authenticationService.changePassword(
  73. newConfirmPassword,
  74. token
  75. );
  76. if (success) {
  77. setError('');
  78. console.log('change password success');
  79. router.replace('accountMainPage');
  80. } else {
  81. setError('密碼更改失敗,請稍後再試');
  82. }
  83. } catch (error) {
  84. console.error('Error changing password:', error);
  85. setError('發生錯誤,請稍後再試');
  86. } finally {
  87. setIsLoading2(false);
  88. }
  89. };
  90. return (
  91. <SafeAreaView
  92. className="flex-1 bg-white"
  93. edges={['top', 'right', 'left']}
  94. >
  95. <ScrollView
  96. className="flex-1 mx-[5%]"
  97. showsVerticalScrollIndicator={false}
  98. >
  99. <View style={{ marginTop: 25 }}>
  100. <Pressable
  101. onPress={() => {
  102. if (router.canGoBack()) {
  103. router.back();
  104. } else {
  105. router.replace('/accountMainPage');
  106. }
  107. }}
  108. >
  109. <CrossLogoSvg />
  110. </Pressable>
  111. <Text style={{ fontSize: 45, marginVertical: 25 }}>
  112. 更改密碼
  113. </Text>
  114. <Text className="text-xl ">請輸入您現時的帳戶密碼</Text>
  115. <View className="py-2">
  116. <NormalInput
  117. placeholder="帳戶密碼"
  118. onChangeText={(t) => setCurrentPassword(t)}
  119. secureTextEntry={true}
  120. editable={!isPasswordVerified}
  121. />
  122. </View>
  123. <NormalButton
  124. title={
  125. <Text style={{ color: '#fff' }}>
  126. {isLoading
  127. ? '驗證中...'
  128. : isPasswordVerified
  129. ? '已驗證'
  130. : '下一步'}
  131. </Text>
  132. }
  133. onPress={() => {
  134. if (currentPassword) {
  135. handleVerifyPassword(currentPassword);
  136. }
  137. }}
  138. disabled={isPasswordVerified}
  139. extendedStyle={
  140. isPasswordVerified == true
  141. ? { backgroundColor: '#70787C' }
  142. : {}
  143. }
  144. />
  145. </View>
  146. {isPasswordVerified && (
  147. <View
  148. style={[
  149. styles.hiddenPasswordFields,
  150. isPasswordVerified
  151. ? styles.opacityFull
  152. : styles.opacityZero
  153. ]}
  154. >
  155. <NormalInput
  156. placeholder="新密碼"
  157. onChangeText={(t) => setNewPassword(t)}
  158. secureTextEntry={true}
  159. textContentType={'oneTimeCode'}
  160. />
  161. <NormalInput
  162. placeholder="確認密碼"
  163. onChangeText={(t) => setNewConfirmPassword(t)}
  164. secureTextEntry={true}
  165. textContentType={'oneTimeCode'}
  166. />
  167. <NormalButton
  168. title={
  169. <Text style={{ color: '#fff' }}>
  170. {isLoading2 ? '更改中...' : '確認'}
  171. </Text>
  172. }
  173. onPress={handlePasswordChange}
  174. />
  175. </View>
  176. )}
  177. {error && <Text style={styles.errorMessage}>{error}</Text>}
  178. </ScrollView>
  179. </SafeAreaView>
  180. );
  181. };
  182. const styles = StyleSheet.create({
  183. container: {
  184. flex: 1,
  185. marginHorizontal: 20
  186. },
  187. titleText: {
  188. fontSize: 24,
  189. fontWeight: '300'
  190. },
  191. bottomContainer: {
  192. flex: 3,
  193. paddingBottom: 100
  194. },
  195. breakline: {
  196. width: 24,
  197. height: 1,
  198. backgroundColor: '#000000',
  199. marginVertical: 17
  200. },
  201. text: {
  202. fontSize: 18,
  203. paddingBottom: 10
  204. },
  205. hiddenPasswordFields: {
  206. gap: 10,
  207. paddingTop: 10
  208. },
  209. opacityZero: {
  210. opacity: 0
  211. },
  212. opacityFull: {
  213. opacity: 1
  214. },
  215. errorMessage: {
  216. fontSize: 14,
  217. color: '#ff0033',
  218. fontWeight: '400',
  219. marginLeft: 10,
  220. marginTop: 10
  221. },
  222. footer: { color: '#02677D', fontSize: 16, paddingVertical: 10 }
  223. });
  224. export default changePasswordPageComponent;
  225. // <NormalButton
  226. // title={<Text className="text-white text-lg">確認</Text>}
  227. // onPress={() => {
  228. // // poSSIBLY ADD ERROR HANDLING AND LOADING
  229. // // authenticationService.changePassword(password, token);
  230. // router.replace('accountMainPage');
  231. // }}
  232. // />