Application Android et IOS pour l'amicale des élèves
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.js 8.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. // @flow
  2. import * as React from 'react';
  3. import {KeyboardAvoidingView, ScrollView, StyleSheet, View} from "react-native";
  4. import {Avatar, Button, Card, HelperText, Paragraph, TextInput, withTheme} from 'react-native-paper';
  5. import ConnectionManager from "../../managers/ConnectionManager";
  6. import {openBrowser} from "../../utils/WebBrowser";
  7. import i18n from 'i18n-js';
  8. import ErrorDialog from "../../components/Dialog/ErrorDialog";
  9. type Props = {
  10. navigation: Object,
  11. }
  12. type State = {
  13. email: string,
  14. password: string,
  15. isEmailValidated: boolean,
  16. isPasswordValidated: boolean,
  17. loading: boolean,
  18. dialogVisible: boolean,
  19. dialogError: number,
  20. }
  21. const ICON_AMICALE = require('../../../assets/amicale.png');
  22. const RESET_PASSWORD_LINK = "https://www.amicale-insat.fr/password/reset";
  23. const emailRegex = /^.+@.+\..+$/;
  24. class LoginScreen extends React.Component<Props, State> {
  25. state = {
  26. email: '',
  27. password: '',
  28. isEmailValidated: false,
  29. isPasswordValidated: false,
  30. loading: false,
  31. dialogVisible: false,
  32. dialogError: 0,
  33. };
  34. colors: Object;
  35. onEmailChange: Function;
  36. onPasswordChange: Function;
  37. passwordInputRef: Object;
  38. constructor(props) {
  39. super(props);
  40. this.onEmailChange = this.onInputChange.bind(this, true);
  41. this.onPasswordChange = this.onInputChange.bind(this, false);
  42. this.colors = props.theme.colors;
  43. }
  44. showErrorDialog = (error: number) =>
  45. this.setState({
  46. dialogVisible: true,
  47. dialogError: error,
  48. });
  49. hideErrorDialog = () => this.setState({dialogVisible: false});
  50. handleSuccess = () => this.props.navigation.navigate('profile');
  51. onResetPasswordClick = () => openBrowser(RESET_PASSWORD_LINK, this.colors.primary);
  52. validateEmail = () => this.setState({isEmailValidated: true});
  53. isEmailValid() {return emailRegex.test(this.state.email);}
  54. shouldShowEmailError() {return this.state.isEmailValidated && !this.isEmailValid();}
  55. validatePassword = () => this.setState({isPasswordValidated: true});
  56. isPasswordValid() {return this.state.password !== '';}
  57. shouldShowPasswordError() {return this.state.isPasswordValidated && !this.isPasswordValid();}
  58. shouldEnableLogin() {return this.isEmailValid() && this.isPasswordValid() && !this.state.loading;}
  59. onInputChange(isEmail: boolean, value: string) {
  60. if (isEmail) {
  61. this.setState({
  62. email: value,
  63. isEmailValidated: false,
  64. });
  65. } else {
  66. this.setState({
  67. password: value,
  68. isPasswordValidated: false,
  69. });
  70. }
  71. }
  72. onEmailSubmit = () => this.passwordInputRef.focus();
  73. onSubmit = () => {
  74. if (this.shouldEnableLogin()) {
  75. this.setState({loading: true});
  76. ConnectionManager.getInstance().connect(this.state.email, this.state.password)
  77. .then(this.handleSuccess)
  78. .catch(this.showErrorDialog)
  79. .finally(() => {
  80. this.setState({loading: false});
  81. });
  82. }
  83. };
  84. getFormInput() {
  85. return (
  86. <View>
  87. <TextInput
  88. label={i18n.t("loginScreen.email")}
  89. mode='outlined'
  90. value={this.state.email}
  91. onChangeText={this.onEmailChange}
  92. onBlur={this.validateEmail}
  93. onSubmitEditing={this.onEmailSubmit}
  94. error={this.shouldShowEmailError()}
  95. textContentType={'emailAddress'}
  96. autoCapitalize={'none'}
  97. autoCompleteType={'email'}
  98. autoCorrect={false}
  99. keyboardType={'email-address'}
  100. returnKeyType={'next'}
  101. secureTextEntry={false}
  102. />
  103. <HelperText
  104. type="error"
  105. visible={this.shouldShowEmailError()}
  106. >
  107. {i18n.t("loginScreen.emailError")}
  108. </HelperText>
  109. <TextInput
  110. ref={(ref) => {
  111. this.passwordInputRef = ref;
  112. }}
  113. label={i18n.t("loginScreen.password")}
  114. mode='outlined'
  115. value={this.state.password}
  116. onChangeText={this.onPasswordChange}
  117. onBlur={this.validatePassword}
  118. onSubmitEditing={this.onSubmit}
  119. error={this.shouldShowPasswordError()}
  120. textContentType={'password'}
  121. autoCapitalize={'none'}
  122. autoCompleteType={'password'}
  123. autoCorrect={false}
  124. keyboardType={'default'}
  125. returnKeyType={'done'}
  126. secureTextEntry={true}
  127. />
  128. <HelperText
  129. type="error"
  130. visible={this.shouldShowPasswordError()}
  131. >
  132. {i18n.t("loginScreen.passwordError")}
  133. </HelperText>
  134. </View>
  135. );
  136. }
  137. getMainCard() {
  138. return (
  139. <Card style={styles.card}>
  140. <Card.Title
  141. title={i18n.t("loginScreen.title")}
  142. subtitle={i18n.t("loginScreen.subtitle")}
  143. left={(props) => <Avatar.Image
  144. {...props}
  145. source={ICON_AMICALE}
  146. style={{backgroundColor: 'transparent'}}/>}
  147. />
  148. <Card.Content>
  149. {this.getFormInput()}
  150. <Card.Actions>
  151. <Button
  152. icon="send"
  153. mode="contained"
  154. disabled={!this.shouldEnableLogin()}
  155. loading={this.state.loading}
  156. onPress={this.onSubmit}
  157. style={{marginLeft: 'auto'}}>
  158. {i18n.t("loginScreen.login")}
  159. </Button>
  160. </Card.Actions>
  161. <Card.Actions>
  162. <Button
  163. icon="help-circle"
  164. mode="contained"
  165. onPress={this.onResetPasswordClick}
  166. style={{marginLeft: 'auto'}}>
  167. {i18n.t("loginScreen.resetPassword")}
  168. </Button>
  169. </Card.Actions>
  170. </Card.Content>
  171. </Card>
  172. );
  173. }
  174. getSecondaryCard() {
  175. return (
  176. <Card style={styles.card}>
  177. <Card.Title
  178. title={i18n.t("loginScreen.whyAccountTitle")}
  179. subtitle={i18n.t("loginScreen.whyAccountSub")}
  180. left={(props) => <Avatar.Icon
  181. {...props}
  182. icon={"help"}
  183. color={this.colors.primary}
  184. style={{backgroundColor: 'transparent'}}/>}
  185. />
  186. <Card.Content>
  187. <Paragraph>{i18n.t("loginScreen.whyAccountParagraph")}</Paragraph>
  188. <Paragraph>{i18n.t("loginScreen.whyAccountParagraph2")}</Paragraph>
  189. <Paragraph>{i18n.t("loginScreen.noAccount")}</Paragraph>
  190. </Card.Content>
  191. </Card>
  192. );
  193. }
  194. render() {
  195. return (
  196. <KeyboardAvoidingView
  197. behavior={"height"}
  198. contentContainerStyle={styles.container}
  199. style={styles.container}
  200. enabled
  201. keyboardVerticalOffset={100}
  202. >
  203. <ScrollView>
  204. <View>
  205. {this.getMainCard()}
  206. {this.getSecondaryCard()}
  207. </View>
  208. <ErrorDialog
  209. visible={this.state.dialogVisible}
  210. onDismiss={this.hideErrorDialog}
  211. errorCode={this.state.dialogError}
  212. />
  213. </ScrollView>
  214. </KeyboardAvoidingView>
  215. );
  216. }
  217. }
  218. const styles = StyleSheet.create({
  219. container: {
  220. flex: 1,
  221. flexDirection: 'column',
  222. justifyContent: 'center',
  223. },
  224. card: {
  225. margin: 10,
  226. },
  227. header: {
  228. fontSize: 36,
  229. marginBottom: 48
  230. },
  231. textInput: {},
  232. btnContainer: {
  233. marginTop: 5,
  234. marginBottom: 10,
  235. }
  236. });
  237. export default withTheme(LoginScreen);