From 652b74b003b768babefb17c2fee4144c9160b98c Mon Sep 17 00:00:00 2001 From: Omar Mihilmy Date: Thu, 31 Jan 2019 06:48:46 +0000 Subject: [PATCH] UPS14-SuggestContacts (pull request #1) --- src/components/lists/ContactListItem.js | 24 +--- src/components/new/ListActivityIndicator.js | 20 +++ src/components/new/TagferAvatar.js | 30 +++++ src/components/new/TagferCheckbox.js | 32 +++++ src/components/new/UserListItem.js | 28 +++++ src/config/apiEndpoints.js | 6 +- src/config/router.js | 4 +- src/locales/translations/en.json | 4 +- src/screens/auth/SignupScreen5.js | 5 +- src/screens/auth/SignupScreen6.js | 133 ++++++++++++++++++++ 10 files changed, 261 insertions(+), 25 deletions(-) create mode 100644 src/components/new/ListActivityIndicator.js create mode 100644 src/components/new/TagferAvatar.js create mode 100644 src/components/new/TagferCheckbox.js create mode 100644 src/components/new/UserListItem.js create mode 100644 src/screens/auth/SignupScreen6.js diff --git a/src/components/lists/ContactListItem.js b/src/components/lists/ContactListItem.js index f266bdf..f3a0ec6 100644 --- a/src/components/lists/ContactListItem.js +++ b/src/components/lists/ContactListItem.js @@ -1,8 +1,10 @@ import React from 'react'; -import { CheckBox, ListItem, Avatar } from 'react-native-elements'; +import { ListItem, Avatar } from 'react-native-elements'; + import colors from '../../config/colors.json'; import { isEmpty } from '../../utils/aux'; +import TagferCheckbox from '../new/TagferCheckbox.js'; const ContactListItem = ({ contact, selected, onPress }) => { const { givenName, familyName, phoneNumbers } = contact; @@ -14,7 +16,7 @@ const ContactListItem = ({ contact, selected, onPress }) => { return ( } + avatar={} title={fullName} subtitle={phoneNumbers.length !== 0 ? phoneNumbers[0].number : ''} subtitleStyle={{ fontSize: 12, fontWeight: 'normal' }} @@ -25,23 +27,7 @@ const ContactListItem = ({ contact, selected, onPress }) => { ); }; -const TagferCheckbox = ({ isChecked, onPress }) => ( - -); - -const TagferAvatar = ({ firstName, lastName }) => { +const TagferInitialsAvatar = ({ firstName, lastName }) => { let initials = ''; if (!isEmpty(firstName)) { initials += firstName[0]; diff --git a/src/components/new/ListActivityIndicator.js b/src/components/new/ListActivityIndicator.js new file mode 100644 index 0000000..a03f1ca --- /dev/null +++ b/src/components/new/ListActivityIndicator.js @@ -0,0 +1,20 @@ +import React from 'react'; +import { ActivityIndicator, View } from 'react-native'; + +import colors from '../../config/colors.json'; + +const ListActivityIndicator = () => ( + + + +); + +const styles = { + container: { + flex: 1, + justifyContent: 'center', + marginTop: 30 + } +}; + +export default ListActivityIndicator; diff --git a/src/components/new/TagferAvatar.js b/src/components/new/TagferAvatar.js new file mode 100644 index 0000000..e8f8a7c --- /dev/null +++ b/src/components/new/TagferAvatar.js @@ -0,0 +1,30 @@ +import React from 'react'; +import { Avatar } from 'react-native-elements'; + +import { isEmpty } from '../../utils/aux'; + +const TagferAvatar = ({ size, photoURL }) => { + const uri = !isEmpty(photoURL) ? { uri: photoURL } : null; + const icon = isEmpty(photoURL) ? { name: 'user', type: 'entypo' } : null; + + return ( + + ); +}; + +function getSize(size) { + switch (size) { + case 'small': return { small: true }; + case 'medium': return { medium: true }; + case 'large': return { large: true }; + case 'xlarge': return { xlarge: true }; + default: throw new Error('Unsupported Tagfer Avatar size'); + } +} +export default TagferAvatar; diff --git a/src/components/new/TagferCheckbox.js b/src/components/new/TagferCheckbox.js new file mode 100644 index 0000000..e300970 --- /dev/null +++ b/src/components/new/TagferCheckbox.js @@ -0,0 +1,32 @@ +import React from 'react'; +import { CheckBox } from 'react-native-elements'; + +import colors from '../../config/colors.json'; + +const TagferCheckbox = ({ isChecked, onPress }) => ( + +); + +const styles = { + checkboxConainer: { + backgroundColor: colors.transparent, + borderWidth: 0, + margin: 0, + padding: 0, + marginRight: 0 + } +}; + +export default TagferCheckbox; diff --git a/src/components/new/UserListItem.js b/src/components/new/UserListItem.js new file mode 100644 index 0000000..a8d1624 --- /dev/null +++ b/src/components/new/UserListItem.js @@ -0,0 +1,28 @@ +import React from 'react'; +import { ListItem } from 'react-native-elements'; + +import TagferAvatar from './TagferAvatar'; +import TagferCheckbox from './TagferCheckbox'; + +import colors from '../../config/colors.json'; + +const UserListItem = ({ profile, selected, onPress }) => { + const { tagferId, fullName, jobTitle, companyName, photoURL } = profile; + const subtitle = `@${tagferId}\n${jobTitle} at ${companyName}`; + + return ( + } + title={fullName} + subtitle={subtitle} + subtitleNumberOfLines={3} + subtitleStyle={{ fontSize: 12, fontWeight: 'normal' }} + titleStyle={{ fontSize: 16, color: colors.black }} + rightIcon={} + containerStyle={{ backgroundColor: colors.white }} + />); +}; + +export default UserListItem +; diff --git a/src/config/apiEndpoints.js b/src/config/apiEndpoints.js index bc94af6..b29f775 100644 --- a/src/config/apiEndpoints.js +++ b/src/config/apiEndpoints.js @@ -30,7 +30,11 @@ const endpoints = { }, findUsersByPhone: { method: 'POST', - url: `${baseurl}/users/by/phone` + url: `${baseurl}/auth/findUsers/byPhone` + }, + suggestProfiles: { + method: 'GET', + url: `${baseurl}/profiles/suggest` }, signup: { method: 'PUT', diff --git a/src/config/router.js b/src/config/router.js index a89c4db..5da4291 100644 --- a/src/config/router.js +++ b/src/config/router.js @@ -7,6 +7,7 @@ import SignupScreenThreeA from '../screens/auth/SignupScreen3a'; import SignupScreenThreeB from '../screens/auth/SignupScreen3b'; import SignupScreenFour from '../screens/auth/SignupScreen4/SignupScreen4'; import SignupScreenFive from '../screens/auth/SignupScreen5'; +import SignupScreenSix from '../screens/auth/SignupScreen6'; import TwitterWebView from '../screens/auth/TwitterWebView'; import LinkedInWebView from '../screens/auth/LinkedInWebView'; import ForgotPasswordScreen from '../screens/auth/ForgotPasswordScreen'; @@ -20,7 +21,8 @@ const MainNavigator = createStackNavigator({ signup3a: SignupScreenThreeA, signup3b: SignupScreenThreeB, signup4: SignupScreenFour, - signup5: SignupScreenFive + signup5: SignupScreenFive, + signup6: SignupScreenSix }); const RootNavigator = createStackNavigator( diff --git a/src/locales/translations/en.json b/src/locales/translations/en.json index eacd7c3..1f2d303 100644 --- a/src/locales/translations/en.json +++ b/src/locales/translations/en.json @@ -202,6 +202,8 @@ }, "contact": { + "suggestedContacts_title": "Suggested contacts", + "suggestedContacts_description": "Link up with Tagfer’s Power Networkers", "createScreen_title": "Add Contact", "editScreen_title": "Edit Contact", "editScreen_textButton": "Text Contact", @@ -573,7 +575,7 @@ "minPassword": "6+ characters", "password": "Password", "password2": "Confirm Password", - "title": "Sign Up", + "title": "Signup", "urgencyMessage": "Claim your Tagfer ID before it's taken." }, "defaultProfileCreate": { diff --git a/src/screens/auth/SignupScreen5.js b/src/screens/auth/SignupScreen5.js index 0c9ed13..703c524 100644 --- a/src/screens/auth/SignupScreen5.js +++ b/src/screens/auth/SignupScreen5.js @@ -53,7 +53,7 @@ export default class SignupScreenFive extends React.Component { if (selectedContacts.has(index)) { selectedContacts.delete(index); } else { - const phoneNumbers = this.state.allContacts[index].phoneNumbers; + const phoneNumbers = state.allContacts[index].phoneNumbers; selectedContacts.set(index, phoneNumbers); } @@ -69,7 +69,7 @@ export default class SignupScreenFive extends React.Component { phoneNumbers.push(...record.map(entry => entry.number)); } - fetchAuth(endpoints.findUsersByPhone, { contacts: phoneNumbers }) + fetchAuth(endpoints.findUsersByPhone, { phoneNumbers }) .then(res => console.log(res)) .catch(() => console.log(errors.APP_NETWORK_ERROR)); @@ -152,7 +152,6 @@ export default class SignupScreenFive extends React.Component { onPress={this.onSaveButtonPress.bind(this)} title={strings('common.buttons.saveAndContinue')} buttonStyle={styles.buttonStyle} - loading={this.state.loading} fontSize={20} iconRight={styles.chevronIconStyle} /> diff --git a/src/screens/auth/SignupScreen6.js b/src/screens/auth/SignupScreen6.js new file mode 100644 index 0000000..50e227d --- /dev/null +++ b/src/screens/auth/SignupScreen6.js @@ -0,0 +1,133 @@ +import React from 'react'; +import { Dimensions, Text, View, FlatList, TouchableOpacity } from 'react-native'; +import { Button } from 'react-native-elements'; + +import { strings } from '../../locales/i18n'; +import { fetchAuth } from '../../utils/fetch'; +import { showFlashErrorMessage } from '../../utils/errorHandler'; + +import UserListItem from '../../components/new/UserListItem'; +import ListActivityIndicator from '../../components/new/ListActivityIndicator'; +import colors from '../../config/colors.json'; +import errors from '../../config/errors'; +import endpoints from '../../config/apiEndpoints'; + +export default class SignupScreenSix extends React.Component { + static navigationOptions = { + title: strings('contact.suggestedContacts_title'), + headerStyle: { borderBottomWidth: 0, backgroundColor: colors.offWhite }, + headerTintColor: '#0D497E', + headerRight: 6/6 + }; + + constructor(props) { + super(props); + this.state = { + users: [], + selectedUsers: new Map() + }; + + this.onLoad(); + } + + // Load suggested contacts + onLoad() { + fetchAuth(endpoints.suggestProfiles) + .then(result => this.setState({ users: result.profiles })) + .catch(() => showFlashErrorMessage(errors.APP_NETWORK_ERROR)); + } + + // Add user to selected map + onSelectUser(index) { + this.setState((state) => { + const selectedUsers = new Map(state.selectedUsers); + if (selectedUsers.has(index)) { + selectedUsers.delete(index); + } else { + selectedUsers.set(index, state.users[index].tagferId); + } + + return { selectedUsers }; + }); + } + + // Implement the signup functionality + // TODO: Add all the Realm handlers to handle saving the data + onSignup() { + console.log('Unimplemented Signup'); + console.log([...this.state.selectedUsers.values()]); + } + + // Render a single entry in the list + renderItem(profile, index) { + const selected = this.state.selectedUsers.has(index); + return this.onSelectUser(index)} />; + } + + render() { + return ( + + {/* INSTRUCTIONS + SKIP BUTTON */} + + + {/* SUGGESTED CONTACTS */} + this.renderItem(item, index)} + keyExtractor={(item) => item.tagferId} + style={{ flex: 1, marginHorizontal: 10 }} + ListEmptyComponent={} + /> + + {/* SIGNUP BUTTON */} +