Application Android et IOS pour l'amicale des élèves https://play.google.com/store/apps/details?id=fr.amicaleinsat.application
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.tsx 5.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. /*
  2. * Copyright (c) 2019 - 2020 Arnaud Vergnet.
  3. *
  4. * This file is part of Campus INSAT.
  5. *
  6. * Campus INSAT is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * Campus INSAT is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with Campus INSAT. If not, see <https://www.gnu.org/licenses/>.
  18. */
  19. import React, { useCallback, useState } from 'react';
  20. import { KeyboardAvoidingView, View } from 'react-native';
  21. import i18n from 'i18n-js';
  22. import { StackNavigationProp, StackScreenProps } from '@react-navigation/stack';
  23. import LinearGradient from 'react-native-linear-gradient';
  24. import ErrorDialog from '../../components/Dialogs/ErrorDialog';
  25. import { MASCOT_STYLE } from '../../components/Mascot/Mascot';
  26. import MascotPopup from '../../components/Mascot/MascotPopup';
  27. import CollapsibleScrollView from '../../components/Collapsible/CollapsibleScrollView';
  28. import { MainStackParamsList } from '../../navigation/MainNavigator';
  29. import GENERAL_STYLES from '../../constants/Styles';
  30. import Urls from '../../constants/Urls';
  31. import { ApiRejectType, connectToAmicale } from '../../utils/WebData';
  32. import { REQUEST_STATUS } from '../../utils/Requests';
  33. import LoginForm from '../../components/Amicale/Login/LoginForm';
  34. import { useFocusEffect, useNavigation } from '@react-navigation/native';
  35. import { TabRoutes } from '../../navigation/TabNavigator';
  36. import { useShouldShowMascot } from '../../context/preferencesContext';
  37. import { useLogin } from '../../context/loginContext';
  38. type Props = StackScreenProps<MainStackParamsList, 'login'>;
  39. function LoginScreen(props: Props) {
  40. const navigation = useNavigation<StackNavigationProp<any>>();
  41. const { setLogin } = useLogin();
  42. const [loading, setLoading] = useState(false);
  43. const [nextScreen, setNextScreen] = useState<string | undefined>(undefined);
  44. const [mascotDialogVisible, setMascotDialogVisible] =
  45. useState<undefined | boolean>(undefined);
  46. const [currentError, setCurrentError] = useState<ApiRejectType>({
  47. status: REQUEST_STATUS.SUCCESS,
  48. });
  49. const homeMascot = useShouldShowMascot(TabRoutes.Home);
  50. useFocusEffect(
  51. useCallback(() => {
  52. setNextScreen(props.route.params?.nextScreen);
  53. }, [props.route.params])
  54. );
  55. const onResetPasswordClick = () => {
  56. navigation.navigate('website', {
  57. host: Urls.websites.amicale,
  58. path: Urls.amicale.resetPassword,
  59. title: i18n.t('screens.websites.amicale'),
  60. });
  61. };
  62. /**
  63. * Called when the user clicks on login or finishes to type his password.
  64. *
  65. * Checks if we should allow the user to login,
  66. * then makes the login request and enters a loading state until the request finishes
  67. *
  68. */
  69. const onSubmit = (email: string, password: string) => {
  70. setLoading(true);
  71. connectToAmicale(email, password)
  72. .then(handleSuccess)
  73. .catch(setCurrentError)
  74. .finally(() => setLoading(false));
  75. };
  76. const hideMascotDialog = () => setMascotDialogVisible(false);
  77. const showMascotDialog = () => setMascotDialogVisible(true);
  78. const hideErrorDialog = () =>
  79. setCurrentError({ status: REQUEST_STATUS.SUCCESS });
  80. /**
  81. * Navigates to the screen specified in navigation parameters or simply go back tha stack.
  82. * Saves in user preferences to not show the login banner again.
  83. */
  84. const handleSuccess = (token: string) => {
  85. // Do not show the home login banner again
  86. if (homeMascot.shouldShow) {
  87. homeMascot.setShouldShow(false);
  88. }
  89. setLogin(token);
  90. if (!nextScreen) {
  91. navigation.goBack();
  92. } else {
  93. navigation.replace(nextScreen);
  94. }
  95. };
  96. return (
  97. <LinearGradient
  98. style={GENERAL_STYLES.flex}
  99. colors={['#9e0d18', '#530209']}
  100. start={{ x: 0, y: 0.1 }}
  101. end={{ x: 0.1, y: 1 }}
  102. >
  103. <KeyboardAvoidingView
  104. behavior={'height'}
  105. contentContainerStyle={GENERAL_STYLES.flex}
  106. style={GENERAL_STYLES.flex}
  107. enabled={true}
  108. keyboardVerticalOffset={100}
  109. >
  110. <CollapsibleScrollView headerColors={'transparent'}>
  111. <View style={GENERAL_STYLES.flex}>
  112. <LoginForm
  113. loading={loading}
  114. onSubmit={onSubmit}
  115. onResetPasswordPress={onResetPasswordClick}
  116. onHelpPress={showMascotDialog}
  117. />
  118. </View>
  119. <MascotPopup
  120. visible={mascotDialogVisible}
  121. title={i18n.t('screens.login.mascotDialog.title')}
  122. message={i18n.t('screens.login.mascotDialog.message')}
  123. icon={'help'}
  124. buttons={{
  125. cancel: {
  126. message: i18n.t('screens.login.mascotDialog.button'),
  127. icon: 'check',
  128. onPress: hideMascotDialog,
  129. },
  130. }}
  131. emotion={MASCOT_STYLE.NORMAL}
  132. />
  133. <ErrorDialog
  134. visible={
  135. currentError.status !== REQUEST_STATUS.SUCCESS ||
  136. currentError.code !== undefined
  137. }
  138. onDismiss={hideErrorDialog}
  139. status={currentError.status}
  140. code={currentError.code}
  141. />
  142. </CollapsibleScrollView>
  143. </KeyboardAvoidingView>
  144. </LinearGradient>
  145. );
  146. }
  147. export default LoginScreen;