Improve Dashboard edit components to match linter

This commit is contained in:
Arnaud Vergnet 2020-08-04 09:31:27 +02:00
parent 93d12b27f8
commit 70365136ac
4 changed files with 312 additions and 271 deletions

View file

@ -2,66 +2,83 @@
import * as React from 'react'; import * as React from 'react';
import {withTheme} from 'react-native-paper'; import {withTheme} from 'react-native-paper';
import {FlatList, Image, View} from "react-native"; import {FlatList, Image, View} from 'react-native';
import DashboardEditItem from "./DashboardEditItem"; import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
import AnimatedAccordion from "../../Animations/AnimatedAccordion"; import DashboardEditItem from './DashboardEditItem';
import type {ServiceCategory, ServiceItem} from "../../../managers/ServicesManager"; import AnimatedAccordion from '../../Animations/AnimatedAccordion';
import MaterialCommunityIcons from "react-native-vector-icons/MaterialCommunityIcons"; import type {
import type {CustomTheme} from "../../../managers/ThemeManager"; ServiceCategoryType,
ServiceItemType,
} from '../../../managers/ServicesManager';
import type {CustomTheme} from '../../../managers/ThemeManager';
type Props = { type PropsType = {
item: ServiceCategory, item: ServiceCategoryType,
activeDashboard: Array<string>, activeDashboard: Array<string>,
onPress: (service: ServiceItem) => void, onPress: (service: ServiceItemType) => void,
theme: CustomTheme, theme: CustomTheme,
} };
const LIST_ITEM_HEIGHT = 64; const LIST_ITEM_HEIGHT = 64;
class DashboardEditAccordion extends React.Component<Props> { class DashboardEditAccordion extends React.Component<PropsType> {
getRenderItem = ({item}: {item: ServiceItemType}): React.Node => {
renderItem = ({item}: { item: ServiceItem }) => { const {props} = this;
return ( return (
<DashboardEditItem <DashboardEditItem
height={LIST_ITEM_HEIGHT} height={LIST_ITEM_HEIGHT}
item={item} item={item}
isActive={this.props.activeDashboard.includes(item.key)} isActive={props.activeDashboard.includes(item.key)}
onPress={() => this.props.onPress(item)}/> onPress={() => {
props.onPress(item);
}}
/>
); );
} };
itemLayout = (data, index) => ({length: LIST_ITEM_HEIGHT, offset: LIST_ITEM_HEIGHT * index, index}); getItemLayout = (
data: ?Array<ServiceItemType>,
index: number,
): {length: number, offset: number, index: number} => ({
length: LIST_ITEM_HEIGHT,
offset: LIST_ITEM_HEIGHT * index,
index,
});
render() { render(): React.Node {
const item = this.props.item; const {props} = this;
const {item} = props;
return ( return (
<View> <View>
<AnimatedAccordion <AnimatedAccordion
title={item.title} title={item.title}
left={props => typeof item.image === "number" left={(): React.Node =>
? <Image typeof item.image === 'number' ? (
{...props} <Image
source={item.image} source={item.image}
style={{ style={{
width: 40, width: 40,
height: 40 height: 40,
}} }}
/> />
: <MaterialCommunityIcons ) : (
<MaterialCommunityIcons
// $FlowFixMe // $FlowFixMe
name={item.image} name={item.image}
color={this.props.theme.colors.primary} color={props.theme.colors.primary}
size={40}/>} size={40}
> />
)
}>
{/* $FlowFixMe */} {/* $FlowFixMe */}
<FlatList <FlatList
data={item.content} data={item.content}
extraData={this.props.activeDashboard.toString()} extraData={props.activeDashboard.toString()}
renderItem={this.renderItem} renderItem={this.getRenderItem}
listKey={item.key} listKey={item.key}
// Performance props, see https://reactnative.dev/docs/optimizing-flatlist-configuration // Performance props, see https://reactnative.dev/docs/optimizing-flatlist-configuration
getItemLayout={this.itemLayout} getItemLayout={this.getItemLayout}
removeClippedSubviews={true} removeClippedSubviews
/> />
</AnimatedAccordion> </AnimatedAccordion>
</View> </View>
@ -69,4 +86,4 @@ class DashboardEditAccordion extends React.Component<Props> {
} }
} }
export default withTheme(DashboardEditAccordion) export default withTheme(DashboardEditAccordion);

View file

@ -1,51 +1,57 @@
// @flow // @flow
import * as React from 'react'; import * as React from 'react';
import {Image} from "react-native"; import {Image} from 'react-native';
import {List, withTheme} from 'react-native-paper'; import {List, withTheme} from 'react-native-paper';
import type {CustomTheme} from "../../../managers/ThemeManager"; import type {CustomTheme} from '../../../managers/ThemeManager';
import type {ServiceItem} from "../../../managers/ServicesManager"; import type {ServiceItemType} from '../../../managers/ServicesManager';
type Props = { type PropsType = {
item: ServiceItem, item: ServiceItemType,
isActive: boolean, isActive: boolean,
height: number, height: number,
onPress: () => void, onPress: () => void,
theme: CustomTheme, theme: CustomTheme,
};
class DashboardEditItem extends React.Component<PropsType> {
shouldComponentUpdate(nextProps: PropsType): boolean {
const {isActive} = this.props;
return nextProps.isActive !== isActive;
} }
class DashboardEditItem extends React.Component<Props> { render(): React.Node {
const {props} = this;
shouldComponentUpdate(nextProps: Props) {
return (nextProps.isActive !== this.props.isActive);
}
render() {
return ( return (
<List.Item <List.Item
title={this.props.item.title} title={props.item.title}
description={this.props.item.subtitle} description={props.item.subtitle}
onPress={this.props.isActive ? null : this.props.onPress} onPress={props.isActive ? null : props.onPress}
left={props => left={(): React.Node => (
<Image <Image
{...props} source={{uri: props.item.image}}
source={{uri: this.props.item.image}}
style={{ style={{
width: 40, width: 40,
height: 40 height: 40,
}} }}
/>} />
right={props => this.props.isActive )}
? <List.Icon right={({size}: {size: number}): React.Node =>
{...props} props.isActive ? (
icon={"check"} <List.Icon
color={this.props.theme.colors.success} size={size}
/> : null} icon="check"
color={props.theme.colors.success}
/>
) : null
}
style={{ style={{
height: this.props.height, height: props.height,
justifyContent: 'center', justifyContent: 'center',
paddingLeft: 30, paddingLeft: 30,
backgroundColor: this.props.isActive ? this.props.theme.colors.proxiwashFinishedColor : "transparent" backgroundColor: props.isActive
? props.theme.colors.proxiwashFinishedColor
: 'transparent',
}} }}
/> />
); );

View file

@ -2,10 +2,10 @@
import * as React from 'react'; import * as React from 'react';
import {TouchableRipple, withTheme} from 'react-native-paper'; import {TouchableRipple, withTheme} from 'react-native-paper';
import {Dimensions, Image, View} from "react-native"; import {Dimensions, Image, View} from 'react-native';
import type {CustomTheme} from "../../../managers/ThemeManager"; import type {CustomTheme} from '../../../managers/ThemeManager';
type Props = { type PropsType = {
image: string, image: string,
isActive: boolean, isActive: boolean,
onPress: () => void, onPress: () => void,
@ -15,44 +15,44 @@ type Props = {
/** /**
* Component used to render a small dashboard item * Component used to render a small dashboard item
*/ */
class DashboardEditPreviewItem extends React.Component<Props> { class DashboardEditPreviewItem extends React.Component<PropsType> {
itemSize: number; itemSize: number;
constructor(props: Props) { constructor(props: PropsType) {
super(props); super(props);
this.itemSize = Dimensions.get('window').width / 8; this.itemSize = Dimensions.get('window').width / 8;
} }
render() { render(): React.Node {
const props = this.props; const {props} = this;
return ( return (
<TouchableRipple <TouchableRipple
onPress={this.props.onPress} onPress={props.onPress}
borderless={true} borderless
style={{ style={{
marginLeft: 5, marginLeft: 5,
marginRight: 5, marginRight: 5,
backgroundColor: this.props.isActive ? this.props.theme.colors.textDisabled : "transparent", backgroundColor: props.isActive
borderRadius: 5 ? props.theme.colors.textDisabled
}} : 'transparent',
> borderRadius: 5,
<View style={{ }}>
<View
style={{
width: this.itemSize, width: this.itemSize,
height: this.itemSize, height: this.itemSize,
}}> }}>
<Image <Image
source={{uri: props.image}} source={{uri: props.image}}
style={{ style={{
width: "100%", width: '100%',
height: "100%", height: '100%',
}} }}
/> />
</View> </View>
</TouchableRipple> </TouchableRipple>
); );
} }
} }
export default withTheme(DashboardEditPreviewItem) export default withTheme(DashboardEditPreviewItem);

View file

@ -1,27 +1,28 @@
// @flow // @flow
import * as React from 'react'; import * as React from 'react';
import {StackNavigationProp} from "@react-navigation/stack"; import {StackNavigationProp} from '@react-navigation/stack';
import type {CustomTheme} from "../../../managers/ThemeManager"; import {Button, Card, Paragraph, withTheme} from 'react-native-paper';
import {Button, Card, Paragraph, withTheme} from "react-native-paper"; import {FlatList} from 'react-native';
import type {ServiceCategory, ServiceItem} from "../../../managers/ServicesManager"; import {View} from 'react-native-animatable';
import DashboardManager from "../../../managers/DashboardManager"; import i18n from 'i18n-js';
import DashboardItem from "../../../components/Home/EventDashboardItem"; import type {
import {FlatList} from "react-native"; ServiceCategoryType,
import {View} from "react-native-animatable"; ServiceItemType,
import DashboardEditAccordion from "../../../components/Lists/DashboardEdit/DashboardEditAccordion"; } from '../../../managers/ServicesManager';
import DashboardEditPreviewItem from "../../../components/Lists/DashboardEdit/DashboardEditPreviewItem"; import DashboardManager from '../../../managers/DashboardManager';
import AsyncStorageManager from "../../../managers/AsyncStorageManager"; import DashboardItem from '../../../components/Home/EventDashboardItem';
import i18n from "i18n-js"; import DashboardEditAccordion from '../../../components/Lists/DashboardEdit/DashboardEditAccordion';
import CollapsibleFlatList from "../../../components/Collapsible/CollapsibleFlatList"; import DashboardEditPreviewItem from '../../../components/Lists/DashboardEdit/DashboardEditPreviewItem';
import AsyncStorageManager from '../../../managers/AsyncStorageManager';
import CollapsibleFlatList from '../../../components/Collapsible/CollapsibleFlatList';
type Props = { type PropsType = {
navigation: StackNavigationProp, navigation: StackNavigationProp,
theme: CustomTheme,
}; };
type State = { type StateType = {
currentDashboard: Array<ServiceItem>, currentDashboard: Array<ServiceItemType | null>,
currentDashboardIdList: Array<string>, currentDashboardIdList: Array<string>,
activeItem: number, activeItem: number,
}; };
@ -29,120 +30,137 @@ type State = {
/** /**
* Class defining the Settings screen. This screen shows controls to modify app preferences. * Class defining the Settings screen. This screen shows controls to modify app preferences.
*/ */
class DashboardEditScreen extends React.Component<Props, State> { class DashboardEditScreen extends React.Component<PropsType, StateType> {
content: Array<ServiceCategoryType>;
initialDashboard: Array<ServiceItemType | null>;
content: Array<ServiceCategory>;
initialDashboard: Array<ServiceItem>;
initialDashboardIdList: Array<string>; initialDashboardIdList: Array<string>;
constructor(props: Props) { constructor(props: PropsType) {
super(props); super(props);
let dashboardManager = new DashboardManager(this.props.navigation); const dashboardManager = new DashboardManager(props.navigation);
this.initialDashboardIdList = AsyncStorageManager.getObject(AsyncStorageManager.PREFERENCES.dashboardItems.key); this.initialDashboardIdList = AsyncStorageManager.getObject(
AsyncStorageManager.PREFERENCES.dashboardItems.key,
);
this.initialDashboard = dashboardManager.getCurrentDashboard(); this.initialDashboard = dashboardManager.getCurrentDashboard();
this.state = { this.state = {
currentDashboard: [...this.initialDashboard], currentDashboard: [...this.initialDashboard],
currentDashboardIdList: [...this.initialDashboardIdList], currentDashboardIdList: [...this.initialDashboardIdList],
activeItem: 0, activeItem: 0,
} };
this.content = dashboardManager.getCategories(); this.content = dashboardManager.getCategories();
} }
dashboardRowRenderItem = ({item, index}: { item: DashboardItem, index: number }) => { getDashboardRowRenderItem = ({
item,
index,
}: {
item: DashboardItem,
index: number,
}): React.Node => {
const {activeItem} = this.state;
return ( return (
<DashboardEditPreviewItem <DashboardEditPreviewItem
image={item.image} image={item.image}
onPress={() => this.setState({activeItem: index})} onPress={() => {
isActive={this.state.activeItem === index} this.setState({activeItem: index});
}}
isActive={activeItem === index}
/> />
); );
}; };
getDashboard(content: Array<DashboardItem>) { getDashboard(content: Array<DashboardItem>): React.Node {
return ( return (
<FlatList <FlatList
data={content} data={content}
extraData={this.state} extraData={this.state}
renderItem={this.dashboardRowRenderItem} renderItem={this.getDashboardRowRenderItem}
horizontal={true} horizontal
contentContainerStyle={{ contentContainerStyle={{
marginLeft: 'auto', marginLeft: 'auto',
marginRight: 'auto', marginRight: 'auto',
marginTop: 5, marginTop: 5,
}} }}
/>); />
);
} }
renderItem = ({item}: { item: ServiceCategory }) => { getRenderItem = ({item}: {item: ServiceCategoryType}): React.Node => {
const {currentDashboardIdList} = this.state;
return ( return (
<DashboardEditAccordion <DashboardEditAccordion
item={item} item={item}
onPress={this.updateDashboard} onPress={this.updateDashboard}
activeDashboard={this.state.currentDashboardIdList} activeDashboard={currentDashboardIdList}
/> />
); );
}; };
updateDashboard = (service: ServiceItem) => { getListHeader(): React.Node {
let currentDashboard = this.state.currentDashboard; const {currentDashboard} = this.state;
let currentDashboardIdList = this.state.currentDashboardIdList;
currentDashboard[this.state.activeItem] = service;
currentDashboardIdList[this.state.activeItem] = service.key;
this.setState({
currentDashboard: currentDashboard,
currentDashboardIdList: currentDashboardIdList,
});
AsyncStorageManager.set(AsyncStorageManager.PREFERENCES.dashboardItems.key, currentDashboardIdList);
}
undoDashboard = () => {
this.setState({
currentDashboard: [...this.initialDashboard],
currentDashboardIdList: [...this.initialDashboardIdList]
});
AsyncStorageManager.set(AsyncStorageManager.PREFERENCES.dashboardItems.key, this.initialDashboardIdList);
}
getListHeader() {
return ( return (
<Card style={{margin: 5}}> <Card style={{margin: 5}}>
<Card.Content> <Card.Content>
<View style={{padding: 5}}> <View style={{padding: 5}}>
<Button <Button
mode={"contained"} mode="contained"
onPress={this.undoDashboard} onPress={this.undoDashboard}
style={{ style={{
marginLeft: "auto", marginLeft: 'auto',
marginRight: "auto", marginRight: 'auto',
marginBottom: 10, marginBottom: 10,
}} }}>
> {i18n.t('screens.settings.dashboardEdit.undo')}
{i18n.t("screens.settings.dashboardEdit.undo")}
</Button> </Button>
<View style={{height: 50}}> <View style={{height: 50}}>
{this.getDashboard(this.state.currentDashboard)} {this.getDashboard(currentDashboard)}
</View> </View>
</View> </View>
<Paragraph style={{textAlign: "center"}}> <Paragraph style={{textAlign: 'center'}}>
{i18n.t("screens.settings.dashboardEdit.message")} {i18n.t('screens.settings.dashboardEdit.message')}
</Paragraph> </Paragraph>
</Card.Content> </Card.Content>
</Card> </Card>
); );
} }
updateDashboard = (service: ServiceItemType) => {
const {currentDashboard, currentDashboardIdList, activeItem} = this.state;
currentDashboard[activeItem] = service;
currentDashboardIdList[activeItem] = service.key;
this.setState({
currentDashboard,
currentDashboardIdList,
});
AsyncStorageManager.set(
AsyncStorageManager.PREFERENCES.dashboardItems.key,
currentDashboardIdList,
);
};
render() { undoDashboard = () => {
this.setState({
currentDashboard: [...this.initialDashboard],
currentDashboardIdList: [...this.initialDashboardIdList],
});
AsyncStorageManager.set(
AsyncStorageManager.PREFERENCES.dashboardItems.key,
this.initialDashboardIdList,
);
};
render(): React.Node {
return ( return (
<CollapsibleFlatList <CollapsibleFlatList
data={this.content} data={this.content}
renderItem={this.renderItem} renderItem={this.getRenderItem}
ListHeaderComponent={this.getListHeader()} ListHeaderComponent={this.getListHeader()}
style={{}} style={{}}
/> />
); );
} }
} }
export default withTheme(DashboardEditScreen); export default withTheme(DashboardEditScreen);