From dcb89be83851022ccdfa92666b11de20e2d863f5 Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Thu, 30 Mar 2023 15:31:57 +0000 Subject: [PATCH 01/27] Connect to SetContactMethodAsDefault --- src/libs/actions/User.js | 67 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/src/libs/actions/User.js b/src/libs/actions/User.js index 1c9a296c975..c4f371a6f66 100644 --- a/src/libs/actions/User.js +++ b/src/libs/actions/User.js @@ -23,10 +23,12 @@ import DateUtils from '../DateUtils'; import * as Session from './Session'; let currentUserAccountID = ''; +let currentEmail = ''; Onyx.connect({ key: ONYXKEYS.SESSION, callback: (val) => { currentUserAccountID = lodashGet(val, 'accountID', ''); + currentEmail = lodashGet(val, 'email', ''); }, }); @@ -654,6 +656,70 @@ function generateStatementPDF(period) { }); } +function setContactMethodAsDefault(newDefaultContactMethod) { + const oldDefaultContactMethod = currentEmail; + const optimisticData = [ + { + onyxMethod: CONST.ONYX.METHOD.MERGE, + key: ONYXKEYS.SESSION, + value: { + email: newDefaultContactMethod, + }, + }, + { + onyxMethod: CONST.ONYX.METHOD.MERGE, + key: ONYXKEYS.LOGIN_LIST, + value: { + [newDefaultContactMethod]: { + pendingFields: { + defaultLogin: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE, + }, + errorFields: { + defaultLogin: null, + }, + }, + }, + }, + ]; + const successData = [{ + onyxMethod: CONST.ONYX.METHOD.MERGE, + key: ONYXKEYS.LOGIN_LIST, + value: { + [newDefaultContactMethod]: { + pendingFields: { + defaultLogin: null, + }, + }, + }, + }]; + const failureData = [ + { + onyxMethod: CONST.ONYX.METHOD.MERGE, + key: ONYXKEYS.SESSION, + value: { + email: oldDefaultContactMethod, + }, + }, + { + onyxMethod: CONST.ONYX.METHOD.MERGE, + key: ONYXKEYS.LOGIN_LIST, + value: { + [newDefaultContact]: { + pendingFields: { + defaultLogin: null, + }, + errorFields: { + defaultLogin: { + [DateUtils.getMicroseconds()]: Localize.translateLocal('contacts.genericFailureMessages.setDefaultContactMethod'), + }, + }, + }, + }, + }, + ]; + API.write('SetContactMethodAsDefault', {partnerUserID: newDefaultContactMethod}, {optimisticData, successData, failureData}); +} + export { updatePassword, closeAccount, @@ -678,4 +744,5 @@ export { deletePaypalMeAddress, addPaypalMeAddress, updateChatPriorityMode, + setContactMethodAsDefault, }; From 8c20ecbc857311f44aaf20e949fd86f760e54619 Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Tue, 4 Apr 2023 11:05:24 +0200 Subject: [PATCH 02/27] New copy for generic error --- src/languages/en.js | 1 + src/languages/es.js | 1 + 2 files changed, 2 insertions(+) diff --git a/src/languages/en.js b/src/languages/en.js index 8c57c762946..dc42c8e9d27 100755 --- a/src/languages/en.js +++ b/src/languages/en.js @@ -370,6 +370,7 @@ export default { requestContactMethodValidateCode: 'Failed to send a new magic code. Please wait a bit and try again.', validateSecondaryLogin: 'Failed to validate contact method with given magic code. Please request a new code and try again.', deleteContactMethod: 'Failed to delete contact method. Please reach out to Concierge for help.', + setDefaultContactMethod: 'Failed to set a new default contact method. Please reach out to Concierge for help.', }, }, pronouns: { diff --git a/src/languages/es.js b/src/languages/es.js index 3fd57e36576..3e62ae26ebd 100644 --- a/src/languages/es.js +++ b/src/languages/es.js @@ -369,6 +369,7 @@ export default { requestContactMethodValidateCode: 'No se ha podido enviar un nuevo código mágico. Espera un rato y vuelve a intentarlo.', validateSecondaryLogin: 'No se ha podido validar el método de contacto con el código mágico provisto. Solicita un nuevo código y vuelve a intentarlo.', deleteContactMethod: 'No se ha podido eliminar el método de contacto. Por favor contacta con Concierge para obtener ayuda.', + setDefaultContactMethod: 'No se pudo establecer un nuevo método de contacto predeterminado. Por favor contacta con Concierge para obtener ayuda.', }, }, pronouns: { From 692dbf5b64028f232d930083fa7ac6554dd13390 Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Tue, 4 Apr 2023 11:05:40 +0200 Subject: [PATCH 03/27] Connect new set default button --- .../Contacts/ContactMethodDetailsPage.js | 27 ++++++++++++------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.js b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.js index eca350a4e69..70176f354d8 100644 --- a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.js +++ b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.js @@ -225,19 +225,26 @@ class ContactMethodDetailsPage extends Component { {this.props.translate('contacts.yourDefaultContactMethod')} ) : ( - User.clearContactMethodErrors(contactMethod, 'deletedLogin')} - > + <> + User.clearContactMethodErrors(contactMethod, 'deletedLogin')} + > + this.toggleDeleteModal(true)} + /> + this.toggleDeleteModal(true)} + onPress={() => User.setContactMethodAsDefault(contactMethod)} /> - + )} From c70731a65b3c9457ad993d8d20e711087cb57665 Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Wed, 5 Apr 2023 14:08:35 +0200 Subject: [PATCH 04/27] Add function docs --- src/libs/actions/User.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/libs/actions/User.js b/src/libs/actions/User.js index c4f371a6f66..682dff07dc0 100644 --- a/src/libs/actions/User.js +++ b/src/libs/actions/User.js @@ -656,6 +656,11 @@ function generateStatementPDF(period) { }); } +/** + * Sets a contact method / secondary login as the user's "Default" contact method + * + * @param {String} newDefaultContactMethod + */ function setContactMethodAsDefault(newDefaultContactMethod) { const oldDefaultContactMethod = currentEmail; const optimisticData = [ From 8d333b7dbace3bfc9a27cb52370df9397ad93c9e Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Wed, 5 Apr 2023 14:46:54 +0200 Subject: [PATCH 05/27] New icon for set as default --- assets/images/circle-check.svg | 9 +++++++++ src/components/Icon/Expensicons.js | 2 ++ .../Profile/Contacts/ContactMethodDetailsPage.js | 2 +- 3 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 assets/images/circle-check.svg diff --git a/assets/images/circle-check.svg b/assets/images/circle-check.svg new file mode 100644 index 00000000000..f578050520b --- /dev/null +++ b/assets/images/circle-check.svg @@ -0,0 +1,9 @@ + + + + + + diff --git a/src/components/Icon/Expensicons.js b/src/components/Icon/Expensicons.js index 85560a76c57..466a4a2cd1c 100644 --- a/src/components/Icon/Expensicons.js +++ b/src/components/Icon/Expensicons.js @@ -19,6 +19,7 @@ import Cash from '../../../assets/images/cash.svg'; import ChatBubble from '../../../assets/images/chatbubble.svg'; import Checkmark from '../../../assets/images/checkmark.svg'; import Chair from '../../../assets/images/chair.svg'; +import CircleCheck from '../../../assets/images/circle-check.svg'; import Clipboard from '../../../assets/images/clipboard.svg'; import Close from '../../../assets/images/close.svg'; import ClosedSign from '../../../assets/images/closed-sign.svg'; @@ -133,6 +134,7 @@ export { ChatBubble, Checkmark, Chair, + CircleCheck, Clipboard, Close, ClosedSign, diff --git a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.js b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.js index 70176f354d8..eb0a1a3bcbf 100644 --- a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.js +++ b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.js @@ -241,7 +241,7 @@ class ContactMethodDetailsPage extends Component { User.setContactMethodAsDefault(contactMethod)} /> From 1bf0be7a653f8470ea04b4d71edbaa1b1e9b2879 Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Thu, 6 Apr 2023 11:22:10 +0200 Subject: [PATCH 06/27] Add set default translation & offline UX --- src/languages/en.js | 1 + src/languages/es.js | 1 + .../Contacts/ContactMethodDetailsPage.js | 17 ++++++++++++----- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/languages/en.js b/src/languages/en.js index 4a8feaad063..5bca69993f0 100755 --- a/src/languages/en.js +++ b/src/languages/en.js @@ -367,6 +367,7 @@ export default { pleaseVerify: 'Please verify this contact method', getInTouch: "Whenever we need to get in touch with you, we'll use this contact method.", enterMagicCode: ({contactMethod}) => `Please enter the magic code sent to ${contactMethod}`, + setAsDefault: 'Set as default', yourDefaultContactMethod: 'This is your current default contact method. You will not be able to delete this contact method until you set an alternative default by selecting another contact method and pressing “Set as default”.', removeContactMethod: 'Remove contact method', removeAreYouSure: 'Are you sure you want to remove this contact method? This action cannot be undone.', diff --git a/src/languages/es.js b/src/languages/es.js index b05959f4969..a6c15f7b4d1 100644 --- a/src/languages/es.js +++ b/src/languages/es.js @@ -366,6 +366,7 @@ export default { pleaseVerify: 'Por favor verifica este método de contacto', getInTouch: 'Utilizaremos este método de contacto cuando necesitemos contactarte.', enterMagicCode: ({contactMethod}) => `Por favor, introduce el código mágico enviado a ${contactMethod}`, + setAsDefault: 'Establecer como predeterminado', yourDefaultContactMethod: 'Este es tu método de contacto predeterminado. No podrás eliminarlo hasta que añadas otro método de contacto y lo marques como predeterminado pulsando "Establecer como predeterminado".', removeContactMethod: 'Eliminar método de contacto', removeAreYouSure: '¿Estás seguro de que quieres eliminar este método de contacto? Esta acción no se puede deshacer.', diff --git a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.js b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.js index eb0a1a3bcbf..212f9d96a4f 100644 --- a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.js +++ b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.js @@ -226,6 +226,18 @@ class ContactMethodDetailsPage extends Component { ) : ( <> + User.clearContactMethodErrors(contactMethod, 'defaultLogin')} + > + User.setContactMethodAsDefault(contactMethod)} + /> + this.toggleDeleteModal(true)} /> - User.setContactMethodAsDefault(contactMethod)} - /> )} From f5035d5dcb1b33c030d2d73b471be291c065d6b6 Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Thu, 6 Apr 2023 11:22:28 +0200 Subject: [PATCH 07/27] Use more appropriate icon --- assets/images/circle-check.svg | 9 --------- src/components/Icon/Expensicons.js | 2 -- .../Profile/Contacts/ContactMethodDetailsPage.js | 2 +- 3 files changed, 1 insertion(+), 12 deletions(-) delete mode 100644 assets/images/circle-check.svg diff --git a/assets/images/circle-check.svg b/assets/images/circle-check.svg deleted file mode 100644 index f578050520b..00000000000 --- a/assets/images/circle-check.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - diff --git a/src/components/Icon/Expensicons.js b/src/components/Icon/Expensicons.js index 466a4a2cd1c..85560a76c57 100644 --- a/src/components/Icon/Expensicons.js +++ b/src/components/Icon/Expensicons.js @@ -19,7 +19,6 @@ import Cash from '../../../assets/images/cash.svg'; import ChatBubble from '../../../assets/images/chatbubble.svg'; import Checkmark from '../../../assets/images/checkmark.svg'; import Chair from '../../../assets/images/chair.svg'; -import CircleCheck from '../../../assets/images/circle-check.svg'; import Clipboard from '../../../assets/images/clipboard.svg'; import Close from '../../../assets/images/close.svg'; import ClosedSign from '../../../assets/images/closed-sign.svg'; @@ -134,7 +133,6 @@ export { ChatBubble, Checkmark, Chair, - CircleCheck, Clipboard, Close, ClosedSign, diff --git a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.js b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.js index 212f9d96a4f..a9caa91b103 100644 --- a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.js +++ b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.js @@ -234,7 +234,7 @@ class ContactMethodDetailsPage extends Component { > User.setContactMethodAsDefault(contactMethod)} /> From 62c25d5be8daa376799124e57dff057e642c8df0 Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Thu, 6 Apr 2023 11:22:43 +0200 Subject: [PATCH 08/27] Fix spacing & var --- src/libs/actions/User.js | 2 +- src/styles/utilities/spacing.js | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/libs/actions/User.js b/src/libs/actions/User.js index 682dff07dc0..7ce636741cd 100644 --- a/src/libs/actions/User.js +++ b/src/libs/actions/User.js @@ -709,7 +709,7 @@ function setContactMethodAsDefault(newDefaultContactMethod) { onyxMethod: CONST.ONYX.METHOD.MERGE, key: ONYXKEYS.LOGIN_LIST, value: { - [newDefaultContact]: { + [newDefaultContactMethod]: { pendingFields: { defaultLogin: null, }, diff --git a/src/styles/utilities/spacing.js b/src/styles/utilities/spacing.js index 44cc709fe46..7bb8f9d4bf8 100644 --- a/src/styles/utilities/spacing.js +++ b/src/styles/utilities/spacing.js @@ -45,6 +45,10 @@ export default { marginHorizontal: 20, }, + mh6: { + marginHorizontal: 24, + }, + mh8: { marginHorizontal: 32, }, From 33b5f76c582fbf2a1fa271a318db2ec717226950 Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Thu, 6 Apr 2023 14:53:39 +0200 Subject: [PATCH 09/27] Hide Set as Default if security group restricts it --- src/ONYXKEYS.js | 4 ++ .../Contacts/ContactMethodDetailsPage.js | 61 +++++++++++++++---- 2 files changed, 53 insertions(+), 12 deletions(-) diff --git a/src/ONYXKEYS.js b/src/ONYXKEYS.js index 6fe8a0625cd..73e61032d9a 100755 --- a/src/ONYXKEYS.js +++ b/src/ONYXKEYS.js @@ -112,6 +112,7 @@ export default { REPORT_IS_COMPOSER_FULL_SIZE: 'reportIsComposerFullSize_', POLICY_MEMBER_LIST: 'policyMemberList_', DOWNLOAD: 'download_', + SECURITY_GROUP: 'securityGroup_', }, // Indicates which locale should be used @@ -197,4 +198,7 @@ export default { // Whether the auth token is valid IS_TOKEN_VALID: 'isTokenValid', + + // A map of the user's security group IDs they belong to in specific domains + MY_DOMAIN_SECURITY_GROUPS: 'myDomainSecurityGroups', }; diff --git a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.js b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.js index a9caa91b103..512fa464f9f 100644 --- a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.js +++ b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.js @@ -140,6 +140,30 @@ class ContactMethodDetailsPage extends Component { } } + /** + * Checks if the user is allowed to change their default contact method by looking at + * their security group settings on their primary domain. + * + * @returns {Boolean} + */ + getCanChangeDefaultContactMethod() { + const domainName = Str.extractEmailDomain(this.props.session.email); + const primaryDomainSecurityGroupID = lodashGet(this.props.myDomainSecurityGroups, domainName); + + // If there's no security group associated with the user for the primary domain, + // default to allowing the user to change their default contact method. + if (!primaryDomainSecurityGroupID) { + return true; + } + + const hasRestrictedPrimaryLogin = lodashGet(this.props.securityGroups, [ + `${ONYXKEYS.COLLECTION.SECURITY_GROUP}${primaryDomainSecurityGroupID}`, + 'hasRestrictedPrimaryLogin' + ], false); + + return !hasRestrictedPrimaryLogin; + } + render() { const contactMethod = this.getContactMethod(); const loginData = this.props.loginList[contactMethod]; @@ -151,6 +175,8 @@ class ContactMethodDetailsPage extends Component { const hasMagicCodeBeenSent = lodashGet(this.props.loginList, [contactMethod, 'validateCodeSent'], false); const formErrorText = this.state.formError ? this.props.translate(this.state.formError) : ''; + const canChangeDefaultContactMethod = !isDefaultContactMethod && this.getCanChangeDefaultContactMethod(); + return ( ) : ( <> - User.clearContactMethodErrors(contactMethod, 'defaultLogin')} - > - User.setContactMethodAsDefault(contactMethod)} - /> - + {canChangeDefaultContactMethod && ( + User.clearContactMethodErrors(contactMethod, 'defaultLogin')} + > + { + User.setContactMethodAsDefault(contactMethod); + Navigation.navigate(ROUTES.SETTINGS_CONTACT_METHODS); + }} + /> + + )} Date: Thu, 6 Apr 2023 15:04:33 +0200 Subject: [PATCH 10/27] Add new onyx key proptypes --- .../Contacts/ContactMethodDetailsPage.js | 58 +++++++++++-------- 1 file changed, 34 insertions(+), 24 deletions(-) diff --git a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.js b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.js index 512fa464f9f..4128f447ed0 100644 --- a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.js +++ b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.js @@ -54,6 +54,14 @@ const propTypes = { email: PropTypes.string.isRequired, }), + /** User's security group IDs by domain */ + myDomainSecurityGroups: PropTypes.objectOf(PropTypes.string), + + /** All of the user's security groups and their settings */ + securityGroups: PropTypes.shape({ + hasRestrictedPrimaryLogin: PropTypes.bool, + }), + /** Route params */ route: PropTypes.shape({ params: PropTypes.shape({ @@ -70,6 +78,8 @@ const defaultProps = { session: { email: null, }, + myDomainSecurityGroups: {}, + securityGroups: {}, route: { params: { contactMethod: '', @@ -103,6 +113,30 @@ class ContactMethodDetailsPage extends Component { return decodeURIComponent(lodashGet(this.props.route, 'params.contactMethod')); } + /** + * Checks if the user is allowed to change their default contact method by looking at + * their security group settings on their primary domain. + * + * @returns {Boolean} + */ + getCanChangeDefaultContactMethod() { + const domainName = Str.extractEmailDomain(this.props.session.email); + const primaryDomainSecurityGroupID = lodashGet(this.props.myDomainSecurityGroups, domainName); + + // If there's no security group associated with the user for the primary domain, + // default to allowing the user to change their default contact method. + if (!primaryDomainSecurityGroupID) { + return true; + } + + const hasRestrictedPrimaryLogin = lodashGet(this.props.securityGroups, [ + `${ONYXKEYS.COLLECTION.SECURITY_GROUP}${primaryDomainSecurityGroupID}`, + 'hasRestrictedPrimaryLogin', + ], false); + + return !hasRestrictedPrimaryLogin; + } + /** * Toggle delete confirm modal visibility * @param {Boolean} isOpen @@ -140,30 +174,6 @@ class ContactMethodDetailsPage extends Component { } } - /** - * Checks if the user is allowed to change their default contact method by looking at - * their security group settings on their primary domain. - * - * @returns {Boolean} - */ - getCanChangeDefaultContactMethod() { - const domainName = Str.extractEmailDomain(this.props.session.email); - const primaryDomainSecurityGroupID = lodashGet(this.props.myDomainSecurityGroups, domainName); - - // If there's no security group associated with the user for the primary domain, - // default to allowing the user to change their default contact method. - if (!primaryDomainSecurityGroupID) { - return true; - } - - const hasRestrictedPrimaryLogin = lodashGet(this.props.securityGroups, [ - `${ONYXKEYS.COLLECTION.SECURITY_GROUP}${primaryDomainSecurityGroupID}`, - 'hasRestrictedPrimaryLogin' - ], false); - - return !hasRestrictedPrimaryLogin; - } - render() { const contactMethod = this.getContactMethod(); const loginData = this.props.loginList[contactMethod]; From 106b0085626dd91ce51a7b14c5f8bf9e62f1fd27 Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Fri, 7 Apr 2023 15:19:21 +0200 Subject: [PATCH 11/27] Dont show set default if not validated --- .../Contacts/ContactMethodDetailsPage.js | 52 +++++++++++-------- 1 file changed, 31 insertions(+), 21 deletions(-) diff --git a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.js b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.js index 4128f447ed0..ffe1f4b6e8b 100644 --- a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.js +++ b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.js @@ -185,7 +185,11 @@ class ContactMethodDetailsPage extends Component { const hasMagicCodeBeenSent = lodashGet(this.props.loginList, [contactMethod, 'validateCodeSent'], false); const formErrorText = this.state.formError ? this.props.translate(this.state.formError) : ''; - const canChangeDefaultContactMethod = !isDefaultContactMethod && this.getCanChangeDefaultContactMethod(); + // Users are only allowed to change their default contact method to the current one if the current one: + // 1. Is not already their default contact method + // 2. Is validated + // 3. Is allowed by their domain security group (if this exists) + const canChangeDefaultContactMethod = !isDefaultContactMethod && loginData.validatedDate && this.getCanChangeDefaultContactMethod(); return ( @@ -256,29 +260,35 @@ class ContactMethodDetailsPage extends Component { )} + {canChangeDefaultContactMethod && ( + User.clearContactMethodErrors(contactMethod, 'defaultLogin')} + > + { + User.setContactMethodAsDefault(contactMethod); + Navigation.navigate(ROUTES.SETTINGS_CONTACT_METHODS); + }} + /> + + )} {isDefaultContactMethod ? ( - - {this.props.translate('contacts.yourDefaultContactMethod')} - + User.clearContactMethodErrors(contactMethod, 'defaultLogin')} + > + + {this.props.translate('contacts.yourDefaultContactMethod')} + + ) : ( <> - {canChangeDefaultContactMethod && ( - User.clearContactMethodErrors(contactMethod, 'defaultLogin')} - > - { - User.setContactMethodAsDefault(contactMethod); - Navigation.navigate(ROUTES.SETTINGS_CONTACT_METHODS); - }} - /> - - )} Date: Fri, 7 Apr 2023 15:23:05 +0200 Subject: [PATCH 12/27] Simplify logic a bit --- .../settings/Profile/Contacts/ContactMethodDetailsPage.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.js b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.js index ffe1f4b6e8b..fc40f23ff76 100644 --- a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.js +++ b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.js @@ -129,12 +129,11 @@ class ContactMethodDetailsPage extends Component { return true; } - const hasRestrictedPrimaryLogin = lodashGet(this.props.securityGroups, [ + // Return true if there's no security group with 'hasRestrictedPrimaryLogin' set to true. + return !lodashGet(this.props.securityGroups, [ `${ONYXKEYS.COLLECTION.SECURITY_GROUP}${primaryDomainSecurityGroupID}`, 'hasRestrictedPrimaryLogin', ], false); - - return !hasRestrictedPrimaryLogin; } /** From 3f1055a137024b63db8dfecc68ea5bc1f06ff3bf Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Fri, 7 Apr 2023 16:59:44 +0200 Subject: [PATCH 13/27] Add Set as Default page for non-passwordless --- src/ONYXKEYS.js | 1 + src/ROUTES.js | 2 + .../AppNavigator/ModalStackNavigators.js | 7 ++ src/libs/Navigation/linkingConfig.js | 3 + .../Contacts/SetDefaultContactMethodPage.js | 87 +++++++++++++++++++ 5 files changed, 100 insertions(+) create mode 100644 src/pages/settings/Profile/Contacts/SetDefaultContactMethodPage.js diff --git a/src/ONYXKEYS.js b/src/ONYXKEYS.js index 73e61032d9a..aaa77bf4bb5 100755 --- a/src/ONYXKEYS.js +++ b/src/ONYXKEYS.js @@ -188,6 +188,7 @@ export default { HOME_ADDRESS_FORM: 'homeAddressForm', NEW_ROOM_FORM: 'newRoomForm', ROOM_SETTINGS_FORM: 'roomSettingsForm', + SET_AS_DEFAULT_FORM: 'setAsDefaultForm', }, // Whether we should show the compose input or not diff --git a/src/ROUTES.js b/src/ROUTES.js index d5ba2406e32..3a4af9c7700 100644 --- a/src/ROUTES.js +++ b/src/ROUTES.js @@ -53,6 +53,8 @@ export default { SETTINGS_CONTACT_METHODS, SETTINGS_CONTACT_METHOD_DETAILS: `${SETTINGS_CONTACT_METHODS}/:contactMethod/details`, getEditContactMethodRoute: contactMethod => `${SETTINGS_CONTACT_METHODS}/${encodeURIComponent(contactMethod)}/details`, + SETTINGS_CONTACT_METHODS_SET_DEFAULT: `${SETTINGS_CONTACT_METHODS}/:contactMethod/set-default`, + getSetDefaultContactMethodRoute: contactMethod => `${SETTINGS_CONTACT_METHODS}/${encodeURIComponent(contactMethod)}/set-default`, NEW_GROUP: 'new/group', NEW_CHAT: 'new/chat', REPORT, diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators.js b/src/libs/Navigation/AppNavigator/ModalStackNavigators.js index 7b46354e939..32d5b04172c 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators.js +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators.js @@ -287,6 +287,13 @@ const SettingsModalStackNavigator = createModalStackNavigator([ }, name: 'Settings_ContactMethodDetails', }, + { + getComponent: () => { + const SettingsSetDefaultContactMethod = require('../../../pages/settings/Profile/Contacts/SetDefaultContactMethodPage').default; + return SettingsSetDefaultContactMethod; + }, + name: 'Settings_SetDefaultContactMethod', + }, { getComponent: () => { const SettingsAddSecondaryLoginPage = require('../../../pages/settings/Profile/Contacts/AddSecondaryLoginPage').default; diff --git a/src/libs/Navigation/linkingConfig.js b/src/libs/Navigation/linkingConfig.js index a096a742186..d9a73b009a7 100644 --- a/src/libs/Navigation/linkingConfig.js +++ b/src/libs/Navigation/linkingConfig.js @@ -127,6 +127,9 @@ export default { Settings_ContactMethodDetails: { path: ROUTES.SETTINGS_CONTACT_METHOD_DETAILS, }, + Settings_SetDefaultContactMethod: { + path: ROUTES.SETTINGS_CONTACT_METHODS_SET_DEFAULT, + }, Settings_Add_Secondary_Login: { path: ROUTES.SETTINGS_ADD_LOGIN, }, diff --git a/src/pages/settings/Profile/Contacts/SetDefaultContactMethodPage.js b/src/pages/settings/Profile/Contacts/SetDefaultContactMethodPage.js new file mode 100644 index 00000000000..016cf2f0411 --- /dev/null +++ b/src/pages/settings/Profile/Contacts/SetDefaultContactMethodPage.js @@ -0,0 +1,87 @@ +import lodashGet from 'lodash/get'; +import PropTypes from 'prop-types'; +import {withOnyx} from 'react-native-onyx'; +import {View} from 'react-native'; +import _ from 'underscore'; +import Form from '../../../../components/Form'; +import HeaderWithCloseButton from '../../../../components/HeaderWithCloseButton'; +import ScreenWrapper from '../../../../components/ScreenWrapper'; +import withLocalize, { withLocalizePropTypes } from '../../../../components/withLocalize'; +import Navigation from '../../../../libs/Navigation/Navigation'; +import ONYXKEYS from '../../../../ONYXKEYS'; +import ROUTES from '../../../../ROUTES'; +import * as User from '../../../../libs/actions/User'; +import Text from '../../../../components/Text'; +import TextInput from '../../../../components/TextInput'; + +const propTypes = { + /* Onyx Props */ + + /** List of betas available to current user */ + betas: PropTypes.arrayOf(PropTypes.string), + + ...withLocalizePropTypes, +}; + +const defaultProps = { + betas: [], +}; + +const SetDefaultContactMethod = (props) => { + const contactMethod = decodeURIComponent(lodashGet(props.route, 'params.contactMethod')); + + /** + * @param {Object} values + * @param {String} values.password + */ + function validate(values) { + const errors = {}; + + if (_.isEmpty(values.password)) { + errors.password = props.translate('common.error.fieldRequired'); + } + + return errors; + } + + return ( + + Navigation.navigate(ROUTES.getEditContactMethodRoute(contactMethod))} + onCloseButtonPress={() => Navigation.dismissModal(true)} + /> +
+ + {'For your security, please re-enter your password to set a new default.'} + + + + +
+
+ ); +}; + +SetDefaultContactMethod.propTypes = propTypes; +SetDefaultContactMethod.defaultProps = defaultProps; +SetDefaultContactMethod.displayName = 'SetDefaultContactMethod'; + +export default compose( + withLocalize, + withOnyx({ + betas: { + key: ONYXKEYS.BETAS, + }, + }), +)(SetDefaultContactMethod); From 0fb43c7f8fcb8d166fd837f55de9e2650a15f3cd Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Mon, 10 Apr 2023 14:47:16 +0200 Subject: [PATCH 14/27] Allow password to be sent to command --- src/libs/actions/User.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/libs/actions/User.js b/src/libs/actions/User.js index 7ce636741cd..4623b177be0 100644 --- a/src/libs/actions/User.js +++ b/src/libs/actions/User.js @@ -657,11 +657,13 @@ function generateStatementPDF(period) { } /** - * Sets a contact method / secondary login as the user's "Default" contact method + * Sets a contact method / secondary login as the user's "Default" contact method. + * Note: password is not used if the user is on the Passwordless beta. * * @param {String} newDefaultContactMethod + * @param {String} [password] */ -function setContactMethodAsDefault(newDefaultContactMethod) { +function setContactMethodAsDefault(newDefaultContactMethod, password = '') { const oldDefaultContactMethod = currentEmail; const optimisticData = [ { @@ -722,7 +724,7 @@ function setContactMethodAsDefault(newDefaultContactMethod) { }, }, ]; - API.write('SetContactMethodAsDefault', {partnerUserID: newDefaultContactMethod}, {optimisticData, successData, failureData}); + API.write('SetContactMethodAsDefault', {partnerUserID: newDefaultContactMethod, password}, {optimisticData, successData, failureData}); } export { From 12ec0eb92192f6b84a8daa1407b1ae5704a50803 Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Mon, 10 Apr 2023 15:02:46 +0200 Subject: [PATCH 15/27] Remove unnecessary new file, oops --- src/ROUTES.js | 2 - .../AppNavigator/ModalStackNavigators.js | 7 -- src/libs/Navigation/linkingConfig.js | 3 - .../Contacts/SetDefaultContactMethodPage.js | 87 ------------------- 4 files changed, 99 deletions(-) delete mode 100644 src/pages/settings/Profile/Contacts/SetDefaultContactMethodPage.js diff --git a/src/ROUTES.js b/src/ROUTES.js index 3a4af9c7700..d5ba2406e32 100644 --- a/src/ROUTES.js +++ b/src/ROUTES.js @@ -53,8 +53,6 @@ export default { SETTINGS_CONTACT_METHODS, SETTINGS_CONTACT_METHOD_DETAILS: `${SETTINGS_CONTACT_METHODS}/:contactMethod/details`, getEditContactMethodRoute: contactMethod => `${SETTINGS_CONTACT_METHODS}/${encodeURIComponent(contactMethod)}/details`, - SETTINGS_CONTACT_METHODS_SET_DEFAULT: `${SETTINGS_CONTACT_METHODS}/:contactMethod/set-default`, - getSetDefaultContactMethodRoute: contactMethod => `${SETTINGS_CONTACT_METHODS}/${encodeURIComponent(contactMethod)}/set-default`, NEW_GROUP: 'new/group', NEW_CHAT: 'new/chat', REPORT, diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators.js b/src/libs/Navigation/AppNavigator/ModalStackNavigators.js index 32d5b04172c..7b46354e939 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators.js +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators.js @@ -287,13 +287,6 @@ const SettingsModalStackNavigator = createModalStackNavigator([ }, name: 'Settings_ContactMethodDetails', }, - { - getComponent: () => { - const SettingsSetDefaultContactMethod = require('../../../pages/settings/Profile/Contacts/SetDefaultContactMethodPage').default; - return SettingsSetDefaultContactMethod; - }, - name: 'Settings_SetDefaultContactMethod', - }, { getComponent: () => { const SettingsAddSecondaryLoginPage = require('../../../pages/settings/Profile/Contacts/AddSecondaryLoginPage').default; diff --git a/src/libs/Navigation/linkingConfig.js b/src/libs/Navigation/linkingConfig.js index d9a73b009a7..a096a742186 100644 --- a/src/libs/Navigation/linkingConfig.js +++ b/src/libs/Navigation/linkingConfig.js @@ -127,9 +127,6 @@ export default { Settings_ContactMethodDetails: { path: ROUTES.SETTINGS_CONTACT_METHOD_DETAILS, }, - Settings_SetDefaultContactMethod: { - path: ROUTES.SETTINGS_CONTACT_METHODS_SET_DEFAULT, - }, Settings_Add_Secondary_Login: { path: ROUTES.SETTINGS_ADD_LOGIN, }, diff --git a/src/pages/settings/Profile/Contacts/SetDefaultContactMethodPage.js b/src/pages/settings/Profile/Contacts/SetDefaultContactMethodPage.js deleted file mode 100644 index 016cf2f0411..00000000000 --- a/src/pages/settings/Profile/Contacts/SetDefaultContactMethodPage.js +++ /dev/null @@ -1,87 +0,0 @@ -import lodashGet from 'lodash/get'; -import PropTypes from 'prop-types'; -import {withOnyx} from 'react-native-onyx'; -import {View} from 'react-native'; -import _ from 'underscore'; -import Form from '../../../../components/Form'; -import HeaderWithCloseButton from '../../../../components/HeaderWithCloseButton'; -import ScreenWrapper from '../../../../components/ScreenWrapper'; -import withLocalize, { withLocalizePropTypes } from '../../../../components/withLocalize'; -import Navigation from '../../../../libs/Navigation/Navigation'; -import ONYXKEYS from '../../../../ONYXKEYS'; -import ROUTES from '../../../../ROUTES'; -import * as User from '../../../../libs/actions/User'; -import Text from '../../../../components/Text'; -import TextInput from '../../../../components/TextInput'; - -const propTypes = { - /* Onyx Props */ - - /** List of betas available to current user */ - betas: PropTypes.arrayOf(PropTypes.string), - - ...withLocalizePropTypes, -}; - -const defaultProps = { - betas: [], -}; - -const SetDefaultContactMethod = (props) => { - const contactMethod = decodeURIComponent(lodashGet(props.route, 'params.contactMethod')); - - /** - * @param {Object} values - * @param {String} values.password - */ - function validate(values) { - const errors = {}; - - if (_.isEmpty(values.password)) { - errors.password = props.translate('common.error.fieldRequired'); - } - - return errors; - } - - return ( - - Navigation.navigate(ROUTES.getEditContactMethodRoute(contactMethod))} - onCloseButtonPress={() => Navigation.dismissModal(true)} - /> -
- - {'For your security, please re-enter your password to set a new default.'} - - - - -
-
- ); -}; - -SetDefaultContactMethod.propTypes = propTypes; -SetDefaultContactMethod.defaultProps = defaultProps; -SetDefaultContactMethod.displayName = 'SetDefaultContactMethod'; - -export default compose( - withLocalize, - withOnyx({ - betas: { - key: ONYXKEYS.BETAS, - }, - }), -)(SetDefaultContactMethod); From 4aa6e7f424d7683dde59b85fd483ab647f39a093 Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Tue, 11 Apr 2023 13:59:15 +0200 Subject: [PATCH 16/27] Only show set default if on passwordless --- src/ONYXKEYS.js | 1 - src/libs/actions/User.js | 7 ++-- .../Contacts/ContactMethodDetailsPage.js | 35 ++++++++++++++----- 3 files changed, 29 insertions(+), 14 deletions(-) diff --git a/src/ONYXKEYS.js b/src/ONYXKEYS.js index aaa77bf4bb5..73e61032d9a 100755 --- a/src/ONYXKEYS.js +++ b/src/ONYXKEYS.js @@ -188,7 +188,6 @@ export default { HOME_ADDRESS_FORM: 'homeAddressForm', NEW_ROOM_FORM: 'newRoomForm', ROOM_SETTINGS_FORM: 'roomSettingsForm', - SET_AS_DEFAULT_FORM: 'setAsDefaultForm', }, // Whether we should show the compose input or not diff --git a/src/libs/actions/User.js b/src/libs/actions/User.js index 4623b177be0..ec21597cf24 100644 --- a/src/libs/actions/User.js +++ b/src/libs/actions/User.js @@ -658,12 +658,10 @@ function generateStatementPDF(period) { /** * Sets a contact method / secondary login as the user's "Default" contact method. - * Note: password is not used if the user is on the Passwordless beta. * * @param {String} newDefaultContactMethod - * @param {String} [password] */ -function setContactMethodAsDefault(newDefaultContactMethod, password = '') { +function setContactMethodAsDefault(newDefaultContactMethod) { const oldDefaultContactMethod = currentEmail; const optimisticData = [ { @@ -724,7 +722,8 @@ function setContactMethodAsDefault(newDefaultContactMethod, password = '') { }, }, ]; - API.write('SetContactMethodAsDefault', {partnerUserID: newDefaultContactMethod, password}, {optimisticData, successData, failureData}); + API.write('SetContactMethodAsDefault', {partnerUserID: newDefaultContactMethod}, {optimisticData, successData, failureData}); + Navigation.navigate(ROUTES.SETTINGS_CONTACT_METHODS); } export { diff --git a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.js b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.js index fc40f23ff76..5e84ebbe420 100644 --- a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.js +++ b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.js @@ -27,10 +27,14 @@ import * as ErrorUtils from '../../../../libs/ErrorUtils'; import themeColors from '../../../../styles/themes/default'; import NotFoundPage from '../../../ErrorPage/NotFoundPage'; import * as ValidationUtils from '../../../../libs/ValidationUtils'; +import Permissions from '../../../../libs/Permissions'; const propTypes = { /* Onyx Props */ + /** List of betas available to current user */ + betas: PropTypes.arrayOf(PropTypes.string), + /** Login list for the user that is signed in */ loginList: PropTypes.shape({ /** Value of partner name */ @@ -74,6 +78,7 @@ const propTypes = { }; const defaultProps = { + betas: [], loginList: {}, session: { email: null, @@ -96,6 +101,7 @@ class ContactMethodDetailsPage extends Component { this.resendValidateCode = this.resendValidateCode.bind(this); this.getContactMethod = this.getContactMethod.bind(this); this.validateAndSubmitCode = this.validateAndSubmitCode.bind(this); + this.setAsDefault = this.setAsDefault.bind(this); this.state = { formError: '', @@ -173,6 +179,13 @@ class ContactMethodDetailsPage extends Component { } } + /** + * Attempt to set this contact method as user's "Default contact method" + */ + setAsDefault() { + User.setContactMethodAsDefault(this.getContactMethod()); + } + render() { const contactMethod = this.getContactMethod(); const loginData = this.props.loginList[contactMethod]; @@ -184,11 +197,15 @@ class ContactMethodDetailsPage extends Component { const hasMagicCodeBeenSent = lodashGet(this.props.loginList, [contactMethod, 'validateCodeSent'], false); const formErrorText = this.state.formError ? this.props.translate(this.state.formError) : ''; - // Users are only allowed to change their default contact method to the current one if the current one: - // 1. Is not already their default contact method - // 2. Is validated - // 3. Is allowed by their domain security group (if this exists) - const canChangeDefaultContactMethod = !isDefaultContactMethod && loginData.validatedDate && this.getCanChangeDefaultContactMethod(); + // Users are only allowed to change their default contact method to the current one if: + // 1. This contact method is not already their default + // 2. This contact method is validated + // 3. Default contact method switching is allowed by their domain security group (if this exists) + // 4. The user is on the passwordless beta + const canChangeDefaultContactMethod = !isDefaultContactMethod + && loginData.validatedDate + && this.getCanChangeDefaultContactMethod() + && Permissions.canUsePasswordlessLogins(this.props.betas); return ( @@ -268,10 +285,7 @@ class ContactMethodDetailsPage extends Component { { - User.setContactMethodAsDefault(contactMethod); - Navigation.navigate(ROUTES.SETTINGS_CONTACT_METHODS); - }} + onPress={this.setAsDefault} />
)} @@ -315,6 +329,9 @@ ContactMethodDetailsPage.defaultProps = defaultProps; export default compose( withLocalize, withOnyx({ + betas: { + key: ONYXKEYS.BETAS, + }, loginList: { key: ONYXKEYS.LOGIN_LIST, }, From 92f928bdef2f6892bc652366370c8f427a7a2918 Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Thu, 13 Apr 2023 14:09:39 +0200 Subject: [PATCH 17/27] A few lint fixes --- .../Contacts/ContactMethodDetailsPage.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.js b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.js index d11ea2db22f..c15a501d07a 100644 --- a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.js +++ b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.js @@ -145,6 +145,13 @@ class ContactMethodDetailsPage extends Component { ], false); } + /** + * Attempt to set this contact method as user's "Default contact method" + */ + setAsDefault() { + User.setContactMethodAsDefault(this.getContactMethod()); + } + /** * Deletes the contact method if it has errors. Otherwise, it shows the confirmation alert and deletes it only if the user confirms. */ @@ -193,13 +200,6 @@ class ContactMethodDetailsPage extends Component { } } - /** - * Attempt to set this contact method as user's "Default contact method" - */ - setAsDefault() { - User.setContactMethodAsDefault(this.getContactMethod()); - } - render() { const contactMethod = this.getContactMethod(); const loginData = this.props.loginList[contactMethod]; @@ -292,7 +292,7 @@ class ContactMethodDetailsPage extends Component { )} - {canChangeDefaultContactMethod && ( + {canChangeDefaultContactMethod ? ( - )} + ) : null} {isDefaultContactMethod ? ( Date: Thu, 13 Apr 2023 14:15:56 +0200 Subject: [PATCH 18/27] Remove unused style --- src/styles/utilities/spacing.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/styles/utilities/spacing.js b/src/styles/utilities/spacing.js index 477da7ff129..7e8b51529c7 100644 --- a/src/styles/utilities/spacing.js +++ b/src/styles/utilities/spacing.js @@ -45,10 +45,6 @@ export default { marginHorizontal: 20, }, - mh6: { - marginHorizontal: 24, - }, - mh8: { marginHorizontal: 32, }, From 79c2a4664fb90672bd9ac75afc8c4b7b719a9c8a Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Wed, 26 Apr 2023 12:25:16 +0100 Subject: [PATCH 19/27] Set new default contact method in personalDetails --- src/libs/actions/User.js | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/libs/actions/User.js b/src/libs/actions/User.js index 6bf607c53df..2fa88a2d8d4 100644 --- a/src/libs/actions/User.js +++ b/src/libs/actions/User.js @@ -31,6 +31,18 @@ Onyx.connect({ }, }); +let myPersonalDetails = {}; +Onyx.connect({ + key: ONYXKEYS.PERSONAL_DETAILS, + callback: (val) => { + if (!val || !currentEmail) { + return; + } + + myPersonalDetails = val[currentEmail]; + }, +}); + /** * Changes a password for a given account * @@ -712,6 +724,14 @@ function setContactMethodAsDefault(newDefaultContactMethod) { }, }, }, + { + onyxMethod: CONST.ONYX.METHOD.MERGE, + key: ONYXKEYS.PERSONAL_DETAILS, + value: { + [newDefaultContactMethod]: {...myPersonalDetails}, + [oldDefaultContactMethod]: null, + }, + }, ]; const successData = [{ onyxMethod: CONST.ONYX.METHOD.MERGE, @@ -748,6 +768,14 @@ function setContactMethodAsDefault(newDefaultContactMethod) { }, }, }, + { + onyxMethod: CONST.ONYX.METHOD.MERGE, + key: ONYXKEYS.PERSONAL_DETAILS, + value: { + [newDefaultContactMethod]: null, + [oldDefaultContactMethod]: {...myPersonalDetails}, + }, + }, ]; API.write('SetContactMethodAsDefault', {partnerUserID: newDefaultContactMethod}, {optimisticData, successData, failureData}); Navigation.navigate(ROUTES.SETTINGS_CONTACT_METHODS); From a26b278c4e9ee8c8fed7e12cb173ced0f57c3688 Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Mon, 1 May 2023 14:32:36 +0300 Subject: [PATCH 20/27] Update personal details w/ new default cm --- src/libs/actions/User.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/libs/actions/User.js b/src/libs/actions/User.js index 33bb1c672ed..55e64b1ad71 100644 --- a/src/libs/actions/User.js +++ b/src/libs/actions/User.js @@ -20,6 +20,7 @@ import * as Report from './Report'; import * as ReportActionsUtils from '../ReportActionsUtils'; import DateUtils from '../DateUtils'; import * as Session from './Session'; +import * as PersonalDetails from './PersonalDetails'; let currentUserAccountID = ''; let currentEmail = ''; @@ -727,7 +728,14 @@ function setContactMethodAsDefault(newDefaultContactMethod) { onyxMethod: CONST.ONYX.METHOD.MERGE, key: ONYXKEYS.PERSONAL_DETAILS, value: { - [newDefaultContactMethod]: {...myPersonalDetails}, + [newDefaultContactMethod]: { + ...myPersonalDetails, + login: newDefaultContactMethod, + displayName: PersonalDetails.getDisplayName( + newDefaultContactMethod, + myPersonalDetails, + ), + }, [oldDefaultContactMethod]: null, }, }, From ec9918e484ad97464bf932364ae3fff7e6458cfb Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Mon, 8 May 2023 12:37:49 +0300 Subject: [PATCH 21/27] Update to new constant location --- src/libs/actions/User.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/libs/actions/User.js b/src/libs/actions/User.js index ab051152055..f0e4bbb5ffb 100644 --- a/src/libs/actions/User.js +++ b/src/libs/actions/User.js @@ -715,14 +715,14 @@ function setContactMethodAsDefault(newDefaultContactMethod) { const oldDefaultContactMethod = currentEmail; const optimisticData = [ { - onyxMethod: CONST.ONYX.METHOD.MERGE, + onyxMethod: Onyx.METHOD.MERGE, key: ONYXKEYS.SESSION, value: { email: newDefaultContactMethod, }, }, { - onyxMethod: CONST.ONYX.METHOD.MERGE, + onyxMethod: Onyx.METHOD.MERGE, key: ONYXKEYS.LOGIN_LIST, value: { [newDefaultContactMethod]: { @@ -736,7 +736,7 @@ function setContactMethodAsDefault(newDefaultContactMethod) { }, }, { - onyxMethod: CONST.ONYX.METHOD.MERGE, + onyxMethod: Onyx.METHOD.MERGE, key: ONYXKEYS.PERSONAL_DETAILS, value: { [newDefaultContactMethod]: { @@ -752,7 +752,7 @@ function setContactMethodAsDefault(newDefaultContactMethod) { }, ]; const successData = [{ - onyxMethod: CONST.ONYX.METHOD.MERGE, + onyxMethod: Onyx.METHOD.MERGE, key: ONYXKEYS.LOGIN_LIST, value: { [newDefaultContactMethod]: { @@ -764,14 +764,14 @@ function setContactMethodAsDefault(newDefaultContactMethod) { }]; const failureData = [ { - onyxMethod: CONST.ONYX.METHOD.MERGE, + onyxMethod: Onyx.METHOD.MERGE, key: ONYXKEYS.SESSION, value: { email: oldDefaultContactMethod, }, }, { - onyxMethod: CONST.ONYX.METHOD.MERGE, + onyxMethod: Onyx.METHOD.MERGE, key: ONYXKEYS.LOGIN_LIST, value: { [newDefaultContactMethod]: { @@ -787,7 +787,7 @@ function setContactMethodAsDefault(newDefaultContactMethod) { }, }, { - onyxMethod: CONST.ONYX.METHOD.MERGE, + onyxMethod: Onyx.METHOD.MERGE, key: ONYXKEYS.PERSONAL_DETAILS, value: { [newDefaultContactMethod]: null, From bbe41977ffded406bb48122c9d64a8bc4c557ab5 Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Mon, 8 May 2023 12:37:59 +0300 Subject: [PATCH 22/27] Update other actions to new onyx constant location --- src/libs/actions/Session/index.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/libs/actions/Session/index.js b/src/libs/actions/Session/index.js index f351c496130..82be9822b4d 100644 --- a/src/libs/actions/Session/index.js +++ b/src/libs/actions/Session/index.js @@ -652,7 +652,7 @@ function authenticatePusher(socketID, channelName, callback) { */ function requestUnlinkValidationLink() { const optimisticData = [{ - onyxMethod: CONST.ONYX.METHOD.MERGE, + onyxMethod: Onyx.METHOD.MERGE, key: ONYXKEYS.ACCOUNT, value: { isLoading: true, @@ -661,7 +661,7 @@ function requestUnlinkValidationLink() { }, }]; const successData = [{ - onyxMethod: CONST.ONYX.METHOD.MERGE, + onyxMethod: Onyx.METHOD.MERGE, key: ONYXKEYS.ACCOUNT, value: { isLoading: false, @@ -669,7 +669,7 @@ function requestUnlinkValidationLink() { }, }]; const failureData = [{ - onyxMethod: CONST.ONYX.METHOD.MERGE, + onyxMethod: Onyx.METHOD.MERGE, key: ONYXKEYS.ACCOUNT, value: { isLoading: false, @@ -681,7 +681,7 @@ function requestUnlinkValidationLink() { function unlinkLogin(accountID, validateCode) { const optimisticData = [{ - onyxMethod: CONST.ONYX.METHOD.MERGE, + onyxMethod: Onyx.METHOD.MERGE, key: ONYXKEYS.ACCOUNT, value: { ...CONST.DEFAULT_ACCOUNT_DATA, @@ -689,7 +689,7 @@ function unlinkLogin(accountID, validateCode) { }, }]; const successData = [{ - onyxMethod: CONST.ONYX.METHOD.MERGE, + onyxMethod: Onyx.METHOD.MERGE, key: ONYXKEYS.ACCOUNT, value: { isLoading: false, @@ -697,14 +697,14 @@ function unlinkLogin(accountID, validateCode) { }, }, { - onyxMethod: CONST.ONYX.METHOD.MERGE, + onyxMethod: Onyx.METHOD.MERGE, key: ONYXKEYS.CREDENTIALS, value: { login: '', }, }]; const failureData = [{ - onyxMethod: CONST.ONYX.METHOD.MERGE, + onyxMethod: Onyx.METHOD.MERGE, key: ONYXKEYS.ACCOUNT, value: { isLoading: false, From 6d15fdf572948bc5d236a0ecc53952d52b045254 Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Mon, 8 May 2023 13:05:41 +0300 Subject: [PATCH 23/27] Remove passwordless references --- .../Profile/Contacts/ContactMethodDetailsPage.js | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.js b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.js index 123ccd9f7e1..f33ec093895 100644 --- a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.js +++ b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.js @@ -29,14 +29,10 @@ import * as ErrorUtils from '../../../../libs/ErrorUtils'; import themeColors from '../../../../styles/themes/default'; import NotFoundPage from '../../../ErrorPage/NotFoundPage'; import * as ValidationUtils from '../../../../libs/ValidationUtils'; -import Permissions from '../../../../libs/Permissions'; const propTypes = { /* Onyx Props */ - /** List of betas available to current user */ - betas: PropTypes.arrayOf(PropTypes.string), - /** Login list for the user that is signed in */ loginList: PropTypes.shape({ /** Value of partner name */ @@ -80,7 +76,6 @@ const propTypes = { }; const defaultProps = { - betas: [], loginList: {}, session: { email: null, @@ -233,11 +228,9 @@ class ContactMethodDetailsPage extends Component { // 1. This contact method is not already their default // 2. This contact method is validated // 3. Default contact method switching is allowed by their domain security group (if this exists) - // 4. The user is on the passwordless beta const canChangeDefaultContactMethod = !isDefaultContactMethod && loginData.validatedDate - && this.getCanChangeDefaultContactMethod() - && Permissions.canUsePasswordlessLogins(this.props.betas); + && this.getCanChangeDefaultContactMethod(); return ( @@ -366,9 +359,6 @@ ContactMethodDetailsPage.defaultProps = defaultProps; export default compose( withLocalize, withOnyx({ - betas: { - key: ONYXKEYS.BETAS, - }, loginList: { key: ONYXKEYS.LOGIN_LIST, }, From ab5862a4fcc68f4712be325d6c68f0640f0521f8 Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Wed, 10 May 2023 11:24:22 +0300 Subject: [PATCH 24/27] prettify files --- src/libs/actions/User.js | 23 +++++++++---------- .../Contacts/ContactMethodDetailsPage.js | 13 +++-------- 2 files changed, 14 insertions(+), 22 deletions(-) diff --git a/src/libs/actions/User.js b/src/libs/actions/User.js index a725123ddad..fbe3f691cd0 100644 --- a/src/libs/actions/User.js +++ b/src/libs/actions/User.js @@ -811,26 +811,25 @@ function setContactMethodAsDefault(newDefaultContactMethod) { [newDefaultContactMethod]: { ...myPersonalDetails, login: newDefaultContactMethod, - displayName: PersonalDetails.getDisplayName( - newDefaultContactMethod, - myPersonalDetails, - ), + displayName: PersonalDetails.getDisplayName(newDefaultContactMethod, myPersonalDetails), }, [oldDefaultContactMethod]: null, }, }, ]; - const successData = [{ - onyxMethod: Onyx.METHOD.MERGE, - key: ONYXKEYS.LOGIN_LIST, - value: { - [newDefaultContactMethod]: { - pendingFields: { - defaultLogin: null, + const successData = [ + { + onyxMethod: Onyx.METHOD.MERGE, + key: ONYXKEYS.LOGIN_LIST, + value: { + [newDefaultContactMethod]: { + pendingFields: { + defaultLogin: null, + }, }, }, }, - }]; + ]; const failureData = [ { onyxMethod: Onyx.METHOD.MERGE, diff --git a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.js b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.js index 770c98e20d5..ee4b0c11428 100644 --- a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.js +++ b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.js @@ -145,10 +145,7 @@ class ContactMethodDetailsPage extends Component { } // Return true if there's no security group with 'hasRestrictedPrimaryLogin' set to true. - return !lodashGet(this.props.securityGroups, [ - `${ONYXKEYS.COLLECTION.SECURITY_GROUP}${primaryDomainSecurityGroupID}`, - 'hasRestrictedPrimaryLogin', - ], false); + return !lodashGet(this.props.securityGroups, [`${ONYXKEYS.COLLECTION.SECURITY_GROUP}${primaryDomainSecurityGroupID}`, 'hasRestrictedPrimaryLogin'], false); } /** @@ -226,9 +223,7 @@ class ContactMethodDetailsPage extends Component { // 1. This contact method is not already their default // 2. This contact method is validated // 3. Default contact method switching is allowed by their domain security group (if this exists) - const canChangeDefaultContactMethod = !isDefaultContactMethod - && loginData.validatedDate - && this.getCanChangeDefaultContactMethod(); + const canChangeDefaultContactMethod = !isDefaultContactMethod && loginData.validatedDate && this.getCanChangeDefaultContactMethod(); return ( @@ -332,9 +327,7 @@ class ContactMethodDetailsPage extends Component { errorRowStyles={[styles.ml8, styles.mr5]} onClose={() => User.clearContactMethodErrors(contactMethod, 'defaultLogin')} > - - {this.props.translate('contacts.yourDefaultContactMethod')} - + {this.props.translate('contacts.yourDefaultContactMethod')} ) : ( <> From d54ca1906a80c986960921076e7b906b8129e7c5 Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Wed, 10 May 2023 11:24:42 +0300 Subject: [PATCH 25/27] Remove unnecessary fragment --- .../Contacts/ContactMethodDetailsPage.js | 28 +++++++++---------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.js b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.js index ee4b0c11428..acbc1a3cf2f 100644 --- a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.js +++ b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.js @@ -330,21 +330,19 @@ class ContactMethodDetailsPage extends Component { {this.props.translate('contacts.yourDefaultContactMethod')} ) : ( - <> - User.clearContactMethodErrors(contactMethod, 'deletedLogin')} - > - this.toggleDeleteModal(true)} - /> - - + User.clearContactMethodErrors(contactMethod, 'deletedLogin')} + > + this.toggleDeleteModal(true)} + /> + )}
From 0c1fc10c3e1a2a7d9efc2e42e1793bdaa88d7877 Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Wed, 10 May 2023 12:46:54 +0300 Subject: [PATCH 26/27] Refactor to put all change logic into 1 fn --- .../Contacts/ContactMethodDetailsPage.js | 32 ++++++++++++------- 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.js b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.js index acbc1a3cf2f..aa75189569e 100644 --- a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.js +++ b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.js @@ -129,12 +129,25 @@ class ContactMethodDetailsPage extends Component { } /** - * Checks if the user is allowed to change their default contact method by looking at - * their security group settings on their primary domain. + * Checks if the user is allowed to change their default contact method. This should only be allowed if: + * 1. The viewed contact method is not already their default contact method + * 2. The viewed contact method is validated + * 3. If the user is on a private domain, their security group must allow primary login switching * * @returns {Boolean} */ - getCanChangeDefaultContactMethod() { + canChangeDefaultContactMethod() { + const contactMethod = this.getContactMethod(); + const loginData = lodashGet(this.props.loginList, contactMethod, {}); + const isDefaultContactMethod = this.props.session.email === loginData.partnerUserID; + + // Cannot set this contact method as default if: + // 1. This contact method is already their default + // 2. This contact method is not validated + if (isDefaultContactMethod || !loginData.validatedDate) { + return false; + } + const domainName = Str.extractEmailDomain(this.props.session.email); const primaryDomainSecurityGroupID = lodashGet(this.props.myDomainSecurityGroups, domainName); @@ -144,7 +157,8 @@ class ContactMethodDetailsPage extends Component { return true; } - // Return true if there's no security group with 'hasRestrictedPrimaryLogin' set to true. + // Allow user to change their default contact method if they don't have a security group OR if their security group + // does NOT restrict primary login switching. return !lodashGet(this.props.securityGroups, [`${ONYXKEYS.COLLECTION.SECURITY_GROUP}${primaryDomainSecurityGroupID}`, 'hasRestrictedPrimaryLogin'], false); } @@ -206,7 +220,7 @@ class ContactMethodDetailsPage extends Component { render() { const contactMethod = this.getContactMethod(); - // replacing spaces with "hard spaces" to prevent breaking the number + // Replacing spaces with "hard spaces" to prevent breaking the number const formattedContactMethod = Str.isSMSLogin(contactMethod) ? this.props.formatPhoneNumber(contactMethod).replace(/ /g, '\u00A0') : contactMethod; const loginData = this.props.loginList[contactMethod]; @@ -219,12 +233,6 @@ class ContactMethodDetailsPage extends Component { const formErrorText = this.state.formError ? this.props.translate(this.state.formError) : ''; const isFailedAddContactMethod = Boolean(lodashGet(loginData, 'errorFields.addedLogin')); - // Users are only allowed to change their default contact method to the current one if: - // 1. This contact method is not already their default - // 2. This contact method is validated - // 3. Default contact method switching is allowed by their domain security group (if this exists) - const canChangeDefaultContactMethod = !isDefaultContactMethod && loginData.validatedDate && this.getCanChangeDefaultContactMethod(); - return ( )} - {canChangeDefaultContactMethod ? ( + {this.canChangeDefaultContactMethod() ? ( Date: Wed, 10 May 2023 12:59:46 +0300 Subject: [PATCH 27/27] linter told me to do this --- .../Profile/Contacts/ContactMethodDetailsPage.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.js b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.js index aa75189569e..c7d9a890af8 100644 --- a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.js +++ b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.js @@ -128,6 +128,13 @@ class ContactMethodDetailsPage extends Component { return decodeURIComponent(lodashGet(this.props.route, 'params.contactMethod')); } + /** + * Attempt to set this contact method as user's "Default contact method" + */ + setAsDefault() { + User.setContactMethodAsDefault(this.getContactMethod()); + } + /** * Checks if the user is allowed to change their default contact method. This should only be allowed if: * 1. The viewed contact method is not already their default contact method @@ -162,13 +169,6 @@ class ContactMethodDetailsPage extends Component { return !lodashGet(this.props.securityGroups, [`${ONYXKEYS.COLLECTION.SECURITY_GROUP}${primaryDomainSecurityGroupID}`, 'hasRestrictedPrimaryLogin'], false); } - /** - * Attempt to set this contact method as user's "Default contact method" - */ - setAsDefault() { - User.setContactMethodAsDefault(this.getContactMethod()); - } - /** * Deletes the contact method if it has errors. Otherwise, it shows the confirmation alert and deletes it only if the user confirms. */