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

Solved closing of keyboard on changing text field on profile page #9441

Merged
merged 76 commits into from
Sep 6, 2022
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
76 commits
Select commit Hold shift + click to select a range
8e9b60d
fixed closing of keyboard on changing text field on profile page
liyamahendra Jun 14, 2022
54e0294
Solved the incorrect display of error at bottom
liyamahendra Jun 16, 2022
26d331a
Solved automatic timezone checkbox not being clickable
liyamahendra Jun 16, 2022
060f307
Making CheckboxWithLabel compatible with the Form
liyamahendra Jun 17, 2022
d04ecac
Renamed Set Automatic Timezone Checkbox inputID
liyamahendra Jun 17, 2022
7d07035
Moved the character limit value to CONST
liyamahendra Jun 17, 2022
c4e1cf3
refactored doesFailCharacterLimit function and ProfilePage validation
liyamahendra Jun 17, 2022
e844388
Refactoring ProfilePage validation
liyamahendra Jun 17, 2022
651efb7
Fixed lint error
liyamahendra Jun 17, 2022
885ef63
added JSDoc for validate method
liyamahendra Jun 24, 2022
7fe6433
Using PROFILE_INPUTS_CHARACTER_LIMIT in RequestCallPage and PersonalD…
liyamahendra Jun 24, 2022
c7e6ae2
Removed the redundant style
liyamahendra Jun 24, 2022
a9a8b78
Refactored form name from PROFILE_FORM to PROFILE_SETTINGS_FORM
liyamahendra Jun 25, 2022
bcbee9a
refactored ProfilePage
liyamahendra Jun 25, 2022
fafbdeb
Removed inputID from LoginField
liyamahendra Jun 27, 2022
bacc8eb
Removed usage of getMaxCharacterError from validate method
liyamahendra Jun 27, 2022
10cfb09
Added missing import for Localize
liyamahendra Jun 29, 2022
b901c3c
Added JSdocs for values
liyamahendra Jun 29, 2022
e2e3e85
Removed firstName, lastName and pronouns from state
liyamahendra Jun 29, 2022
db10881
Removed firstName, lastName and pronouns from state and console.log s…
liyamahendra Jun 30, 2022
3fe935b
Moved state variables to class properties
liyamahendra Jul 1, 2022
329595b
changed if condition to ternary operator
liyamahendra Jul 2, 2022
0368f9b
Adding early return instead of conditionally wrapped function body
liyamahendra Jul 2, 2022
849ea0f
Added flexGrow1 to form style
liyamahendra Jul 2, 2022
614109e
Fixed self-select picker
liyamahendra Jul 2, 2022
b750b7b
Merge branch 'Expensify:main' into 9234
liyamahendra Jul 5, 2022
6bc29d9
Renamed PROFILE_INPUTS_CHARACTER_LIMIT to FORM_CHARACTER_LIMIT
liyamahendra Jul 11, 2022
bd42089
Making isAvatarChanged to true when updateAvatar is called
liyamahendra Jul 11, 2022
3c1b5c3
Saving draft values for all form elements
liyamahendra Jul 11, 2022
49f8a6d
Moved AvatarWithImagePicker outside form
liyamahendra Jul 11, 2022
0c93128
created a new function doesFailCharacterLimitAfterTrim
liyamahendra Jul 12, 2022
fe5933a
Resolved enable/disable of timezone picker
liyamahendra Jul 14, 2022
0e9ffbc
resolved conflicts
liyamahendra Jul 17, 2022
1542247
Merge branch 'Expensify:main' into 9234
liyamahendra Jul 20, 2022
303ab2c
Moved AvatarWithImagePicker inside Form
liyamahendra Jul 20, 2022
369ebe9
Merge branch '9234' of https://github.com/liyamahendra/Expensify into…
liyamahendra Jul 20, 2022
10f7274
Resolved conflicts due to rename of myPersonalDetails to currentUserP…
liyamahendra Jul 20, 2022
b60e13e
removed doesFailCharacterLimit
liyamahendra Jul 20, 2022
a1a1f38
Tested change related to currentUserPersonalDetails
liyamahendra Jul 20, 2022
7174104
solved the timezone guessing
liyamahendra Aug 2, 2022
e916b9f
Moved logins to state
liyamahendra Aug 2, 2022
eab67a8
Resolved merge conflicts
liyamahendra Aug 2, 2022
557c218
added missing curly brace
liyamahendra Aug 2, 2022
2247af9
Resolved conflicts
liyamahendra Aug 6, 2022
f43cbe7
Update src/libs/ValidationUtils.js
liyamahendra Aug 6, 2022
af2ba91
Keeping both doesFailCharacterLimit and doesFailCharacterLimitAfterTrim
liyamahendra Aug 6, 2022
a6d08bc
Revert package-lock.json
liyamahendra Aug 6, 2022
3ef2ae7
Update package-lock.json to main's codebase
liyamahendra Aug 8, 2022
78dcfd3
Fixed lint issue
liyamahendra Aug 8, 2022
7f88f46
Added a new line at bottom of package-lock.json
liyamahendra Aug 8, 2022
1791c52
Using doesFailCharacterLimit and trimming values
liyamahendra Aug 11, 2022
b760b67
Merge branch 'Expensify:main' into 9234
liyamahendra Aug 11, 2022
60c468b
Removed trim
liyamahendra Aug 12, 2022
3109ce3
Changes suggested by @luacmartins - Update src/pages/settings/Profile…
liyamahendra Aug 17, 2022
c088aca
Using PersonalDetails.updateProfile
liyamahendra Aug 17, 2022
63785a9
Merge branch 'Expensify:main' into 9234
liyamahendra Aug 19, 2022
4a7dcd8
Update src/pages/settings/Profile/ProfilePage.js
liyamahendra Aug 19, 2022
8e0b8b5
Update src/pages/settings/Profile/ProfilePage.js
liyamahendra Aug 19, 2022
13c853d
Update src/libs/actions/PersonalDetails.js
liyamahendra Aug 20, 2022
b80c9b8
Update src/pages/settings/Profile/ProfilePage.js
liyamahendra Aug 20, 2022
6664779
Update PersonalDetails.js
liyamahendra Aug 20, 2022
5822b7e
resolved conflicts
liyamahendra Aug 20, 2022
a059ebe
Removed shouldSaveDraft
liyamahendra Aug 22, 2022
313df27
Updated updateProfile function
liyamahendra Aug 23, 2022
30e704d
Moved PROFILE_SETTINGS_FORM to CONST
liyamahendra Aug 24, 2022
9dd6f06
Fixed lint - removed unused variable
liyamahendra Aug 25, 2022
c87184c
Resolved merge conflicts
liyamahendra Aug 25, 2022
82dd959
Removed KeyboardAvoidingView
liyamahendra Aug 31, 2022
da7d1b1
Resolved lint errors
liyamahendra Aug 31, 2022
963d242
resolved conflicts
liyamahendra Aug 31, 2022
447cd8a
Solved profile avatar update crash
liyamahendra Sep 3, 2022
a9c2cff
Trigger checks again
liyamahendra Sep 3, 2022
36061f6
Trigger checks again
liyamahendra Sep 3, 2022
9686c11
Using lodashGet for firstName and lastName
liyamahendra Sep 5, 2022
a796a5b
Removed unused constants
liyamahendra Sep 6, 2022
d035720
removed empty lines
liyamahendra Sep 6, 2022
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
1 change: 1 addition & 0 deletions src/ONYXKEYS.js
Original file line number Diff line number Diff line change
Expand Up @@ -194,5 +194,6 @@ export default {
// List of Form ids
FORMS: {
ADD_DEBIT_CARD_FORM: 'addDebitCardForm',
PROFILE_FORM: 'profileForm',
liyamahendra marked this conversation as resolved.
Show resolved Hide resolved
},
};
4 changes: 4 additions & 0 deletions src/libs/actions/PersonalDetails.js
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,10 @@ function setPersonalDetails(details, shouldGrowl) {
} else {
console.debug('Error while setting personal details', response);
}

Onyx.merge(ONYXKEYS.FORMS.PROFILE_FORM, {
isSubmitting: false,
});
});
}

Expand Down
136 changes: 87 additions & 49 deletions src/pages/settings/Profile/ProfilePage.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import lodashGet from 'lodash/get';
import React, {Component} from 'react';
import {withOnyx} from 'react-native-onyx';
import PropTypes from 'prop-types';
import {View, ScrollView} from 'react-native';
import {View} from 'react-native';
import Str from 'expensify-common/lib/str';
import moment from 'moment-timezone';
import _ from 'underscore';
Expand All @@ -18,17 +18,15 @@ import Text from '../../../components/Text';
import LoginField from './LoginField';
import withLocalize, {withLocalizePropTypes} from '../../../components/withLocalize';
import compose from '../../../libs/compose';
import Button from '../../../components/Button';
import KeyboardAvoidingView from '../../../components/KeyboardAvoidingView';
import FixedFooter from '../../../components/FixedFooter';
import TextInput from '../../../components/TextInput';
import Picker from '../../../components/Picker';
import FullNameInputRow from '../../../components/FullNameInputRow';
import CheckboxWithLabel from '../../../components/CheckboxWithLabel';
import AvatarWithImagePicker from '../../../components/AvatarWithImagePicker';
import currentUserPersonalDetailsPropsTypes from './currentUserPersonalDetailsPropsTypes';
import * as ValidationUtils from '../../../libs/ValidationUtils';
import * as ReportUtils from '../../../libs/ReportUtils';
import Form from '../../../components/Form';

const propTypes = {
/* Onyx Props */
Expand Down Expand Up @@ -86,9 +84,9 @@ class ProfilePage extends Component {
};

this.getLogins = this.getLogins.bind(this);
this.validate = this.validate.bind(this);
this.setAutomaticTimezone = this.setAutomaticTimezone.bind(this);
this.updatePersonalDetails = this.updatePersonalDetails.bind(this);
this.validateInputs = this.validateInputs.bind(this);
this.updateAvatar = this.updateAvatar.bind(this);
}

Expand Down Expand Up @@ -162,10 +160,6 @@ class ProfilePage extends Component {
* Submit form to update personal details
*/
liyamahendra marked this conversation as resolved.
Show resolved Hide resolved
updatePersonalDetails() {
if (!this.validateInputs()) {
return;
}

// Check if the user has modified their avatar
if ((this.props.myPersonalDetails.avatar !== this.state.avatar.uri) && this.state.isAvatarChanged) {
liyamahendra marked this conversation as resolved.
Show resolved Hide resolved
// If the user removed their profile photo, replace it accordingly with the default avatar
Expand All @@ -190,17 +184,46 @@ class ProfilePage extends Component {
}, true);
}

validateInputs() {
const [hasFirstNameError, hasLastNameError, hasPronounError] = ValidationUtils.doesFailCharacterLimit(
50,
[this.state.firstName.trim(), this.state.lastName.trim(), this.state.pronouns.trim()],
);
this.setState({
hasFirstNameError,
hasLastNameError,
hasPronounError,
});
return !hasFirstNameError && !hasLastNameError && !hasPronounError;
validate(values) {
liyamahendra marked this conversation as resolved.
Show resolved Hide resolved
const errors = {};

if (values.firstName) {
const [hasFirstNameError] = ValidationUtils.doesFailCharacterLimit(
50,
liyamahendra marked this conversation as resolved.
Show resolved Hide resolved
[values.firstName.trim()],
);

if(hasFirstNameError) {
this.setState({hasFirstNameError});
errors.firstName = PersonalDetails.getMaxCharacterError(this.state.hasFirstNameError);
}
}

if (values.lastName) {
liyamahendra marked this conversation as resolved.
Show resolved Hide resolved
const [hasLastNameError] = ValidationUtils.doesFailCharacterLimit(
50,
[values.lastName.trim()],
);

if(hasLastNameError) {
this.setState({hasLastNameError});
errors.lastName = PersonalDetails.getMaxCharacterError(this.state.hasLastNameError);
}
}

if (values.pronouns) {
const [hasPronounError] = ValidationUtils.doesFailCharacterLimit(
50,
[values.pronouns.trim()],
);

if(hasPronounError) {
this.setState({hasPronounError});
errors.pronouns = PersonalDetails.getMaxCharacterError(this.state.hasPronounError);
}
}

return errors;
}

render() {
Expand All @@ -209,14 +232,6 @@ class ProfilePage extends Component {
value: `${CONST.PRONOUNS.PREFIX}${key}`,
}));

// Disables button if none of the form values have changed
const isButtonDisabled = (this.props.myPersonalDetails.firstName === this.state.firstName.trim())
&& (this.props.myPersonalDetails.lastName === this.state.lastName.trim())
&& (this.props.myPersonalDetails.timezone.selected === this.state.selectedTimezone)
&& (this.props.myPersonalDetails.timezone.automatic === this.state.isAutomaticTimezone)
&& (this.props.myPersonalDetails.pronouns === this.state.pronouns.trim())
&& (!this.state.isAvatarChanged || this.props.myPersonalDetails.avatarUploading);

const pronounsPickerValue = this.state.hasSelfSelectedPronouns ? CONST.PRONOUNS.SELF_SELECT : this.state.pronouns;
liyamahendra marked this conversation as resolved.
Show resolved Hide resolved

return (
Expand All @@ -228,8 +243,15 @@ class ProfilePage extends Component {
onBackButtonPress={() => Navigation.navigate(ROUTES.SETTINGS)}
onCloseButtonPress={() => Navigation.dismissModal(true)}
/>
<ScrollView style={styles.flex1} contentContainerStyle={styles.p5}>
<Form
style={[styles.flex1, styles.p5]}
liyamahendra marked this conversation as resolved.
Show resolved Hide resolved
formID={ONYXKEYS.FORMS.PROFILE_FORM}
validate={this.validate}
onSubmit={this.updatePersonalDetails}
submitButtonText={this.props.translate('common.save')}
>
<AvatarWithImagePicker
inputID="avatar"
liyamahendra marked this conversation as resolved.
Show resolved Hide resolved
isUploading={this.props.myPersonalDetails.avatarUploading}
isUsingDefaultAvatar={this.state.avatar.uri.includes('/images/avatars/avatar')}
avatarURL={this.state.avatar.uri}
Expand All @@ -241,17 +263,36 @@ class ProfilePage extends Component {
<Text style={[styles.mt6, styles.mb6]}>
{this.props.translate('profilePage.tellUsAboutYourself')}
</Text>
<FullNameInputRow
firstName={this.state.firstName}
firstNameError={PersonalDetails.getMaxCharacterError(this.state.hasFirstNameError)}
lastName={this.state.lastName}
lastNameError={PersonalDetails.getMaxCharacterError(this.state.hasLastNameError)}
onChangeFirstName={firstName => this.setState({firstName})}
onChangeLastName={lastName => this.setState({lastName})}
style={[styles.mt4, styles.mb4]}
/>

liyamahendra marked this conversation as resolved.
Show resolved Hide resolved
<View style={[styles.flexRow, styles.mt4, styles.mb4]}>
<View style={styles.flex1}>
<TextInput
inputID="firstName"
name="fname"
label={this.props.translate('common.firstName')}
value={this.state.firstName}
liyamahendra marked this conversation as resolved.
Show resolved Hide resolved
hasError={this.state.hasFirstNameError}
errorText={PersonalDetails.getMaxCharacterError(this.state.hasFirstNameError)}
onChangeText={firstName => this.setState({firstName})}
liyamahendra marked this conversation as resolved.
Show resolved Hide resolved
placeholder={this.props.translate('profilePage.john')}
/>
</View>
<View style={[styles.flex1, styles.ml2]}>
<TextInput
inputID="lastName"
name="lname"
label={this.props.translate('common.lastName')}
value={this.state.lastName}
hasError={this.state.hasLastNameError}
errorText={PersonalDetails.getMaxCharacterError(this.state.hasLastNameError)}
onChangeText={lastName => this.setState({lastName})}
liyamahendra marked this conversation as resolved.
Show resolved Hide resolved
placeholder={this.props.translate('profilePage.doe')}
/>
</View>
</View>
<View style={styles.mb6}>
<Picker
inputID="pronounsPicker"
liyamahendra marked this conversation as resolved.
Show resolved Hide resolved
liyamahendra marked this conversation as resolved.
Show resolved Hide resolved
label={this.props.translate('profilePage.preferredPronouns')}
onInputChange={(pronouns) => {
liyamahendra marked this conversation as resolved.
Show resolved Hide resolved
const hasSelfSelectedPronouns = pronouns === CONST.PRONOUNS.SELF_SELECT;
Expand All @@ -266,53 +307,50 @@ class ProfilePage extends Component {
label: this.props.translate('profilePage.selectYourPronouns'),
}}
value={pronounsPickerValue}
liyamahendra marked this conversation as resolved.
Show resolved Hide resolved
shouldSaveDraft
/>
{this.state.hasSelfSelectedPronouns && (
<View style={styles.mt2}>
<TextInput
inputID="pronounSelected"
liyamahendra marked this conversation as resolved.
Show resolved Hide resolved
value={this.state.pronouns}
onChangeText={pronouns => this.setState({pronouns})}
liyamahendra marked this conversation as resolved.
Show resolved Hide resolved
placeholder={this.props.translate('profilePage.selfSelectYourPronoun')}
hasError={this.state.hasPronounError}
errorText={PersonalDetails.getMaxCharacterError(this.state.hasPronounError)}
liyamahendra marked this conversation as resolved.
Show resolved Hide resolved
/>
</View>
)}
</View>
<LoginField
liyamahendra marked this conversation as resolved.
Show resolved Hide resolved
inputID="loginEmail"
label={this.props.translate('profilePage.emailAddress')}
type="email"
login={this.state.logins.email}
/>
<LoginField
inputID="loginPhoneNumber"
label={this.props.translate('common.phoneNumber')}
type="phone"
login={this.state.logins.phone}
/>
<View style={styles.mb3}>
<Picker
liyamahendra marked this conversation as resolved.
Show resolved Hide resolved
inputID="timezonePicker"
liyamahendra marked this conversation as resolved.
Show resolved Hide resolved
label={this.props.translate('profilePage.timezone')}
onInputChange={selectedTimezone => this.setState({selectedTimezone})}
liyamahendra marked this conversation as resolved.
Show resolved Hide resolved
items={timezones}
isDisabled={this.state.isAutomaticTimezone}
value={this.state.selectedTimezone}
liyamahendra marked this conversation as resolved.
Show resolved Hide resolved
shouldSaveDraft
liyamahendra marked this conversation as resolved.
Show resolved Hide resolved
/>
</View>
<CheckboxWithLabel
label={this.props.translate('profilePage.setMyTimezoneAutomatically')}
isChecked={this.state.isAutomaticTimezone}
onInputChange={this.setAutomaticTimezone}
liyamahendra marked this conversation as resolved.
Show resolved Hide resolved
/>
</ScrollView>
<FixedFooter>
<Button
success
isDisabled={isButtonDisabled}
onPress={this.updatePersonalDetails}
style={[styles.w100]}
text={this.props.translate('common.save')}
pressOnEnter
/>
</FixedFooter>
</Form>
</KeyboardAvoidingView>
</ScreenWrapper>
);
Expand Down