You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

LoginScreen.jsx 7.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. import React, { useEffect, useState } from "react";
  2. import { View, Text, TouchableOpacity, StyleSheet } from "react-native";
  3. import MaterialIcons from "@expo/vector-icons/MaterialIcons";
  4. import Ionicons from "@expo/vector-icons/Ionicons";
  5. import LoginSVG from "@assets/images/login.svg";
  6. import GoogleSVG from "@assets/images/google.svg";
  7. import FacebookSVG from "@assets/images/facebook.svg";
  8. import TwitterSVG from "@assets/images/twitter.svg";
  9. import CustomButton from "@components/Buttons/CustomButton";
  10. import InputField from "@components/InputField";
  11. import { globalStyles } from "@styles/global";
  12. import Loader from "@components/Loader";
  13. import { Formik } from "formik";
  14. import { loginSchema } from "@schemas/loginSchema";
  15. import { useDispatch } from "react-redux";
  16. import useAuthHook from "../hooks/useAuthHook";
  17. import Layout from "@components/Layout/Layout";
  18. import { useTheme } from "@styles";
  19. import { useTranslation } from "react-i18next";
  20. import { useLoginMutation } from "@features/auth/authApiSlice";
  21. import { setCredentials } from "@features/auth/authSlice";
  22. import { useAuthProviderMutation } from "@features/auth/authApiSlice";
  23. import { storeData } from "@service/asyncStorage";
  24. import { ACCESS_TOKEN } from "@constants/localStorage";
  25. const LoginScreen = ({ navigation }) => {
  26. const [authProvider, { isLoading: isLoadingProvider }] =
  27. useAuthProviderMutation();
  28. const [currentProvider, setCurrentProvider] = useState("");
  29. const { colors } = useTheme();
  30. const { t } = useTranslation();
  31. const [login, { isLoading, error }] = useLoginMutation();
  32. const { response, promptAsync } = useAuthHook();
  33. const dispatch = useDispatch();
  34. const authProviderHandler = async (response) => {
  35. if (response?.type === "success") {
  36. const accessToken = response.authentication.accessToken;
  37. if (accessToken) {
  38. await storeData(ACCESS_TOKEN, accessToken)
  39. try {
  40. const userResponse = await authProvider({
  41. provider: currentProvider,
  42. accessToken,
  43. }).unwrap();
  44. if (userResponse) {
  45. dispatch(setCredentials(userResponse));
  46. }
  47. } catch (e) {
  48. console.log(e);
  49. }
  50. }
  51. }
  52. };
  53. useEffect(() => {
  54. authProviderHandler(response);
  55. }, [response, currentProvider]);
  56. const handleGoogleAuth = () => {
  57. promptAsync();
  58. };
  59. const handleLogin = async (values) => {
  60. const { email: identifier, password } = values;
  61. try {
  62. const userData = await login({ identifier, password }).unwrap();
  63. dispatch(setCredentials(userData));
  64. } catch (e) {
  65. console.log("Login error", e);
  66. }
  67. };
  68. return (
  69. <Layout>
  70. <Loader visible={isLoading || isLoadingProvider} />
  71. <View style={{ paddingHorizontal: 25 }}>
  72. <View style={{ alignItems: "center" }}>
  73. <LoginSVG height={300} width={300} />
  74. </View>
  75. <Formik
  76. initialValues={{
  77. email: "",
  78. password: "",
  79. }}
  80. validationSchema={loginSchema}
  81. onSubmit={handleLogin}
  82. validateOnChange={false}
  83. validateOnBlur={false}
  84. >
  85. {({
  86. handleChange,
  87. handleBlur,
  88. handleSubmit,
  89. values,
  90. isValid,
  91. errors,
  92. }) => (
  93. <>
  94. <Text
  95. style={[globalStyles.boldText, { color: colors.textPrimary }]}
  96. >
  97. {t("login.signIn")}
  98. </Text>
  99. <InputField
  100. name="email"
  101. label={t("login.email")}
  102. keyboardType="email-address"
  103. onChangeText={handleChange("email")}
  104. text={values.email}
  105. style={{ color: colors.textPrimary }}
  106. handleBlur={handleBlur("email")}
  107. icon={
  108. <MaterialIcons
  109. name="alternate-email"
  110. size={20}
  111. color="#666"
  112. style={{ marginRight: 5 }}
  113. />
  114. }
  115. />
  116. {errors.email && (
  117. <Text style={styles.errorMessage}>{errors.email}</Text>
  118. )}
  119. <InputField
  120. name="password"
  121. label={t("login.password")}
  122. filedButtonLabel={t("register.forgot")}
  123. fieldButtonFunction={() => {}}
  124. inputType="password"
  125. handleBlur={handleBlur("password")}
  126. text={values.password}
  127. onChangeText={handleChange("password")}
  128. icon={
  129. <Ionicons
  130. name="ios-lock-closed-outline"
  131. size={20}
  132. color="#666"
  133. style={{ marginRight: 5 }}
  134. />
  135. }
  136. />
  137. {errors.password && (
  138. <Text style={styles.errorMessage}>{errors.password}</Text>
  139. )}
  140. {error && (
  141. <Text style={styles.errorMessage}>
  142. {error?.data?.error?.message}
  143. </Text>
  144. )}
  145. <CustomButton label={t("login.login")} onPress={handleSubmit} />
  146. </>
  147. )}
  148. </Formik>
  149. <Text
  150. style={[
  151. globalStyles.regularCenteredText,
  152. { color: colors.textPrimary },
  153. ]}
  154. >
  155. {t("login.orLoginWith")}
  156. </Text>
  157. <View style={styles.providersContainer}>
  158. <TouchableOpacity
  159. onPress={() => {
  160. setCurrentProvider("google");
  161. handleGoogleAuth();
  162. }}
  163. style={globalStyles.iconButton}
  164. >
  165. <GoogleSVG height={24} width={24} />
  166. </TouchableOpacity>
  167. <TouchableOpacity onPress={() => {}} style={globalStyles.iconButton}>
  168. <FacebookSVG height={24} width={24} />
  169. </TouchableOpacity>
  170. <TouchableOpacity onPress={() => {}} style={globalStyles.iconButton}>
  171. <TwitterSVG height={24} width={24} />
  172. </TouchableOpacity>
  173. </View>
  174. <View style={styles.registerContainer}>
  175. <Text
  176. style={[globalStyles.regularText, { color: colors.textPrimary }]}
  177. >
  178. {t("login.needAccount")}{" "}
  179. </Text>
  180. <TouchableOpacity onPress={() => navigation.navigate("Register")}>
  181. <Text style={styles.registerButtonText}>{t("login.signUp")}</Text>
  182. </TouchableOpacity>
  183. </View>
  184. </View>
  185. </Layout>
  186. );
  187. };
  188. const styles = StyleSheet.create({
  189. providerText: {
  190. textAlign: "center",
  191. color: "#666",
  192. marginBottom: 30,
  193. fontFamily: "poppins-regular",
  194. },
  195. providersContainer: {
  196. flexDirection: "row",
  197. justifyContent: "space-between",
  198. marginBottom: 30,
  199. },
  200. registerContainer: {
  201. flexDirection: "row",
  202. justifyContent: "center",
  203. marginBottom: 30,
  204. },
  205. registerButtonText: {
  206. color: "#AD40AF",
  207. fontWeight: "700",
  208. fontFamily: "poppins-semibold",
  209. },
  210. errorMessage: {
  211. marginBottom: 30,
  212. color: "red",
  213. },
  214. });
  215. export default LoginScreen;