UPS8: Add profile switching for profile view form

- user can now switch between profiles using the footer
- footer implemented
- still working on menu drawer
This commit is contained in:
Okechi Onyeje 2019-02-02 22:30:45 -05:00
parent fc103856a9
commit 933185f478
10 changed files with 7586 additions and 17242 deletions

24487
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -7,6 +7,7 @@
"test": "jest"
},
"dependencies": {
"@babel/runtime": "^7.3.1",
"acorn": "^6.0.4",
"i18n-js": "^3.1.0",
"react": "16.6.3",

View File

@ -4,7 +4,7 @@ import React, { Component } from 'react';
import { Dimensions, Image, Text, View } from 'react-native';
import { Icon } from 'react-native-elements';
import ModalDropdown from 'react-native-modal-dropdown';
import { NavigationActions } from 'react-navigation';
import { NavigationActions, StackActions } from 'react-navigation';
import colors from '../../config/colors.json';
const GREEN_CHECK_IMAGE = require('../../../assets/GreenCheck.png');
@ -13,10 +13,25 @@ const SCREEN_WIDTH = Dimensions.get('window').width;
let profileNames = [];
export default class Footer extends Component {
constructor(props) {
super(props);
if (props.profiles) {
profileNames = [];
for (let i = 0; i < this.props.profiles.length; i++) {
const profile = this.props.profiles[i].profile;
if (profile) {
profileNames.push(profile.profileName);
}
}
}
}
/**
* Component Will Mount
**/
componentWillMount() {
console.log("will profile fetch");
//this.props.profileFetch();
}
@ -26,8 +41,13 @@ export default class Footer extends Component {
componentWillReceiveProps(nextProps) {
if (nextProps.profiles) {
profileNames = [];
for (let i = 0; i < this.props.profiles.length; i++) {
profileNames.push(this.props.profiles[i].profileName);
const profiles = (nextProps.profiles ? nextProps.profiles : this.props.profiles);
profiles.shift();
for (let i = 0; i < profiles.length; i++) {
const profile = profiles[i].profile;
if (profile) {
profileNames.push(profile.profileName);
}
}
}
}
@ -82,10 +102,11 @@ export default class Footer extends Component {
* Navigates to the profile home screen for the given profile
**/
processProfileSelection(idx) {
const resetAction = NavigationActions.reset({
const profile = this.props.profiles[idx].profile;
const resetAction = StackActions.reset({
index: 0,
actions: [
NavigationActions.navigate({ routeName: 'mainOptionsMenu', params: { profileIndex: idx, profileName: this.props.profiles[idx].profileName } })
NavigationActions.navigate({ routeName: 'profileHome', params: { profileIndex: idx, profileName: (profile ? profile.profileName : null), profiles: this.props.profiles } })
]
});
@ -118,7 +139,9 @@ export default class Footer extends Component {
* Adds an icon to the left of the profile name in the profile row
**/
renderLeftIcon(rowID) {
const base64 = this.props.profiles[rowID].profileAvatarImg;
const profile = this.props.profiles[rowID].profile;
const base64 = profile ? profile.photoURL : null;
if (base64) {
return (
@ -127,7 +150,7 @@ export default class Footer extends Component {
source={{ uri: base64 }}
style={styles.avatarSmallImageStyle}
/>
<Text style={[styles.modalDropdownDropdownTextStyle, { color: this.props.profiles[rowID].isDisabled ? colors.lightGrey : colors.black }]}>
<Text style={[styles.modalDropdownDropdownTextStyle, { color: (profile ? profile.isDisabled : false) ? colors.lightGrey : colors.black }]}>
{profileNames[rowID]}
</Text>
</View>
@ -142,7 +165,7 @@ export default class Footer extends Component {
color={colors.middleGrey}
containerStyle={styles.editIconWithAvatar}
/>
<Text style={[styles.modalDropdownDropdownTextStyle, { color: this.props.profiles[rowID].isDisabled ? colors.lightGrey : colors.black }]}>
<Text style={[styles.modalDropdownDropdownTextStyle, { color: (profile ? profile.isDisabled : false) ? colors.lightGrey : colors.black }]}>
{profileNames[rowID]}
</Text>
</View>
@ -153,8 +176,10 @@ export default class Footer extends Component {
* Used for custom styling of the modal dropdown
**/
renderModalDropdownRow(rowData, rowID, highlighted) {
const profile = this.props.profiles[rowID].profile;
return (
<View style={{ backgroundColor: this.props.profiles[rowID].isDisabled ? colors.offWhite : colors.white }}>
<View style={{ backgroundColor: (profile ? profile.isDisabled : false) ? colors.offWhite : colors.white }}>
<View style={styles.modalDropdownDropdownViewStyle}>
{this.renderLeftIcon(rowID)}
@ -169,8 +194,9 @@ export default class Footer extends Component {
**/
renderFinalIcon() {
const profileIndex = parseInt(this.props.profileIndex, 10);
const profile = this.props.profiles[profileIndex].profile;
const base64 = this.props.profileAvatarImg;
const base64 = profile.photoURL;
if (base64) {
return (

View File

@ -9,58 +9,13 @@ const scrollX = new Animated.Value(0);
export default class ProfileForm extends Component {
render() {
console.log(this.props.selectedProfile);
switch (this.props.profileFormMode) {
case 'view':
return (
<View>
<ProfileViewForm
defaultProfile={/*this.props.defaultProfile*/
{
keywords: ['webdev', 'music', 'freelance'],
profileName: 'Business Profile',
tagferId: 'jdshgbjdhbf',
fullName: 'testName',
headline: 'Software Engineer at Company',
titleAndCompany: 'Title and Company',
location: 'Some Location',
isPublicProfile: true,
about: 'about txt',
bizCardImg: null,
avatarImg: null,
firstName: null,
lastName: 'Lastynameson',
primaryPhone: '4435465434',
secondaryPhone: '4434532432',
extension: 'nice-extension',
howIHelp: 'i help alot i think...',
whatINeed: 'i need more needs',
workPhone: '4435243746',
fax: '7654635432',
email: 'some@example.com',
website: 'examplesofexam.com',
street: 'street road',
address2: '443 agreat dres',
city: 'cityville',
region: 'DC',
postalCode: '20001',
country: 'USA',
referralId: '',
addedExperience: [{
jobTitle: 'Engineer',
jobCompany: 'Some Company',
jobDates: '01/01/19 - 01/15/19',
jobLocation: 'USA',
jobSummary: 'My great job summary'
}],
addedEducation: [{
school: 'UMD',
degree: 'B.S.',
fieldOfStudy: 'Computer Engineering',
schoolDates: '01/11/18 - 01/19/19',
educationSummary: 'Some cool education'
}]
}
}
selectedProfile={this.props.selectedProfile.profile}
profiles={this.props.profiles}
formMode={PROFILE_FORM}
DOTS_SIZE={DOTS_SIZE}

View File

@ -7,6 +7,7 @@ import BizCardView from '../../../components/BizCard/BizCardView';
import styles from './styles';
import { Keyword } from './../../common/Keyword';
import { strings } from '../../../locales/i18n';
import TagferAvatar from '../../new/TagferAvatar';
export default class ProfileViewForm extends Component {
constructor(props) {
@ -16,60 +17,63 @@ export default class ProfileViewForm extends Component {
}
renderAboutSection() {
const defaultProfile = this.props.defaultProfile;
const selectedProfile = this.props.selectedProfile;
return (
<Card>
<FormLabel bold labelText={strings('common.contactFields.about_labelText')} />
<FormLabel labelText={defaultProfile.about} />
<FormLabel labelText={selectedProfile.about} />
<FormLabel bold labelText={strings('common.contactFields.howIHelp_labelText_profile')} />
<FormLabel labelText={defaultProfile.howIHelp} />
<FormLabel labelText={selectedProfile.help} />
<FormLabel bold labelText={strings('common.contactFields.whatINeed_labelText_profile')} />
<FormLabel labelText={defaultProfile.whatINeed} />
<FormLabel labelText={selectedProfile.need} />
</Card>
);
}
renderDetailsSection() {
const defaultProfile = this.props.defaultProfile;
const selectedProfile = this.props.selectedProfile;
console.log(`selected profiile: ${selectedProfile}`);
return (
<View style={{ flex: 1, flexDirection: 'column', alignItems: 'center', marginLeft: -10 }}>
<FormLabel bold labelText={`@${defaultProfile.tagferId}`} textStyle={{ color: styles.colors.darkGreen, fontSize: 18 }} />
<FormLabel bold labelText={defaultProfile.fullName} textStyle={{ fontSize: 22, marginHorizontal: 20, color: styles.colors.darkGrey }} />
<FormLabel bold labelText={defaultProfile.headline} textStyle={{ fontSize: 15, marginHorizontal: 20, color: styles.colors.labelBlue }} />
<FormLabel bold labelText={defaultProfile.titleAndCompany} textStyle={{ fontSize: 15, marginHorizontal: 20 }} />
<FormLabel bold labelText={defaultProfile.location} textStyle={{ fontSize: 15, marginHorizontal: 20, color: styles.colors.middleGrey }} />
<FormLabel bold labelText={`@${selectedProfile.tagferId}`} textStyle={{ color: styles.colors.darkGreen, fontSize: 18 }} />
<FormLabel bold labelText={selectedProfile.fullName} textStyle={{ fontSize: 22, marginHorizontal: 20, color: styles.colors.darkGrey }} />
{/* <FormLabel bold labelText={selectedProfile.headline} textStyle={{ fontSize: 15, marginHorizontal: 20, color: styles.colors.labelBlue }} /> */}
<FormLabel bold labelText={`${selectedProfile.jobTitle} at ${selectedProfile.companyName}`} textStyle={{ fontSize: 15, marginHorizontal: 20 }} />
<FormLabel bold labelText={selectedProfile.companyLocation} textStyle={{ fontSize: 15, marginHorizontal: 20, color: styles.colors.middleGrey }} />
</View>
);
}
renderExperienceSection() {
const defaultProfile = this.props.defaultProfile;
const selectedProfile = this.props.selectedProfile;
// NORMAL - VIEW MODE
let isAddedExperienceEmpty = true;
console.log(`addedExperience: ${defaultProfile.addedExperience}`);
for (let i = 0; i < defaultProfile.addedExperience.length; i++) {
if (!isAddedExperienceEmpty) {
break;
let isExperienceEmpty = true;
console.log(`experience: ${selectedProfile.experience}`);
if (selectedProfile.experience) {
for (let i = 0; i < selectedProfile.experience.length; i++) {
if (!isExperienceEmpty) {
break;
}
for (const property in selectedProfile.experience[i]) {
if (selectedProfile.experience[i][property].length > 0) {
isExperienceEmpty = false;
break;
}
}
}
// for (const property in defaultProfile.addedExperience[i]) {
// if (defaultProfile.addedExperience[i][property].length > 0) {
// isAddedExperienceEmpty = false;
// break;
// }
// }
}
if (!isAddedExperienceEmpty) {
const experienceList = defaultProfile.addedExperience.map((data, index) => {
if (!isExperienceEmpty) {
const experienceList = selectedProfile.experience.map((data, index) => {
if (index > 0) {
return (
<View key={index}>
<Divider style={styles.dividerStyle} />
<FormLabel labelText={data.jobTitle} />
<FormLabel labelText={data.jobCompany} />
<FormLabel labelText={data.jobDates} />
<FormLabel labelText={`${data.startDate} - ${data.endDate}`} />
<FormLabel labelText={data.jobLocation} />
<FormLabel labelText={data.jobSummary} />
</View>
@ -79,7 +83,7 @@ export default class ProfileViewForm extends Component {
<View key={index}>
<FormLabel labelText={data.jobTitle} />
<FormLabel labelText={data.jobCompany} />
<FormLabel labelText={data.jobDates} />
<FormLabel labelText={`${data.startDate} - ${data.endDate}`} />
<FormLabel labelText={data.jobLocation} />
<FormLabel labelText={data.jobSummary} />
</View>
@ -96,23 +100,25 @@ export default class ProfileViewForm extends Component {
}
renderEducationSection() {
const defaultProfile = this.props.defaultProfile;
let isAddedEducationEmpty = true;
console.log(`addedEducation: ${defaultProfile.addedEducation}`);
for (let i = 0; i < defaultProfile.addedEducation.length; i++) {
if (!isAddedEducationEmpty) {
break;
const selectedProfile = this.props.selectedProfile;
let isEducationEmpty = true;
console.log(`education: ${selectedProfile.education}`);
if (selectedProfile.education) {
for (let i = 0; i < selectedProfile.education.length; i++) {
if (!isEducationEmpty) {
break;
}
for (const property in selectedProfile.education[i]) {
if (selectedProfile.education[i][property].length > 0) {
isEducationEmpty = false;
break;
}
}
}
// for (const property in defaultProfile.addedEducation[i]) {
// if (defaultProfile.addedEducation[i][property].length > 0) {
// isAddedEducationEmpty = false;
// break;
// }
// }
}
if (!isAddedEducationEmpty) {
const educationList = defaultProfile.addedEducation.map((data, index) => {
if (!isEducationEmpty) {
const educationList = selectedProfile.education.map((data, index) => {
if (index > 0) {
return (
<View key={index}>
@ -120,8 +126,8 @@ export default class ProfileViewForm extends Component {
<FormLabel labelText={data.school} />
<FormLabel labelText={data.degree} />
<FormLabel labelText={data.fieldOfStudy} />
<FormLabel labelText={data.schoolDates} />
<FormLabel labelText={data.educationSummary} />
<FormLabel labelText={`${data.startDate} - ${data.endDate}`} />
<FormLabel labelText={data.summary} />
</View>
);
}
@ -130,8 +136,8 @@ export default class ProfileViewForm extends Component {
<FormLabel labelText={data.school} />
<FormLabel labelText={data.degree} />
<FormLabel labelText={data.fieldOfStudy} />
<FormLabel labelText={data.schoolDates} />
<FormLabel labelText={data.educationSummary} />
<FormLabel labelText={`${data.startDate} - ${data.endDate}`} />
<FormLabel labelText={data.summary} />
</View>
);
});
@ -146,8 +152,8 @@ export default class ProfileViewForm extends Component {
}
renderKeywordsSection() {
const defaultProfile = this.props.defaultProfile;
if (defaultProfile.keywords.length > 0) {
const selectedProfile = this.props.selectedProfile;
if (selectedProfile.keywords && selectedProfile.keywords.length > 0) {
return (
<Card>
<View style={styles.keywordViewStyle}>
@ -172,7 +178,7 @@ export default class ProfileViewForm extends Component {
}
renderWorkPhoneSection() {
const { workPhone, extension } = this.props.defaultProfile;
const { workPhone, extension } = this.props.selectedProfile;
console.log(`Work Phone: ${workPhone}`);
console.log(`Extension: ${extension}`);
if (!workPhone && !extension) {
@ -194,14 +200,13 @@ export default class ProfileViewForm extends Component {
* Renders each keyword onto the screen
**/
renderKeywords() {
const keywords = this.props.defaultProfile.keywords;
const keywords = this.props.selectedProfile.keywords;
return keywords.map((data, index) =>
(
<Keyword
key={index}
title={data}
onPressX={() => this.removeKeyword(index)}
displayX={this.props.isEditMode}
displayX={false}
index={index}
/>
));
@ -220,11 +225,12 @@ export default class ProfileViewForm extends Component {
scrollEventThrottle={16}
>
<View style={styles.slideStyle}>
{/* <ProfileAvatar
{...this.props}
formType={PROFILE_FORM}
isEditMode={this.props.profileFormMode}
/> */}
<View style={styles.avatar} >
<TagferAvatar
size={'large'}
photoURL={this.props.selectedProfile.photoURL}
/>
</View>
{this.renderDetailsSection()}
</View>
@ -258,7 +264,7 @@ export default class ProfileViewForm extends Component {
}
renderEmailSection() {
const { email } = this.props.defaultProfile;
const { email } = this.props.selectedProfile;
if (!email) {
return;
}
@ -272,7 +278,7 @@ export default class ProfileViewForm extends Component {
}
renderWebsiteSection() {
const { website } = this.props.defaultProfile;
const { website } = this.props.selectedProfile;
if (!website) {
return;
}
@ -286,7 +292,7 @@ export default class ProfileViewForm extends Component {
}
renderAddressSection() {
const { street, address2, city, region, postalCode, country } = this.props.defaultProfile;
const { street, address2, city, region, postalCode, country } = this.props.selectedProfile;
if (!street && !address2 && !city && !region && !postalCode && !country) {
return;
}
@ -315,10 +321,10 @@ export default class ProfileViewForm extends Component {
{this.renderWebsiteSection()}
{this.renderAddressSection()}
{this.renderPhoneSection(this.props.defaultProfile.primaryPhone, strings('common.contactFields.phone_primary_labelText'))}
{this.renderPhoneSection(this.props.defaultProfile.secondaryPhone, strings('common.contactFields.phone_secondary_labelText'))}
{this.renderPhoneSection(this.props.selectedProfile.primaryPhone, strings('common.contactFields.phone_primary_labelText'))}
{this.renderPhoneSection(this.props.selectedProfile.secondaryPhone, strings('common.contactFields.phone_secondary_labelText'))}
{this.renderWorkPhoneSection()}
{this.renderPhoneSection(this.props.defaultProfile.fax, strings('common.contactFields.fax_labelText'))}
{this.renderPhoneSection(this.props.selectedProfile.fax, strings('common.contactFields.fax_labelText'))}
{this.renderEmailSection()}
{this.renderKeywordsSection()}

View File

@ -3,6 +3,10 @@ import { SCREEN_WIDTH, colors } from '../../styleVars';
const styles = {
slideStyle: {
width: SCREEN_WIDTH,
alignItems: 'center'
},
avatar: {
paddingTop: 10
},
detailsSectionStyle: {
backgroundColor: colors.white,

View File

@ -42,7 +42,7 @@ const RootNavigator = createStackNavigator(
navigationOptions: { header: null }
},
twitterWebView: TwitterWebView,
linkedInWebView: LinkedInWebView
linkedInWebView: LinkedInWebView,
mainOptions: MainOptionsMenu
},
{

View File

@ -10,10 +10,13 @@ import { getUserProfiles } from '../../utils/profile';
import { showFlashErrorMessage } from '../../utils/errorHandler';
import styles from './styles';
let navigationObj;
export default class ProfileHomeScreen extends Component {
static navigationOptions = ({ navigation }) =>
({
title: 'Business Profile',
static navigationOptions = ({ navigation }) => {
navigationObj = navigation;
return ({
title: navigation.state.params ? navigation.state.params.profileName : 'Business Profile',
headerLeft: (
<Button
icon={{
@ -29,37 +32,67 @@ export default class ProfileHomeScreen extends Component {
/>
),
headerRight: <HeaderRight navigation={navigation} />
});
}
setStateAsync(state) {
return new Promise((resolve) => {
this.setState(state, resolve);
});
}
constructor(props) {
super(props);
console.log('component will be constructed');
console.log(this.props.navigation);
const navState = this.props.navigation.state;
let profiles;
let profileIndex;
let loading;
if (navState.params) {
profiles = navState.params.profiles;
profileIndex = navState.params.profileIndex;
loading = false;
} else {
profiles = [{ profile: {} }, { profile: {} }, { profile: {} }, { profile: {} }];
profileIndex = 0;
loading = true;
}
this.state = {
profiles: [],
loading: false,
profiles,
loading,
profileIndex,
profileFormMode: 'view'//props.profileFormMode
};
}
componentDidMount() {
this.getUserProfiles();
componentWillReceiveProps(nextProps) {
console.log(`Component receiving props:\n ${nextProps}`);
// if (nextProps) {
// this.setState({
// profiles: nextProps.profiles,
// profileIndex: nextProps.navigation.state.params.profileIndex
// });
// }
}
getUserProfiles() {
if (!this.state.profiles.length === 0) {
this.setState({
loading: true
}, async () => {
try {
const { profiles, defaultProfile } = await getUserProfiles();
this.setState({
loading: false,
profiles, //these two states will be replaced with calls to realm to save the state in the apps memory db
defaultProfile
});
} catch (error) {
showFlashErrorMessage(error);
}
});
async componentWillMount() {
console.log('component about to mount');
await this.getUserProfiles();
}
async getUserProfiles() {
if (!(this.state.profiles.length === 0) && this.state.loading) {
try {
const { profiles, defaultProfileIdx } = await getUserProfiles();
await this.setStateAsync({
loading: false,
profiles, //these two states will be replaced with calls to realm to save the state in the apps memory db
profileIndex: defaultProfileIdx
});
} catch (error) {
showFlashErrorMessage(error);
}
}
}
@ -74,7 +107,7 @@ export default class ProfileHomeScreen extends Component {
<ProfileForm
profileFormMode={this.state.profileFormMode}
profiles={this.state.profiles}
defaultProfile={this.props.defaultProfile}
selectedProfile={this.state.profiles[this.state.profileIndex]}
/>
<Spacer space={80} />
</ScrollView>
@ -84,7 +117,8 @@ export default class ProfileHomeScreen extends Component {
<Footer
{...this.props}
index={4}
profileIndex={this.props.profileIndex}
profiles={this.state.profiles}
profileIndex={this.state.profileIndex}
/>
</View>
</View>

View File

@ -1,20 +1,25 @@
import appConfig from '../config/appConfig.json';
const realm_auth_token = 'ed707765-ee0b-4fbc-8993-ccb8876f8045'; //@TODO: Remove when finished testing
//should only be used during signup and login flow to authenticate user
export function fetchAuth(endpoint, body, userAuthToken) {
export const fetchAuth = async (endpoint, body, userAuthToken) => {
const request = {
method: endpoint.method,
headers: {
Authorization: (!userAuthToken ? appConfig.appSecret : userAuthToken),
'Content-Type': 'application/json'
},
body: JSON.stringify(body)
body: endpoint.method !== 'GET' ? JSON.stringify(body) : undefined
};
return fetch(endpoint.url, request).then(res => res.json());
}
console.log(request);
return await fetch(endpoint.url, request).then(res => {
console.log(res);
return res.json();
}).catch(error => {
console.log(error);
throw error;
});
};
//should be called after user has been authenticated inorder to access rest of applications api services on the baclend
export function fetchGeneric(endpoint, body) {
return fetchAuth(endpoint, body, 'realm-user-auth-token');
}
export const fetchGeneric = async (endpoint, body) => await fetchAuth(endpoint, body, realm_auth_token /* test value */);

View File

@ -5,12 +5,12 @@ export const getUserProfiles = async () => {
try {
let i;
const profiles = [];
let defaultProfile;
let defaultProfileIdx;
for (i = 1; i <= 4; i++) {
profiles[i] = await fetchGeneric(endpoints.getUserProfile(i), {});
if (profiles[i].isPublicProfile) { defaultProfile = profiles[i]; }
if (profiles[i].profile.isPublicProfile) { defaultProfileIdx = i; }
}
return { profiles, defaultProfile };
return { profiles, defaultProfileIdx };
} catch (error) {
throw error;
}