|
@@ -1,11 +1,12 @@
|
1
|
1
|
// @flow
|
2
|
2
|
|
3
|
3
|
import * as React from 'react';
|
4
|
|
-import {Image, Platform, ScrollView, View} from "react-native";
|
|
4
|
+import {FlatList, Image, Platform, ScrollView, View} from "react-native";
|
5
|
5
|
import i18n from "i18n-js";
|
6
|
6
|
import CustomModal from "../../components/Custom/CustomModal";
|
7
|
|
-import {Avatar, IconButton, List, RadioButton, Searchbar, Subheading, Text, Title, withTheme} from "react-native-paper";
|
8
|
|
-import PureFlatList from "../../components/Lists/PureFlatList";
|
|
7
|
+import {IconButton, RadioButton, Searchbar, Subheading, Text, Title, withTheme} from "react-native-paper";
|
|
8
|
+import {stringMatchQuery} from "../../utils/Search";
|
|
9
|
+import ProximoListItem from "../../components/Lists/ProximoListItem";
|
9
|
10
|
|
10
|
11
|
function sortPrice(a, b) {
|
11
|
12
|
return a.price - b.price;
|
|
@@ -39,7 +40,7 @@ type Props = {
|
39
|
40
|
type State = {
|
40
|
41
|
currentSortMode: number,
|
41
|
42
|
modalCurrentDisplayItem: React.Node,
|
42
|
|
- currentlyDisplayedData: Array<Object>,
|
|
43
|
+ currentSearchString: string,
|
43
|
44
|
};
|
44
|
45
|
|
45
|
46
|
/**
|
|
@@ -48,30 +49,21 @@ type State = {
|
48
|
49
|
class ProximoListScreen extends React.Component<Props, State> {
|
49
|
50
|
|
50
|
51
|
modalRef: Object;
|
51
|
|
- originalData: Array<Object>;
|
|
52
|
+ listData: Array<Object>;
|
52
|
53
|
shouldFocusSearchBar: boolean;
|
53
|
54
|
|
54
|
|
- onSearchStringChange: Function;
|
55
|
|
- onSortMenuPress: Function;
|
56
|
|
- renderItem: Function;
|
57
|
|
- onModalRef: Function;
|
58
|
|
-
|
59
|
55
|
colors: Object;
|
60
|
56
|
|
61
|
57
|
constructor(props) {
|
62
|
58
|
super(props);
|
63
|
|
- this.originalData = this.props.route.params['data']['data'];
|
|
59
|
+ this.listData = this.props.route.params['data']['data'];
|
64
|
60
|
this.shouldFocusSearchBar = this.props.route.params['shouldFocusSearchBar'];
|
65
|
61
|
this.state = {
|
66
|
|
- currentlyDisplayedData: this.originalData.sort(sortName),
|
|
62
|
+ currentSearchString: '',
|
67
|
63
|
currentSortMode: 3,
|
68
|
64
|
modalCurrentDisplayItem: null,
|
69
|
65
|
};
|
70
|
66
|
|
71
|
|
- this.onSearchStringChange = this.onSearchStringChange.bind(this);
|
72
|
|
- this.onSortMenuPress = this.onSortMenuPress.bind(this);
|
73
|
|
- this.renderItem = this.renderItem.bind(this);
|
74
|
|
- this.onModalRef = this.onModalRef.bind(this);
|
75
|
67
|
this.colors = props.theme.colors;
|
76
|
68
|
}
|
77
|
69
|
|
|
@@ -80,11 +72,9 @@ class ProximoListScreen extends React.Component<Props, State> {
|
80
|
72
|
* Creates the header content
|
81
|
73
|
*/
|
82
|
74
|
componentDidMount() {
|
83
|
|
- const button = this.getSortMenuButton.bind(this);
|
84
|
|
- const title = this.getSearchBar.bind(this);
|
85
|
75
|
this.props.navigation.setOptions({
|
86
|
|
- headerRight: button,
|
87
|
|
- headerTitle: title,
|
|
76
|
+ headerRight: this.getSortMenuButton,
|
|
77
|
+ headerTitle: this.getSearchBar,
|
88
|
78
|
headerBackTitleVisible: false,
|
89
|
79
|
headerTitleContainerStyle: Platform.OS === 'ios' ?
|
90
|
80
|
{marginHorizontal: 0, width: '70%'} :
|
|
@@ -97,21 +87,21 @@ class ProximoListScreen extends React.Component<Props, State> {
|
97
|
87
|
*
|
98
|
88
|
* @return {*}
|
99
|
89
|
*/
|
100
|
|
- getSearchBar() {
|
|
90
|
+ getSearchBar = () => {
|
101
|
91
|
return (
|
102
|
92
|
<Searchbar
|
103
|
93
|
placeholder={i18n.t('proximoScreen.search')}
|
104
|
94
|
onChangeText={this.onSearchStringChange}
|
105
|
95
|
/>
|
106
|
96
|
);
|
107
|
|
- }
|
|
97
|
+ };
|
108
|
98
|
|
109
|
99
|
/**
|
110
|
100
|
* Gets the sort menu header button
|
111
|
101
|
*
|
112
|
102
|
* @return {*}
|
113
|
103
|
*/
|
114
|
|
- getSortMenuButton() {
|
|
104
|
+ getSortMenuButton = () => {
|
115
|
105
|
return (
|
116
|
106
|
<IconButton
|
117
|
107
|
icon="sort"
|
|
@@ -120,20 +110,20 @@ class ProximoListScreen extends React.Component<Props, State> {
|
120
|
110
|
onPress={this.onSortMenuPress}
|
121
|
111
|
/>
|
122
|
112
|
);
|
123
|
|
- }
|
|
113
|
+ };
|
124
|
114
|
|
125
|
115
|
/**
|
126
|
116
|
* Callback used when clicking on the sort menu button.
|
127
|
117
|
* It will open the modal to show a sort selection
|
128
|
118
|
*/
|
129
|
|
- onSortMenuPress() {
|
|
119
|
+ onSortMenuPress = () => {
|
130
|
120
|
this.setState({
|
131
|
121
|
modalCurrentDisplayItem: this.getModalSortMenu()
|
132
|
122
|
});
|
133
|
123
|
if (this.modalRef) {
|
134
|
124
|
this.modalRef.open();
|
135
|
125
|
}
|
136
|
|
- }
|
|
126
|
+ };
|
137
|
127
|
|
138
|
128
|
/**
|
139
|
129
|
* Sets the current sort mode.
|
|
@@ -144,19 +134,18 @@ class ProximoListScreen extends React.Component<Props, State> {
|
144
|
134
|
this.setState({
|
145
|
135
|
currentSortMode: mode,
|
146
|
136
|
});
|
147
|
|
- let data = this.state.currentlyDisplayedData;
|
148
|
137
|
switch (mode) {
|
149
|
138
|
case 1:
|
150
|
|
- data.sort(sortPrice);
|
|
139
|
+ this.listData.sort(sortPrice);
|
151
|
140
|
break;
|
152
|
141
|
case 2:
|
153
|
|
- data.sort(sortPriceReverse);
|
|
142
|
+ this.listData.sort(sortPriceReverse);
|
154
|
143
|
break;
|
155
|
144
|
case 3:
|
156
|
|
- data.sort(sortName);
|
|
145
|
+ this.listData.sort(sortName);
|
157
|
146
|
break;
|
158
|
147
|
case 4:
|
159
|
|
- data.sort(sortNameReverse);
|
|
148
|
+ this.listData.sort(sortNameReverse);
|
160
|
149
|
break;
|
161
|
150
|
}
|
162
|
151
|
if (this.modalRef && mode !== this.state.currentSortMode) {
|
|
@@ -182,45 +171,13 @@ class ProximoListScreen extends React.Component<Props, State> {
|
182
|
171
|
}
|
183
|
172
|
|
184
|
173
|
/**
|
185
|
|
- * Sanitizes the given string to improve search performance
|
186
|
|
- *
|
187
|
|
- * @param str The string to sanitize
|
188
|
|
- * @return {string} The sanitized string
|
189
|
|
- */
|
190
|
|
- sanitizeString(str: string): string {
|
191
|
|
- return str.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "");
|
192
|
|
- }
|
193
|
|
-
|
194
|
|
- /**
|
195
|
|
- * Returns only articles whose name contains the given string.
|
196
|
|
- * Case and accents insensitive.
|
197
|
|
- *
|
198
|
|
- * @param str The string used to filter article names
|
199
|
|
- * @returns {[]}
|
200
|
|
- */
|
201
|
|
- filterData(str: string) {
|
202
|
|
- let filteredData = [];
|
203
|
|
- const testStr = this.sanitizeString(str);
|
204
|
|
- const articles = this.originalData;
|
205
|
|
- for (const article of articles) {
|
206
|
|
- const name = this.sanitizeString(article.name);
|
207
|
|
- if (name.includes(testStr)) {
|
208
|
|
- filteredData.push(article)
|
209
|
|
- }
|
210
|
|
- }
|
211
|
|
- return filteredData;
|
212
|
|
- }
|
213
|
|
-
|
214
|
|
- /**
|
215
|
174
|
* Callback used when the search changes
|
216
|
175
|
*
|
217
|
176
|
* @param str The new search string
|
218
|
177
|
*/
|
219
|
|
- onSearchStringChange(str: string) {
|
220
|
|
- this.setState({
|
221
|
|
- currentlyDisplayedData: this.filterData(str)
|
222
|
|
- })
|
223
|
|
- }
|
|
178
|
+ onSearchStringChange = (str: string) => {
|
|
179
|
+ this.setState({currentSearchString: str})
|
|
180
|
+ };
|
224
|
181
|
|
225
|
182
|
/**
|
226
|
183
|
* Gets the modal content depending on the given article
|
|
@@ -333,23 +290,20 @@ class ProximoListScreen extends React.Component<Props, State> {
|
333
|
290
|
* @param item The article to render
|
334
|
291
|
* @return {*}
|
335
|
292
|
*/
|
336
|
|
- renderItem({item}: Object) {
|
337
|
|
- const onPress = this.onListItemPress.bind(this, item);
|
338
|
|
- return (
|
339
|
|
- <List.Item
|
340
|
|
- title={item.name}
|
341
|
|
- description={item.quantity + ' ' + i18n.t('proximoScreen.inStock')}
|
342
|
|
- descriptionStyle={{color: this.getStockColor(parseInt(item.quantity))}}
|
343
|
|
- onPress={onPress}
|
344
|
|
- left={() => <Avatar.Image style={{backgroundColor: 'transparent'}} size={64}
|
345
|
|
- source={{uri: item.image}}/>}
|
346
|
|
- right={() =>
|
347
|
|
- <Text style={{fontWeight: "bold"}}>
|
348
|
|
- {item.price}€
|
349
|
|
- </Text>}
|
350
|
|
- />
|
351
|
|
- );
|
352
|
|
- }
|
|
293
|
+ renderItem = ({item}: Object) => {
|
|
294
|
+ if (stringMatchQuery(item.name, this.state.currentSearchString)) {
|
|
295
|
+ const onPress = this.onListItemPress.bind(this, item);
|
|
296
|
+ const color = this.getStockColor(parseInt(item.quantity));
|
|
297
|
+ return (
|
|
298
|
+ <ProximoListItem
|
|
299
|
+ item={item}
|
|
300
|
+ onPress={onPress}
|
|
301
|
+ color={color}
|
|
302
|
+ />
|
|
303
|
+ );
|
|
304
|
+ } else
|
|
305
|
+ return null;
|
|
306
|
+ };
|
353
|
307
|
|
354
|
308
|
/**
|
355
|
309
|
* Extracts a key for the given article
|
|
@@ -366,9 +320,9 @@ class ProximoListScreen extends React.Component<Props, State> {
|
366
|
320
|
*
|
367
|
321
|
* @param ref
|
368
|
322
|
*/
|
369
|
|
- onModalRef(ref: Object) {
|
|
323
|
+ onModalRef = (ref: Object) => {
|
370
|
324
|
this.modalRef = ref;
|
371
|
|
- }
|
|
325
|
+ };
|
372
|
326
|
|
373
|
327
|
render() {
|
374
|
328
|
return (
|
|
@@ -378,11 +332,12 @@ class ProximoListScreen extends React.Component<Props, State> {
|
378
|
332
|
<CustomModal onRef={this.onModalRef}>
|
379
|
333
|
{this.state.modalCurrentDisplayItem}
|
380
|
334
|
</CustomModal>
|
381
|
|
- <PureFlatList
|
382
|
|
- data={this.state.currentlyDisplayedData}
|
|
335
|
+ {/*$FlowFixMe*/}
|
|
336
|
+ <FlatList
|
|
337
|
+ data={this.listData}
|
|
338
|
+ extraData={this.state.currentSearchString + this.state.currentSortMode}
|
383
|
339
|
keyExtractor={this.keyExtractor}
|
384
|
340
|
renderItem={this.renderItem}
|
385
|
|
- updateData={this.state.currentSortMode}
|
386
|
341
|
/>
|
387
|
342
|
</View>
|
388
|
343
|
);
|