Browse Source

Update Home base components to use TypeScript

Arnaud Vergnet 3 years ago
parent
commit
e4530ded18

+ 0
- 75
src/components/Home/ActionsDashboardItem.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 {List, withTheme} from 'react-native-paper';
24
-import {View} from 'react-native';
25
-import i18n from 'i18n-js';
26
-import {StackNavigationProp} from '@react-navigation/stack';
27
-import type {CustomThemeType} from '../../managers/ThemeManager';
28
-import type {ListIconPropsType} from '../../constants/PaperStyles';
29
-
30
-type PropsType = {
31
-  navigation: StackNavigationProp,
32
-  theme: CustomThemeType,
33
-};
34
-
35
-class ActionsDashBoardItem extends React.Component<PropsType> {
36
-  shouldComponentUpdate(nextProps: PropsType): boolean {
37
-    const {props} = this;
38
-    return nextProps.theme.dark !== props.theme.dark;
39
-  }
40
-
41
-  render(): React.Node {
42
-    const {navigation} = this.props;
43
-    return (
44
-      <View>
45
-        <List.Item
46
-          title={i18n.t('screens.feedback.homeButtonTitle')}
47
-          description={i18n.t('screens.feedback.homeButtonSubtitle')}
48
-          left={(props: ListIconPropsType): React.Node => (
49
-            <List.Icon
50
-              color={props.color}
51
-              style={props.style}
52
-              icon="comment-quote"
53
-            />
54
-          )}
55
-          right={(props: ListIconPropsType): React.Node => (
56
-            <List.Icon
57
-              color={props.color}
58
-              style={props.style}
59
-              icon="chevron-right"
60
-            />
61
-          )}
62
-          onPress={(): void => navigation.navigate('feedback')}
63
-          style={{
64
-            paddingTop: 0,
65
-            paddingBottom: 0,
66
-            marginLeft: 10,
67
-            marginRight: 10,
68
-          }}
69
-        />
70
-      </View>
71
-    );
72
-  }
73
-}
74
-
75
-export default withTheme(ActionsDashBoardItem);

+ 59
- 0
src/components/Home/ActionsDashboardItem.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 {List} from 'react-native-paper';
22
+import {View} from 'react-native';
23
+import i18n from 'i18n-js';
24
+import {useNavigation} from '@react-navigation/native';
25
+
26
+function ActionsDashBoardItem() {
27
+  const navigation = useNavigation();
28
+  return (
29
+    <View>
30
+      <List.Item
31
+        title={i18n.t('screens.feedback.homeButtonTitle')}
32
+        description={i18n.t('screens.feedback.homeButtonSubtitle')}
33
+        left={(props) => (
34
+          <List.Icon
35
+            color={props.color}
36
+            style={props.style}
37
+            icon="comment-quote"
38
+          />
39
+        )}
40
+        right={(props) => (
41
+          <List.Icon
42
+            color={props.color}
43
+            style={props.style}
44
+            icon="chevron-right"
45
+          />
46
+        )}
47
+        onPress={(): void => navigation.navigate('feedback')}
48
+        style={{
49
+          paddingTop: 0,
50
+          paddingBottom: 0,
51
+          marginLeft: 10,
52
+          marginRight: 10,
53
+        }}
54
+      />
55
+    </View>
56
+  );
57
+}
58
+
59
+export default ActionsDashBoardItem;

+ 0
- 116
src/components/Home/EventDashboardItem.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 {
24
-  Avatar,
25
-  Card,
26
-  Text,
27
-  TouchableRipple,
28
-  withTheme,
29
-} from 'react-native-paper';
30
-import {StyleSheet, View} from 'react-native';
31
-import i18n from 'i18n-js';
32
-import type {CustomThemeType} from '../../managers/ThemeManager';
33
-import type {CardTitleIconPropsType} from '../../constants/PaperStyles';
34
-
35
-type PropsType = {
36
-  eventNumber: number,
37
-  clickAction: () => void,
38
-  theme: CustomThemeType,
39
-  children?: React.Node,
40
-};
41
-
42
-const styles = StyleSheet.create({
43
-  card: {
44
-    width: 'auto',
45
-    marginLeft: 10,
46
-    marginRight: 10,
47
-    marginTop: 10,
48
-    overflow: 'hidden',
49
-  },
50
-  avatar: {
51
-    backgroundColor: 'transparent',
52
-  },
53
-});
54
-
55
-/**
56
- * Component used to display a dashboard item containing a preview event
57
- */
58
-class EventDashBoardItem extends React.Component<PropsType> {
59
-  static defaultProps = {
60
-    children: null,
61
-  };
62
-
63
-  shouldComponentUpdate(nextProps: PropsType): boolean {
64
-    const {props} = this;
65
-    return (
66
-      nextProps.theme.dark !== props.theme.dark ||
67
-      nextProps.eventNumber !== props.eventNumber
68
-    );
69
-  }
70
-
71
-  render(): React.Node {
72
-    const {props} = this;
73
-    const {colors} = props.theme;
74
-    const isAvailable = props.eventNumber > 0;
75
-    const iconColor = isAvailable ? colors.planningColor : colors.textDisabled;
76
-    const textColor = isAvailable ? colors.text : colors.textDisabled;
77
-    let subtitle;
78
-    if (isAvailable) {
79
-      subtitle = (
80
-        <Text>
81
-          <Text style={{fontWeight: 'bold'}}>{props.eventNumber}</Text>
82
-          <Text>
83
-            {props.eventNumber > 1
84
-              ? i18n.t('screens.home.dashboard.todayEventsSubtitlePlural')
85
-              : i18n.t('screens.home.dashboard.todayEventsSubtitle')}
86
-          </Text>
87
-        </Text>
88
-      );
89
-    } else subtitle = i18n.t('screens.home.dashboard.todayEventsSubtitleNA');
90
-    return (
91
-      <Card style={styles.card}>
92
-        <TouchableRipple style={{flex: 1}} onPress={props.clickAction}>
93
-          <View>
94
-            <Card.Title
95
-              title={i18n.t('screens.home.dashboard.todayEventsTitle')}
96
-              titleStyle={{color: textColor}}
97
-              subtitle={subtitle}
98
-              subtitleStyle={{color: textColor}}
99
-              left={(iconProps: CardTitleIconPropsType): React.Node => (
100
-                <Avatar.Icon
101
-                  icon="calendar-range"
102
-                  color={iconColor}
103
-                  size={iconProps.size}
104
-                  style={styles.avatar}
105
-                />
106
-              )}
107
-            />
108
-            <Card.Content>{props.children}</Card.Content>
109
-          </View>
110
-        </TouchableRipple>
111
-      </Card>
112
-    );
113
-  }
114
-}
115
-
116
-export default withTheme(EventDashBoardItem);

+ 104
- 0
src/components/Home/EventDashboardItem.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 {
22
+  Avatar,
23
+  Card,
24
+  Text,
25
+  TouchableRipple,
26
+  useTheme,
27
+} from 'react-native-paper';
28
+import {StyleSheet, View} from 'react-native';
29
+import i18n from 'i18n-js';
30
+
31
+type PropsType = {
32
+  eventNumber: number;
33
+  clickAction: () => void;
34
+  children?: React.ReactNode;
35
+};
36
+
37
+const styles = StyleSheet.create({
38
+  card: {
39
+    width: 'auto',
40
+    marginLeft: 10,
41
+    marginRight: 10,
42
+    marginTop: 10,
43
+    overflow: 'hidden',
44
+  },
45
+  avatar: {
46
+    backgroundColor: 'transparent',
47
+  },
48
+});
49
+
50
+/**
51
+ * Component used to display a dashboard item containing a preview event
52
+ */
53
+function EventDashBoardItem(props: PropsType) {
54
+  const theme = useTheme();
55
+  const isAvailable = props.eventNumber > 0;
56
+  const iconColor = isAvailable
57
+    ? theme.colors.planningColor
58
+    : theme.colors.textDisabled;
59
+  const textColor = isAvailable ? theme.colors.text : theme.colors.textDisabled;
60
+  let subtitle;
61
+  if (isAvailable) {
62
+    subtitle = (
63
+      <Text>
64
+        <Text style={{fontWeight: 'bold'}}>{props.eventNumber}</Text>
65
+        <Text>
66
+          {props.eventNumber > 1
67
+            ? i18n.t('screens.home.dashboard.todayEventsSubtitlePlural')
68
+            : i18n.t('screens.home.dashboard.todayEventsSubtitle')}
69
+        </Text>
70
+      </Text>
71
+    );
72
+  } else {
73
+    subtitle = i18n.t('screens.home.dashboard.todayEventsSubtitleNA');
74
+  }
75
+  return (
76
+    <Card style={styles.card}>
77
+      <TouchableRipple style={{flex: 1}} onPress={props.clickAction}>
78
+        <View>
79
+          <Card.Title
80
+            title={i18n.t('screens.home.dashboard.todayEventsTitle')}
81
+            titleStyle={{color: textColor}}
82
+            subtitle={subtitle}
83
+            subtitleStyle={{color: textColor}}
84
+            left={(iconProps) => (
85
+              <Avatar.Icon
86
+                icon="calendar-range"
87
+                color={iconColor}
88
+                size={iconProps.size}
89
+                style={styles.avatar}
90
+              />
91
+            )}
92
+          />
93
+          <Card.Content>{props.children}</Card.Content>
94
+        </View>
95
+      </TouchableRipple>
96
+    </Card>
97
+  );
98
+}
99
+
100
+const areEqual = (prevProps: PropsType, nextProps: PropsType): boolean => {
101
+  return nextProps.eventNumber !== prevProps.eventNumber;
102
+};
103
+
104
+export default React.memo(EventDashBoardItem, areEqual);

+ 0
- 139
src/components/Home/FeedItem.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 {Button, Card, Text, TouchableRipple} from 'react-native-paper';
24
-import {Image, View} from 'react-native';
25
-import Autolink from 'react-native-autolink';
26
-import i18n from 'i18n-js';
27
-import {StackNavigationProp} from '@react-navigation/stack';
28
-import type {FeedItemType} from '../../screens/Home/HomeScreen';
29
-import NewsSourcesConstants from '../../constants/NewsSourcesConstants';
30
-import type {NewsSourceType} from '../../constants/NewsSourcesConstants';
31
-import ImageGalleryButton from '../Media/ImageGalleryButton';
32
-
33
-type PropsType = {
34
-  navigation: StackNavigationProp,
35
-  item: FeedItemType,
36
-  height: number,
37
-};
38
-
39
-/**
40
- * Component used to display a feed item
41
- */
42
-class FeedItem extends React.Component<PropsType> {
43
-  /**
44
-   * Converts a dateString using Unix Timestamp to a formatted date
45
-   *
46
-   * @param dateString {string} The Unix Timestamp representation of a date
47
-   * @return {string} The formatted output date
48
-   */
49
-  static getFormattedDate(dateString: number): string {
50
-    const date = new Date(dateString * 1000);
51
-    return date.toLocaleString();
52
-  }
53
-
54
-  shouldComponentUpdate(): boolean {
55
-    return false;
56
-  }
57
-
58
-  onPress = () => {
59
-    const {item, navigation} = this.props;
60
-    navigation.navigate('feed-information', {
61
-      data: item,
62
-      date: FeedItem.getFormattedDate(item.time),
63
-    });
64
-  };
65
-
66
-  render(): React.Node {
67
-    const {item, height, navigation} = this.props;
68
-    const image = item.image !== '' && item.image != null ? item.image : null;
69
-    const pageSource: NewsSourceType = NewsSourcesConstants[item.page_id];
70
-    const cardMargin = 10;
71
-    const cardHeight = height - 2 * cardMargin;
72
-    const imageSize = 250;
73
-    const titleHeight = 80;
74
-    const actionsHeight = 60;
75
-    const textHeight =
76
-      image != null
77
-        ? cardHeight - titleHeight - actionsHeight - imageSize
78
-        : cardHeight - titleHeight - actionsHeight;
79
-    return (
80
-      <Card
81
-        style={{
82
-          margin: cardMargin,
83
-          height: cardHeight,
84
-        }}>
85
-        <TouchableRipple style={{flex: 1}} onPress={this.onPress}>
86
-          <View>
87
-            <Card.Title
88
-              title={pageSource.name}
89
-              subtitle={FeedItem.getFormattedDate(item.time)}
90
-              left={(): React.Node => (
91
-                <Image
92
-                  size={48}
93
-                  source={pageSource.icon}
94
-                  style={{
95
-                    width: 48,
96
-                    height: 48,
97
-                  }}
98
-                />
99
-              )}
100
-              style={{height: titleHeight}}
101
-            />
102
-            {image != null ? (
103
-              <ImageGalleryButton
104
-                navigation={navigation}
105
-                images={[{url: image}]}
106
-                style={{
107
-                  width: imageSize,
108
-                  height: imageSize,
109
-                  marginLeft: 'auto',
110
-                  marginRight: 'auto',
111
-                }}
112
-              />
113
-            ) : null}
114
-            <Card.Content>
115
-              {item.message !== undefined ? (
116
-                <Autolink
117
-                  text={item.message}
118
-                  hashtag="facebook"
119
-                  component={Text}
120
-                  style={{height: textHeight}}
121
-                />
122
-              ) : null}
123
-            </Card.Content>
124
-            <Card.Actions style={{height: actionsHeight}}>
125
-              <Button
126
-                onPress={this.onPress}
127
-                icon="plus"
128
-                style={{marginLeft: 'auto'}}>
129
-                {i18n.t('screens.home.dashboard.seeMore')}
130
-              </Button>
131
-            </Card.Actions>
132
-          </View>
133
-        </TouchableRipple>
134
-      </Card>
135
-    );
136
-  }
137
-}
138
-
139
-export default FeedItem;

+ 128
- 0
src/components/Home/FeedItem.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 {Button, Card, Text, TouchableRipple} from 'react-native-paper';
22
+import {Image, View} from 'react-native';
23
+import Autolink from 'react-native-autolink';
24
+import i18n from 'i18n-js';
25
+import type {FeedItemType} from '../../screens/Home/HomeScreen';
26
+import NewsSourcesConstants, {
27
+  AvailablePages,
28
+} from '../../constants/NewsSourcesConstants';
29
+import type {NewsSourceType} from '../../constants/NewsSourcesConstants';
30
+import ImageGalleryButton from '../Media/ImageGalleryButton';
31
+import {useNavigation} from '@react-navigation/native';
32
+
33
+type PropsType = {
34
+  item: FeedItemType;
35
+  height: number;
36
+};
37
+
38
+/**
39
+ * Converts a dateString using Unix Timestamp to a formatted date
40
+ *
41
+ * @param dateString {string} The Unix Timestamp representation of a date
42
+ * @return {string} The formatted output date
43
+ */
44
+function getFormattedDate(dateString: number): string {
45
+  const date = new Date(dateString * 1000);
46
+  return date.toLocaleString();
47
+}
48
+
49
+/**
50
+ * Component used to display a feed item
51
+ */
52
+function FeedItem(props: PropsType) {
53
+  const navigation = useNavigation();
54
+  const onPress = () => {
55
+    navigation.navigate('feed-information', {
56
+      data: item,
57
+      date: getFormattedDate(props.item.time),
58
+    });
59
+  };
60
+
61
+  const {item, height} = props;
62
+  const image = item.image !== '' && item.image != null ? item.image : null;
63
+  const pageSource: NewsSourceType =
64
+    NewsSourcesConstants[item.page_id as AvailablePages];
65
+  const cardMargin = 10;
66
+  const cardHeight = height - 2 * cardMargin;
67
+  const imageSize = 250;
68
+  const titleHeight = 80;
69
+  const actionsHeight = 60;
70
+  const textHeight =
71
+    image != null
72
+      ? cardHeight - titleHeight - actionsHeight - imageSize
73
+      : cardHeight - titleHeight - actionsHeight;
74
+  return (
75
+    <Card
76
+      style={{
77
+        margin: cardMargin,
78
+        height: cardHeight,
79
+      }}>
80
+      <TouchableRipple style={{flex: 1}} onPress={onPress}>
81
+        <View>
82
+          <Card.Title
83
+            title={pageSource.name}
84
+            subtitle={getFormattedDate(item.time)}
85
+            left={() => (
86
+              <Image
87
+                source={pageSource.icon}
88
+                style={{
89
+                  width: 48,
90
+                  height: 48,
91
+                }}
92
+              />
93
+            )}
94
+            style={{height: titleHeight}}
95
+          />
96
+          {image != null ? (
97
+            <ImageGalleryButton
98
+              images={[{url: image}]}
99
+              style={{
100
+                width: imageSize,
101
+                height: imageSize,
102
+                marginLeft: 'auto',
103
+                marginRight: 'auto',
104
+              }}
105
+            />
106
+          ) : null}
107
+          <Card.Content>
108
+            {item.message !== undefined ? (
109
+              <Autolink<typeof Text>
110
+                text={item.message}
111
+                hashtag="facebook"
112
+                component={Text}
113
+                style={{height: textHeight}}
114
+              />
115
+            ) : null}
116
+          </Card.Content>
117
+          <Card.Actions style={{height: actionsHeight}}>
118
+            <Button onPress={onPress} icon="plus" style={{marginLeft: 'auto'}}>
119
+              {i18n.t('screens.home.dashboard.seeMore')}
120
+            </Button>
121
+          </Card.Actions>
122
+        </View>
123
+      </TouchableRipple>
124
+    </Card>
125
+  );
126
+}
127
+
128
+export default React.memo(FeedItem, () => true);

+ 0
- 113
src/components/Home/PreviewEventDashboardItem.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 {StyleSheet, View} from 'react-native';
24
-import i18n from 'i18n-js';
25
-import {Avatar, Button, Card, TouchableRipple} from 'react-native-paper';
26
-import {getTimeOnlyString, isDescriptionEmpty} from '../../utils/Planning';
27
-import CustomHTML from '../Overrides/CustomHTML';
28
-import type {PlanningEventType} from '../../utils/Planning';
29
-
30
-type PropsType = {
31
-  event?: PlanningEventType | null,
32
-  clickAction: () => void,
33
-};
34
-
35
-const styles = StyleSheet.create({
36
-  card: {
37
-    marginBottom: 10,
38
-  },
39
-  content: {
40
-    maxHeight: 150,
41
-    overflow: 'hidden',
42
-  },
43
-  actions: {
44
-    marginLeft: 'auto',
45
-    marginTop: 'auto',
46
-    flexDirection: 'row',
47
-  },
48
-  avatar: {
49
-    backgroundColor: 'transparent',
50
-  },
51
-});
52
-
53
-/**
54
- * Component used to display an event preview if an event is available
55
- */
56
-// eslint-disable-next-line react/prefer-stateless-function
57
-class PreviewEventDashboardItem extends React.Component<PropsType> {
58
-  static defaultProps = {
59
-    event: null,
60
-  };
61
-
62
-  render(): React.Node {
63
-    const {props} = this;
64
-    const {event} = props;
65
-    const isEmpty =
66
-      event == null ? true : isDescriptionEmpty(event.description);
67
-
68
-    if (event != null) {
69
-      const hasImage = event.logo !== '' && event.logo != null;
70
-      const getImage = (): React.Node => (
71
-        <Avatar.Image
72
-          source={{uri: event.logo}}
73
-          size={50}
74
-          style={styles.avatar}
75
-        />
76
-      );
77
-      return (
78
-        <Card style={styles.card} elevation={3}>
79
-          <TouchableRipple style={{flex: 1}} onPress={props.clickAction}>
80
-            <View>
81
-              {hasImage ? (
82
-                <Card.Title
83
-                  title={event.title}
84
-                  subtitle={getTimeOnlyString(event.date_begin)}
85
-                  left={getImage}
86
-                />
87
-              ) : (
88
-                <Card.Title
89
-                  title={event.title}
90
-                  subtitle={getTimeOnlyString(event.date_begin)}
91
-                />
92
-              )}
93
-              {!isEmpty ? (
94
-                <Card.Content style={styles.content}>
95
-                  <CustomHTML html={event.description} />
96
-                </Card.Content>
97
-              ) : null}
98
-
99
-              <Card.Actions style={styles.actions}>
100
-                <Button icon="chevron-right">
101
-                  {i18n.t('screens.home.dashboard.seeMore')}
102
-                </Button>
103
-              </Card.Actions>
104
-            </View>
105
-          </TouchableRipple>
106
-        </Card>
107
-      );
108
-    }
109
-    return null;
110
-  }
111
-}
112
-
113
-export default PreviewEventDashboardItem;

+ 93
- 0
src/components/Home/PreviewEventDashboardItem.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 {StyleSheet, View} from 'react-native';
22
+import i18n from 'i18n-js';
23
+import {Avatar, Button, Card, TouchableRipple} from 'react-native-paper';
24
+import {getTimeOnlyString, isDescriptionEmpty} from '../../utils/Planning';
25
+import CustomHTML from '../Overrides/CustomHTML';
26
+import type {PlanningEventType} from '../../utils/Planning';
27
+
28
+type PropsType = {
29
+  event?: PlanningEventType | null;
30
+  clickAction: () => void;
31
+};
32
+
33
+const styles = StyleSheet.create({
34
+  card: {
35
+    marginBottom: 10,
36
+  },
37
+  content: {
38
+    maxHeight: 150,
39
+    overflow: 'hidden',
40
+  },
41
+  actions: {
42
+    marginLeft: 'auto',
43
+    marginTop: 'auto',
44
+    flexDirection: 'row',
45
+  },
46
+  avatar: {
47
+    backgroundColor: 'transparent',
48
+  },
49
+});
50
+
51
+/**
52
+ * Component used to display an event preview if an event is available
53
+ */
54
+function PreviewEventDashboardItem(props: PropsType) {
55
+  const {event} = props;
56
+  const isEmpty = event == null ? true : isDescriptionEmpty(event.description);
57
+
58
+  if (event != null) {
59
+    const logo = event.logo;
60
+    const getImage = logo
61
+      ? () => (
62
+          <Avatar.Image source={{uri: logo}} size={50} style={styles.avatar} />
63
+        )
64
+      : () => null;
65
+    return (
66
+      <Card style={styles.card} elevation={3}>
67
+        <TouchableRipple style={{flex: 1}} onPress={props.clickAction}>
68
+          <View>
69
+            <Card.Title
70
+              title={event.title}
71
+              subtitle={getTimeOnlyString(event.date_begin)}
72
+              left={getImage}
73
+            />
74
+            {!isEmpty ? (
75
+              <Card.Content style={styles.content}>
76
+                <CustomHTML html={event.description} />
77
+              </Card.Content>
78
+            ) : null}
79
+
80
+            <Card.Actions style={styles.actions}>
81
+              <Button icon="chevron-right">
82
+                {i18n.t('screens.home.dashboard.seeMore')}
83
+              </Button>
84
+            </Card.Actions>
85
+          </View>
86
+        </TouchableRipple>
87
+      </Card>
88
+    );
89
+  }
90
+  return null;
91
+}
92
+
93
+export default PreviewEventDashboardItem;

+ 0
- 106
src/components/Home/SmallDashboardItem.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 {Badge, TouchableRipple, withTheme} from 'react-native-paper';
24
-import {Dimensions, Image, View} from 'react-native';
25
-import * as Animatable from 'react-native-animatable';
26
-import type {CustomThemeType} from '../../managers/ThemeManager';
27
-
28
-type PropsType = {
29
-  image: string | null,
30
-  onPress: () => void | null,
31
-  badgeCount: number | null,
32
-  theme: CustomThemeType,
33
-};
34
-
35
-/**
36
- * Component used to render a small dashboard item
37
- */
38
-class SmallDashboardItem extends React.Component<PropsType> {
39
-  itemSize: number;
40
-
41
-  constructor(props: PropsType) {
42
-    super(props);
43
-    this.itemSize = Dimensions.get('window').width / 8;
44
-  }
45
-
46
-  shouldComponentUpdate(nextProps: PropsType): boolean {
47
-    const {props} = this;
48
-    return (
49
-      nextProps.theme.dark !== props.theme.dark ||
50
-      nextProps.badgeCount !== props.badgeCount
51
-    );
52
-  }
53
-
54
-  render(): React.Node {
55
-    const {props} = this;
56
-    return (
57
-      <TouchableRipple
58
-        onPress={props.onPress}
59
-        borderless
60
-        style={{
61
-          marginLeft: this.itemSize / 6,
62
-          marginRight: this.itemSize / 6,
63
-        }}>
64
-        <View
65
-          style={{
66
-            width: this.itemSize,
67
-            height: this.itemSize,
68
-          }}>
69
-          <Image
70
-            source={{uri: props.image}}
71
-            style={{
72
-              width: '80%',
73
-              height: '80%',
74
-              marginLeft: 'auto',
75
-              marginRight: 'auto',
76
-              marginTop: 'auto',
77
-              marginBottom: 'auto',
78
-            }}
79
-          />
80
-          {props.badgeCount != null && props.badgeCount > 0 ? (
81
-            <Animatable.View
82
-              animation="zoomIn"
83
-              duration={300}
84
-              useNativeDriver
85
-              style={{
86
-                position: 'absolute',
87
-                top: 0,
88
-                right: 0,
89
-              }}>
90
-              <Badge
91
-                style={{
92
-                  backgroundColor: props.theme.colors.primary,
93
-                  borderColor: props.theme.colors.background,
94
-                  borderWidth: 2,
95
-                }}>
96
-                {props.badgeCount}
97
-              </Badge>
98
-            </Animatable.View>
99
-          ) : null}
100
-        </View>
101
-      </TouchableRipple>
102
-    );
103
-  }
104
-}
105
-
106
-export default withTheme(SmallDashboardItem);

+ 94
- 0
src/components/Home/SmallDashboardItem.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 {Badge, TouchableRipple, useTheme} from 'react-native-paper';
22
+import {Dimensions, Image, View} from 'react-native';
23
+import * as Animatable from 'react-native-animatable';
24
+
25
+type PropsType = {
26
+  image: string | null;
27
+  onPress: () => void | null;
28
+  badgeCount: number | null;
29
+};
30
+
31
+/**
32
+ * Component used to render a small dashboard item
33
+ */
34
+function SmallDashboardItem(props: PropsType) {
35
+  const itemSize = Dimensions.get('window').width / 8;
36
+  const theme = useTheme();
37
+  const {image} = props;
38
+  return (
39
+    <TouchableRipple
40
+      onPress={props.onPress}
41
+      borderless
42
+      style={{
43
+        marginLeft: itemSize / 6,
44
+        marginRight: itemSize / 6,
45
+      }}>
46
+      <View
47
+        style={{
48
+          width: itemSize,
49
+          height: itemSize,
50
+        }}>
51
+        {image ? (
52
+          <Image
53
+            source={{uri: image}}
54
+            style={{
55
+              width: '80%',
56
+              height: '80%',
57
+              marginLeft: 'auto',
58
+              marginRight: 'auto',
59
+              marginTop: 'auto',
60
+              marginBottom: 'auto',
61
+            }}
62
+          />
63
+        ) : null}
64
+        {props.badgeCount != null && props.badgeCount > 0 ? (
65
+          <Animatable.View
66
+            animation="zoomIn"
67
+            duration={300}
68
+            useNativeDriver
69
+            style={{
70
+              position: 'absolute',
71
+              top: 0,
72
+              right: 0,
73
+            }}>
74
+            <Badge
75
+              visible={true}
76
+              style={{
77
+                backgroundColor: theme.colors.primary,
78
+                borderColor: theme.colors.background,
79
+                borderWidth: 2,
80
+              }}>
81
+              {props.badgeCount}
82
+            </Badge>
83
+          </Animatable.View>
84
+        ) : null}
85
+      </View>
86
+    </TouchableRipple>
87
+  );
88
+}
89
+
90
+const areEqual = (prevProps: PropsType, nextProps: PropsType): boolean => {
91
+  return nextProps.badgeCount !== prevProps.badgeCount;
92
+};
93
+
94
+export default React.memo(SmallDashboardItem, areEqual);

+ 2
- 0
src/constants/NewsSourcesConstants.ts View File

27
   name: string;
27
   name: string;
28
 };
28
 };
29
 
29
 
30
+export type AvailablePages = 'amicale.deseleves' | 'campus.insat';
31
+
30
 export default {
32
 export default {
31
   'amicale.deseleves': {
33
   'amicale.deseleves': {
32
     icon: ICON_AMICALE,
34
     icon: ICON_AMICALE,

Loading…
Cancel
Save