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.

AuthenticatedScreen.js 5.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. // @flow
  2. import * as React from 'react';
  3. import ConnectionManager from "../../managers/ConnectionManager";
  4. import {ERROR_TYPE} from "../../utils/WebData";
  5. import ErrorView from "../Custom/ErrorView";
  6. import BasicLoadingScreen from "../Custom/BasicLoadingScreen";
  7. type Props = {
  8. navigation: Object,
  9. requests: Array<{
  10. link: string,
  11. params: Object,
  12. mandatory: boolean
  13. }>,
  14. renderFunction: Function,
  15. }
  16. type State = {
  17. loading: boolean,
  18. }
  19. class AuthenticatedScreen extends React.Component<Props, State> {
  20. state = {
  21. loading: true,
  22. };
  23. currentUserToken: string | null;
  24. connectionManager: ConnectionManager;
  25. errors: Array<number>;
  26. fetchedData: Array<Object>;
  27. constructor(props: Object) {
  28. super(props);
  29. this.connectionManager = ConnectionManager.getInstance();
  30. this.props.navigation.addListener('focus', this.onScreenFocus);
  31. this.fetchedData = new Array(this.props.requests.length);
  32. this.errors = new Array(this.props.requests.length);
  33. }
  34. /**
  35. * Refreshes screen if user changed
  36. */
  37. onScreenFocus = () => {
  38. if (this.currentUserToken !== this.connectionManager.getToken()) {
  39. this.currentUserToken = this.connectionManager.getToken();
  40. this.fetchData();
  41. }
  42. };
  43. /**
  44. * Fetches the data from the server.
  45. *
  46. * If the user is not logged in errorCode is set to BAD_TOKEN and all requests fail.
  47. *
  48. * If the user is logged in, send all requests.
  49. */
  50. fetchData = () => {
  51. if (!this.state.loading)
  52. this.setState({loading: true});
  53. if (this.connectionManager.isLoggedIn()) {
  54. for (let i = 0; i < this.props.requests.length; i++) {
  55. this.connectionManager.authenticatedRequest(
  56. this.props.requests[i].link,
  57. this.props.requests[i].params)
  58. .then((data) => {
  59. this.onRequestFinished(data, i, -1);
  60. })
  61. .catch((error) => {
  62. this.onRequestFinished(null, i, error);
  63. });
  64. }
  65. } else {
  66. for (let i = 0; i < this.props.requests.length; i++) {
  67. this.onRequestFinished(null, i, ERROR_TYPE.BAD_TOKEN);
  68. }
  69. }
  70. };
  71. /**
  72. * Callback used when a request finishes, successfully or not.
  73. * Saves data and error code.
  74. * If the token is invalid, logout the user and open the login screen.
  75. * If the last request was received, stop the loading screen.
  76. *
  77. * @param data The data fetched from the server
  78. * @param index The index for the data
  79. * @param error The error code received
  80. */
  81. onRequestFinished(data: Object | null, index: number, error: number) {
  82. if (index >= 0 && index < this.props.requests.length) {
  83. this.fetchedData[index] = data;
  84. this.errors[index] = error;
  85. }
  86. if (error === ERROR_TYPE.BAD_TOKEN) // Token expired, logout user
  87. this.connectionManager.disconnect();
  88. if (this.allRequestsFinished())
  89. this.setState({loading: false});
  90. }
  91. /**
  92. * Checks if all requests finished processing
  93. *
  94. * @return {boolean} True if all finished
  95. */
  96. allRequestsFinished() {
  97. let finished = true;
  98. for (let i = 0; i < this.fetchedData.length; i++) {
  99. if (this.fetchedData[i] === undefined) {
  100. finished = false;
  101. break;
  102. }
  103. }
  104. return finished;
  105. }
  106. /**
  107. * Checks if all requests have finished successfully.
  108. * This will return false only if a mandatory request failed.
  109. * All non-mandatory requests can fail without impacting the return value.
  110. *
  111. * @return {boolean} True if all finished successfully
  112. */
  113. allRequestsValid() {
  114. let valid = true;
  115. for (let i = 0; i < this.fetchedData.length; i++) {
  116. if (this.fetchedData[i] === null && this.props.requests[i].mandatory) {
  117. valid = false;
  118. break;
  119. }
  120. }
  121. return valid;
  122. }
  123. /**
  124. * Gets the error to render.
  125. * Non-mandatory requests are ignored.
  126. *
  127. *
  128. * @return {number} The error code or ERROR_TYPE.SUCCESS if no error was found
  129. */
  130. getError() {
  131. for (let i = 0; i < this.errors.length; i++) {
  132. if (this.errors[i] !== 0 && this.props.requests[i].mandatory) {
  133. return this.errors[i];
  134. }
  135. }
  136. return ERROR_TYPE.SUCCESS;
  137. }
  138. /**
  139. * Gets the error view to display in case of error
  140. *
  141. * @return {*}
  142. */
  143. getErrorRender() {
  144. return (
  145. <ErrorView
  146. {...this.props}
  147. errorCode={this.getError()}
  148. onRefresh={this.fetchData}
  149. />
  150. );
  151. }
  152. /**
  153. * Reloads the data, to be called using ref by parent components
  154. */
  155. reload() {
  156. this.fetchData();
  157. }
  158. render() {
  159. return (
  160. this.state.loading
  161. ? <BasicLoadingScreen/>
  162. : (this.allRequestsValid()
  163. ? this.props.renderFunction(this.fetchedData)
  164. : this.getErrorRender())
  165. );
  166. }
  167. }
  168. export default AuthenticatedScreen;