Browse Source

Update Amicale and related components to use TypeScript

Arnaud Vergnet 3 years ago
parent
commit
f95635136e

src/components/Amicale/AuthenticatedScreen.js → src/components/Amicale/AuthenticatedScreen.tsx View File

17
  * along with Campus INSAT.  If not, see <https://www.gnu.org/licenses/>.
17
  * along with Campus INSAT.  If not, see <https://www.gnu.org/licenses/>.
18
  */
18
  */
19
 
19
 
20
-// @flow
21
-
22
 import * as React from 'react';
20
 import * as React from 'react';
23
 import {StackNavigationProp} from '@react-navigation/stack';
21
 import {StackNavigationProp} from '@react-navigation/stack';
24
 import ConnectionManager from '../../managers/ConnectionManager';
22
 import ConnectionManager from '../../managers/ConnectionManager';
25
-import type {ApiGenericDataType} from '../../utils/WebData';
26
 import {ERROR_TYPE} from '../../utils/WebData';
23
 import {ERROR_TYPE} from '../../utils/WebData';
27
 import ErrorView from '../Screens/ErrorView';
24
 import ErrorView from '../Screens/ErrorView';
28
 import BasicLoadingScreen from '../Screens/BasicLoadingScreen';
25
 import BasicLoadingScreen from '../Screens/BasicLoadingScreen';
29
 
26
 
30
-type PropsType = {
31
-  navigation: StackNavigationProp,
27
+type PropsType<T> = {
28
+  navigation: StackNavigationProp<any>;
32
   requests: Array<{
29
   requests: Array<{
33
-    link: string,
34
-    params: {...},
35
-    mandatory: boolean,
36
-  }>,
37
-  renderFunction: (Array<ApiGenericDataType | null>) => React.Node,
30
+    link: string;
31
+    params: object;
32
+    mandatory: boolean;
33
+  }>;
34
+  renderFunction: (data: Array<T | null>) => React.ReactNode;
38
   errorViewOverride?: Array<{
35
   errorViewOverride?: Array<{
39
-    errorCode: number,
40
-    message: string,
41
-    icon: string,
42
-    showRetryButton: boolean,
43
-  }> | null,
36
+    errorCode: number;
37
+    message: string;
38
+    icon: string;
39
+    showRetryButton: boolean;
40
+  }> | null;
44
 };
41
 };
45
 
42
 
46
 type StateType = {
43
 type StateType = {
47
-  loading: boolean,
44
+  loading: boolean;
48
 };
45
 };
49
 
46
 
50
-class AuthenticatedScreen extends React.Component<PropsType, StateType> {
47
+class AuthenticatedScreen<T> extends React.Component<PropsType<T>, StateType> {
51
   static defaultProps = {
48
   static defaultProps = {
52
     errorViewOverride: null,
49
     errorViewOverride: null,
53
   };
50
   };
58
 
55
 
59
   errors: Array<number>;
56
   errors: Array<number>;
60
 
57
 
61
-  fetchedData: Array<ApiGenericDataType | null>;
58
+  fetchedData: Array<T | null>;
62
 
59
 
63
-  constructor(props: PropsType) {
60
+  constructor(props: PropsType<T>) {
64
     super(props);
61
     super(props);
65
     this.state = {
62
     this.state = {
66
       loading: true,
63
       loading: true,
67
     };
64
     };
65
+    this.currentUserToken = null;
68
     this.connectionManager = ConnectionManager.getInstance();
66
     this.connectionManager = ConnectionManager.getInstance();
69
     props.navigation.addListener('focus', this.onScreenFocus);
67
     props.navigation.addListener('focus', this.onScreenFocus);
70
     this.fetchedData = new Array(props.requests.length);
68
     this.fetchedData = new Array(props.requests.length);
91
    * @param index The index for the data
89
    * @param index The index for the data
92
    * @param error The error code received
90
    * @param error The error code received
93
    */
91
    */
94
-  onRequestFinished(
95
-    data: ApiGenericDataType | null,
96
-    index: number,
97
-    error?: number,
98
-  ) {
92
+  onRequestFinished(data: T | null, index: number, error?: number) {
99
     const {props} = this;
93
     const {props} = this;
100
     if (index >= 0 && index < props.requests.length) {
94
     if (index >= 0 && index < props.requests.length) {
101
       this.fetchedData[index] = data;
95
       this.fetchedData[index] = data;
102
       this.errors[index] = error != null ? error : ERROR_TYPE.SUCCESS;
96
       this.errors[index] = error != null ? error : ERROR_TYPE.SUCCESS;
103
     }
97
     }
104
     // Token expired, logout user
98
     // Token expired, logout user
105
-    if (error === ERROR_TYPE.BAD_TOKEN) this.connectionManager.disconnect();
99
+    if (error === ERROR_TYPE.BAD_TOKEN) {
100
+      this.connectionManager.disconnect();
101
+    }
106
 
102
 
107
-    if (this.allRequestsFinished()) this.setState({loading: false});
103
+    if (this.allRequestsFinished()) {
104
+      this.setState({loading: false});
105
+    }
108
   }
106
   }
109
 
107
 
110
   /**
108
   /**
132
    *
130
    *
133
    * @return {*}
131
    * @return {*}
134
    */
132
    */
135
-  getErrorRender(): React.Node {
133
+  getErrorRender() {
136
     const {props} = this;
134
     const {props} = this;
137
     const errorCode = this.getError();
135
     const errorCode = this.getError();
138
     let shouldOverride = false;
136
     let shouldOverride = false;
169
    */
167
    */
170
   fetchData = () => {
168
   fetchData = () => {
171
     const {state, props} = this;
169
     const {state, props} = this;
172
-    if (!state.loading) this.setState({loading: true});
170
+    if (!state.loading) {
171
+      this.setState({loading: true});
172
+    }
173
 
173
 
174
     if (this.connectionManager.isLoggedIn()) {
174
     if (this.connectionManager.isLoggedIn()) {
175
       for (let i = 0; i < props.requests.length; i += 1) {
175
       for (let i = 0; i < props.requests.length; i += 1) {
176
         this.connectionManager
176
         this.connectionManager
177
-          .authenticatedRequest(
177
+          .authenticatedRequest<T>(
178
             props.requests[i].link,
178
             props.requests[i].link,
179
             props.requests[i].params,
179
             props.requests[i].params,
180
           )
180
           )
181
-          .then((response: ApiGenericDataType): void =>
182
-            this.onRequestFinished(response, i),
183
-          )
181
+          .then((response: T): void => this.onRequestFinished(response, i))
184
           .catch((error: number): void =>
182
           .catch((error: number): void =>
185
             this.onRequestFinished(null, i, error),
183
             this.onRequestFinished(null, i, error),
186
           );
184
           );
200
   allRequestsFinished(): boolean {
198
   allRequestsFinished(): boolean {
201
     let finished = true;
199
     let finished = true;
202
     this.errors.forEach((error: number | null) => {
200
     this.errors.forEach((error: number | null) => {
203
-      if (error == null) finished = false;
201
+      if (error == null) {
202
+        finished = false;
203
+      }
204
     });
204
     });
205
     return finished;
205
     return finished;
206
   }
206
   }
212
     this.fetchData();
212
     this.fetchData();
213
   }
213
   }
214
 
214
 
215
-  render(): React.Node {
215
+  render() {
216
     const {state, props} = this;
216
     const {state, props} = this;
217
-    if (state.loading) return <BasicLoadingScreen />;
218
-    if (this.getError() === ERROR_TYPE.SUCCESS)
217
+    if (state.loading) {
218
+      return <BasicLoadingScreen />;
219
+    }
220
+    if (this.getError() === ERROR_TYPE.SUCCESS) {
219
       return props.renderFunction(this.fetchedData);
221
       return props.renderFunction(this.fetchedData);
222
+    }
220
     return this.getErrorRender();
223
     return this.getErrorRender();
221
   }
224
   }
222
 }
225
 }

src/components/Amicale/LogoutDialog.js → src/components/Amicale/LogoutDialog.tsx View File

17
  * along with Campus INSAT.  If not, see <https://www.gnu.org/licenses/>.
17
  * along with Campus INSAT.  If not, see <https://www.gnu.org/licenses/>.
18
  */
18
  */
19
 
19
 
20
-// @flow
21
-
22
 import * as React from 'react';
20
 import * as React from 'react';
23
 import i18n from 'i18n-js';
21
 import i18n from 'i18n-js';
24
-import {StackNavigationProp} from '@react-navigation/stack';
25
 import LoadingConfirmDialog from '../Dialogs/LoadingConfirmDialog';
22
 import LoadingConfirmDialog from '../Dialogs/LoadingConfirmDialog';
26
 import ConnectionManager from '../../managers/ConnectionManager';
23
 import ConnectionManager from '../../managers/ConnectionManager';
24
+import {useNavigation} from '@react-navigation/native';
27
 
25
 
28
 type PropsType = {
26
 type PropsType = {
29
-  navigation: StackNavigationProp,
30
-  visible: boolean,
31
-  onDismiss: () => void,
27
+  visible: boolean;
28
+  onDismiss: () => void;
32
 };
29
 };
33
 
30
 
34
-class LogoutDialog extends React.PureComponent<PropsType> {
35
-  onClickAccept = async (): Promise<void> => {
36
-    const {props} = this;
31
+function LogoutDialog(props: PropsType) {
32
+  const navigation = useNavigation();
33
+  const onClickAccept = async (): Promise<void> => {
37
     return new Promise((resolve: () => void) => {
34
     return new Promise((resolve: () => void) => {
38
       ConnectionManager.getInstance()
35
       ConnectionManager.getInstance()
39
         .disconnect()
36
         .disconnect()
40
         .then(() => {
37
         .then(() => {
41
-          props.navigation.reset({
38
+          navigation.reset({
42
             index: 0,
39
             index: 0,
43
             routes: [{name: 'main'}],
40
             routes: [{name: 'main'}],
44
           });
41
           });
48
     });
45
     });
49
   };
46
   };
50
 
47
 
51
-  render(): React.Node {
52
-    const {props} = this;
53
-    return (
54
-      <LoadingConfirmDialog
55
-        visible={props.visible}
56
-        onDismiss={props.onDismiss}
57
-        onAccept={this.onClickAccept}
58
-        title={i18n.t('dialog.disconnect.title')}
59
-        titleLoading={i18n.t('dialog.disconnect.titleLoading')}
60
-        message={i18n.t('dialog.disconnect.message')}
61
-      />
62
-    );
63
-  }
48
+  return (
49
+    <LoadingConfirmDialog
50
+      visible={props.visible}
51
+      onDismiss={props.onDismiss}
52
+      onAccept={onClickAccept}
53
+      title={i18n.t('dialog.disconnect.title')}
54
+      titleLoading={i18n.t('dialog.disconnect.titleLoading')}
55
+      message={i18n.t('dialog.disconnect.message')}
56
+    />
57
+  );
64
 }
58
 }
65
 
59
 
66
 export default LogoutDialog;
60
 export default LogoutDialog;

src/components/Amicale/Vote/VoteNotAvailable.js → src/components/Amicale/Vote/VoteNotAvailable.tsx View File

17
  * along with Campus INSAT.  If not, see <https://www.gnu.org/licenses/>.
17
  * along with Campus INSAT.  If not, see <https://www.gnu.org/licenses/>.
18
  */
18
  */
19
 
19
 
20
-// @flow
21
-
22
-import * as React from 'react';
20
+import React from 'react';
23
 import {View} from 'react-native';
21
 import {View} from 'react-native';
24
-import {Headline, withTheme} from 'react-native-paper';
22
+import {Headline, useTheme} from 'react-native-paper';
25
 import i18n from 'i18n-js';
23
 import i18n from 'i18n-js';
26
-import type {CustomThemeType} from '../../../managers/ThemeManager';
27
-
28
-type PropsType = {
29
-  theme: CustomThemeType,
30
-};
31
-
32
-class VoteNotAvailable extends React.Component<PropsType> {
33
-  shouldComponentUpdate(): boolean {
34
-    return false;
35
-  }
36
 
24
 
37
-  render(): React.Node {
38
-    const {props} = this;
39
-    return (
40
-      <View
25
+function VoteNotAvailable() {
26
+  const theme = useTheme();
27
+  return (
28
+    <View
29
+      style={{
30
+        width: '100%',
31
+        marginTop: 10,
32
+        marginBottom: 10,
33
+      }}>
34
+      <Headline
41
         style={{
35
         style={{
42
-          width: '100%',
43
-          marginTop: 10,
44
-          marginBottom: 10,
36
+          color: theme.colors.textDisabled,
37
+          textAlign: 'center',
45
         }}>
38
         }}>
46
-        <Headline
47
-          style={{
48
-            color: props.theme.colors.textDisabled,
49
-            textAlign: 'center',
50
-          }}>
51
-          {i18n.t('screens.vote.noVote')}
52
-        </Headline>
53
-      </View>
54
-    );
55
-  }
39
+        {i18n.t('screens.vote.noVote')}
40
+      </Headline>
41
+    </View>
42
+  );
56
 }
43
 }
57
 
44
 
58
-export default withTheme(VoteNotAvailable);
45
+export default VoteNotAvailable;

src/components/Amicale/Vote/VoteResults.js → src/components/Amicale/Vote/VoteResults.tsx View File

17
  * along with Campus INSAT.  If not, see <https://www.gnu.org/licenses/>.
17
  * along with Campus INSAT.  If not, see <https://www.gnu.org/licenses/>.
18
  */
18
  */
19
 
19
 
20
-// @flow
21
-
22
 import * as React from 'react';
20
 import * as React from 'react';
23
 import {
21
 import {
24
   Avatar,
22
   Avatar,
31
 import {FlatList, StyleSheet} from 'react-native';
29
 import {FlatList, StyleSheet} from 'react-native';
32
 import i18n from 'i18n-js';
30
 import i18n from 'i18n-js';
33
 import type {VoteTeamType} from '../../../screens/Amicale/VoteScreen';
31
 import type {VoteTeamType} from '../../../screens/Amicale/VoteScreen';
34
-import type {CustomThemeType} from '../../../managers/ThemeManager';
35
-import type {
36
-  CardTitleIconPropsType,
37
-  ListIconPropsType,
38
-} from '../../../constants/PaperStyles';
39
 
32
 
40
 type PropsType = {
33
 type PropsType = {
41
-  teams: Array<VoteTeamType>,
42
-  dateEnd: string,
43
-  theme: CustomThemeType,
34
+  teams: Array<VoteTeamType>;
35
+  dateEnd: string;
36
+  theme: ReactNativePaper.Theme;
44
 };
37
 };
45
 
38
 
46
 const styles = StyleSheet.create({
39
 const styles = StyleSheet.create({
58
   winnerIds: Array<number>;
51
   winnerIds: Array<number>;
59
 
52
 
60
   constructor(props: PropsType) {
53
   constructor(props: PropsType) {
61
-    super();
54
+    super(props);
62
     props.teams.sort(this.sortByVotes);
55
     props.teams.sort(this.sortByVotes);
63
-    this.getTotalVotes(props.teams);
64
-    this.getWinnerIds(props.teams);
56
+    this.totalVotes = this.getTotalVotes(props.teams);
57
+    this.winnerIds = this.getWinnerIds(props.teams);
65
   }
58
   }
66
 
59
 
67
   shouldComponentUpdate(): boolean {
60
   shouldComponentUpdate(): boolean {
69
   }
62
   }
70
 
63
 
71
   getTotalVotes(teams: Array<VoteTeamType>) {
64
   getTotalVotes(teams: Array<VoteTeamType>) {
72
-    this.totalVotes = 0;
65
+    let totalVotes = 0;
73
     for (let i = 0; i < teams.length; i += 1) {
66
     for (let i = 0; i < teams.length; i += 1) {
74
-      this.totalVotes += teams[i].votes;
67
+      totalVotes += teams[i].votes;
75
     }
68
     }
69
+    return totalVotes;
76
   }
70
   }
77
 
71
 
78
   getWinnerIds(teams: Array<VoteTeamType>) {
72
   getWinnerIds(teams: Array<VoteTeamType>) {
79
     const max = teams[0].votes;
73
     const max = teams[0].votes;
80
-    this.winnerIds = [];
74
+    let winnerIds = [];
81
     for (let i = 0; i < teams.length; i += 1) {
75
     for (let i = 0; i < teams.length; i += 1) {
82
-      if (teams[i].votes === max) this.winnerIds.push(teams[i].id);
83
-      else break;
76
+      if (teams[i].votes === max) {
77
+        winnerIds.push(teams[i].id);
78
+      } else {
79
+        break;
80
+      }
84
     }
81
     }
82
+    return winnerIds;
85
   }
83
   }
86
 
84
 
87
   sortByVotes = (a: VoteTeamType, b: VoteTeamType): number => b.votes - a.votes;
85
   sortByVotes = (a: VoteTeamType, b: VoteTeamType): number => b.votes - a.votes;
88
 
86
 
89
   voteKeyExtractor = (item: VoteTeamType): string => item.id.toString();
87
   voteKeyExtractor = (item: VoteTeamType): string => item.id.toString();
90
 
88
 
91
-  resultRenderItem = ({item}: {item: VoteTeamType}): React.Node => {
89
+  resultRenderItem = ({item}: {item: VoteTeamType}) => {
92
     const isWinner = this.winnerIds.indexOf(item.id) !== -1;
90
     const isWinner = this.winnerIds.indexOf(item.id) !== -1;
93
     const isDraw = this.winnerIds.length > 1;
91
     const isDraw = this.winnerIds.length > 1;
94
     const {props} = this;
92
     const {props} = this;
101
         <List.Item
99
         <List.Item
102
           title={item.name}
100
           title={item.name}
103
           description={`${item.votes} ${i18n.t('screens.vote.results.votes')}`}
101
           description={`${item.votes} ${i18n.t('screens.vote.results.votes')}`}
104
-          left={(iconProps: ListIconPropsType): React.Node =>
102
+          left={(iconProps) =>
105
             isWinner ? (
103
             isWinner ? (
106
               <List.Icon
104
               <List.Icon
107
                 style={iconProps.style}
105
                 style={iconProps.style}
125
     );
123
     );
126
   };
124
   };
127
 
125
 
128
-  render(): React.Node {
126
+  render() {
129
     const {props} = this;
127
     const {props} = this;
130
     return (
128
     return (
131
       <Card style={styles.card}>
129
       <Card style={styles.card}>
134
           subtitle={`${i18n.t('screens.vote.results.subtitle')} ${
132
           subtitle={`${i18n.t('screens.vote.results.subtitle')} ${
135
             props.dateEnd
133
             props.dateEnd
136
           }`}
134
           }`}
137
-          left={(iconProps: CardTitleIconPropsType): React.Node => (
135
+          left={(iconProps) => (
138
             <Avatar.Icon size={iconProps.size} icon="podium-gold" />
136
             <Avatar.Icon size={iconProps.size} icon="podium-gold" />
139
           )}
137
           )}
140
         />
138
         />
141
         <Card.Content>
139
         <Card.Content>
142
-          <Subheading>{`${i18n.t('screens.vote.results.totalVotes')} ${
143
-            this.totalVotes
144
-          }`}</Subheading>
145
-          {/* $FlowFixMe */}
140
+          <Subheading>
141
+            {`${i18n.t('screens.vote.results.totalVotes')} ${this.totalVotes}`}
142
+          </Subheading>
146
           <FlatList
143
           <FlatList
147
             data={props.teams}
144
             data={props.teams}
148
             keyExtractor={this.voteKeyExtractor}
145
             keyExtractor={this.voteKeyExtractor}

src/components/Amicale/Vote/VoteSelect.js → src/components/Amicale/Vote/VoteSelect.tsx View File

17
  * along with Campus INSAT.  If not, see <https://www.gnu.org/licenses/>.
17
  * along with Campus INSAT.  If not, see <https://www.gnu.org/licenses/>.
18
  */
18
  */
19
 
19
 
20
-// @flow
21
-
22
 import * as React from 'react';
20
 import * as React from 'react';
23
 import {Avatar, Button, Card, RadioButton} from 'react-native-paper';
21
 import {Avatar, Button, Card, RadioButton} from 'react-native-paper';
24
 import {FlatList, StyleSheet, View} from 'react-native';
22
 import {FlatList, StyleSheet, View} from 'react-native';
27
 import LoadingConfirmDialog from '../../Dialogs/LoadingConfirmDialog';
25
 import LoadingConfirmDialog from '../../Dialogs/LoadingConfirmDialog';
28
 import ErrorDialog from '../../Dialogs/ErrorDialog';
26
 import ErrorDialog from '../../Dialogs/ErrorDialog';
29
 import type {VoteTeamType} from '../../../screens/Amicale/VoteScreen';
27
 import type {VoteTeamType} from '../../../screens/Amicale/VoteScreen';
30
-import type {CardTitleIconPropsType} from '../../../constants/PaperStyles';
31
 
28
 
32
 type PropsType = {
29
 type PropsType = {
33
-  teams: Array<VoteTeamType>,
34
-  onVoteSuccess: () => void,
35
-  onVoteError: () => void,
30
+  teams: Array<VoteTeamType>;
31
+  onVoteSuccess: () => void;
32
+  onVoteError: () => void;
36
 };
33
 };
37
 
34
 
38
 type StateType = {
35
 type StateType = {
39
-  selectedTeam: string,
40
-  voteDialogVisible: boolean,
41
-  errorDialogVisible: boolean,
42
-  currentError: number,
36
+  selectedTeam: string;
37
+  voteDialogVisible: boolean;
38
+  errorDialogVisible: boolean;
39
+  currentError: number;
43
 };
40
 };
44
 
41
 
45
 const styles = StyleSheet.create({
42
 const styles = StyleSheet.create({
53
 
50
 
54
 export default class VoteSelect extends React.PureComponent<
51
 export default class VoteSelect extends React.PureComponent<
55
   PropsType,
52
   PropsType,
56
-  StateType,
53
+  StateType
57
 > {
54
 > {
58
-  constructor() {
59
-    super();
55
+  constructor(props: PropsType) {
56
+    super(props);
60
     this.state = {
57
     this.state = {
61
       selectedTeam: 'none',
58
       selectedTeam: 'none',
62
       voteDialogVisible: false,
59
       voteDialogVisible: false,
70
 
67
 
71
   voteKeyExtractor = (item: VoteTeamType): string => item.id.toString();
68
   voteKeyExtractor = (item: VoteTeamType): string => item.id.toString();
72
 
69
 
73
-  voteRenderItem = ({item}: {item: VoteTeamType}): React.Node => (
70
+  voteRenderItem = ({item}: {item: VoteTeamType}) => (
74
     <RadioButton.Item label={item.name} value={item.id.toString()} />
71
     <RadioButton.Item label={item.name} value={item.id.toString()} />
75
   );
72
   );
76
 
73
 
111
     props.onVoteError();
108
     props.onVoteError();
112
   };
109
   };
113
 
110
 
114
-  render(): React.Node {
111
+  render() {
115
     const {state, props} = this;
112
     const {state, props} = this;
116
     return (
113
     return (
117
       <View>
114
       <View>
119
           <Card.Title
116
           <Card.Title
120
             title={i18n.t('screens.vote.select.title')}
117
             title={i18n.t('screens.vote.select.title')}
121
             subtitle={i18n.t('screens.vote.select.subtitle')}
118
             subtitle={i18n.t('screens.vote.select.subtitle')}
122
-            left={(iconProps: CardTitleIconPropsType): React.Node => (
119
+            left={(iconProps) => (
123
               <Avatar.Icon size={iconProps.size} icon="alert-decagram" />
120
               <Avatar.Icon size={iconProps.size} icon="alert-decagram" />
124
             )}
121
             )}
125
           />
122
           />
127
             <RadioButton.Group
124
             <RadioButton.Group
128
               onValueChange={this.onVoteSelectionChange}
125
               onValueChange={this.onVoteSelectionChange}
129
               value={state.selectedTeam}>
126
               value={state.selectedTeam}>
130
-              {/* $FlowFixMe */}
131
               <FlatList
127
               <FlatList
132
                 data={props.teams}
128
                 data={props.teams}
133
                 keyExtractor={this.voteKeyExtractor}
129
                 keyExtractor={this.voteKeyExtractor}

src/components/Amicale/Vote/VoteTease.js → src/components/Amicale/Vote/VoteTease.tsx View File

17
  * along with Campus INSAT.  If not, see <https://www.gnu.org/licenses/>.
17
  * along with Campus INSAT.  If not, see <https://www.gnu.org/licenses/>.
18
  */
18
  */
19
 
19
 
20
-// @flow
21
-
22
 import * as React from 'react';
20
 import * as React from 'react';
23
 import {Avatar, Card, Paragraph} from 'react-native-paper';
21
 import {Avatar, Card, Paragraph} from 'react-native-paper';
24
 import {StyleSheet} from 'react-native';
22
 import {StyleSheet} from 'react-native';
25
 import i18n from 'i18n-js';
23
 import i18n from 'i18n-js';
26
-import type {CardTitleIconPropsType} from '../../../constants/PaperStyles';
27
 
24
 
28
 type PropsType = {
25
 type PropsType = {
29
-  startDate: string,
26
+  startDate: string;
30
 };
27
 };
31
 
28
 
32
 const styles = StyleSheet.create({
29
 const styles = StyleSheet.create({
38
   },
35
   },
39
 });
36
 });
40
 
37
 
41
-export default class VoteTease extends React.Component<PropsType> {
42
-  shouldComponentUpdate(): boolean {
43
-    return false;
44
-  }
45
-
46
-  render(): React.Node {
47
-    const {props} = this;
48
-    return (
49
-      <Card style={styles.card}>
50
-        <Card.Title
51
-          title={i18n.t('screens.vote.tease.title')}
52
-          subtitle={i18n.t('screens.vote.tease.subtitle')}
53
-          left={(iconProps: CardTitleIconPropsType): React.Node => (
54
-            <Avatar.Icon size={iconProps.size} icon="vote" />
55
-          )}
56
-        />
57
-        <Card.Content>
58
-          <Paragraph>
59
-            {`${i18n.t('screens.vote.tease.message')} ${props.startDate}`}
60
-          </Paragraph>
61
-        </Card.Content>
62
-      </Card>
63
-    );
64
-  }
38
+export default function VoteTease(props: PropsType) {
39
+  return (
40
+    <Card style={styles.card}>
41
+      <Card.Title
42
+        title={i18n.t('screens.vote.tease.title')}
43
+        subtitle={i18n.t('screens.vote.tease.subtitle')}
44
+        left={(iconProps) => <Avatar.Icon size={iconProps.size} icon="vote" />}
45
+      />
46
+      <Card.Content>
47
+        <Paragraph>
48
+          {`${i18n.t('screens.vote.tease.message')} ${props.startDate}`}
49
+        </Paragraph>
50
+      </Card.Content>
51
+    </Card>
52
+  );
65
 }
53
 }

+ 0
- 93
src/components/Amicale/Vote/VoteWait.js View File

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
-
20
-// @flow
21
-
22
-import * as React from 'react';
23
-import {Avatar, Card, Paragraph, withTheme} from 'react-native-paper';
24
-import {StyleSheet} from 'react-native';
25
-import i18n from 'i18n-js';
26
-import type {CustomThemeType} from '../../../managers/ThemeManager';
27
-import type {CardTitleIconPropsType} from '../../../constants/PaperStyles';
28
-
29
-type PropsType = {
30
-  startDate: string | null,
31
-  justVoted: boolean,
32
-  hasVoted: boolean,
33
-  isVoteRunning: boolean,
34
-  theme: CustomThemeType,
35
-};
36
-
37
-const styles = StyleSheet.create({
38
-  card: {
39
-    margin: 10,
40
-  },
41
-  icon: {
42
-    backgroundColor: 'transparent',
43
-  },
44
-});
45
-
46
-class VoteWait extends React.Component<PropsType> {
47
-  shouldComponentUpdate(): boolean {
48
-    return false;
49
-  }
50
-
51
-  render(): React.Node {
52
-    const {props} = this;
53
-    const {startDate} = props;
54
-    return (
55
-      <Card style={styles.card}>
56
-        <Card.Title
57
-          title={
58
-            props.isVoteRunning
59
-              ? i18n.t('screens.vote.wait.titleSubmitted')
60
-              : i18n.t('screens.vote.wait.titleEnded')
61
-          }
62
-          subtitle={i18n.t('screens.vote.wait.subtitle')}
63
-          left={(iconProps: CardTitleIconPropsType): React.Node => (
64
-            <Avatar.Icon size={iconProps.size} icon="progress-check" />
65
-          )}
66
-        />
67
-        <Card.Content>
68
-          {props.justVoted ? (
69
-            <Paragraph style={{color: props.theme.colors.success}}>
70
-              {i18n.t('screens.vote.wait.messageSubmitted')}
71
-            </Paragraph>
72
-          ) : null}
73
-          {props.hasVoted ? (
74
-            <Paragraph style={{color: props.theme.colors.success}}>
75
-              {i18n.t('screens.vote.wait.messageVoted')}
76
-            </Paragraph>
77
-          ) : null}
78
-          {startDate != null ? (
79
-            <Paragraph>
80
-              {`${i18n.t('screens.vote.wait.messageDate')} ${startDate}`}
81
-            </Paragraph>
82
-          ) : (
83
-            <Paragraph>
84
-              {i18n.t('screens.vote.wait.messageDateUndefined')}
85
-            </Paragraph>
86
-          )}
87
-        </Card.Content>
88
-      </Card>
89
-    );
90
-  }
91
-}
92
-
93
-export default withTheme(VoteWait);

+ 80
- 0
src/components/Amicale/Vote/VoteWait.tsx View File

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
+
20
+import * as React from 'react';
21
+import {Avatar, Card, Paragraph, useTheme} from 'react-native-paper';
22
+import {StyleSheet} from 'react-native';
23
+import i18n from 'i18n-js';
24
+
25
+type PropsType = {
26
+  startDate: string | null;
27
+  justVoted: boolean;
28
+  hasVoted: boolean;
29
+  isVoteRunning: boolean;
30
+};
31
+
32
+const styles = StyleSheet.create({
33
+  card: {
34
+    margin: 10,
35
+  },
36
+  icon: {
37
+    backgroundColor: 'transparent',
38
+  },
39
+});
40
+
41
+export default function VoteWait(props: PropsType) {
42
+  const theme = useTheme();
43
+  const {startDate} = props;
44
+  return (
45
+    <Card style={styles.card}>
46
+      <Card.Title
47
+        title={
48
+          props.isVoteRunning
49
+            ? i18n.t('screens.vote.wait.titleSubmitted')
50
+            : i18n.t('screens.vote.wait.titleEnded')
51
+        }
52
+        subtitle={i18n.t('screens.vote.wait.subtitle')}
53
+        left={(iconProps) => (
54
+          <Avatar.Icon size={iconProps.size} icon="progress-check" />
55
+        )}
56
+      />
57
+      <Card.Content>
58
+        {props.justVoted ? (
59
+          <Paragraph style={{color: theme.colors.success}}>
60
+            {i18n.t('screens.vote.wait.messageSubmitted')}
61
+          </Paragraph>
62
+        ) : null}
63
+        {props.hasVoted ? (
64
+          <Paragraph style={{color: theme.colors.success}}>
65
+            {i18n.t('screens.vote.wait.messageVoted')}
66
+          </Paragraph>
67
+        ) : null}
68
+        {startDate != null ? (
69
+          <Paragraph>
70
+            {`${i18n.t('screens.vote.wait.messageDate')} ${startDate}`}
71
+          </Paragraph>
72
+        ) : (
73
+          <Paragraph>
74
+            {i18n.t('screens.vote.wait.messageDateUndefined')}
75
+          </Paragraph>
76
+        )}
77
+      </Card.Content>
78
+    </Card>
79
+  );
80
+}

+ 0
- 78
src/components/Collapsible/CollapsibleComponent.js View File

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
-
20
-// @flow
21
-
22
-import * as React from 'react';
23
-import {Collapsible} from 'react-navigation-collapsible';
24
-import withCollapsible from '../../utils/withCollapsible';
25
-import CustomTabBar from '../Tabbar/CustomTabBar';
26
-
27
-export type CollapsibleComponentPropsType = {
28
-  children?: React.Node,
29
-  hasTab?: boolean,
30
-  onScroll?: (event: SyntheticEvent<EventTarget>) => void,
31
-};
32
-
33
-type PropsType = {
34
-  ...CollapsibleComponentPropsType,
35
-  collapsibleStack: Collapsible,
36
-  // eslint-disable-next-line flowtype/no-weak-types
37
-  component: any,
38
-};
39
-
40
-class CollapsibleComponent extends React.Component<PropsType> {
41
-  static defaultProps = {
42
-    children: null,
43
-    hasTab: false,
44
-    onScroll: null,
45
-  };
46
-
47
-  onScroll = (event: SyntheticEvent<EventTarget>) => {
48
-    const {props} = this;
49
-    if (props.onScroll) props.onScroll(event);
50
-  };
51
-
52
-  render(): React.Node {
53
-    const {props} = this;
54
-    const Comp = props.component;
55
-    const {
56
-      containerPaddingTop,
57
-      scrollIndicatorInsetTop,
58
-      onScrollWithListener,
59
-    } = props.collapsibleStack;
60
-
61
-    return (
62
-      <Comp
63
-        // eslint-disable-next-line react/jsx-props-no-spreading
64
-        {...props}
65
-        onScroll={onScrollWithListener(this.onScroll)}
66
-        contentContainerStyle={{
67
-          paddingTop: containerPaddingTop,
68
-          paddingBottom: props.hasTab ? CustomTabBar.TAB_BAR_HEIGHT : 0,
69
-          minHeight: '100%',
70
-        }}
71
-        scrollIndicatorInsets={{top: scrollIndicatorInsetTop}}>
72
-        {props.children}
73
-      </Comp>
74
-    );
75
-  }
76
-}
77
-
78
-export default withCollapsible(CollapsibleComponent);

+ 63
- 0
src/components/Collapsible/CollapsibleComponent.tsx View File

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
+
20
+import * as React from 'react';
21
+import {useCollapsibleStack} from 'react-navigation-collapsible';
22
+import CustomTabBar from '../Tabbar/CustomTabBar';
23
+import {NativeScrollEvent, NativeSyntheticEvent} from 'react-native';
24
+
25
+export interface CollapsibleComponentPropsType {
26
+  children?: React.ReactNode;
27
+  hasTab?: boolean;
28
+  onScroll?: (event: NativeSyntheticEvent<NativeScrollEvent>) => void;
29
+}
30
+
31
+interface PropsType extends CollapsibleComponentPropsType {
32
+  component: React.ComponentType<any>;
33
+}
34
+
35
+function CollapsibleComponent(props: PropsType) {
36
+  const onScroll = (event: NativeSyntheticEvent<NativeScrollEvent>) => {
37
+    if (props.onScroll) {
38
+      props.onScroll(event);
39
+    }
40
+  };
41
+  const Comp = props.component;
42
+  const {
43
+    containerPaddingTop,
44
+    scrollIndicatorInsetTop,
45
+    onScrollWithListener,
46
+  } = useCollapsibleStack();
47
+
48
+  return (
49
+    <Comp
50
+      {...props}
51
+      onScroll={onScrollWithListener(onScroll)}
52
+      contentContainerStyle={{
53
+        paddingTop: containerPaddingTop,
54
+        paddingBottom: props.hasTab ? CustomTabBar.TAB_BAR_HEIGHT : 0,
55
+        minHeight: '100%',
56
+      }}
57
+      scrollIndicatorInsets={{top: scrollIndicatorInsetTop}}>
58
+      {props.children}
59
+    </Comp>
60
+  );
61
+}
62
+
63
+export default CollapsibleComponent;

src/components/Collapsible/CollapsibleFlatList.js → src/components/Collapsible/CollapsibleFlatList.tsx View File

17
  * along with Campus INSAT.  If not, see <https://www.gnu.org/licenses/>.
17
  * along with Campus INSAT.  If not, see <https://www.gnu.org/licenses/>.
18
  */
18
  */
19
 
19
 
20
-// @flow
21
-
22
 import * as React from 'react';
20
 import * as React from 'react';
23
-import {Animated} from 'react-native';
21
+import {Animated, FlatListProps} from 'react-native';
24
 import type {CollapsibleComponentPropsType} from './CollapsibleComponent';
22
 import type {CollapsibleComponentPropsType} from './CollapsibleComponent';
25
 import CollapsibleComponent from './CollapsibleComponent';
23
 import CollapsibleComponent from './CollapsibleComponent';
26
 
24
 
27
-type PropsType = {
28
-  ...CollapsibleComponentPropsType,
29
-};
25
+type Props<T> = FlatListProps<T> & CollapsibleComponentPropsType;
30
 
26
 
31
-// eslint-disable-next-line react/prefer-stateless-function
32
-class CollapsibleFlatList extends React.Component<PropsType> {
33
-  render(): React.Node {
34
-    const {props} = this;
35
-    return (
36
-      <CollapsibleComponent // eslint-disable-next-line react/jsx-props-no-spreading
37
-        {...props}
38
-        component={Animated.FlatList}>
39
-        {props.children}
40
-      </CollapsibleComponent>
41
-    );
42
-  }
27
+function CollapsibleFlatList<T>(props: Props<T>) {
28
+  return (
29
+    <CollapsibleComponent {...props} component={Animated.FlatList}>
30
+      {props.children}
31
+    </CollapsibleComponent>
32
+  );
43
 }
33
 }
44
 
34
 
45
 export default CollapsibleFlatList;
35
 export default CollapsibleFlatList;

src/components/Collapsible/CollapsibleScrollView.js → src/components/Collapsible/CollapsibleScrollView.tsx View File

17
  * along with Campus INSAT.  If not, see <https://www.gnu.org/licenses/>.
17
  * along with Campus INSAT.  If not, see <https://www.gnu.org/licenses/>.
18
  */
18
  */
19
 
19
 
20
-// @flow
21
-
22
 import * as React from 'react';
20
 import * as React from 'react';
23
-import {Animated} from 'react-native';
21
+import {Animated, ScrollViewProps} from 'react-native';
24
 import type {CollapsibleComponentPropsType} from './CollapsibleComponent';
22
 import type {CollapsibleComponentPropsType} from './CollapsibleComponent';
25
 import CollapsibleComponent from './CollapsibleComponent';
23
 import CollapsibleComponent from './CollapsibleComponent';
26
 
24
 
27
-type PropsType = {
28
-  ...CollapsibleComponentPropsType,
29
-};
25
+type Props = ScrollViewProps & CollapsibleComponentPropsType;
30
 
26
 
31
-// eslint-disable-next-line react/prefer-stateless-function
32
-class CollapsibleScrollView extends React.Component<PropsType> {
33
-  render(): React.Node {
34
-    const {props} = this;
35
-    return (
36
-      <CollapsibleComponent // eslint-disable-next-line react/jsx-props-no-spreading
37
-        {...props}
38
-        component={Animated.ScrollView}>
39
-        {props.children}
40
-      </CollapsibleComponent>
41
-    );
42
-  }
27
+function CollapsibleScrollView(props: Props) {
28
+  return (
29
+    <CollapsibleComponent {...props} component={Animated.ScrollView}>
30
+      {props.children}
31
+    </CollapsibleComponent>
32
+  );
43
 }
33
 }
44
 
34
 
45
 export default CollapsibleScrollView;
35
 export default CollapsibleScrollView;

src/components/Collapsible/CollapsibleSectionList.js → src/components/Collapsible/CollapsibleSectionList.tsx View File

17
  * along with Campus INSAT.  If not, see <https://www.gnu.org/licenses/>.
17
  * along with Campus INSAT.  If not, see <https://www.gnu.org/licenses/>.
18
  */
18
  */
19
 
19
 
20
-// @flow
21
-
22
 import * as React from 'react';
20
 import * as React from 'react';
23
-import {Animated} from 'react-native';
21
+import {Animated, SectionListProps} from 'react-native';
24
 import type {CollapsibleComponentPropsType} from './CollapsibleComponent';
22
 import type {CollapsibleComponentPropsType} from './CollapsibleComponent';
25
 import CollapsibleComponent from './CollapsibleComponent';
23
 import CollapsibleComponent from './CollapsibleComponent';
26
 
24
 
27
-type PropsType = {
28
-  ...CollapsibleComponentPropsType,
29
-};
25
+type Props<T> = SectionListProps<T> & CollapsibleComponentPropsType;
30
 
26
 
31
-// eslint-disable-next-line react/prefer-stateless-function
32
-class CollapsibleSectionList extends React.Component<PropsType> {
33
-  render(): React.Node {
34
-    const {props} = this;
35
-    return (
36
-      <CollapsibleComponent // eslint-disable-next-line react/jsx-props-no-spreading
37
-        {...props}
38
-        component={Animated.SectionList}>
39
-        {props.children}
40
-      </CollapsibleComponent>
41
-    );
42
-  }
27
+function CollapsibleSectionList<T>(props: Props<T>) {
28
+  return (
29
+    <CollapsibleComponent {...props} component={Animated.SectionList}>
30
+      {props.children}
31
+    </CollapsibleComponent>
32
+  );
43
 }
33
 }
44
 
34
 
45
 export default CollapsibleSectionList;
35
 export default CollapsibleSectionList;

src/components/Screens/BasicLoadingScreen.js → src/components/Screens/BasicLoadingScreen.tsx View File

21
 
21
 
22
 import * as React from 'react';
22
 import * as React from 'react';
23
 import {View} from 'react-native';
23
 import {View} from 'react-native';
24
-import {ActivityIndicator, withTheme} from 'react-native-paper';
25
-import type {CustomThemeType} from '../../managers/ThemeManager';
24
+import {ActivityIndicator, useTheme} from 'react-native-paper';
25
+
26
+type Props = {
27
+  isAbsolute?: boolean;
28
+};
26
 
29
 
27
 /**
30
 /**
28
  * Component used to display a header button
31
  * Component used to display a header button
30
  * @param props Props to pass to the component
33
  * @param props Props to pass to the component
31
  * @return {*}
34
  * @return {*}
32
  */
35
  */
33
-function BasicLoadingScreen(props: {
34
-  theme: CustomThemeType,
35
-  isAbsolute: boolean,
36
-}): React.Node {
37
-  const {theme, isAbsolute} = props;
38
-  const {colors} = theme;
39
-  let position;
40
-  if (isAbsolute != null && isAbsolute) position = 'absolute';
41
-
36
+export default function BasicLoadingScreen(props: Props) {
37
+  const theme = useTheme();
38
+  const {isAbsolute} = props;
42
   return (
39
   return (
43
     <View
40
     <View
44
       style={{
41
       style={{
45
-        backgroundColor: colors.background,
46
-        position,
42
+        backgroundColor: theme.colors.background,
43
+        position: isAbsolute ? 'absolute' : 'relative',
47
         top: 0,
44
         top: 0,
48
         right: 0,
45
         right: 0,
49
         width: '100%',
46
         width: '100%',
50
         height: '100%',
47
         height: '100%',
51
         justifyContent: 'center',
48
         justifyContent: 'center',
52
       }}>
49
       }}>
53
-      <ActivityIndicator animating size="large" color={colors.primary} />
50
+      <ActivityIndicator animating size="large" color={theme.colors.primary} />
54
     </View>
51
     </View>
55
   );
52
   );
56
 }
53
 }
57
-
58
-export default withTheme(BasicLoadingScreen);

src/components/Screens/ErrorView.js → src/components/Screens/ErrorView.tsx View File

17
  * along with Campus INSAT.  If not, see <https://www.gnu.org/licenses/>.
17
  * along with Campus INSAT.  If not, see <https://www.gnu.org/licenses/>.
18
  */
18
  */
19
 
19
 
20
-// @flow
21
-
22
 import * as React from 'react';
20
 import * as React from 'react';
23
 import {Button, Subheading, withTheme} from 'react-native-paper';
21
 import {Button, Subheading, withTheme} from 'react-native-paper';
24
 import {StyleSheet, View} from 'react-native';
22
 import {StyleSheet, View} from 'react-native';
27
 import * as Animatable from 'react-native-animatable';
25
 import * as Animatable from 'react-native-animatable';
28
 import {StackNavigationProp} from '@react-navigation/stack';
26
 import {StackNavigationProp} from '@react-navigation/stack';
29
 import {ERROR_TYPE} from '../../utils/WebData';
27
 import {ERROR_TYPE} from '../../utils/WebData';
30
-import type {CustomThemeType} from '../../managers/ThemeManager';
31
 
28
 
32
 type PropsType = {
29
 type PropsType = {
33
-  navigation: StackNavigationProp,
34
-  theme: CustomThemeType,
35
-  route: {name: string},
36
-  onRefresh?: () => void,
37
-  errorCode?: number,
38
-  icon?: string,
39
-  message?: string,
40
-  showRetryButton?: boolean,
30
+  navigation?: StackNavigationProp<any>;
31
+  theme: ReactNativePaper.Theme;
32
+  route?: {name: string};
33
+  onRefresh?: () => void;
34
+  errorCode?: number;
35
+  icon?: string;
36
+  message?: string;
37
+  showRetryButton?: boolean;
41
 };
38
 };
42
 
39
 
43
 const styles = StyleSheet.create({
40
 const styles = StyleSheet.create({
82
   constructor(props: PropsType) {
79
   constructor(props: PropsType) {
83
     super(props);
80
     super(props);
84
     this.icon = '';
81
     this.icon = '';
82
+    this.showLoginButton = false;
83
+    this.message = '';
85
   }
84
   }
86
 
85
 
87
-  getRetryButton(): React.Node {
86
+  getRetryButton() {
88
     const {props} = this;
87
     const {props} = this;
89
     return (
88
     return (
90
       <Button
89
       <Button
97
     );
96
     );
98
   }
97
   }
99
 
98
 
100
-  getLoginButton(): React.Node {
99
+  getLoginButton() {
101
     return (
100
     return (
102
       <Button
101
       <Button
103
         mode="contained"
102
         mode="contained"
111
 
110
 
112
   goToLogin = () => {
111
   goToLogin = () => {
113
     const {props} = this;
112
     const {props} = this;
114
-    props.navigation.navigate('login', {
115
-      screen: 'login',
116
-      params: {nextScreen: props.route.name},
117
-    });
113
+    if (props.navigation) {
114
+      props.navigation.navigate('login', {
115
+        screen: 'login',
116
+        params: {nextScreen: props.route ? props.route.name : undefined},
117
+      });
118
+    }
118
   };
119
   };
119
 
120
 
120
   generateMessage() {
121
   generateMessage() {
169
     }
170
     }
170
   }
171
   }
171
 
172
 
172
-  render(): React.Node {
173
+  render() {
173
     const {props} = this;
174
     const {props} = this;
174
     this.generateMessage();
175
     this.generateMessage();
175
     let button;
176
     let button;
176
-    if (this.showLoginButton) button = this.getLoginButton();
177
-    else if (props.showRetryButton) button = this.getRetryButton();
178
-    else button = null;
177
+    if (this.showLoginButton) {
178
+      button = this.getLoginButton();
179
+    } else if (props.showRetryButton) {
180
+      button = this.getRetryButton();
181
+    } else {
182
+      button = null;
183
+    }
179
 
184
 
180
     return (
185
     return (
181
       <Animatable.View
186
       <Animatable.View

src/screens/Amicale/VoteScreen.js → src/screens/Amicale/VoteScreen.tsx View File

17
  * along with Campus INSAT.  If not, see <https://www.gnu.org/licenses/>.
17
  * along with Campus INSAT.  If not, see <https://www.gnu.org/licenses/>.
18
  */
18
  */
19
 
19
 
20
-// @flow
21
-
22
 import * as React from 'react';
20
 import * as React from 'react';
23
 import {RefreshControl, View} from 'react-native';
21
 import {RefreshControl, View} from 'react-native';
24
 import {StackNavigationProp} from '@react-navigation/stack';
22
 import {StackNavigationProp} from '@react-navigation/stack';
35
 import AsyncStorageManager from '../../managers/AsyncStorageManager';
33
 import AsyncStorageManager from '../../managers/AsyncStorageManager';
36
 import VoteNotAvailable from '../../components/Amicale/Vote/VoteNotAvailable';
34
 import VoteNotAvailable from '../../components/Amicale/Vote/VoteNotAvailable';
37
 import CollapsibleFlatList from '../../components/Collapsible/CollapsibleFlatList';
35
 import CollapsibleFlatList from '../../components/Collapsible/CollapsibleFlatList';
38
-import type {ApiGenericDataType} from '../../utils/WebData';
39
 
36
 
40
 export type VoteTeamType = {
37
 export type VoteTeamType = {
41
-  id: number,
42
-  name: string,
43
-  votes: number,
38
+  id: number;
39
+  name: string;
40
+  votes: number;
44
 };
41
 };
45
 
42
 
46
 type TeamResponseType = {
43
 type TeamResponseType = {
47
-  has_voted: boolean,
48
-  teams: Array<VoteTeamType>,
44
+  has_voted: boolean;
45
+  teams: Array<VoteTeamType>;
49
 };
46
 };
50
 
47
 
51
 type VoteDatesStringType = {
48
 type VoteDatesStringType = {
52
-  date_begin: string,
53
-  date_end: string,
54
-  date_result_begin: string,
55
-  date_result_end: string,
49
+  date_begin: string;
50
+  date_end: string;
51
+  date_result_begin: string;
52
+  date_result_end: string;
56
 };
53
 };
57
 
54
 
58
 type VoteDatesObjectType = {
55
 type VoteDatesObjectType = {
59
-  date_begin: Date,
60
-  date_end: Date,
61
-  date_result_begin: Date,
62
-  date_result_end: Date,
56
+  date_begin: Date;
57
+  date_end: Date;
58
+  date_result_begin: Date;
59
+  date_result_end: Date;
63
 };
60
 };
64
 
61
 
65
 // const FAKE_DATE = {
62
 // const FAKE_DATE = {
113
 const MIN_REFRESH_TIME = 5 * 1000;
110
 const MIN_REFRESH_TIME = 5 * 1000;
114
 
111
 
115
 type PropsType = {
112
 type PropsType = {
116
-  navigation: StackNavigationProp,
113
+  navigation: StackNavigationProp<any>;
117
 };
114
 };
118
 
115
 
119
 type StateType = {
116
 type StateType = {
120
-  hasVoted: boolean,
121
-  mascotDialogVisible: boolean,
117
+  hasVoted: boolean;
118
+  mascotDialogVisible: boolean;
122
 };
119
 };
123
 
120
 
124
 /**
121
 /**
139
 
136
 
140
   lastRefresh: Date | null;
137
   lastRefresh: Date | null;
141
 
138
 
142
-  authRef: {current: null | AuthenticatedScreen};
139
+  authRef: {current: null | AuthenticatedScreen<any>};
143
 
140
 
144
-  constructor() {
145
-    super();
141
+  constructor(props: PropsType) {
142
+    super(props);
143
+    this.teams = [];
144
+    this.datesString = null;
145
+    this.dates = null;
146
     this.state = {
146
     this.state = {
147
       hasVoted: false,
147
       hasVoted: false,
148
       mascotDialogVisible: AsyncStorageManager.getBool(
148
       mascotDialogVisible: AsyncStorageManager.getBool(
174
     return dateString;
174
     return dateString;
175
   }
175
   }
176
 
176
 
177
-  getMainRenderItem = ({item}: {item: {key: string}}): React.Node => {
178
-    if (item.key === 'info')
177
+  getMainRenderItem = ({item}: {item: {key: string}}) => {
178
+    if (item.key === 'info') {
179
       return (
179
       return (
180
         <View>
180
         <View>
181
           <Button
181
           <Button
191
           </Button>
191
           </Button>
192
         </View>
192
         </View>
193
       );
193
       );
194
+    }
194
     return this.getContent();
195
     return this.getContent();
195
   };
196
   };
196
 
197
 
197
-  getScreen = (data: Array<ApiGenericDataType | null>): React.Node => {
198
+  getScreen = (data: Array<TeamResponseType | VoteDatesStringType | null>) => {
198
     const {state} = this;
199
     const {state} = this;
199
     // data[0] = FAKE_TEAMS2;
200
     // data[0] = FAKE_TEAMS2;
200
     // data[1] = FAKE_DATE;
201
     // data[1] = FAKE_DATE;
201
     this.lastRefresh = new Date();
202
     this.lastRefresh = new Date();
202
 
203
 
203
-    const teams: TeamResponseType | null = data[0];
204
-    const dateStrings: VoteDatesStringType | null = data[1];
204
+    const teams = data[0] as TeamResponseType | null;
205
+    const dateStrings = data[1] as VoteDatesStringType | null;
205
 
206
 
206
-    if (dateStrings != null && dateStrings.date_begin == null)
207
+    if (dateStrings != null && dateStrings.date_begin == null) {
207
       this.datesString = null;
208
       this.datesString = null;
208
-    else this.datesString = dateStrings;
209
+    } else {
210
+      this.datesString = dateStrings;
211
+    }
209
 
212
 
210
     if (teams != null) {
213
     if (teams != null) {
211
       this.teams = teams.teams;
214
       this.teams = teams.teams;
225
     );
228
     );
226
   };
229
   };
227
 
230
 
228
-  getContent(): React.Node {
231
+  getContent() {
229
     const {state} = this;
232
     const {state} = this;
230
-    if (!this.isVoteStarted()) return this.getTeaseVoteCard();
231
-    if (this.isVoteRunning() && !this.hasVoted && !state.hasVoted)
233
+    if (!this.isVoteStarted()) {
234
+      return this.getTeaseVoteCard();
235
+    }
236
+    if (this.isVoteRunning() && !this.hasVoted && !state.hasVoted) {
232
       return this.getVoteCard();
237
       return this.getVoteCard();
233
-    if (!this.isResultStarted()) return this.getWaitVoteCard();
234
-    if (this.isResultRunning()) return this.getVoteResultCard();
238
+    }
239
+    if (!this.isResultStarted()) {
240
+      return this.getWaitVoteCard();
241
+    }
242
+    if (this.isResultRunning()) {
243
+      return this.getVoteResultCard();
244
+    }
235
     return <VoteNotAvailable />;
245
     return <VoteNotAvailable />;
236
   }
246
   }
237
 
247
 
240
   /**
250
   /**
241
    * The user has not voted yet, and the votes are open
251
    * The user has not voted yet, and the votes are open
242
    */
252
    */
243
-  getVoteCard(): React.Node {
253
+  getVoteCard() {
244
     return (
254
     return (
245
       <VoteSelect
255
       <VoteSelect
246
         teams={this.teams}
256
         teams={this.teams}
253
   /**
263
   /**
254
    * Votes have ended, results can be displayed
264
    * Votes have ended, results can be displayed
255
    */
265
    */
256
-  getVoteResultCard(): React.Node {
257
-    if (this.dates != null && this.datesString != null)
266
+  getVoteResultCard() {
267
+    if (this.dates != null && this.datesString != null) {
258
       return (
268
       return (
259
         <VoteResults
269
         <VoteResults
260
           teams={this.teams}
270
           teams={this.teams}
264
           )}
274
           )}
265
         />
275
         />
266
       );
276
       );
277
+    }
267
     return <VoteNotAvailable />;
278
     return <VoteNotAvailable />;
268
   }
279
   }
269
 
280
 
270
   /**
281
   /**
271
    * Vote will open shortly
282
    * Vote will open shortly
272
    */
283
    */
273
-  getTeaseVoteCard(): React.Node {
274
-    if (this.dates != null && this.datesString != null)
284
+  getTeaseVoteCard() {
285
+    if (this.dates != null && this.datesString != null) {
275
       return (
286
       return (
276
         <VoteTease
287
         <VoteTease
277
           startDate={this.getDateString(
288
           startDate={this.getDateString(
280
           )}
291
           )}
281
         />
292
         />
282
       );
293
       );
294
+    }
283
     return <VoteNotAvailable />;
295
     return <VoteNotAvailable />;
284
   }
296
   }
285
 
297
 
286
   /**
298
   /**
287
    * Votes have ended, or user has voted waiting for results
299
    * Votes have ended, or user has voted waiting for results
288
    */
300
    */
289
-  getWaitVoteCard(): React.Node {
301
+  getWaitVoteCard() {
290
     const {state} = this;
302
     const {state} = this;
291
     let startDate = null;
303
     let startDate = null;
292
     if (
304
     if (
293
       this.dates != null &&
305
       this.dates != null &&
294
       this.datesString != null &&
306
       this.datesString != null &&
295
       this.dates.date_result_begin != null
307
       this.dates.date_result_begin != null
296
-    )
308
+    ) {
297
       startDate = this.getDateString(
309
       startDate = this.getDateString(
298
         this.dates.date_result_begin,
310
         this.dates.date_result_begin,
299
         this.datesString.date_result_begin,
311
         this.datesString.date_result_begin,
300
       );
312
       );
313
+    }
301
     return (
314
     return (
302
       <VoteWait
315
       <VoteWait
303
         startDate={startDate}
316
         startDate={startDate}
314
   reloadData = () => {
327
   reloadData = () => {
315
     let canRefresh;
328
     let canRefresh;
316
     const {lastRefresh} = this;
329
     const {lastRefresh} = this;
317
-    if (lastRefresh != null)
330
+    if (lastRefresh != null) {
318
       canRefresh =
331
       canRefresh =
319
         new Date().getTime() - lastRefresh.getTime() > MIN_REFRESH_TIME;
332
         new Date().getTime() - lastRefresh.getTime() > MIN_REFRESH_TIME;
320
-    else canRefresh = true;
321
-    if (canRefresh && this.authRef.current != null)
333
+    } else {
334
+      canRefresh = true;
335
+    }
336
+    if (canRefresh && this.authRef.current != null) {
322
       this.authRef.current.reload();
337
       this.authRef.current.reload();
338
+    }
323
   };
339
   };
324
 
340
 
325
   showMascotDialog = () => {
341
   showMascotDialog = () => {
380
           date_result_begin: dateResultBegin,
396
           date_result_begin: dateResultBegin,
381
           date_result_end: dateResultEnd,
397
           date_result_end: dateResultEnd,
382
         };
398
         };
383
-      } else this.dates = null;
384
-    } else this.dates = null;
399
+      } else {
400
+        this.dates = null;
401
+      }
402
+    } else {
403
+      this.dates = null;
404
+    }
385
   }
405
   }
386
 
406
 
387
   /**
407
   /**
391
    *
411
    *
392
    * @returns {*}
412
    * @returns {*}
393
    */
413
    */
394
-  render(): React.Node {
414
+  render() {
395
     const {props, state} = this;
415
     const {props, state} = this;
396
     return (
416
     return (
397
       <View style={{flex: 1}}>
417
       <View style={{flex: 1}}>
398
-        <AuthenticatedScreen
418
+        <AuthenticatedScreen<TeamResponseType | VoteDatesStringType>
399
           navigation={props.navigation}
419
           navigation={props.navigation}
400
           ref={this.authRef}
420
           ref={this.authRef}
401
           requests={[
421
           requests={[
418
           message={i18n.t('screens.vote.mascotDialog.message')}
438
           message={i18n.t('screens.vote.mascotDialog.message')}
419
           icon="vote"
439
           icon="vote"
420
           buttons={{
440
           buttons={{
421
-            action: null,
422
             cancel: {
441
             cancel: {
423
               message: i18n.t('screens.vote.mascotDialog.button'),
442
               message: i18n.t('screens.vote.mascotDialog.button'),
424
               icon: 'check',
443
               icon: 'check',

+ 1
- 3
src/utils/WebData.ts View File

35
   token: string;
35
   token: string;
36
 };
36
 };
37
 
37
 
38
-export type ApiGenericDataType = {[key: string]: any};
39
-
40
 type ApiResponseType<T> = {
38
 type ApiResponseType<T> = {
41
   error: number;
39
   error: number;
42
   data: T;
40
   data: T;
70
  * @param path The API path from the API endpoint
68
  * @param path The API path from the API endpoint
71
  * @param method The HTTP method to use (GET or POST)
69
  * @param method The HTTP method to use (GET or POST)
72
  * @param params The params to use for this request
70
  * @param params The params to use for this request
73
- * @returns {Promise<ApiGenericDataType>}
71
+ * @returns {Promise<T>}
74
  */
72
  */
75
 export async function apiRequest<T>(
73
 export async function apiRequest<T>(
76
   path: string,
74
   path: string,

Loading…
Cancel
Save