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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  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] = useState(false);
  45. const [currentError, setCurrentError] = useState<ApiRejectType>({
  46. status: REQUEST_STATUS.SUCCESS,
  47. });
  48. const homeMascot = useShouldShowMascot(TabRoutes.Home);
  49. useFocusEffect(
  50. useCallback(() => {
  51. setNextScreen(props.route.params?.nextScreen);
  52. }, [props.route.params])
  53. );
  54. const onResetPasswordClick = () => {
  55. navigation.navigate('website', {
  56. host: Urls.websites.amicale,
  57. path: Urls.amicale.resetPassword,
  58. title: i18n.t('screens.websites.amicale'),
  59. });
  60. };
  61. /**
  62. * Called when the user clicks on login or finishes to type his password.
  63. *
  64. * Checks if we should allow the user to login,
  65. * then makes the login request and enters a loading state until the request finishes
  66. *
  67. */
  68. const onSubmit = (email: string, password: string) => {
  69. setLoading(true);
  70. connectToAmicale(email, password)
  71. .then(handleSuccess)
  72. .catch(setCurrentError)
  73. .finally(() => setLoading(false));
  74. };
  75. const hideMascotDialog = () => setMascotDialogVisible(true);
  76. const showMascotDialog = () => setMascotDialogVisible(false);
  77. const hideErrorDialog = () =>
  78. setCurrentError({ status: REQUEST_STATUS.SUCCESS });
  79. /**
  80. * Navigates to the screen specified in navigation parameters or simply go back tha stack.
  81. * Saves in user preferences to not show the login banner again.
  82. */
  83. const handleSuccess = (token: string) => {
  84. // Do not show the home login banner again
  85. if (homeMascot.shouldShow) {
  86. homeMascot.setShouldShow(false);
  87. }
  88. setLogin(token);
  89. if (!nextScreen) {
  90. navigation.goBack();
  91. } else {
  92. navigation.replace(nextScreen);
  93. }
  94. };
  95. return (
  96. <LinearGradient
  97. style={GENERAL_STYLES.flex}
  98. colors={['#9e0d18', '#530209']}
  99. start={{ x: 0, y: 0.1 }}
  100. end={{ x: 0.1, y: 1 }}
  101. >
  102. <KeyboardAvoidingView
  103. behavior={'height'}
  104. contentContainerStyle={GENERAL_STYLES.flex}
  105. style={GENERAL_STYLES.flex}
  106. enabled={true}
  107. keyboardVerticalOffset={100}
  108. >
  109. <CollapsibleScrollView headerColors={'transparent'}>
  110. <View style={GENERAL_STYLES.flex}>
  111. <LoginForm
  112. loading={loading}
  113. onSubmit={onSubmit}
  114. onResetPasswordPress={onResetPasswordClick}
  115. onHelpPress={showMascotDialog}
  116. />
  117. </View>
  118. <MascotPopup
  119. visible={mascotDialogVisible}
  120. title={i18n.t('screens.login.mascotDialog.title')}
  121. message={i18n.t('screens.login.mascotDialog.message')}
  122. icon={'help'}
  123. buttons={{
  124. cancel: {
  125. message: i18n.t('screens.login.mascotDialog.button'),
  126. icon: 'check',
  127. onPress: hideMascotDialog,
  128. },
  129. }}
  130. emotion={MASCOT_STYLE.NORMAL}
  131. />
  132. <ErrorDialog
  133. visible={
  134. currentError.status !== REQUEST_STATUS.SUCCESS ||
  135. currentError.code !== undefined
  136. }
  137. onDismiss={hideErrorDialog}
  138. status={currentError.status}
  139. code={currentError.code}
  140. />
  141. </CollapsibleScrollView>
  142. </KeyboardAvoidingView>
  143. </LinearGradient>
  144. );
  145. }
  146. export default LoginScreen;