Browse Source

Added club list

Arnaud Vergnet 1 year ago
parent
commit
a42d743aeb

+ 6
- 0
components/Sidebar/Sidebar.js View File

@@ -65,6 +65,12 @@ class SideBar extends React.PureComponent<Props, State> {
65 65
                 onlyWhenLoggedIn: true,
66 66
             },
67 67
             {
68
+                name: "CLUBS",
69
+                route: "ClubListScreen",
70
+                icon: "account-group",
71
+                onlyWhenLoggedIn: true,
72
+            },
73
+            {
68 74
                 name: i18n.t('screens.logout'),
69 75
                 route: 'disconnect',
70 76
                 action: this.showDisconnectDialog,

+ 43
- 0
navigation/DrawerNavigator.js View File

@@ -17,6 +17,8 @@ import HeaderButton from "../components/Custom/HeaderButton";
17 17
 import i18n from "i18n-js";
18 18
 import LoginScreen from "../screens/Amicale/LoginScreen";
19 19
 import ProfileScreen from "../screens/Amicale/ProfileScreen";
20
+import ClubListScreen from "../screens/Amicale/ClubListScreen";
21
+import ClubDisplayScreen from "../screens/Amicale/ClubDisplayScreen";
20 22
 
21 23
 const defaultScreenOptions = {
22 24
     gestureEnabled: true,
@@ -236,6 +238,43 @@ function ProfileStackComponent() {
236 238
     );
237 239
 }
238 240
 
241
+const ClubStack = createStackNavigator();
242
+
243
+function ClubStackComponent() {
244
+    return (
245
+        <ClubStack.Navigator
246
+            initialRouteName="ClubListScreen"
247
+            headerMode="float"
248
+            screenOptions={defaultScreenOptions}
249
+        >
250
+            <ClubStack.Screen
251
+                name="ClubListScreen"
252
+                component={ClubListScreen}
253
+                options={({navigation}) => {
254
+                    const openDrawer = getDrawerButton.bind(this, navigation);
255
+                    return {
256
+                        title: "CLUBS LIST",
257
+                        headerLeft: openDrawer
258
+                    };
259
+                }}
260
+            />
261
+            <ClubStack.Screen
262
+                name="ClubDisplayScreen"
263
+                component={ClubDisplayScreen}
264
+                options={({navigation}) => {
265
+                    const openDrawer = getDrawerButton.bind(this, navigation);
266
+                    return {
267
+                        title: "CLUBS DISPLAY",
268
+                        headerLeft: openDrawer,
269
+                        ...TransitionPresets.ModalSlideFromBottomIOS,
270
+                    };
271
+                }}
272
+            />
273
+        </ClubStack.Navigator>
274
+    );
275
+}
276
+
277
+
239 278
 const Drawer = createDrawerNavigator();
240 279
 
241 280
 function getDrawerContent(props) {
@@ -289,6 +328,10 @@ export default function DrawerNavigator() {
289 328
                 name="ProfileScreen"
290 329
                 component={ProfileStackComponent}
291 330
             />
331
+            <Drawer.Screen
332
+                name="ClubListScreen"
333
+                component={ClubStackComponent}
334
+            />
292 335
         </Drawer.Navigator>
293 336
     );
294 337
 }

+ 113
- 0
screens/Amicale/ClubDisplayScreen.js View File

@@ -0,0 +1,113 @@
1
+// @flow
2
+
3
+import * as React from 'react';
4
+import {Image, ScrollView, TouchableOpacity, View} from 'react-native';
5
+import HTML from "react-native-render-html";
6
+import {Linking} from "expo";
7
+import {Avatar, Card, Paragraph, Portal, withTheme} from 'react-native-paper';
8
+import ImageView from "react-native-image-viewing";
9
+
10
+type Props = {
11
+    navigation: Object,
12
+    route: Object
13
+};
14
+
15
+type State = {
16
+    imageModalVisible: boolean,
17
+};
18
+
19
+function openWebLink(event, link) {
20
+    Linking.openURL(link).catch((err) => console.error('Error opening link', err));
21
+}
22
+
23
+/**
24
+ * Class defining a planning event information page.
25
+ */
26
+class ClubDisplayScreen extends React.Component<Props, State> {
27
+
28
+    displayData = this.props.route.params['data'];
29
+
30
+    colors: Object;
31
+
32
+    state = {
33
+        imageModalVisible: false,
34
+    };
35
+
36
+    constructor(props) {
37
+        super(props);
38
+        this.colors = props.theme.colors;
39
+    }
40
+
41
+    componentDidMount(): * {
42
+        this.props.navigation.setOptions({title: this.displayData.name})
43
+    }
44
+
45
+    showImageModal = () => {
46
+        this.setState({imageModalVisible: true});
47
+    };
48
+
49
+    hideImageModal = () => {
50
+        this.setState({imageModalVisible: false});
51
+    };
52
+
53
+    getResponsiblesRender(resp: Array<string>) {
54
+        let final = [];
55
+        for (let i = 0; i < resp.length; i++) {
56
+            final.push(<Paragraph>{resp[i]}</Paragraph>)
57
+        }
58
+        return (
59
+            <Card style={{marginTop: 10, marginBottom: 10}}>
60
+                <Card.Title
61
+                    title={"RESPO"}
62
+                    subtitle={"CONTACTS"}
63
+                    left={(props) => <Avatar.Icon
64
+                        style={{backgroundColor: 'transparent'}}
65
+                        {...props}
66
+                        icon="account-tie" />}
67
+                />
68
+                <Card.Content>
69
+                    {final}
70
+                </Card.Content>
71
+            </Card>
72
+        );
73
+    }
74
+
75
+    render() {
76
+        return (
77
+            <ScrollView style={{paddingLeft: 5, paddingRight: 5}}>
78
+                {this.displayData.logo !== null ?
79
+                    <TouchableOpacity
80
+                        onPress={this.showImageModal}
81
+                        style={{width: '100%', height: 300, marginBottom: 10}}>
82
+                        <Image style={{flex: 1, resizeMode: "contain"}}
83
+                               source={{uri: this.displayData.logo}}/>
84
+                    </TouchableOpacity>
85
+                    : <View/>}
86
+
87
+                {this.displayData.description !== null ?
88
+                    // Surround description with div to allow text styling if the description is not html
89
+                    <Card.Content>
90
+                        <HTML html={"<div>" + this.displayData.description + "</div>"}
91
+                              tagsStyles={{
92
+                                  p: {color: this.colors.text,},
93
+                                  div: {color: this.colors.text}
94
+                              }}
95
+                              onLinkPress={openWebLink}/>
96
+                    </Card.Content>
97
+                    : <View/>}
98
+                {this.getResponsiblesRender(this.displayData.responsibles)}
99
+                <Portal>
100
+                    <ImageView
101
+                        images={[{uri: this.displayData.logo}]}
102
+                        imageIndex={0}
103
+                        presentationStyle={"fullScreen"}
104
+                        visible={this.state.imageModalVisible}
105
+                        onRequestClose={this.hideImageModal}
106
+                    />
107
+                </Portal>
108
+            </ScrollView>
109
+        );
110
+    }
111
+}
112
+
113
+export default withTheme(ClubDisplayScreen);

+ 102
- 0
screens/Amicale/ClubListScreen.js View File

@@ -0,0 +1,102 @@
1
+// @flow
2
+
3
+import * as React from 'react';
4
+import {View} from "react-native";
5
+import {Avatar, Chip, List, withTheme} from 'react-native-paper';
6
+import AuthenticatedScreen from "../../components/Amicale/AuthenticatedScreen";
7
+import PureFlatList from "../../components/Lists/PureFlatList";
8
+
9
+type Props = {
10
+    navigation: Object,
11
+    theme: Object,
12
+}
13
+
14
+type State = {}
15
+
16
+class ClubListScreen extends React.Component<Props, State> {
17
+
18
+    state = {};
19
+
20
+    colors: Object;
21
+
22
+    getRenderItem: Function;
23
+
24
+    categories: Array<Object>;
25
+
26
+    constructor(props) {
27
+        super(props);
28
+        this.colors = props.theme.colors;
29
+    }
30
+
31
+    keyExtractor = (item: Object) => {
32
+        return item.name + item.logo;
33
+    };
34
+
35
+    getScreen = (data: Object) => {
36
+        this.categories = data.categories;
37
+        return (
38
+            <PureFlatList
39
+                data={data.clubs}
40
+                keyExtractor={this.keyExtractor}
41
+                renderItem={this.getRenderItem}
42
+                updateData={0}
43
+            />
44
+        )
45
+    };
46
+
47
+    getCategoryName(id: number) {
48
+        for (let i = 0; i < this.categories.length; i++) {
49
+            if (id === this.categories[i].id)
50
+                return this.categories[i].name;
51
+        }
52
+        return "";
53
+    }
54
+
55
+    getCategoriesRender(categories: Array<number|null>) {
56
+        let final = [];
57
+        for (let i = 0; i < categories.length; i++) {
58
+            if (categories[i] !== null)
59
+                final.push(<Chip style={{marginRight: 5}}>{this.getCategoryName(categories[i])}</Chip>);
60
+        }
61
+        return <View style={{flexDirection: 'row'}}>{final}</View>;
62
+    }
63
+
64
+    getRenderItem = ({item}: Object) => {
65
+        const onPress = this.onListItemPress.bind(this, item);
66
+        const categoriesRender = this.getCategoriesRender.bind(this, item.category);
67
+        return (
68
+            <List.Item
69
+                title={item.name}
70
+                description={categoriesRender}
71
+                onPress={onPress}
72
+                left={(props) => <Avatar.Image
73
+                    {...props}
74
+                    style={{backgroundColor: 'transparent'}}
75
+                    size={64}
76
+                    source={{uri: item.logo}}/>}
77
+            />
78
+        );
79
+    };
80
+
81
+    /**
82
+     * Callback used when clicking an article in the list.
83
+     * It opens the modal to show detailed information about the article
84
+     *
85
+     * @param item The article pressed
86
+     */
87
+    onListItemPress(item: Object) {
88
+        this.props.navigation.navigate("ClubDisplayScreen", {data: item});
89
+    }
90
+
91
+    render() {
92
+        return (
93
+            <AuthenticatedScreen
94
+                {...this.props}
95
+                link={'https://www.amicale-insat.fr/api/clubs/list'}
96
+                renderFunction={this.getScreen}
97
+            />
98
+        );
99
+    }
100
+}
101
+
102
+export default withTheme(ClubListScreen);

Loading…
Cancel
Save