loginPage.tsx 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. import { View, Text, Image, StyleSheet, Pressable, Alert, Dimensions, ActivityIndicator } from 'react-native';
  2. import { Ionicons } from '@expo/vector-icons';
  3. import Logo from '../../../global/logo';
  4. import NormalButton from '../../../global/normal_button';
  5. import NormalInput from '../../../global/normal_input';
  6. import { useEffect, useState } from 'react';
  7. import { useAuth } from '../../../../context/AuthProvider';
  8. import { useSafeAreaInsets } from 'react-native-safe-area-context';
  9. import AsyncStorage from '@react-native-async-storage/async-storage';
  10. import Checkbox from 'expo-checkbox';
  11. type LoginPageProps = {
  12. goToNextPage: () => void;
  13. goToForgetPassWordPage: () => void;
  14. goToBindingPhoneNumberPage: () => void;
  15. };
  16. const screenHeight = Dimensions.get('window').height;
  17. const LoginPage: React.FC<LoginPageProps> = ({ goToNextPage, goToForgetPassWordPage, goToBindingPhoneNumberPage }) => {
  18. const [loginEmail, setLoginEmail] = useState('');
  19. const [loginPassword, setLoginPassword] = useState('');
  20. const [saveAccount, setSaveAccount] = useState(false);
  21. const [isLoading, setIsLoading] = useState(false);
  22. const { login } = useAuth();
  23. const [isChecked, setChecked] = useState(false);
  24. const [showPassword, setShowPassword] = useState(false);
  25. useEffect(() => {
  26. loadSavedCredentials();
  27. }, []);
  28. const loadSavedCredentials = async () => {
  29. try {
  30. const savedEmail = await AsyncStorage.getItem('savedEmail');
  31. const savedPassword = await AsyncStorage.getItem('savedPassword');
  32. if (savedEmail && savedPassword) {
  33. setLoginEmail(savedEmail);
  34. setLoginPassword(savedPassword);
  35. setSaveAccount(true);
  36. setChecked(true);
  37. }
  38. } catch (error) {
  39. console.error('Error loading saved credentials:', error);
  40. }
  41. };
  42. // const _login = async (username: string, password: string) => {
  43. // setIsLoading(true);
  44. // if (username === '' || password === '') {
  45. // Alert.alert('請輸入資料', '請輸入電子郵件和密碼');
  46. // } else {
  47. // const lowerCaseUsername = username.toLowerCase();
  48. // const success = await login(lowerCaseUsername, password);
  49. // if (!success) {
  50. // Alert.alert('登入失敗', '請檢查您的電子郵件和密碼');
  51. // }
  52. // }
  53. // setIsLoading(false);
  54. // };
  55. const _login = async (username: string, password: string) => {
  56. setIsLoading(true);
  57. if (username === '' || password === '') {
  58. Alert.alert('請輸入資料', '請輸入電子郵件和密碼');
  59. } else {
  60. // const lowerCaseUsername = username.toLowerCase();
  61. const success = await login(username, password);
  62. if (success) {
  63. if (saveAccount) {
  64. await AsyncStorage.setItem('savedEmail', username);
  65. await AsyncStorage.setItem('savedPassword', password);
  66. } else {
  67. await AsyncStorage.removeItem('savedEmail');
  68. await AsyncStorage.removeItem('savedPassword');
  69. }
  70. } else {
  71. Alert.alert('登入失敗', '請檢查您的電子郵件和密碼');
  72. }
  73. }
  74. setIsLoading(false);
  75. };
  76. const insets = useSafeAreaInsets();
  77. return (
  78. <View className={`flex-1 justify-center ${screenHeight < 750 ? 'h-screen' : 'h-[80vh] space-y-8'}`}>
  79. <View className="flex-3 items-center justify-end" style={{}}>
  80. <Image
  81. source={require('../../../../assets/ccLogo.png')}
  82. resizeMode="contain"
  83. style={{
  84. width: screenHeight > 750 ? 250 : 200,
  85. height: screenHeight > 750 ? 250 : 200
  86. }}
  87. />
  88. </View>
  89. <View
  90. style={{
  91. gap: 10
  92. // paddingBottom: Math.max(insets.bottom, 20)
  93. // marginTop: screenHeight > 750 ? 40 : 0
  94. }}
  95. className="mx-[5%] flex-2 "
  96. >
  97. <NormalInput
  98. placeholder="電子郵件"
  99. value={loginEmail}
  100. onChangeText={(email) => setLoginEmail(email)}
  101. extendedStyle={{ borderRadius: 12, padding: 20 }}
  102. textContentType="username"
  103. autoComplete="username"
  104. keyboardType="email-address"
  105. autoCapitalize="none"
  106. />
  107. <View className="relative">
  108. <NormalInput
  109. value={loginPassword}
  110. placeholder="密碼"
  111. onChangeText={(password) => setLoginPassword(password)}
  112. secureTextEntry={!showPassword}
  113. extendedStyle={{ borderRadius: 12, padding: 20, paddingRight: 50 }}
  114. textContentType="password"
  115. autoComplete="password"
  116. />
  117. <Pressable
  118. className="absolute right-4 top-0 bottom-0 justify-center"
  119. onPress={() => setShowPassword(!showPassword)}
  120. >
  121. <Ionicons name={showPassword ? 'eye-outline' : 'eye-off-outline'} size={24} color="#02677D" />
  122. </Pressable>
  123. </View>
  124. <View className="flex flex-row items-center ">
  125. <Checkbox
  126. style={styles.checkbox}
  127. value={saveAccount}
  128. color={saveAccount ? '#02677D' : '#02677D'}
  129. onValueChange={(newValue) => {
  130. setSaveAccount(newValue);
  131. console.log(newValue);
  132. }}
  133. />
  134. <Text style={styles.text}>記住我的帳號</Text>
  135. </View>
  136. <NormalButton
  137. extendedStyle={{ padding: 20 }}
  138. onPress={() => _login(loginEmail, loginPassword)}
  139. title={
  140. isLoading ? (
  141. <Text
  142. style={{
  143. fontWeight: '700',
  144. fontSize: 20,
  145. color: '#fff'
  146. }}
  147. >
  148. <ActivityIndicator />
  149. </Text>
  150. ) : (
  151. <Text
  152. style={{
  153. fontWeight: '700',
  154. fontSize: 20,
  155. color: '#fff'
  156. }}
  157. >
  158. 登入
  159. </Text>
  160. )
  161. }
  162. />
  163. <View className="flex flex-row justify-between relative">
  164. <Pressable className="self-start" onPress={goToNextPage}>
  165. <Text style={styles.text}>註冊會員</Text>
  166. </Pressable>
  167. <Pressable className="self-start" onPress={() => goToForgetPassWordPage()}>
  168. <Text style={styles.text}>忘記密碼</Text>
  169. </Pressable>
  170. <View className="flex flex-row justify-center absolute top-16 left-0 right-0 items-center">
  171. <View className="flex-1 h-[1px] bg-[#888888] mx-2" />
  172. <Pressable onPress={goToBindingPhoneNumberPage}>
  173. <Text className="text-[#888888] text-lg">舊用戶/已有用戶/手機號碼綁定</Text>
  174. </Pressable>
  175. <View className="flex-1 h-[1px] bg-[#888888] mx-2" />
  176. </View>
  177. </View>
  178. </View>
  179. </View>
  180. );
  181. };
  182. const styles = StyleSheet.create({
  183. container: {
  184. flex: 1,
  185. height: Dimensions.get('window').height,
  186. justifyContent: 'center',
  187. marginHorizontal: 20
  188. },
  189. topContainerForLogo: {},
  190. checkbox: {
  191. margin: 8
  192. },
  193. text: {
  194. color: '#02677D',
  195. fontSize: 16,
  196. paddingVertical: 5
  197. }
  198. });
  199. export default LoginPage;