UPS20-View and search all connections

This commit is contained in:
Omar 2019-02-23 13:30:21 -08:00
parent 5263e032b4
commit 6fd3cc46de
3 changed files with 246 additions and 11 deletions

View File

@ -20,6 +20,7 @@
"react-native-gesture-handler": "^1.0.12",
"react-native-image-picker": "^0.28.0",
"react-native-masked-text": "^1.9.2",
"react-native-material-menu": "^0.4.2",
"react-native-permissions": "^1.1.1",
"react-native-vector-icons": "^4.6.0",
"react-native-webview": "^2.14.3",
@ -27,16 +28,10 @@
"realm": "^2.23.0"
},
"devDependencies": {
"@storybook/react-native": "^4.1.6",
"babel-jest": "23.6.0",
"eslint": "^3.19.0",
"eslint-config-rallycoding": "^3.2.0",
"eslint-plugin-react": "^7.12.4",
"jest": "23.6.0",
"metro-react-native-babel-preset": "0.51.1",
"react-test-renderer": "16.6.3"
},
"jest": {
"preset": "react-native"
}
}

View File

@ -55,6 +55,10 @@ const endpoints = {
removeConnectionRequest: {
method: 'DELETE',
url: `${baseurl}/connections/me`
},
getAllConnections: {
method: 'GET',
url: `${baseurl}/connections/me`
}
};

View File

@ -1,21 +1,257 @@
import React from 'react';
import { Text, View } from 'react-native';
import { View, Text, FlatList, Keyboard, TouchableOpacity } from 'react-native';
import { SearchBar, ListItem, Icon } from 'react-native-elements';
import Menu, { MenuItem, MenuDivider } from 'react-native-material-menu';
import { fetchTagferApi } from '../../utils/fetch';
import { showFlashErrorMessage } from '../../utils/errorHandler';
import TagferAvatar from '../../components/new/TagferAvatar';
import endpoints from '../../config/apiEndpoints';
import colors from '../../config/colors.json';
export default class AllConnectionsScreen extends React.Component {
static navigationOptions = ({ navigation }) => {
const title = navigation.getParam('title', 'All');
return { title };
}
constructor(props) {
super(props);
this.state = {
profileN: 0,
dataViewable: [],
profile0: [],
profile1: [],
profile2: [],
profile3: [],
profile4: [],
loading: true,
isSearch: false
};
this.allProfiles = [];
this.sortMenu = null;
this.onFilter = this.onFilter.bind(this);
}
componentDidMount() {
this.onLoad();
this.keyboardDidShowListener = Keyboard.addListener('keyboardDidShow', () => this.searchMode());
this.keyboardDidShowListener = Keyboard.addListener('keyboardDidHide', () => this.setState({ isSearch: false }));
}
componentWillUnmount() {
this.keyboardDidShowListener.remove();
}
onFilter(profileN) {
this.setState({ profileN, dataViewable: this.state[`profile${profileN}`] });
}
async onLoad() {
const response = await fetchTagferApi(endpoints.getAllConnections);
if (response.error) {
return showFlashErrorMessage(response.error);
}
const { profile1, profile2, profile3, profile4 } = response;
this.allProfiles = [...profile1, ...profile2, ...profile3, ...profile4];
this.allProfiles.sort(this.compareBy('tagferId'));
this.setState({
dataViewable: this.allProfiles,
profile0: this.allProfiles,
profile1,
profile2,
profile3,
profile4,
loading: false
});
this.updateTitle();
}
onSearch(text) {
const profile0 = this.allProfiles.filter(profile => (
profile.fullName.toLowerCase().includes(text.toLowerCase())
|| profile.tagferId.toLowerCase().includes(text.toLowerCase())
));
this.setState((state) => {
if (state.profileN === 0) {
return { profile0, dataViewable: profile0 };
}
return { profile0 };
});
}
onSort(attribute) {
const { profileN } = this.state;
const sorted = this.state[`profile${profileN}`].sort(this.compareBy(attribute));
this.setState({ dataViewable: sorted });
this.sortMenu.hide();
}
searchMode() {
this.setState((state) => {
if (state.profileN !== 0) {
return { profileN: 0, dataViewable: this.allProfiles, isSearch: true };
}
return { isSearch: true };
});
}
updateTitle() {
let numOfContacts = this.allProfiles.length;
if (numOfContacts > 1000 && numOfContacts < 1000000) { numOfContacts = `${Math.floor(numOfContacts / 1000)}k`; }
if (numOfContacts > 1000000) { numOfContacts = `${Math.floor(numOfContacts / 1000000)}m`; }
this.props.navigation.setParams({ title: `All(${numOfContacts})` });
}
compareBy(attribute) {
return (item1, item2) => {
if (item1[attribute] > item2[attribute]) {
return 1;
} else if (item1[attribute] < item2[attribute]) {
return -1;
}
return 0;
};
}
renderItem(item) {
return <UserListItem profile={item} onPress={() => console.log(1)} />;
}
render() {
return (
<View style={styles.container}>
<Text>All Contacts</Text>
<SearchBar
lightTheme
placeholder='Search Contacts'
clearIcon
inputStyle={{ fontSize: 15 }}
onChangeText={(text) => this.onSearch(text)}
autoCorrect={false}
/>
<SortMenu
setMenu={ref => (this.sortMenu = ref)}
showMenu={() => this.sortMenu.show()}
onPress={(attribute) => this.onSort(attribute)}
/>
<FilterBar currFilter={this.state.profileN} onFilter={this.onFilter} isSearch={this.state.isSearch} />
<FlatList
data={this.state.dataViewable}
extraData={this.state}
renderItem={({ item, index }) => this.renderItem(item, index)}
keyExtractor={(item) => item.tagferId}
style={{ flex: 1, marginHorizontal: 10, marginTop: 10, borderRadius: 5 }}
refreshing={this.state.loading}
/>
</View>
);
}
}
const UserListItem = ({ profile, onPress }) => {
const { tagferId, fullName, jobTitle, companyName, photoURL } = profile;
const subtitle = `@${tagferId}\n${jobTitle} at ${companyName}`;
return (
<ListItem
roundAvatar
avatar={<TagferAvatar size='medium' photoURL={photoURL} color={colors.lightGrey} />}
title={fullName}
subtitle={subtitle}
subtitleNumberOfLines={3}
subtitleStyle={{ fontSize: 12, fontWeight: 'normal' }}
titleStyle={{ fontSize: 16, color: 'black' }}
containerStyle={{ backgroundColor: 'white' }}
onPress={onPress}
/>
);
};
const FilterBar = ({ currFilter, onFilter, isSearch }) => (
<View style={{ flexDirection: 'row', justifyContent: 'space-between' }}>
<ProfileFilter profileN={0} currFilter={currFilter} onPress={() => onFilter(0)} disabled={isSearch} />
<ProfileFilter profileN={1} currFilter={currFilter} onPress={() => onFilter(1)} disabled={isSearch} />
<ProfileFilter profileN={2} currFilter={currFilter} onPress={() => onFilter(2)} disabled={isSearch} />
<ProfileFilter profileN={3} currFilter={currFilter} onPress={() => onFilter(3)} disabled={isSearch} />
<ProfileFilter profileN={4} currFilter={currFilter} onPress={() => onFilter(4)} disabled={isSearch} />
</View>
);
const ProfileFilter = ({ profileN, currFilter, onPress, disabled }) => {
const title = profileN === 0 ? 'All' : `Profile ${profileN}`;
const isSelected = currFilter === profileN;
return (
<TouchableOpacity activeOpacity={0.5} style={styles.profileButton(isSelected)} onPress={onPress} disabled={disabled}>
<Text style={styles.profileButtonTitle(isSelected)}>{title}</Text>
</TouchableOpacity>
);
};
const SortButton = ({ onPress }) => (
<TouchableOpacity activeOpacity={0.8} style={styles.sortButton} onPress={onPress}>
<Icon name='chevron-up' type='font-awesome' color='white' size={9} />
<Text style={styles.sortButtonTitle}>AZ</Text>
<Icon name='chevron-down' type='font-awesome' color='white' size={9} />
</TouchableOpacity>
);
const SortMenu = ({ setMenu, showMenu, onPress }) => (
<View style={styles.sortMenu}>
<Menu ref={setMenu} button={<SortButton onPress={showMenu} />}>
<MenuItem onPress={() => onPress('fullName')} style={{ height: 36 }}>Name</MenuItem>
<MenuDivider />
<MenuItem onPress={() => onPress('tagferId')} style={{ height: 36 }}>Tagfer ID</MenuItem>
</Menu>
</View>
);
const styles = {
container: {
flex: 1,
backgroundColor: '#F5F8FA'
},
sortButton: {
backgroundColor: '#AAAFC4',
borderRadius: 5,
alignItems: 'center',
justifyContent: 'center',
alignItems: 'center'
}
paddingHorizontal: 5,
marginRight: 10
},
sortButtonTitle: {
fontSize: 13,
fontWeight: 'bold',
color: 'white'
},
sortMenu: {
alignItems: 'flex-end',
marginTop: 10
},
profileButton: (isSelected) => ({
alignItems: 'center',
flex: 1,
height: 30,
justifyContent: 'flex-end',
borderBottomWidth: 2,
borderColor: isSelected ? '#FF7C41' : '#B3B8CA'
}),
profileButtonTitle: (isSelected) => ({
textAlign: 'center',
fontSize: 15,
color: isSelected ? '#416788' : '#ACACAC',
fontWeight: isSelected ? 'bold' : 'normal'
})
};