diff --git a/src/components/Lists/CardList/CardList.js b/src/components/Lists/CardList/CardList.tsx
similarity index 84%
rename from src/components/Lists/CardList/CardList.js
rename to src/components/Lists/CardList/CardList.tsx
index 985a49e..67eda6a 100644
--- a/src/components/Lists/CardList/CardList.js
+++ b/src/components/Lists/CardList/CardList.tsx
@@ -17,19 +17,16 @@
* along with Campus INSAT. If not, see .
*/
-// @flow
-
import * as React from 'react';
-import {Animated, Dimensions} from 'react-native';
-import type {ViewStyle} from 'react-native/Libraries/StyleSheet/StyleSheet';
+import {Animated, Dimensions, ViewStyle} from 'react-native';
import ImageListItem from './ImageListItem';
import CardListItem from './CardListItem';
import type {ServiceItemType} from '../../../managers/ServicesManager';
type PropsType = {
- dataset: Array,
- isHorizontal?: boolean,
- contentContainerStyle?: ViewStyle | null,
+ dataset: Array;
+ isHorizontal?: boolean;
+ contentContainerStyle?: ViewStyle;
};
export default class CardList extends React.Component {
@@ -45,12 +42,12 @@ export default class CardList extends React.Component {
constructor(props: PropsType) {
super(props);
this.windowWidth = Dimensions.get('window').width;
- this.horizontalItemSize = this.windowWidth / 4; // So that we can fit 3 items and a part of the 4th => user knows he can scroll
+ this.horizontalItemSize = this.windowWidth / 4; // So that we can fit 3 items, and a part of the 4th => user knows he can scroll
}
- getRenderItem = ({item}: {item: ServiceItemType}): React.Node => {
+ getRenderItem = ({item}: {item: ServiceItemType}) => {
const {props} = this;
- if (props.isHorizontal)
+ if (props.isHorizontal) {
return (
{
width={this.horizontalItemSize}
/>
);
+ }
return ;
};
keyExtractor = (item: ServiceItemType): string => item.key;
- render(): React.Node {
+ render() {
const {props} = this;
let containerStyle = {};
if (props.isHorizontal) {
@@ -84,7 +82,7 @@ export default class CardList extends React.Component {
}
pagingEnabled={props.isHorizontal}
snapToInterval={
- props.isHorizontal ? (this.horizontalItemSize + 5) * 3 : null
+ props.isHorizontal ? (this.horizontalItemSize + 5) * 3 : undefined
}
/>
);
diff --git a/src/components/Lists/CardList/CardListItem.js b/src/components/Lists/CardList/CardListItem.tsx
similarity index 53%
rename from src/components/Lists/CardList/CardListItem.js
rename to src/components/Lists/CardList/CardListItem.tsx
index e3cae18..ce0e9f6 100644
--- a/src/components/Lists/CardList/CardListItem.js
+++ b/src/components/Lists/CardList/CardListItem.tsx
@@ -17,45 +17,38 @@
* along with Campus INSAT. If not, see .
*/
-// @flow
-
import * as React from 'react';
import {Caption, Card, Paragraph, TouchableRipple} from 'react-native-paper';
import {View} from 'react-native';
import type {ServiceItemType} from '../../../managers/ServicesManager';
type PropsType = {
- item: ServiceItemType,
+ item: ServiceItemType;
};
-export default class CardListItem extends React.Component {
- shouldComponentUpdate(): boolean {
- return false;
- }
-
- render(): React.Node {
- const {props} = this;
- const {item} = props;
- const source =
- typeof item.image === 'number' ? item.image : {uri: item.image};
- return (
-
-
-
-
-
- {item.title}
- {item.subtitle}
-
-
-
-
- );
- }
+function CardListItem(props: PropsType) {
+ const {item} = props;
+ const source =
+ typeof item.image === 'number' ? item.image : {uri: item.image};
+ return (
+
+
+
+
+
+ {item.title}
+ {item.subtitle}
+
+
+
+
+ );
}
+
+export default React.memo(CardListItem, () => true);
diff --git a/src/components/Lists/CardList/ImageListItem.js b/src/components/Lists/CardList/ImageListItem.js
deleted file mode 100644
index bd855b7..0000000
--- a/src/components/Lists/CardList/ImageListItem.js
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (c) 2019 - 2020 Arnaud Vergnet.
- *
- * This file is part of Campus INSAT.
- *
- * Campus INSAT is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * Campus INSAT is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Campus INSAT. If not, see .
- */
-
-// @flow
-
-import * as React from 'react';
-import {Text, TouchableRipple} from 'react-native-paper';
-import {Image, View} from 'react-native';
-import type {ServiceItemType} from '../../../managers/ServicesManager';
-
-type PropsType = {
- item: ServiceItemType,
- width: number,
-};
-
-export default class ImageListItem extends React.Component {
- shouldComponentUpdate(): boolean {
- return false;
- }
-
- render(): React.Node {
- const {props} = this;
- const {item} = props;
- const source =
- typeof item.image === 'number' ? item.image : {uri: item.image};
- return (
-
-
-
-
- {item.title}
-
-
-
- );
- }
-}
diff --git a/src/components/Lists/CardList/ImageListItem.tsx b/src/components/Lists/CardList/ImageListItem.tsx
new file mode 100644
index 0000000..73dd698
--- /dev/null
+++ b/src/components/Lists/CardList/ImageListItem.tsx
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2019 - 2020 Arnaud Vergnet.
+ *
+ * This file is part of Campus INSAT.
+ *
+ * Campus INSAT is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Campus INSAT is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Campus INSAT. If not, see .
+ */
+
+import * as React from 'react';
+import {Text, TouchableRipple} from 'react-native-paper';
+import {Image, View} from 'react-native';
+import type {ServiceItemType} from '../../../managers/ServicesManager';
+
+type PropsType = {
+ item: ServiceItemType;
+ width: number;
+};
+
+function ImageListItem(props: PropsType) {
+ const {item} = props;
+ const source =
+ typeof item.image === 'number' ? item.image : {uri: item.image};
+ return (
+
+
+
+
+ {item.title}
+
+
+
+ );
+}
+
+export default React.memo(ImageListItem, () => true);
diff --git a/src/components/Lists/Clubs/ClubListHeader.js b/src/components/Lists/Clubs/ClubListHeader.tsx
similarity index 60%
rename from src/components/Lists/Clubs/ClubListHeader.js
rename to src/components/Lists/Clubs/ClubListHeader.tsx
index b1ebd86..d60030c 100644
--- a/src/components/Lists/Clubs/ClubListHeader.js
+++ b/src/components/Lists/Clubs/ClubListHeader.tsx
@@ -17,8 +17,6 @@
* along with Campus INSAT. If not, see .
*/
-// @flow
-
import * as React from 'react';
import {Card, Chip, List, Text} from 'react-native-paper';
import {StyleSheet, View} from 'react-native';
@@ -26,12 +24,11 @@ import i18n from 'i18n-js';
import AnimatedAccordion from '../../Animations/AnimatedAccordion';
import {isItemInCategoryFilter} from '../../../utils/Search';
import type {ClubCategoryType} from '../../../screens/Amicale/Clubs/ClubListScreen';
-import type {ListIconPropsType} from '../../../constants/PaperStyles';
type PropsType = {
- categories: Array,
- onChipSelect: (id: number) => void,
- selectedCategories: Array,
+ categories: Array;
+ onChipSelect: (id: number) => void;
+ selectedCategories: Array;
};
const styles = StyleSheet.create({
@@ -54,16 +51,8 @@ const styles = StyleSheet.create({
},
});
-class ClubListHeader extends React.Component {
- shouldComponentUpdate(nextProps: PropsType): boolean {
- const {props} = this;
- return (
- nextProps.selectedCategories.length !== props.selectedCategories.length
- );
- }
-
- getChipRender = (category: ClubCategoryType, key: string): React.Node => {
- const {props} = this;
+function ClubListHeader(props: PropsType) {
+ const getChipRender = (category: ClubCategoryType, key: string) => {
const onPress = (): void => props.onChipSelect(category.id);
return (
{
);
};
- getCategoriesRender(): React.Node {
- const {props} = this;
- const final = [];
+ const getCategoriesRender = () => {
+ const final: Array = [];
props.categories.forEach((cat: ClubCategoryType) => {
- final.push(this.getChipRender(cat, cat.id.toString()));
+ final.push(getChipRender(cat, cat.id.toString()));
});
return final;
- }
+ };
- render(): React.Node {
- return (
-
- (
-
- )}
- opened>
-
- {i18n.t('screens.clubs.categoriesFilterMessage')}
-
- {this.getCategoriesRender()}
-
-
- );
- }
+ return (
+
+ (
+
+ )}
+ opened>
+
+ {i18n.t('screens.clubs.categoriesFilterMessage')}
+
+ {getCategoriesRender()}
+
+
+ );
}
-export default ClubListHeader;
+const areEqual = (prevProps: PropsType, nextProps: PropsType): boolean => {
+ return (
+ prevProps.selectedCategories.length === nextProps.selectedCategories.length
+ );
+};
+
+export default React.memo(ClubListHeader, areEqual);
diff --git a/src/components/Lists/Clubs/ClubListItem.js b/src/components/Lists/Clubs/ClubListItem.tsx
similarity index 86%
rename from src/components/Lists/Clubs/ClubListItem.js
rename to src/components/Lists/Clubs/ClubListItem.tsx
index 76c592a..ad60cdf 100644
--- a/src/components/Lists/Clubs/ClubListItem.js
+++ b/src/components/Lists/Clubs/ClubListItem.tsx
@@ -17,8 +17,6 @@
* along with Campus INSAT. If not, see .
*/
-// @flow
-
import * as React from 'react';
import {Avatar, Chip, List, withTheme} from 'react-native-paper';
import {View} from 'react-native';
@@ -26,14 +24,13 @@ import type {
ClubCategoryType,
ClubType,
} from '../../../screens/Amicale/Clubs/ClubListScreen';
-import type {CustomThemeType} from '../../../managers/ThemeManager';
type PropsType = {
- onPress: () => void,
- categoryTranslator: (id: number) => ClubCategoryType,
- item: ClubType,
- height: number,
- theme: CustomThemeType,
+ onPress: () => void;
+ categoryTranslator: (id: number) => ClubCategoryType;
+ item: ClubType;
+ height: number;
+ theme: ReactNativePaper.Theme;
};
class ClubListItem extends React.Component {
@@ -48,9 +45,9 @@ class ClubListItem extends React.Component {
return false;
}
- getCategoriesRender(categories: Array): React.Node {
+ getCategoriesRender(categories: Array) {
const {props} = this;
- const final = [];
+ const final: Array = [];
categories.forEach((cat: number | null) => {
if (cat != null) {
const category: ClubCategoryType = props.categoryTranslator(cat);
@@ -66,9 +63,9 @@ class ClubListItem extends React.Component {
return {final};
}
- render(): React.Node {
+ render() {
const {props} = this;
- const categoriesRender = (): React.Node =>
+ const categoriesRender = () =>
this.getCategoriesRender(props.item.category);
const {colors} = props.theme;
return (
@@ -76,7 +73,7 @@ class ClubListItem extends React.Component {
title={props.item.name}
description={categoriesRender}
onPress={props.onPress}
- left={(): React.Node => (
+ left={() => (
{
source={{uri: props.item.logo}}
/>
)}
- right={(): React.Node => (
+ right={() => (
.
- */
-
-// @flow
-
-import * as React from 'react';
-import {withTheme} from 'react-native-paper';
-import {FlatList, Image, View} from 'react-native';
-import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
-import DashboardEditItem from './DashboardEditItem';
-import AnimatedAccordion from '../../Animations/AnimatedAccordion';
-import type {
- ServiceCategoryType,
- ServiceItemType,
-} from '../../../managers/ServicesManager';
-import type {CustomThemeType} from '../../../managers/ThemeManager';
-
-type PropsType = {
- item: ServiceCategoryType,
- activeDashboard: Array,
- onPress: (service: ServiceItemType) => void,
- theme: CustomThemeType,
-};
-
-const LIST_ITEM_HEIGHT = 64;
-
-class DashboardEditAccordion extends React.Component {
- getRenderItem = ({item}: {item: ServiceItemType}): React.Node => {
- const {props} = this;
- return (
- {
- props.onPress(item);
- }}
- />
- );
- };
-
- getItemLayout = (
- data: ?Array,
- index: number,
- ): {length: number, offset: number, index: number} => ({
- length: LIST_ITEM_HEIGHT,
- offset: LIST_ITEM_HEIGHT * index,
- index,
- });
-
- render(): React.Node {
- const {props} = this;
- const {item} = props;
- return (
-
-
- typeof item.image === 'number' ? (
-
- ) : (
-
- )
- }>
- {/* $FlowFixMe */}
-
-
-
- );
- }
-}
-
-export default withTheme(DashboardEditAccordion);
diff --git a/src/components/Lists/DashboardEdit/DashboardEditAccordion.tsx b/src/components/Lists/DashboardEdit/DashboardEditAccordion.tsx
new file mode 100644
index 0000000..b273b9d
--- /dev/null
+++ b/src/components/Lists/DashboardEdit/DashboardEditAccordion.tsx
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2019 - 2020 Arnaud Vergnet.
+ *
+ * This file is part of Campus INSAT.
+ *
+ * Campus INSAT is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Campus INSAT is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Campus INSAT. If not, see .
+ */
+
+import * as React from 'react';
+import {useTheme} from 'react-native-paper';
+import {FlatList, Image, View} from 'react-native';
+import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
+import DashboardEditItem from './DashboardEditItem';
+import AnimatedAccordion from '../../Animations/AnimatedAccordion';
+import type {
+ ServiceCategoryType,
+ ServiceItemType,
+} from '../../../managers/ServicesManager';
+
+type PropsType = {
+ item: ServiceCategoryType;
+ activeDashboard: Array;
+ onPress: (service: ServiceItemType) => void;
+};
+
+const LIST_ITEM_HEIGHT = 64;
+
+function DashboardEditAccordion(props: PropsType) {
+ const theme = useTheme();
+
+ const getRenderItem = ({item}: {item: ServiceItemType}) => {
+ return (
+ {
+ props.onPress(item);
+ }}
+ />
+ );
+ };
+
+ const getItemLayout = (
+ data: Array | null | undefined,
+ index: number,
+ ): {length: number; offset: number; index: number} => ({
+ length: LIST_ITEM_HEIGHT,
+ offset: LIST_ITEM_HEIGHT * index,
+ index,
+ });
+
+ const {item} = props;
+ return (
+
+
+ typeof item.image === 'number' ? (
+
+ ) : (
+
+ )
+ }>
+
+
+
+ );
+}
+
+export default DashboardEditAccordion;
diff --git a/src/components/Lists/DashboardEdit/DashboardEditItem.js b/src/components/Lists/DashboardEdit/DashboardEditItem.js
deleted file mode 100644
index 0831fb6..0000000
--- a/src/components/Lists/DashboardEdit/DashboardEditItem.js
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (c) 2019 - 2020 Arnaud Vergnet.
- *
- * This file is part of Campus INSAT.
- *
- * Campus INSAT is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * Campus INSAT is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Campus INSAT. If not, see .
- */
-
-// @flow
-
-import * as React from 'react';
-import {Image} from 'react-native';
-import {List, withTheme} from 'react-native-paper';
-import type {CustomThemeType} from '../../../managers/ThemeManager';
-import type {ServiceItemType} from '../../../managers/ServicesManager';
-import type {ListIconPropsType} from '../../../constants/PaperStyles';
-
-type PropsType = {
- item: ServiceItemType,
- isActive: boolean,
- height: number,
- onPress: () => void,
- theme: CustomThemeType,
-};
-
-class DashboardEditItem extends React.Component {
- shouldComponentUpdate(nextProps: PropsType): boolean {
- const {isActive} = this.props;
- return nextProps.isActive !== isActive;
- }
-
- render(): React.Node {
- const {item, onPress, height, isActive, theme} = this.props;
- return (
- (
-
- )}
- right={(props: ListIconPropsType): React.Node =>
- isActive ? (
-
- ) : null
- }
- style={{
- height,
- justifyContent: 'center',
- paddingLeft: 30,
- backgroundColor: isActive
- ? theme.colors.proxiwashFinishedColor
- : 'transparent',
- }}
- />
- );
- }
-}
-
-export default withTheme(DashboardEditItem);
diff --git a/src/components/Lists/DashboardEdit/DashboardEditItem.tsx b/src/components/Lists/DashboardEdit/DashboardEditItem.tsx
new file mode 100644
index 0000000..78bade1
--- /dev/null
+++ b/src/components/Lists/DashboardEdit/DashboardEditItem.tsx
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2019 - 2020 Arnaud Vergnet.
+ *
+ * This file is part of Campus INSAT.
+ *
+ * Campus INSAT is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Campus INSAT is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Campus INSAT. If not, see .
+ */
+
+import * as React from 'react';
+import {Image} from 'react-native';
+import {List, useTheme} from 'react-native-paper';
+import type {ServiceItemType} from '../../../managers/ServicesManager';
+
+type PropsType = {
+ item: ServiceItemType;
+ isActive: boolean;
+ height: number;
+ onPress: () => void;
+};
+
+function DashboardEditItem(props: PropsType) {
+ const theme = useTheme();
+ const {item, onPress, height, isActive} = props;
+ return (
+ (
+
+ )}
+ right={(iconProps) =>
+ isActive ? (
+
+ ) : null
+ }
+ style={{
+ height,
+ justifyContent: 'center',
+ paddingLeft: 30,
+ backgroundColor: isActive
+ ? theme.colors.proxiwashFinishedColor
+ : 'transparent',
+ }}
+ />
+ );
+}
+
+const areEqual = (prevProps: PropsType, nextProps: PropsType): boolean => {
+ return nextProps.isActive !== prevProps.isActive;
+};
+
+export default React.memo(DashboardEditItem, areEqual);
diff --git a/src/components/Lists/DashboardEdit/DashboardEditPreviewItem.js b/src/components/Lists/DashboardEdit/DashboardEditPreviewItem.js
deleted file mode 100644
index 2d85a74..0000000
--- a/src/components/Lists/DashboardEdit/DashboardEditPreviewItem.js
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (c) 2019 - 2020 Arnaud Vergnet.
- *
- * This file is part of Campus INSAT.
- *
- * Campus INSAT is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * Campus INSAT is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Campus INSAT. If not, see .
- */
-
-// @flow
-
-import * as React from 'react';
-import {TouchableRipple, withTheme} from 'react-native-paper';
-import {Dimensions, Image, View} from 'react-native';
-import type {CustomThemeType} from '../../../managers/ThemeManager';
-
-type PropsType = {
- image: string,
- isActive: boolean,
- onPress: () => void,
- theme: CustomThemeType,
-};
-
-/**
- * Component used to render a small dashboard item
- */
-class DashboardEditPreviewItem extends React.Component {
- itemSize: number;
-
- constructor(props: PropsType) {
- super(props);
- this.itemSize = Dimensions.get('window').width / 8;
- }
-
- render(): React.Node {
- const {props} = this;
- return (
-
-
-
-
-
- );
- }
-}
-
-export default withTheme(DashboardEditPreviewItem);
diff --git a/src/components/Lists/DashboardEdit/DashboardEditPreviewItem.tsx b/src/components/Lists/DashboardEdit/DashboardEditPreviewItem.tsx
new file mode 100644
index 0000000..e787e76
--- /dev/null
+++ b/src/components/Lists/DashboardEdit/DashboardEditPreviewItem.tsx
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2019 - 2020 Arnaud Vergnet.
+ *
+ * This file is part of Campus INSAT.
+ *
+ * Campus INSAT is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Campus INSAT is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Campus INSAT. If not, see .
+ */
+
+import * as React from 'react';
+import {TouchableRipple, useTheme} from 'react-native-paper';
+import {Dimensions, Image, View} from 'react-native';
+
+type PropsType = {
+ image: string;
+ isActive: boolean;
+ onPress: () => void;
+};
+
+/**
+ * Component used to render a small dashboard item
+ */
+function DashboardEditPreviewItem(props: PropsType) {
+ const theme = useTheme();
+ const itemSize = Dimensions.get('window').width / 8;
+
+ return (
+
+
+
+
+
+ );
+}
+
+export default DashboardEditPreviewItem;
diff --git a/src/components/Lists/Equipment/EquipmentListItem.js b/src/components/Lists/Equipment/EquipmentListItem.js
deleted file mode 100644
index c94dff4..0000000
--- a/src/components/Lists/Equipment/EquipmentListItem.js
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * Copyright (c) 2019 - 2020 Arnaud Vergnet.
- *
- * This file is part of Campus INSAT.
- *
- * Campus INSAT is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * Campus INSAT is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Campus INSAT. If not, see .
- */
-
-// @flow
-
-import * as React from 'react';
-import {Avatar, List, withTheme} from 'react-native-paper';
-import i18n from 'i18n-js';
-import {StackNavigationProp} from '@react-navigation/stack';
-import type {CustomThemeType} from '../../../managers/ThemeManager';
-import type {DeviceType} from '../../../screens/Amicale/Equipment/EquipmentListScreen';
-import {
- getFirstEquipmentAvailability,
- getRelativeDateString,
- isEquipmentAvailable,
-} from '../../../utils/EquipmentBooking';
-
-type PropsType = {
- navigation: StackNavigationProp,
- userDeviceRentDates: [string, string],
- item: DeviceType,
- height: number,
- theme: CustomThemeType,
-};
-
-class EquipmentListItem extends React.Component {
- shouldComponentUpdate(nextProps: PropsType): boolean {
- const {userDeviceRentDates} = this.props;
- return nextProps.userDeviceRentDates !== userDeviceRentDates;
- }
-
- render(): React.Node {
- const {item, userDeviceRentDates, navigation, height, theme} = this.props;
- const isRented = userDeviceRentDates != null;
- const isAvailable = isEquipmentAvailable(item);
- const firstAvailability = getFirstEquipmentAvailability(item);
-
- let onPress;
- if (isRented)
- onPress = () => {
- navigation.navigate('equipment-confirm', {
- item,
- dates: userDeviceRentDates,
- });
- };
- else
- onPress = () => {
- navigation.navigate('equipment-rent', {item});
- };
-
- let description;
- if (isRented) {
- const start = new Date(userDeviceRentDates[0]);
- const end = new Date(userDeviceRentDates[1]);
- if (start.getTime() !== end.getTime())
- description = i18n.t('screens.equipment.bookingPeriod', {
- begin: getRelativeDateString(start),
- end: getRelativeDateString(end),
- });
- else
- description = i18n.t('screens.equipment.bookingDay', {
- date: getRelativeDateString(start),
- });
- } else if (isAvailable)
- description = i18n.t('screens.equipment.bail', {cost: item.caution});
- else
- description = i18n.t('screens.equipment.available', {
- date: getRelativeDateString(firstAvailability),
- });
-
- let icon;
- if (isRented) icon = 'bookmark-check';
- else if (isAvailable) icon = 'check-circle-outline';
- else icon = 'update';
-
- let color;
- if (isRented) color = theme.colors.warning;
- else if (isAvailable) color = theme.colors.success;
- else color = theme.colors.primary;
-
- return (
- (
-
- )}
- right={(): React.Node => (
-
- )}
- style={{
- height,
- justifyContent: 'center',
- }}
- />
- );
- }
-}
-
-export default withTheme(EquipmentListItem);
diff --git a/src/components/Lists/Equipment/EquipmentListItem.tsx b/src/components/Lists/Equipment/EquipmentListItem.tsx
new file mode 100644
index 0000000..19af142
--- /dev/null
+++ b/src/components/Lists/Equipment/EquipmentListItem.tsx
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2019 - 2020 Arnaud Vergnet.
+ *
+ * This file is part of Campus INSAT.
+ *
+ * Campus INSAT is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Campus INSAT is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Campus INSAT. If not, see .
+ */
+
+import * as React from 'react';
+import {Avatar, List, useTheme} from 'react-native-paper';
+import i18n from 'i18n-js';
+import {StackNavigationProp} from '@react-navigation/stack';
+import type {DeviceType} from '../../../screens/Amicale/Equipment/EquipmentListScreen';
+import {
+ getFirstEquipmentAvailability,
+ getRelativeDateString,
+ isEquipmentAvailable,
+} from '../../../utils/EquipmentBooking';
+
+type PropsType = {
+ navigation: StackNavigationProp;
+ userDeviceRentDates: [string, string];
+ item: DeviceType;
+ height: number;
+};
+
+function EquipmentListItem(props: PropsType) {
+ const theme = useTheme();
+ const {item, userDeviceRentDates, navigation, height} = props;
+ const isRented = userDeviceRentDates != null;
+ const isAvailable = isEquipmentAvailable(item);
+ const firstAvailability = getFirstEquipmentAvailability(item);
+
+ let onPress;
+ if (isRented) {
+ onPress = () => {
+ navigation.navigate('equipment-confirm', {
+ item,
+ dates: userDeviceRentDates,
+ });
+ };
+ } else {
+ onPress = () => {
+ navigation.navigate('equipment-rent', {item});
+ };
+ }
+
+ let description;
+ if (isRented) {
+ const start = new Date(userDeviceRentDates[0]);
+ const end = new Date(userDeviceRentDates[1]);
+ if (start.getTime() !== end.getTime()) {
+ description = i18n.t('screens.equipment.bookingPeriod', {
+ begin: getRelativeDateString(start),
+ end: getRelativeDateString(end),
+ });
+ } else {
+ description = i18n.t('screens.equipment.bookingDay', {
+ date: getRelativeDateString(start),
+ });
+ }
+ } else if (isAvailable) {
+ description = i18n.t('screens.equipment.bail', {cost: item.caution});
+ } else {
+ description = i18n.t('screens.equipment.available', {
+ date: getRelativeDateString(firstAvailability),
+ });
+ }
+
+ let icon: string;
+ if (isRented) {
+ icon = 'bookmark-check';
+ } else if (isAvailable) {
+ icon = 'check-circle-outline';
+ } else {
+ icon = 'update';
+ }
+
+ let color: string;
+ if (isRented) {
+ color = theme.colors.warning;
+ } else if (isAvailable) {
+ color = theme.colors.success;
+ } else {
+ color = theme.colors.primary;
+ }
+
+ return (
+ (
+
+ )}
+ right={() => (
+
+ )}
+ style={{
+ height,
+ justifyContent: 'center',
+ }}
+ />
+ );
+}
+
+const areEqual = (prevProps: PropsType, nextProps: PropsType): boolean => {
+ return nextProps.userDeviceRentDates !== prevProps.userDeviceRentDates;
+};
+
+export default React.memo(EquipmentListItem, areEqual);
diff --git a/src/components/Lists/PlanexGroups/GroupListAccordion.js b/src/components/Lists/PlanexGroups/GroupListAccordion.tsx
similarity index 84%
rename from src/components/Lists/PlanexGroups/GroupListAccordion.js
rename to src/components/Lists/PlanexGroups/GroupListAccordion.tsx
index e450f21..e403ebf 100644
--- a/src/components/Lists/PlanexGroups/GroupListAccordion.js
+++ b/src/components/Lists/PlanexGroups/GroupListAccordion.tsx
@@ -17,8 +17,6 @@
* along with Campus INSAT. If not, see .
*/
-// @flow
-
import * as React from 'react';
import {List, withTheme} from 'react-native-paper';
import {FlatList, View} from 'react-native';
@@ -29,17 +27,15 @@ import type {
PlanexGroupType,
PlanexGroupCategoryType,
} from '../../../screens/Planex/GroupSelectionScreen';
-import type {CustomThemeType} from '../../../managers/ThemeManager';
-import type {ListIconPropsType} from '../../../constants/PaperStyles';
type PropsType = {
- item: PlanexGroupCategoryType,
- favorites: Array,
- onGroupPress: (PlanexGroupType) => void,
- onFavoritePress: (PlanexGroupType) => void,
- currentSearchString: string,
- height: number,
- theme: CustomThemeType,
+ item: PlanexGroupCategoryType;
+ favorites: Array;
+ onGroupPress: (data: PlanexGroupType) => void;
+ onFavoritePress: (data: PlanexGroupType) => void;
+ currentSearchString: string;
+ height: number;
+ theme: ReactNativePaper.Theme;
};
const LIST_ITEM_HEIGHT = 64;
@@ -55,7 +51,7 @@ class GroupListAccordion extends React.Component {
);
}
- getRenderItem = ({item}: {item: PlanexGroupType}): React.Node => {
+ getRenderItem = ({item}: {item: PlanexGroupType}) => {
const {props} = this;
const onPress = () => {
props.onGroupPress(item);
@@ -77,18 +73,19 @@ class GroupListAccordion extends React.Component {
getData(): Array {
const {props} = this;
const originalData = props.item.content;
- const displayData = [];
+ const displayData: Array = [];
originalData.forEach((data: PlanexGroupType) => {
- if (stringMatchQuery(data.name, props.currentSearchString))
+ if (stringMatchQuery(data.name, props.currentSearchString)) {
displayData.push(data);
+ }
});
return displayData;
}
itemLayout = (
- data: ?Array,
+ data: Array | null | undefined,
index: number,
- ): {length: number, offset: number, index: number} => ({
+ ): {length: number; offset: number; index: number} => ({
length: LIST_ITEM_HEIGHT,
offset: LIST_ITEM_HEIGHT * index,
index,
@@ -96,7 +93,7 @@ class GroupListAccordion extends React.Component {
keyExtractor = (item: PlanexGroupType): string => item.id.toString();
- render(): React.Node {
+ render() {
const {props} = this;
const {item} = this.props;
return (
@@ -107,7 +104,7 @@ class GroupListAccordion extends React.Component {
height: props.height,
justifyContent: 'center',
}}
- left={(iconProps: ListIconPropsType): React.Node =>
+ left={(iconProps) =>
item.id === 0 ? (
.
*/
-// @flow
-
import * as React from 'react';
import {List, TouchableRipple, withTheme} from 'react-native-paper';
import * as Animatable from 'react-native-animatable';
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
-import type {CustomThemeType} from '../../../managers/ThemeManager';
import type {PlanexGroupType} from '../../../screens/Planex/GroupSelectionScreen';
-import type {ListIconPropsType} from '../../../constants/PaperStyles';
type PropsType = {
- theme: CustomThemeType,
- onPress: () => void,
- onStarPress: () => void,
- item: PlanexGroupType,
- favorites: Array,
- height: number,
+ theme: ReactNativePaper.Theme;
+ onPress: () => void;
+ onStarPress: () => void;
+ item: PlanexGroupType;
+ favorites: Array;
+ height: number;
};
const REPLACE_REGEX = /_/g;
@@ -41,10 +37,11 @@ const REPLACE_REGEX = /_/g;
class GroupListItem extends React.Component {
isFav: boolean;
- starRef: null | Animatable.View;
+ starRef: {current: null | Animatable.View};
constructor(props: PropsType) {
super(props);
+ this.starRef = React.createRef();
this.isFav = this.isGroupInFavorites(props.favorites);
}
@@ -52,7 +49,9 @@ class GroupListItem extends React.Component {
const {favorites} = this.props;
const favChanged = favorites.length !== nextProps.favorites.length;
let newFavState = this.isFav;
- if (favChanged) newFavState = this.isGroupInFavorites(nextProps.favorites);
+ if (favChanged) {
+ newFavState = this.isGroupInFavorites(nextProps.favorites);
+ }
const shouldUpdate = this.isFav !== newFavState;
this.isFav = newFavState;
return shouldUpdate;
@@ -61,9 +60,12 @@ class GroupListItem extends React.Component {
onStarPress = () => {
const {props} = this;
const ref = this.starRef;
- if (ref != null) {
- if (this.isFav) ref.rubberBand();
- else ref.swing();
+ if (ref.current) {
+ if (this.isFav) {
+ ref.current.rubberBand();
+ } else {
+ ref.current.swing();
+ }
}
props.onStarPress();
};
@@ -71,31 +73,29 @@ class GroupListItem extends React.Component {
isGroupInFavorites(favorites: Array): boolean {
const {item} = this.props;
for (let i = 0; i < favorites.length; i += 1) {
- if (favorites[i].id === item.id) return true;
+ if (favorites[i].id === item.id) {
+ return true;
+ }
}
return false;
}
- render(): React.Node {
+ render() {
const {props} = this;
const {colors} = props.theme;
return (
(
+ left={(iconProps) => (
)}
- right={(iconProps: ListIconPropsType): React.Node => (
- {
- this.starRef = ref;
- }}
- useNativeDriver>
+ right={(iconProps) => (
+
.
- */
-
-// @flow
-
-import * as React from 'react';
-import {Avatar, List, Text, withTheme} from 'react-native-paper';
-import i18n from 'i18n-js';
-import type {ProximoArticleType} from '../../../screens/Services/Proximo/ProximoMainScreen';
-
-type PropsType = {
- onPress: () => void,
- color: string,
- item: ProximoArticleType,
- height: number,
-};
-
-class ProximoListItem extends React.Component {
- shouldComponentUpdate(): boolean {
- return false;
- }
-
- render(): React.Node {
- const {props} = this;
- return (
- (
-
- )}
- right={(): React.Node => (
- {props.item.price}€
- )}
- style={{
- height: props.height,
- justifyContent: 'center',
- }}
- />
- );
- }
-}
-
-export default withTheme(ProximoListItem);
diff --git a/src/components/Lists/Proximo/ProximoListItem.tsx b/src/components/Lists/Proximo/ProximoListItem.tsx
new file mode 100644
index 0000000..9465922
--- /dev/null
+++ b/src/components/Lists/Proximo/ProximoListItem.tsx
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2019 - 2020 Arnaud Vergnet.
+ *
+ * This file is part of Campus INSAT.
+ *
+ * Campus INSAT is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Campus INSAT is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Campus INSAT. If not, see .
+ */
+
+import * as React from 'react';
+import {Avatar, List, Text} from 'react-native-paper';
+import i18n from 'i18n-js';
+import type {ProximoArticleType} from '../../../screens/Services/Proximo/ProximoMainScreen';
+
+type PropsType = {
+ onPress: () => void;
+ color: string;
+ item: ProximoArticleType;
+ height: number;
+};
+
+function ProximoListItem(props: PropsType) {
+ return (
+ (
+
+ )}
+ right={() => (
+ {props.item.price}€
+ )}
+ style={{
+ height: props.height,
+ justifyContent: 'center',
+ }}
+ />
+ );
+}
+
+export default React.memo(ProximoListItem, () => true);
diff --git a/src/components/Lists/Proxiwash/ProxiwashListItem.js b/src/components/Lists/Proxiwash/ProxiwashListItem.tsx
similarity index 93%
rename from src/components/Lists/Proxiwash/ProxiwashListItem.js
rename to src/components/Lists/Proxiwash/ProxiwashListItem.tsx
index 69132ce..9b64a59 100644
--- a/src/components/Lists/Proxiwash/ProxiwashListItem.js
+++ b/src/components/Lists/Proxiwash/ProxiwashListItem.tsx
@@ -17,8 +17,6 @@
* along with Campus INSAT. If not, see .
*/
-// @flow
-
import * as React from 'react';
import {
Avatar,
@@ -34,20 +32,19 @@ import i18n from 'i18n-js';
import * as Animatable from 'react-native-animatable';
import ProxiwashConstants from '../../../constants/ProxiwashConstants';
import AprilFoolsManager from '../../../managers/AprilFoolsManager';
-import type {CustomThemeType} from '../../../managers/ThemeManager';
import type {ProxiwashMachineType} from '../../../screens/Proxiwash/ProxiwashScreen';
type PropsType = {
- item: ProxiwashMachineType,
- theme: CustomThemeType,
+ item: ProxiwashMachineType;
+ theme: ReactNativePaper.Theme;
onPress: (
title: string,
item: ProxiwashMachineType,
isDryer: boolean,
- ) => void,
- isWatched: boolean,
- isDryer: boolean,
- height: number,
+ ) => void;
+ isWatched: boolean;
+ isDryer: boolean;
+ height: number;
};
const AnimatedIcon = Animatable.createAnimatableComponent(Avatar.Icon);
@@ -89,10 +86,11 @@ class ProxiwashListItem extends React.Component {
let displayNumber = props.item.number;
const displayMaxWeight = props.item.maxWeight;
- if (AprilFoolsManager.getInstance().isAprilFoolsEnabled())
+ if (AprilFoolsManager.getInstance().isAprilFoolsEnabled()) {
displayNumber = AprilFoolsManager.getProxiwashMachineDisplayNumber(
parseInt(props.item.number, 10),
);
+ }
this.title = props.isDryer
? i18n.t('screens.proxiwash.dryer')
@@ -159,10 +157,10 @@ class ProxiwashListItem extends React.Component {
colors.proxiwashUnknownColor;
}
- render(): React.Node {
+ render() {
const {props} = this;
const {colors} = props.theme;
- const machineState = props.item.state;
+ const machineState = parseInt(props.item.state, 10);
const isRunning = machineState === ProxiwashConstants.machineStates.RUNNING;
const isReady = machineState === ProxiwashConstants.machineStates.AVAILABLE;
const description = isRunning
@@ -171,10 +169,13 @@ class ProxiwashListItem extends React.Component {
const stateIcon = ProxiwashConstants.stateIcons[machineState];
const stateString = this.stateStrings[machineState];
let progress;
- if (isRunning && props.item.donePercent !== '')
+ if (isRunning && props.item.donePercent !== '') {
progress = parseFloat(props.item.donePercent) / 100;
- else if (isRunning) progress = 0;
- else progress = 1;
+ } else if (isRunning) {
+ progress = 0;
+ } else {
+ progress = 1;
+ }
const icon = props.isWatched ? (
{
justifyContent: 'center',
}}
onPress={this.onListItemPress}
- left={(): React.Node => icon}
- right={(): React.Node => (
+ left={() => icon}
+ right={() => (
.
*/
-// @flow
-
import * as React from 'react';
import {Avatar, Text, withTheme} from 'react-native-paper';
import {StyleSheet, View} from 'react-native';
import i18n from 'i18n-js';
-import type {CustomThemeType} from '../../../managers/ThemeManager';
type PropsType = {
- theme: CustomThemeType,
- title: string,
- isDryer: boolean,
- nbAvailable: number,
+ theme: ReactNativePaper.Theme;
+ title: string;
+ isDryer: boolean;
+ nbAvailable: number;
};
const styles = StyleSheet.create({
@@ -61,7 +58,7 @@ class ProxiwashListItem extends React.Component {
);
}
- render(): React.Node {
+ render() {
const {props} = this;
const subtitle = `${props.nbAvailable} ${
props.nbAvailable <= 1
diff --git a/src/managers/ServicesManager.ts b/src/managers/ServicesManager.ts
index b33237d..c1c6eb8 100644
--- a/src/managers/ServicesManager.ts
+++ b/src/managers/ServicesManager.ts
@@ -94,7 +94,7 @@ export type ServiceItemType = {
key: string;
title: string;
subtitle: string;
- image: string;
+ image: string | number;
onPress: () => void;
badgeFunction?: (dashboard: FullDashboardType) => number;
};