From 1a1a489541a6522bd27c2fd601befefc1ac69743 Mon Sep 17 00:00:00 2001 From: chiragsalian Date: Thu, 11 Aug 2022 16:05:34 -0700 Subject: [PATCH 01/14] initial code --- src/libs/actions/Policy.js | 58 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/src/libs/actions/Policy.js b/src/libs/actions/Policy.js index 9470ea25f4e0..8d06d107edec 100644 --- a/src/libs/actions/Policy.js +++ b/src/libs/actions/Policy.js @@ -2,6 +2,7 @@ import _ from 'underscore'; import Onyx from 'react-native-onyx'; import lodashGet from 'lodash/get'; import * as DeprecatedAPI from '../deprecatedAPI'; +import * as API from '../API'; import ONYXKEYS from '../../ONYXKEYS'; import * as PersonalDetails from './PersonalDetails'; import Growl from '../Growl'; @@ -13,6 +14,7 @@ import ROUTES from '../../ROUTES'; import * as OptionsListUtils from '../OptionsListUtils'; import * as Report from './Report'; import * as Pusher from '../Pusher/pusher'; +import DateUtils from '../DateUtils'; const allPolicies = {}; Onyx.connect({ @@ -319,6 +321,60 @@ function removeMembers(members, policyID) { }); } +/** + * Adds members to the specified workspace/policyID + * + * @param {Array} memberLogins + * @param {String} welcomeNote + * @param {String} policyID + */ +function addMembersToWorkspace(memberLogins, welcomeNote, policyID) { + const membersListKey = `${ONYXKEYS.COLLECTION.POLICY_MEMBER_LIST}${policyID}`; + const logins = _.map(memberLogins, memberLogin => OptionsListUtils.addSMSDomainIfPhoneNumber(memberLogin)); + + const optimisticData = [ + { + onyxMethod: 'merge', + key: membersListKey, + + // Convert to object with each key containing {pendingAction: ‘add’} + value: _.object(logins, Array(logins.length).fill({pendingAction: 'add'})), + }, + ]; + + const successData = [ + { + onyxMethod: 'merge', + key: membersListKey, + + // Convert to object with each key clearing pendingAction. We don’t + // need to remove the members since that will be handled by onClose of OfflineWithFeedback. + value: _.object(logins, Array(logins.length).fill({pendingAction: null})), + }, + ]; + + const failureData = [ + { + onyxMethod: 'merge', + key: membersListKey, + + // Convert to object with each key containing the error. We don’t + // need to remove the members since that is handled by onClose of OfflineWithFeedback. + value: _.object(logins, Array(logins.length).fill({ + errors: { + [DateUtils.getMicroseconds()]: 'some generic error', + }, + })), + }, + ]; + + API.write('AddMembersToWorkspace', { + employees: JSON.stringify(_.map(logins, login => ({email: login}))), + welcomeNote, + policyID, + }, {optimisticData, successData, failureData}); +} + /** * Merges the passed in login into the specified policy * @@ -327,6 +383,7 @@ function removeMembers(members, policyID) { * @param {String} policyID */ function invite(logins, welcomeNote, policyID) { + // addMembersToWorkspace(logins, welcomeNote, policyID); const key = `${ONYXKEYS.COLLECTION.POLICY}${policyID}`; const newEmployeeList = _.map(logins, login => OptionsListUtils.addSMSDomainIfPhoneNumber(login)); @@ -580,6 +637,7 @@ export { loadFullPolicy, removeMembers, invite, + addMembersToWorkspace, isAdminOfFreePolicy, create, uploadAvatar, From 36f1a725b191e74f8b1aa5f5409a9ce12773956c Mon Sep 17 00:00:00 2001 From: chiragsalian Date: Tue, 16 Aug 2022 17:23:46 -0700 Subject: [PATCH 02/14] testing addMembersToWorkspace --- src/libs/actions/Policy.js | 85 +++++++++++++++++++------------------- 1 file changed, 43 insertions(+), 42 deletions(-) diff --git a/src/libs/actions/Policy.js b/src/libs/actions/Policy.js index 8d06d107edec..c157af0f6bb2 100644 --- a/src/libs/actions/Policy.js +++ b/src/libs/actions/Policy.js @@ -369,7 +369,8 @@ function addMembersToWorkspace(memberLogins, welcomeNote, policyID) { ]; API.write('AddMembersToWorkspace', { - employees: JSON.stringify(_.map(logins, login => ({email: login}))), + // employees: JSON.stringify(_.map(logins, login => ({email: login}))), + employees: JSON.stringify(logins), welcomeNote, policyID, }, {optimisticData, successData, failureData}); @@ -383,47 +384,47 @@ function addMembersToWorkspace(memberLogins, welcomeNote, policyID) { * @param {String} policyID */ function invite(logins, welcomeNote, policyID) { - // addMembersToWorkspace(logins, welcomeNote, policyID); - const key = `${ONYXKEYS.COLLECTION.POLICY}${policyID}`; - const newEmployeeList = _.map(logins, login => OptionsListUtils.addSMSDomainIfPhoneNumber(login)); - - // Make a shallow copy to preserve original data, and concat the login - const policy = _.clone(allPolicies[key]); - policy.employeeList = [...policy.employeeList, ...newEmployeeList]; - policy.alertMessage = ''; - - // Optimistically add the user to the policy - Onyx.merge(key, policy); - - // Make the API call to merge the login into the policy - DeprecatedAPI.Policy_Employees_Merge({ - employees: JSON.stringify(_.map(logins, login => ({email: login}))), - welcomeNote, - policyID, - }) - .then((data) => { - // Save the personalDetails for the invited user in Onyx and fetch the latest policyExpenseChats - if (data.jsonCode === 200) { - Onyx.merge(ONYXKEYS.PERSONAL_DETAILS, PersonalDetails.formatPersonalDetails(data.personalDetails)); - Navigation.goBack(); - if (!_.isEmpty(data.policyExpenseChatIDs)) { - Report.fetchChatReportsByIDs(data.policyExpenseChatIDs); - } - return; - } - - // If the operation failed, undo the optimistic addition - const policyDataWithoutLogin = _.clone(allPolicies[key]); - policyDataWithoutLogin.employeeList = _.without(allPolicies[key].employeeList, ...newEmployeeList); - - // Show the user feedback that the addition failed - policyDataWithoutLogin.alertMessage = Localize.translateLocal('workspace.invite.genericFailureMessage'); - if (data.jsonCode === 402) { - policyDataWithoutLogin.alertMessage += ` ${Localize.translateLocal('workspace.invite.pleaseEnterValidLogin')}`; - } - - Onyx.set(key, policyDataWithoutLogin); - }); + addMembersToWorkspace(logins, welcomeNote, policyID); + // const key = `${ONYXKEYS.COLLECTION.POLICY}${policyID}`; + // const newEmployeeList = _.map(logins, login => OptionsListUtils.addSMSDomainIfPhoneNumber(login)); + // + // // Make a shallow copy to preserve original data, and concat the login + // const policy = _.clone(allPolicies[key]); + // policy.employeeList = [...policy.employeeList, ...newEmployeeList]; + // policy.alertMessage = ''; + // + // // Optimistically add the user to the policy + // Onyx.merge(key, policy); + // + // // Make the API call to merge the login into the policy + // DeprecatedAPI.Policy_Employees_Merge({ + // employees: JSON.stringify(_.map(logins, login => ({email: login}))), + // welcomeNote, + // policyID, + // }) + // .then((data) => { + // // Save the personalDetails for the invited user in Onyx and fetch the latest policyExpenseChats + // if (data.jsonCode === 200) { + // Onyx.merge(ONYXKEYS.PERSONAL_DETAILS, PersonalDetails.formatPersonalDetails(data.personalDetails)); + // Navigation.goBack(); + // if (!_.isEmpty(data.policyExpenseChatIDs)) { + // Report.fetchChatReportsByIDs(data.policyExpenseChatIDs); + // } + // return; + // } + // + // // If the operation failed, undo the optimistic addition + // const policyDataWithoutLogin = _.clone(allPolicies[key]); + // policyDataWithoutLogin.employeeList = _.without(allPolicies[key].employeeList, ...newEmployeeList); + // + // // Show the user feedback that the addition failed + // policyDataWithoutLogin.alertMessage = Localize.translateLocal('workspace.invite.genericFailureMessage'); + // if (data.jsonCode === 402) { + // policyDataWithoutLogin.alertMessage += ` ${Localize.translateLocal('workspace.invite.pleaseEnterValidLogin')}`; + // } + // + // Onyx.set(key, policyDataWithoutLogin); + // }); } /** From 86055efd7a58f066c697a32a526bf2f9a90972cd Mon Sep 17 00:00:00 2001 From: chiragsalian Date: Thu, 18 Aug 2022 14:43:46 -0700 Subject: [PATCH 03/14] cleanup and navigate back --- src/libs/actions/Policy.js | 52 ---------------------- src/pages/workspace/WorkspaceInvitePage.js | 3 +- 2 files changed, 2 insertions(+), 53 deletions(-) diff --git a/src/libs/actions/Policy.js b/src/libs/actions/Policy.js index c157af0f6bb2..a9f62671b600 100644 --- a/src/libs/actions/Policy.js +++ b/src/libs/actions/Policy.js @@ -376,57 +376,6 @@ function addMembersToWorkspace(memberLogins, welcomeNote, policyID) { }, {optimisticData, successData, failureData}); } -/** - * Merges the passed in login into the specified policy - * - * @param {Array} logins - * @param {String} welcomeNote - * @param {String} policyID - */ -function invite(logins, welcomeNote, policyID) { - addMembersToWorkspace(logins, welcomeNote, policyID); - // const key = `${ONYXKEYS.COLLECTION.POLICY}${policyID}`; - // const newEmployeeList = _.map(logins, login => OptionsListUtils.addSMSDomainIfPhoneNumber(login)); - // - // // Make a shallow copy to preserve original data, and concat the login - // const policy = _.clone(allPolicies[key]); - // policy.employeeList = [...policy.employeeList, ...newEmployeeList]; - // policy.alertMessage = ''; - // - // // Optimistically add the user to the policy - // Onyx.merge(key, policy); - // - // // Make the API call to merge the login into the policy - // DeprecatedAPI.Policy_Employees_Merge({ - // employees: JSON.stringify(_.map(logins, login => ({email: login}))), - // welcomeNote, - // policyID, - // }) - // .then((data) => { - // // Save the personalDetails for the invited user in Onyx and fetch the latest policyExpenseChats - // if (data.jsonCode === 200) { - // Onyx.merge(ONYXKEYS.PERSONAL_DETAILS, PersonalDetails.formatPersonalDetails(data.personalDetails)); - // Navigation.goBack(); - // if (!_.isEmpty(data.policyExpenseChatIDs)) { - // Report.fetchChatReportsByIDs(data.policyExpenseChatIDs); - // } - // return; - // } - // - // // If the operation failed, undo the optimistic addition - // const policyDataWithoutLogin = _.clone(allPolicies[key]); - // policyDataWithoutLogin.employeeList = _.without(allPolicies[key].employeeList, ...newEmployeeList); - // - // // Show the user feedback that the addition failed - // policyDataWithoutLogin.alertMessage = Localize.translateLocal('workspace.invite.genericFailureMessage'); - // if (data.jsonCode === 402) { - // policyDataWithoutLogin.alertMessage += ` ${Localize.translateLocal('workspace.invite.pleaseEnterValidLogin')}`; - // } - // - // Onyx.set(key, policyDataWithoutLogin); - // }); -} - /** * Sets local values for the policy * @param {String} policyID @@ -637,7 +586,6 @@ export { getPolicyList, loadFullPolicy, removeMembers, - invite, addMembersToWorkspace, isAdminOfFreePolicy, create, diff --git a/src/pages/workspace/WorkspaceInvitePage.js b/src/pages/workspace/WorkspaceInvitePage.js index ae2c8627e1e9..626452d9894b 100644 --- a/src/pages/workspace/WorkspaceInvitePage.js +++ b/src/pages/workspace/WorkspaceInvitePage.js @@ -202,7 +202,8 @@ class WorkspaceInvitePage extends React.Component { const logins = _.map(this.state.selectedOptions, option => option.login); const filteredLogins = _.uniq(_.compact(_.map(logins, login => login.toLowerCase().trim()))); - Policy.invite(filteredLogins, this.state.welcomeNote || this.getWelcomeNote(), this.props.route.params.policyID); + Policy.addMembersToWorkspace(filteredLogins, this.state.welcomeNote || this.getWelcomeNote(), this.props.route.params.policyID); + Navigation.goBack() } /** From 2a2392b6e83c806b4450e47fd2dde639aeebbedd Mon Sep 17 00:00:00 2001 From: chiragsalian Date: Thu, 18 Aug 2022 15:36:22 -0700 Subject: [PATCH 04/14] updating WorkspaceMembersPage to display member list --- src/pages/workspace/WorkspaceInvitePage.js | 2 +- src/pages/workspace/WorkspaceMembersPage.js | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/pages/workspace/WorkspaceInvitePage.js b/src/pages/workspace/WorkspaceInvitePage.js index 626452d9894b..b57ed4557521 100644 --- a/src/pages/workspace/WorkspaceInvitePage.js +++ b/src/pages/workspace/WorkspaceInvitePage.js @@ -203,7 +203,7 @@ class WorkspaceInvitePage extends React.Component { const logins = _.map(this.state.selectedOptions, option => option.login); const filteredLogins = _.uniq(_.compact(_.map(logins, login => login.toLowerCase().trim()))); Policy.addMembersToWorkspace(filteredLogins, this.state.welcomeNote || this.getWelcomeNote(), this.props.route.params.policyID); - Navigation.goBack() + Navigation.goBack(); } /** diff --git a/src/pages/workspace/WorkspaceMembersPage.js b/src/pages/workspace/WorkspaceMembersPage.js index 8f10c91b1992..b72fcdb00610 100644 --- a/src/pages/workspace/WorkspaceMembersPage.js +++ b/src/pages/workspace/WorkspaceMembersPage.js @@ -42,6 +42,9 @@ const propTypes = { }), }).isRequired, + /** List of members on this policy */ + memberList: PropTypes.arrayOf(PropTypes.object), + ...fullPolicyPropTypes, ...withLocalizePropTypes, ...windowDimensionsPropTypes, @@ -263,7 +266,7 @@ class WorkspaceMembersPage extends React.Component { } render() { - const policyEmployeeList = lodashGet(this.props, 'policy.employeeList', []); + const policyEmployeeList = _.keys(this.props.memberList); const removableMembers = _.without(this.props.policy.employeeList, this.props.session.email, this.props.policy.owner); const data = _.chain(policyEmployeeList) .map(email => this.props.personalDetails[email]) @@ -353,5 +356,8 @@ export default compose( session: { key: ONYXKEYS.SESSION, }, + memberList: { + key: ({route}) => `${ONYXKEYS.COLLECTION.POLICY_MEMBER_LIST}${route.params.policyID}`, + }, }), )(WorkspaceMembersPage); From 989eaba6eb25d897bb61dc760d18de92e1c337c5 Mon Sep 17 00:00:00 2001 From: chiragsalian Date: Wed, 24 Aug 2022 16:57:35 -0700 Subject: [PATCH 05/14] using key email to future proof code so role can be passed easily in future --- src/libs/actions/Policy.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/libs/actions/Policy.js b/src/libs/actions/Policy.js index 09a2aa1d31c5..c36f1057fa91 100644 --- a/src/libs/actions/Policy.js +++ b/src/libs/actions/Policy.js @@ -362,8 +362,7 @@ function addMembersToWorkspace(memberLogins, welcomeNote, policyID) { ]; API.write('AddMembersToWorkspace', { - // employees: JSON.stringify(_.map(logins, login => ({email: login}))), - employees: JSON.stringify(logins), + employees: JSON.stringify(_.map(logins, login => ({email: login}))), welcomeNote, policyID, }, {optimisticData, successData, failureData}); From 7755c74aad43ecb8ab27da9cae8f5b514c68e60b Mon Sep 17 00:00:00 2001 From: chiragsalian Date: Wed, 24 Aug 2022 17:03:47 -0700 Subject: [PATCH 06/14] removing unnecessary params --- src/pages/workspace/WorkspaceMembersPage.js | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/pages/workspace/WorkspaceMembersPage.js b/src/pages/workspace/WorkspaceMembersPage.js index ee50a96a463b..eca3a2bcbe5f 100644 --- a/src/pages/workspace/WorkspaceMembersPage.js +++ b/src/pages/workspace/WorkspaceMembersPage.js @@ -42,9 +42,6 @@ const propTypes = { }), }).isRequired, - /** List of members on this policy */ - memberList: PropTypes.arrayOf(PropTypes.object), - ...fullPolicyPropTypes, ...withLocalizePropTypes, ...windowDimensionsPropTypes, @@ -357,8 +354,5 @@ export default compose( session: { key: ONYXKEYS.SESSION, }, - memberList: { - key: ({route}) => `${ONYXKEYS.COLLECTION.POLICY_MEMBER_LIST}${route.params.policyID}`, - }, }), )(WorkspaceMembersPage); From 4713df2ca6b9a869a8ef876c7664e93436be156b Mon Sep 17 00:00:00 2001 From: chiragsalian Date: Tue, 13 Sep 2022 16:24:01 -0700 Subject: [PATCH 07/14] Adding translations --- src/languages/en.js | 1 + src/languages/es.js | 1 + src/libs/actions/Policy.js | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/languages/en.js b/src/languages/en.js index c70131508112..716f709b2937 100755 --- a/src/languages/en.js +++ b/src/languages/en.js @@ -810,6 +810,7 @@ export default { removeMembersTitle: 'Remove members', selectAll: 'Select all', error: { + genericAdd: 'There was a problem adding this workspace member.', cannotRemove: 'You cannot remove yourself or the workspace owner.', }, }, diff --git a/src/languages/es.js b/src/languages/es.js index 68b50e078565..87bc60f59c61 100644 --- a/src/languages/es.js +++ b/src/languages/es.js @@ -812,6 +812,7 @@ export default { removeMembersTitle: 'Eliminar miembros', selectAll: 'Seleccionar todo', error: { + genericAdd: '', cannotRemove: 'No puedes eliminarte ni a ti mismo ni al dueño del espacio de trabajo.', }, }, diff --git a/src/libs/actions/Policy.js b/src/libs/actions/Policy.js index cd5428b7ba3b..87856569d434 100644 --- a/src/libs/actions/Policy.js +++ b/src/libs/actions/Policy.js @@ -283,7 +283,7 @@ function addMembersToWorkspace(memberLogins, welcomeNote, policyID) { // need to remove the members since that is handled by onClose of OfflineWithFeedback. value: _.object(logins, Array(logins.length).fill({ errors: { - [DateUtils.getMicroseconds()]: 'some generic error', + [DateUtils.getMicroseconds()]: Localize.translateLocal('workspace.people.error.genericAdd'), }, })), }, From 761ef2150154276357dd7d7094ccdb48d47522b3 Mon Sep 17 00:00:00 2001 From: Chirag Chandrakant Salian Date: Thu, 15 Sep 2022 17:48:22 -0700 Subject: [PATCH 08/14] Update src/languages/es.js Co-authored-by: Ionatan Wiznia --- src/languages/es.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/languages/es.js b/src/languages/es.js index 87bc60f59c61..1b034506ca22 100644 --- a/src/languages/es.js +++ b/src/languages/es.js @@ -812,7 +812,7 @@ export default { removeMembersTitle: 'Eliminar miembros', selectAll: 'Seleccionar todo', error: { - genericAdd: '', + genericAdd: 'Ha ocurrido un problema al agregar el miembro al espacio de trabajo', cannotRemove: 'No puedes eliminarte ni a ti mismo ni al dueño del espacio de trabajo.', }, }, From e11e68286846bc1473a667a2f89e9f53b7e5a14b Mon Sep 17 00:00:00 2001 From: chiragsalian Date: Thu, 15 Sep 2022 17:50:15 -0700 Subject: [PATCH 09/14] using const --- src/libs/actions/Policy.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libs/actions/Policy.js b/src/libs/actions/Policy.js index 96c7a69a11d3..e7e14e730221 100644 --- a/src/libs/actions/Policy.js +++ b/src/libs/actions/Policy.js @@ -255,17 +255,17 @@ function addMembersToWorkspace(memberLogins, welcomeNote, policyID) { const optimisticData = [ { - onyxMethod: 'merge', + onyxMethod: CONST.ONYX.METHOD.MERGE, key: membersListKey, // Convert to object with each key containing {pendingAction: ‘add’} - value: _.object(logins, Array(logins.length).fill({pendingAction: 'add'})), + value: _.object(logins, Array(logins.length).fill({pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD})), }, ]; const successData = [ { - onyxMethod: 'merge', + onyxMethod: CONST.ONYX.METHOD.MERGE, key: membersListKey, // Convert to object with each key clearing pendingAction. We don’t @@ -276,7 +276,7 @@ function addMembersToWorkspace(memberLogins, welcomeNote, policyID) { const failureData = [ { - onyxMethod: 'merge', + onyxMethod: CONST.ONYX.METHOD.MERGE, key: membersListKey, // Convert to object with each key containing the error. We don’t From f8fadfcda92a3b8478f432ed497052b598f1ffa4 Mon Sep 17 00:00:00 2001 From: chiragsalian Date: Tue, 20 Sep 2022 11:49:35 -0700 Subject: [PATCH 10/14] enabledWhenOffline prop --- src/components/FormAlertWithSubmitButton.js | 12 +++++++++--- src/pages/workspace/WorkspaceInvitePage.js | 1 + 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/components/FormAlertWithSubmitButton.js b/src/components/FormAlertWithSubmitButton.js index ca1e86d817ea..5aff947889ea 100644 --- a/src/components/FormAlertWithSubmitButton.js +++ b/src/components/FormAlertWithSubmitButton.js @@ -32,6 +32,9 @@ const propTypes = { /** Submit function */ onSubmit: PropTypes.func.isRequired, + + /** Should the button be enabled when offline */ + enabledWhenOffline: PropTypes.bool, }; const defaultProps = { @@ -41,6 +44,7 @@ const defaultProps = { containerStyles: [], isLoading: false, onFixTheErrorsPressed: () => {}, + enabledWhenOffline: false, }; const FormAlertWithSubmitButton = props => ( @@ -51,12 +55,14 @@ const FormAlertWithSubmitButton = props => ( message={props.message} onFixTheErrorsPressed={props.onFixTheErrorsPressed} > - {isOffline => (isOffline ? ( + {isOffline => ((isOffline && !props.enabledWhenOffline) ? (