forked from vergnet/application-amicale
Improved search performance
This commit is contained in:
parent
8f1fc3f1bd
commit
c48887a0d8
5 changed files with 52 additions and 37 deletions
|
@ -25,8 +25,10 @@ class ClubListItem extends React.PureComponent<Props> {
|
|||
getCategoriesRender(categories: Array<number | null>) {
|
||||
let final = [];
|
||||
for (let i = 0; i < categories.length; i++) {
|
||||
if (categories[i] !== null)
|
||||
final.push(this.props.chipRender(this.props.categoryTranslator(categories[i])));
|
||||
if (categories[i] !== null){
|
||||
const category = this.props.categoryTranslator(categories[i]);
|
||||
final.push(this.props.chipRender(category, this.props.item.id + ':' + category.id));
|
||||
}
|
||||
}
|
||||
return <View style={{flexDirection: 'row'}}>{final}</View>;
|
||||
}
|
||||
|
|
|
@ -262,10 +262,8 @@ function ClubStackComponent() {
|
|||
name="ClubDisplayScreen"
|
||||
component={ClubDisplayScreen}
|
||||
options={({navigation}) => {
|
||||
const openDrawer = getDrawerButton.bind(this, navigation);
|
||||
return {
|
||||
title: "",
|
||||
headerLeft: openDrawer,
|
||||
...TransitionPresets.ModalSlideFromBottomIOS,
|
||||
};
|
||||
}}
|
||||
|
|
|
@ -52,19 +52,26 @@ class ClubDisplayScreen extends React.Component<Props, State> {
|
|||
return "";
|
||||
}
|
||||
|
||||
getCategoriesRender(categories: Array<number|null>) {
|
||||
getCategoriesRender(categories: Array<number | null>) {
|
||||
let final = [];
|
||||
for (let i = 0; i < categories.length; i++) {
|
||||
if (categories[i] !== null)
|
||||
final.push(<Chip style={{marginRight: 5}}>{this.getCategoryName(categories[i])}</Chip>);
|
||||
if (categories[i] !== null) {
|
||||
final.push(
|
||||
<Chip
|
||||
style={{marginRight: 5}}
|
||||
key={i.toString()}>
|
||||
{this.getCategoryName(categories[i])}
|
||||
</Chip>
|
||||
);
|
||||
}
|
||||
}
|
||||
return <View style={{flexDirection: 'row', marginTop: 5}}>{final}</View>;
|
||||
}
|
||||
|
||||
getResponsiblesRender(resp: Array<string>) {
|
||||
getManagersRender(resp: Array<string>) {
|
||||
let final = [];
|
||||
for (let i = 0; i < resp.length; i++) {
|
||||
final.push(<Paragraph>{resp[i]}</Paragraph>)
|
||||
final.push(<Paragraph key={i.toString()}>{resp[i]}</Paragraph>)
|
||||
}
|
||||
const hasManagers = resp.length > 0;
|
||||
return (
|
||||
|
@ -120,7 +127,7 @@ class ClubDisplayScreen extends React.Component<Props, State> {
|
|||
onLinkPress={openWebLink}/>
|
||||
</Card.Content>
|
||||
: <View/>}
|
||||
{this.getResponsiblesRender(this.displayData.responsibles)}
|
||||
{this.getManagersRender(this.displayData.responsibles)}
|
||||
</ScrollView>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import {Chip, Searchbar, withTheme} from 'react-native-paper';
|
|||
import AuthenticatedScreen from "../../components/Amicale/AuthenticatedScreen";
|
||||
import i18n from "i18n-js";
|
||||
import ClubListItem from "../../components/Lists/ClubListItem";
|
||||
import {isItemInCategoryFilter, stringMatchQuery} from "../../utils/Search";
|
||||
|
||||
type Props = {
|
||||
navigation: Object,
|
||||
|
@ -27,7 +28,6 @@ class ClubListScreen extends React.Component<Props, State> {
|
|||
colors: Object;
|
||||
|
||||
getRenderItem: Function;
|
||||
originalData: Array<Object>;
|
||||
categories: Array<Object>;
|
||||
|
||||
constructor(props) {
|
||||
|
@ -69,26 +69,17 @@ class ClubListScreen extends React.Component<Props, State> {
|
|||
* @param str The new search string
|
||||
*/
|
||||
onSearchStringChange = (str: string) => {
|
||||
this.updateFilteredData(this.sanitizeString(str), null);
|
||||
this.updateFilteredData(str, null);
|
||||
};
|
||||
|
||||
/**
|
||||
* Sanitizes the given string to improve search performance
|
||||
*
|
||||
* @param str The string to sanitize
|
||||
* @return {string} The sanitized string
|
||||
*/
|
||||
sanitizeString(str: string): string {
|
||||
return str.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "");
|
||||
}
|
||||
|
||||
keyExtractor = (item: Object) => {
|
||||
return item.name + item.logo;
|
||||
return item.id.toString();
|
||||
};
|
||||
|
||||
getScreen = (data: Object) => {
|
||||
this.categories = data.categories;
|
||||
return (
|
||||
//$FlowFixMe
|
||||
<FlatList
|
||||
data={data.clubs}
|
||||
keyExtractor={this.keyExtractor}
|
||||
|
@ -112,7 +103,7 @@ class ClubListScreen extends React.Component<Props, State> {
|
|||
if (index === -1)
|
||||
newCategoriesState.push(categoryId);
|
||||
else
|
||||
newCategoriesState.splice(index);
|
||||
newCategoriesState.splice(index,1);
|
||||
}
|
||||
if (filterStr !== null || categoryId !== null)
|
||||
this.setState({
|
||||
|
@ -121,21 +112,14 @@ class ClubListScreen extends React.Component<Props, State> {
|
|||
})
|
||||
}
|
||||
|
||||
isItemInCategoryFilter(categories: Array<string>) {
|
||||
for (const category of categories) {
|
||||
if (this.state.currentlySelectedCategories.indexOf(category) !== -1)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
getChipRender = (category: Object) => {
|
||||
getChipRender = (category: Object, key: string) => {
|
||||
const onPress = this.onChipSelect.bind(this, category.id);
|
||||
return <Chip
|
||||
selected={this.isItemInCategoryFilter([category.id])}
|
||||
selected={isItemInCategoryFilter(this.state.currentlySelectedCategories, [category.id])}
|
||||
mode={'outlined'}
|
||||
onPress={onPress}
|
||||
style={{marginRight: 5, marginBottom: 5}}
|
||||
key={key}
|
||||
>
|
||||
{category.name}
|
||||
</Chip>;
|
||||
|
@ -144,7 +128,7 @@ class ClubListScreen extends React.Component<Props, State> {
|
|||
getListHeader() {
|
||||
let final = [];
|
||||
for (let i = 0; i < this.categories.length; i++) {
|
||||
final.push(this.getChipRender(this.categories[i]));
|
||||
final.push(this.getChipRender(this.categories[i], this.categories[i].id));
|
||||
}
|
||||
return <View style={{
|
||||
justifyContent: 'space-around',
|
||||
|
@ -163,9 +147,9 @@ class ClubListScreen extends React.Component<Props, State> {
|
|||
|
||||
shouldRenderItem(item) {
|
||||
let shouldRender = this.state.currentlySelectedCategories.length === 0
|
||||
|| this.isItemInCategoryFilter(item.category);
|
||||
|| isItemInCategoryFilter(this.state.currentlySelectedCategories, item.category);
|
||||
if (shouldRender)
|
||||
shouldRender = this.sanitizeString(item.name).includes(this.state.currentSearchString);
|
||||
shouldRender = stringMatchQuery(item.name, this.state.currentSearchString);
|
||||
return shouldRender;
|
||||
}
|
||||
|
||||
|
|
24
utils/Search.js
Normal file
24
utils/Search.js
Normal file
|
@ -0,0 +1,24 @@
|
|||
|
||||
|
||||
|
||||
/**
|
||||
* Sanitizes the given string to improve search performance
|
||||
*
|
||||
* @param str The string to sanitize
|
||||
* @return {string} The sanitized string
|
||||
*/
|
||||
export function sanitizeString(str: string): string {
|
||||
return str.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "");
|
||||
}
|
||||
|
||||
export function stringMatchQuery(str: string, query: string) {
|
||||
return sanitizeString(str).includes(sanitizeString(query));
|
||||
}
|
||||
|
||||
export function isItemInCategoryFilter(filter: Array<string>, categories: Array<string>) {
|
||||
for (const category of categories) {
|
||||
if (filter.indexOf(category) !== -1)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
Loading…
Reference in a new issue