Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Settings (Change Name/Number/Password) #148

Merged
merged 51 commits into from
May 17, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
c7fbb92
Added new firebase connection
wangannie Apr 12, 2020
6317b4b
Navigation log
wangannie Apr 12, 2020
a1feef5
Log resource card press
wangannie Apr 12, 2020
8174a21
Test logevent on ResourcesScreen
wangannie Apr 12, 2020
8f262ca
Log user id on signup or login
wangannie Apr 12, 2020
6462a3a
Fiex event messages
wangannie Apr 13, 2020
87de651
Cleanup
wangannie Apr 13, 2020
0b90c65
Lots of issues understanding verifier please help
kennethlien Apr 13, 2020
afe451d
gotta scheme
kennethlien Apr 16, 2020
0755220
thingy pops up
kennethlien Apr 16, 2020
0da3a7f
it texts now
kennethlien Apr 17, 2020
c6cf1aa
Rough hopefully functional recaptcha verification
kennethlien Apr 18, 2020
a01643d
Merge branch 'master' of https://github.com/calblueprint/dccentralkit…
wangannie Apr 18, 2020
c757431
Merge branch 'master' of https://github.com/calblueprint/dccentralkit…
wangannie Apr 18, 2020
f635387
Updated setUser to match Sentry
wangannie Apr 18, 2020
b1f4483
Updated to setUserProperties
wangannie Apr 18, 2020
a0b6a6a
Merge branch 'AnnieW/firebase' of https://github.com/calblueprint/dcc…
wangannie Apr 18, 2020
8e17e4e
Merge branch 'master' into kenneth/recaptcha
annieyro Apr 18, 2020
a2bf66d
Remove unused state, rename ref, add explicit modal close call, reord…
annieyro Apr 18, 2020
47f8253
FINISHED
kennethlien Apr 20, 2020
0fb3b16
fixed style and bugs
kennethlien Apr 23, 2020
55e4fe2
this one
kennethlien Apr 23, 2020
9e540e2
KeyboardAvoidingView setup
wangannie Apr 23, 2020
e232096
major bugfix, minor styling
kennethlien Apr 27, 2020
972db55
debugging!
kennethlien Apr 30, 2020
7da0099
Added dismisskeyboard on successful login and signup
wangannie Apr 30, 2020
a4e005a
removed unused line
kennethlien Apr 30, 2020
1194c42
cleaned code
kennethlien May 1, 2020
6125c00
Merge branch 'kenneth/recaptcha' of https://github.com/calblueprint/d…
kennethlien May 1, 2020
e061af5
cleaned code
kennethlien May 1, 2020
dec7605
Merge remote-tracking branch 'origin/master' into kenneth/recaptcha
annieyro May 3, 2020
b329536
fixed a proptype error
kennethlien May 3, 2020
3d76c2f
fixed some promise rejections
kennethlien May 4, 2020
b58ab99
added encryption to reset passwords
kennethlien May 5, 2020
430dbd8
await fixes for logout
kennethlien May 5, 2020
6367c15
Merge branch 'master' of https://github.com/calblueprint/dccentralkit…
wangannie May 5, 2020
7d06c2a
Add error handling back during onTextChange. Refactor permissions (le…
annieyro May 6, 2020
b3fc5e4
Missing peer dependency
annieyro May 6, 2020
6b78342
onTextChange error update edge cases
annieyro May 6, 2020
a1b840f
Move duplicate check
annieyro May 6, 2020
0a62343
figma
kennethlien May 7, 2020
71a40c9
Added back line that was lost in earlier PR
wangannie May 8, 2020
7b50caf
adding reloading and removed back button from success screens
kennethlien May 8, 2020
417643d
Added location settings, fixed About, cleanup
wangannie May 10, 2020
619f0c2
Added Updates.reload to all logout functions
wangannie May 10, 2020
7377130
capitalized O in logout
kennethlien May 11, 2020
daf718b
changed create account on guestmode to redirect to signupscreen
kennethlien May 17, 2020
e99173e
capitalization and forgot to push
kennethlien May 17, 2020
d9da6f8
Capitalization
wangannie May 17, 2020
4b7cb60
Changed to new phone number
wangannie May 17, 2020
aaa9c67
Merge branch 'master' of https://github.com/calblueprint/dccentralkit…
wangannie May 17, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added assets/images/blueprint-logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 5 additions & 3 deletions components/AuthTextField.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,14 @@ function AuthTextField({
errorColor={Colors.error}
returnKeyType="done"
keyboardType={
fieldType === 'Phone Number' || fieldType === 'Verification Code'
fieldType.includes('Phone Number') ||
fieldType === 'Verification Code'
? 'numeric'
: undefined
}
maxLength={
fieldType === 'Phone Number'
// eslint-disable-next-line no-nested-ternary
fieldType.includes('Phone Number')
? 10
: fieldType === 'Verification Code'
? 6
Expand All @@ -49,7 +51,7 @@ function AuthTextField({
secureTextEntry={fieldType.includes('assword')}
labelPadding={6}
/>
{fieldType === 'Name' && !error && (
{fieldType.includes('Name') && !error && (
<Caption color={Colors.activeText}>
Note: this is how clerks will greet you!
</Caption>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { CategoryCard, CategoryHeadingContainer } from '../../styled/resources';
import { Title } from '../BaseComponents';
import CircleIcon from '../CircleIcon';

function ResourceCategoryBar({ icon, title }) {
function CategoryBar({ icon, title }) {
return (
<CategoryCard>
<CircleIcon
Expand All @@ -20,9 +20,9 @@ function ResourceCategoryBar({ icon, title }) {
);
}

ResourceCategoryBar.propTypes = {
CategoryBar.propTypes = {
icon: PropTypes.string.isRequired,
title: PropTypes.string.isRequired,
};

export default ResourceCategoryBar;
export default CategoryBar;
35 changes: 35 additions & 0 deletions components/settings/SettingsCard.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import PropTypes from 'prop-types';
import React from 'react';
import { TouchableOpacity } from 'react-native';
import Colors from '../../constants/Colors';
import { ContentContainer, ResourceItemCard } from '../../styled/resources';
kennethlien marked this conversation as resolved.
Show resolved Hide resolved
import { Body, Subhead } from '../BaseComponents';

function SettingsCard({ title, description, navigation, titleColor }) {
return (
<TouchableOpacity onPress={() => navigation()}>
<ResourceItemCard>
<ContentContainer>
<Subhead color={titleColor}>{title}</Subhead>
{description === '' || (
<Body color={Colors.secondaryText}>{description}</Body>
)}
</ContentContainer>
</ResourceItemCard>
</TouchableOpacity>
);
}

SettingsCard.propTypes = {
title: PropTypes.string.isRequired,
titleColor: PropTypes.string,
description: PropTypes.string,
navigation: PropTypes.func.isRequired,
};

SettingsCard.defaultProps = {
titleColor: Colors.activeText,
description: '',
};

export default SettingsCard;
9 changes: 8 additions & 1 deletion lib/authUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,14 @@ import { createPushTokens, updateCustomers } from './airtable/request';

// Fields

export const signUpFields = { NAME: 0, PHONENUM: 1, PASSWORD: 2, NEWPASSWORD: 3, VERIFYPASSWORD: 4, CODE: 5 };
export const inputFields = {
NAME: 0,
PHONENUM: 1,
PASSWORD: 2,
NEWPASSWORD: 3,
VERIFYPASSWORD: 4,
CODE: 5,
};

// Encryption
export const encryptPassword = async (customerId, password) => {
Expand Down
6 changes: 6 additions & 0 deletions navigation/AppNavigator.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import AuthLoadingScreen from '../screens/auth/AuthLoadingScreen';
import DrawerContent from './DrawerContent';
import AuthStackNavigator from './stack_navigators/AuthStack';
import ResourcesStackNavigator from './stack_navigators/ResourcesStack';
import SettingsStackNavigator from './stack_navigators/SettingsStack';
import StoresStackNavigator from './stack_navigators/StoresStack';

const Drawer = createDrawerNavigator();
Expand Down Expand Up @@ -49,6 +50,11 @@ function DrawerNavigator() {
component={ResourcesStackNavigator}
options={{ title: 'Resources', swipeEnabled: false }}
/>
<Drawer.Screen
name="Settings"
component={SettingsStackNavigator}
options={{ title: 'Settings', swipeEnabled: false }}
/>
</Drawer.Navigator>
);
}
Expand Down
4 changes: 3 additions & 1 deletion navigation/DrawerContent.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { DrawerItemList } from '@react-navigation/drawer';
import { useFocusEffect, useNavigation } from '@react-navigation/native';
import { Updates } from 'expo';
import * as Analytics from 'expo-firebase-analytics';
import PropTypes from 'prop-types';
import React from 'react';
Expand Down Expand Up @@ -80,12 +81,13 @@ function DrawerContent(props) {
return null;
}
const logout = async () => {
AsyncStorage.clear();
await AsyncStorage.clear();
Sentry.configureScope((scope) => scope.clear());
setTimeout(function() {
kennethlien marked this conversation as resolved.
Show resolved Hide resolved
navigation.navigate('Auth');
}, 500);
props.navigation.closeDrawer();
Updates.reload();
};

return (
Expand Down
23 changes: 23 additions & 0 deletions navigation/stack_navigators/SettingsStack.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { createStackNavigator } from '@react-navigation/stack';
import React from 'react';
import Colors from '../../constants/Colors';
import NameChangeScreen from '../../screens/settings/NameChangeScreen';
import PhoneNumberChangeScreen from '../../screens/settings/PhoneNumberChangeScreen';
import SettingsScreen from '../../screens/settings/SettingsScreen';

const SettingsStack = createStackNavigator();

export default function SettingsStackNavigator() {
return (
<SettingsStack.Navigator
screenOptions={{
headerShown: false,
cardStyle: { backgroundColor: Colors.lightest },
gestureEnabled: false,
}}>
<SettingsStack.Screen name="Settings" component={SettingsScreen} />
<SettingsStack.Screen name="Name" component={NameChangeScreen} />
<SettingsStack.Screen name="Number" component={PhoneNumberChangeScreen} />
</SettingsStack.Navigator>
);
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,6 @@
},
"private": true,
"peerDependencies": {
"@unimodules/core": "*"
"@unimodules/core": "^5.1.2"
}
}
99 changes: 50 additions & 49 deletions screens/auth/PasswordResetScreen.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import {
import {
encryptPassword,
formatPhoneNumber,
signUpFields,
inputFields,
} from '../../lib/authUtils';
import {
AuthScreenContainer,
Expand All @@ -46,79 +46,80 @@ export default class PasswordResetScreen extends React.Component {
confirmed: false,
formattedPhoneNumber: '',
values: {
[signUpFields.PHONENUM]: '',
[signUpFields.NEWPASSWORD]: '',
[signUpFields.VERIFYPASSWORD]: '',
[inputFields.PHONENUM]: '',
[inputFields.NEWPASSWORD]: '',
[inputFields.VERIFYPASSWORD]: '',
},
errors: {
[signUpFields.PHONENUM]: '',
[signUpFields.NEWPASSWORD]: '',
[signUpFields.VERIFYPASSWORD]: '',
[inputFields.PHONENUM]: '',
[inputFields.NEWPASSWORD]: '',
[inputFields.VERIFYPASSWORD]: '',
},
};
}

// Check for an error with updated text
// Set errors and updated text in state
updateError = async (text, signUpField) => {
updateError = async (text, inputField) => {
let error = false;
let errorMsg = '';
// validate returns null if no error is found
switch (signUpField) {
case signUpFields.PHONENUM:
switch (inputField) {
case inputFields.PHONENUM:
errorMsg = validate('phoneNumber', text);
error = errorMsg !== null;
break;
case signUpFields.NEWPASSWORD:
case inputFields.NEWPASSWORD:
errorMsg = validate('password', text);
error = errorMsg !== null;
break;
case signUpFields.VERIFYPASSWORD:
case inputFields.VERIFYPASSWORD:
// Compare with new value
errorMsg =
this.state.values[signUpFields.NEWPASSWORD] ===
this.state.values[signUpFields.VERIFYPASSWORD]
this.state.values[inputFields.NEWPASSWORD] === text
? null
: 'Passwords must match';
error = errorMsg !== null;
break;
default:
console.log('Not reached');
}
if (error) {
this.setState({ confirmed: false });
} else if (
this.state.verified &&
this.state.values[signUpFields.NEWPASSWORD] ===
this.state.values[signUpFields.VERIFYPASSWORD]
) {
this.setState({ confirmed: true });
}
this.setState((prevState) => ({
errors: { ...prevState.errors, [signUpField]: errorMsg },
values: { ...prevState.values, [signUpField]: text },
errors: { ...prevState.errors, [inputField]: errorMsg },
values: { ...prevState.values, [inputField]: text },
confirmed:
// Compare with new verifyPassword value
inputField === inputFields.VERIFYPASSWORD
? prevState.verified &&
prevState.values[inputFields.NEWPASSWORD] === text &&
!error
: prevState.verified &&
prevState.values[inputFields.NEWPASSWORD] ===
prevState.values[inputFields.VERIFYPASSWORD] &&
!error,
}));

return error;
};

// onBlur callback is required in case customer taps on field, does nothing, and taps out
onBlur = async (signUpField) => {
await this.updateError(signUpField);
onBlur = async (inputField) => {
await this.updateError(inputField);
};

// onTextChange does a check before updating errors
// It can only remove errors, not trigger them
onTextChange = async (text, signUpField) => {
onTextChange = async (text, inputField) => {
// Only update error if there is currently an error
if (
this.state.errors[signUpField] ||
signUpField === signUpFields.NEWPASSWORD ||
signUpFields.VERIFYPASSWORD
this.state.errors[inputField] ||
inputField === inputFields.NEWPASSWORD ||
inputFields.VERIFYPASSWORD
) {
await this.updateError(text, signUpField);
await this.updateError(text, inputField);
} else {
this.setState((prevState) => ({
values: { ...prevState.values, [signUpField]: text },
values: { ...prevState.values, [inputField]: text },
}));
}
};
Expand All @@ -132,7 +133,7 @@ export default class PasswordResetScreen extends React.Component {
if (!duplicate) {
return;
}
const number = '+1'.concat(this.state.values[signUpFields.PHONENUM]);
const number = '+1'.concat(this.state.values[inputFields.PHONENUM]);
const phoneProvider = new firebase.auth.PhoneAuthProvider();
try {
const verificationId = await phoneProvider.verifyPhoneNumber(
Expand Down Expand Up @@ -167,7 +168,7 @@ export default class PasswordResetScreen extends React.Component {
findCustomer = async () => {
const formattedPhoneNumber = formatPhoneNumber(
// eslint-disable-next-line react/no-access-state-in-setstate
this.state.values[signUpFields.PHONENUM]
this.state.values[inputFields.PHONENUM]
);
this.setState({ formattedPhoneNumber });
try {
Expand All @@ -187,15 +188,15 @@ export default class PasswordResetScreen extends React.Component {
// We use the record ID generated by Airtable as the salt to encrypt
const encrypted = await encryptPassword(
this.state.customer.id,
this.state.values[signUpFields.NEWPASSWORD]
this.state.values[inputFields.NEWPASSWORD]
);
// Update the created record with the encrypted password
await updateCustomers(this.state.customer.id, { password: encrypted });
this.setState({ success: true });
};

render() {
const validNumber = !this.state.errors[signUpFields.PHONENUM];
const validNumber = !this.state.errors[inputFields.PHONENUM];
return (
<AuthScreenContainer>
<AuthScrollContainer
Expand Down Expand Up @@ -225,26 +226,26 @@ export default class PasswordResetScreen extends React.Component {
<FormContainer>
<AuthTextField
fieldType="New Password"
value={this.state.values[signUpFields.NEWPASSWORD]}
value={this.state.values[inputFields.NEWPASSWORD]}
onBlurCallback={(value) => {
this.updateError(value, signUpFields.NEWPASSWORD);
this.updateError(value, inputFields.NEWPASSWORD);
this.scrollView.scrollToEnd({ animated: true });
}}
changeTextCallback={(text) =>
this.onTextChange(text, signUpFields.NEWPASSWORD)
this.onTextChange(text, inputFields.NEWPASSWORD)
}
error={this.state.errors[signUpFields.NEWPASSWORD]}
error={this.state.errors[inputFields.NEWPASSWORD]}
/>
<AuthTextField
fieldType="Re-enter New Password"
value={this.state.values[signUpFields.VERIFYPASSWORD]}
value={this.state.values[inputFields.VERIFYPASSWORD]}
onBlurCallback={(value) =>
this.updateError(value, signUpFields.VERIFYPASSWORD)
this.updateError(value, inputFields.VERIFYPASSWORD)
}
changeTextCallback={(text) =>
this.onTextChange(text, signUpFields.VERIFYPASSWORD)
this.onTextChange(text, inputFields.VERIFYPASSWORD)
}
error={this.state.errors[signUpFields.VERIFYPASSWORD]}
error={this.state.errors[inputFields.VERIFYPASSWORD]}
/>
</FormContainer>
<FilledButtonContainer
Expand Down Expand Up @@ -278,15 +279,15 @@ export default class PasswordResetScreen extends React.Component {
<FormContainer>
<AuthTextField
fieldType="Phone Number"
value={this.state.values[signUpFields.PHONENUM]}
value={this.state.values[inputFields.PHONENUM]}
onBlurCallback={(value) =>
this.updateError(value, signUpFields.PHONENUM)
this.updateError(value, inputFields.PHONENUM)
}
changeTextCallback={(text) => {
this.scrollView.scrollToEnd({ animated: true });
this.onTextChange(text, signUpFields.PHONENUM);
this.onTextChange(text, inputFields.PHONENUM);
}}
error={this.state.errors[signUpFields.PHONENUM]}
error={this.state.errors[inputFields.PHONENUM]}
/>
</FormContainer>
<FilledButtonContainer
Expand Down
Loading