From 6c6ccad77603715868e17dcb43c61b643c75472f Mon Sep 17 00:00:00 2001 From: Francois Laithier Date: Tue, 7 Dec 2021 20:09:37 -0800 Subject: [PATCH 1/6] Show a modal to prompt user to join GuidesPlus screen share --- src/Expensify.js | 29 +++++++++++++++++++++++++++++ src/ONYXKEYS.js | 5 ++++- src/libs/actions/User.js | 10 ++++++++++ 3 files changed, 43 insertions(+), 1 deletion(-) diff --git a/src/Expensify.js b/src/Expensify.js index 506fb2f16637..dffd4d9d0fcc 100644 --- a/src/Expensify.js +++ b/src/Expensify.js @@ -18,6 +18,8 @@ import GrowlNotification from './components/GrowlNotification'; import * as Growl from './libs/Growl'; import StartupTimer from './libs/StartupTimer'; import Log from './libs/Log'; +import ConfirmModal from './components/ConfirmModal'; +import {openOldDotLink} from './libs/actions/Link'; Onyx.registerLogger(({level, message}) => { if (level === 'alert') { @@ -49,6 +51,12 @@ const propTypes = { /** Tells us if the sidebar has rendered */ isSidebarLoaded: PropTypes.bool, + + /** Information about a screen share call requested by a GuidesPlus agent */ + screenShareRequested: PropTypes.objectOf(PropTypes.shape({ + accessToken: PropTypes.string, + roomName: PropTypes.string, + })), }; const defaultProps = { @@ -59,6 +67,7 @@ const defaultProps = { updateAvailable: false, initialReportDataLoaded: false, isSidebarLoaded: false, + screenShareRequested: null, }; class Expensify extends PureComponent { @@ -171,6 +180,23 @@ class Expensify extends PureComponent { {/* We include the modal for showing a new update at the top level so the option is always present. */} {this.props.updateAvailable ? : null} + {this.props.screenShareRequested ? ( + { + Onyx.set(ONYXKEYS.SCREEN_SHARE_REQUEST, null); + openOldDotLink(`inbox?action=screenShare&accessToken=${this.props.screenShareRequested.accessToken}&name=${this.props.screenShareRequested.roomName}`); + }} + onCancel={() => { + Onyx.set(ONYXKEYS.SCREEN_SHARE_REQUEST, null); + }} + prompt="Expensify is inviting you to screen share" + confirmText="Join" + cancelText="Decline" + isVisible + /> + ) : null} ); } @@ -192,4 +218,7 @@ export default withOnyx({ isSidebarLoaded: { key: ONYXKEYS.IS_SIDEBAR_LOADED, }, + screenShareRequested: { + key: ONYXKEYS.SCREEN_SHARE_REQUEST, + }, })(Expensify); diff --git a/src/ONYXKEYS.js b/src/ONYXKEYS.js index 928d3b3f5eb2..d92e68caa638 100755 --- a/src/ONYXKEYS.js +++ b/src/ONYXKEYS.js @@ -58,9 +58,12 @@ export default { // select a currency based on the list CURRENCY_LIST: 'currencyList', - // Indicates whether an update is available and ready to beinstalled. + // Indicates whether an update is available and ready to be installed. UPDATE_AVAILABLE: 'updateAvailable', + // Indicates that a request to join a screen share with a GuidesPlus agent was received + SCREEN_SHARE_REQUEST: 'screenShareRequest', + // Saves the current country code which is displayed when the user types a phone number without // an international code COUNTRY_CODE: 'countryCode', diff --git a/src/libs/actions/User.js b/src/libs/actions/User.js index dc61916e877f..7270d4317d8b 100644 --- a/src/libs/actions/User.js +++ b/src/libs/actions/User.js @@ -14,6 +14,7 @@ import Log from '../Log'; import NetworkConnection from '../NetworkConnection'; import NameValuePair from './NameValuePair'; import getSkinToneEmojiFromIndex from '../../pages/home/report/EmojiPickerMenu/getSkinToneEmojiFromIndex'; +import {openOldDotLink} from './Link'; let sessionAuthToken = ''; let sessionEmail = ''; @@ -279,6 +280,15 @@ function subscribeToUserEvents() { {error, pusherChannelName, eventName: Pusher.TYPE.PREFERRED_LOCALE}, ); }); + + // Subscribe to screen share requests sent by GuidesPlus agents + // TODO use const for push notification type + Pusher.subscribe(pusherChannelName, 'screenshareRequest', (pushJSON) => { + Onyx.merge(ONYXKEYS.SCREEN_SHARE_REQUEST, pushJSON); + }, false, + () => { + NetworkConnection.triggerReconnectionCallbacks('pusher re-subscribed to private user channel'); + }); } /** From 91a99169c557193cf6b4914739c36fe211550740 Mon Sep 17 00:00:00 2001 From: Francois Laithier Date: Wed, 8 Dec 2021 13:58:35 -0800 Subject: [PATCH 2/6] Finalize screen share request modal - Move actions to libs/actions/User - Add translations --- src/Expensify.js | 63 ++++++++++++++++++++-------------------- src/languages/en.js | 6 ++++ src/languages/es.js | 6 ++++ src/libs/actions/User.js | 21 +++++++++++++- 4 files changed, 64 insertions(+), 32 deletions(-) diff --git a/src/Expensify.js b/src/Expensify.js index dffd4d9d0fcc..3b849b9ab0c4 100644 --- a/src/Expensify.js +++ b/src/Expensify.js @@ -19,7 +19,9 @@ import * as Growl from './libs/Growl'; import StartupTimer from './libs/StartupTimer'; import Log from './libs/Log'; import ConfirmModal from './components/ConfirmModal'; -import {openOldDotLink} from './libs/actions/Link'; +import compose from './libs/compose'; +import withLocalize, {withLocalizePropTypes} from './components/withLocalize'; +import * as User from './libs/actions/User'; Onyx.registerLogger(({level, message}) => { if (level === 'alert') { @@ -57,6 +59,8 @@ const propTypes = { accessToken: PropTypes.string, roomName: PropTypes.string, })), + + ...withLocalizePropTypes, }; const defaultProps = { @@ -182,18 +186,12 @@ class Expensify extends PureComponent { {this.props.screenShareRequested ? ( { - Onyx.set(ONYXKEYS.SCREEN_SHARE_REQUEST, null); - openOldDotLink(`inbox?action=screenShare&accessToken=${this.props.screenShareRequested.accessToken}&name=${this.props.screenShareRequested.roomName}`); - }} - onCancel={() => { - Onyx.set(ONYXKEYS.SCREEN_SHARE_REQUEST, null); - }} - prompt="Expensify is inviting you to screen share" - confirmText="Join" - cancelText="Decline" + title={this.props.translate('guides.screenShare')} + onConfirm={() => User.joinScreenShare(this.props.screenShareRequested.accessToken, this.props.screenShareRequested.roomName)} + onCancel={User.clearScreenShareRequest} + prompt={this.props.translate('guides.screenShareRequest')} + confirmText={this.props.translate('common.join')} + cancelText={this.props.translate('common.decline')} isVisible /> ) : null} @@ -204,21 +202,24 @@ class Expensify extends PureComponent { Expensify.propTypes = propTypes; Expensify.defaultProps = defaultProps; -export default withOnyx({ - session: { - key: ONYXKEYS.SESSION, - }, - updateAvailable: { - key: ONYXKEYS.UPDATE_AVAILABLE, - initWithStoredValues: false, - }, - initialReportDataLoaded: { - key: ONYXKEYS.INITIAL_REPORT_DATA_LOADED, - }, - isSidebarLoaded: { - key: ONYXKEYS.IS_SIDEBAR_LOADED, - }, - screenShareRequested: { - key: ONYXKEYS.SCREEN_SHARE_REQUEST, - }, -})(Expensify); +export default compose( + withLocalize, + withOnyx({ + session: { + key: ONYXKEYS.SESSION, + }, + updateAvailable: { + key: ONYXKEYS.UPDATE_AVAILABLE, + initWithStoredValues: false, + }, + initialReportDataLoaded: { + key: ONYXKEYS.INITIAL_REPORT_DATA_LOADED, + }, + isSidebarLoaded: { + key: ONYXKEYS.IS_SIDEBAR_LOADED, + }, + screenShareRequested: { + key: ONYXKEYS.SCREEN_SHARE_REQUEST, + }, + }), +)(Expensify); diff --git a/src/languages/en.js b/src/languages/en.js index 23c5029b2dab..9e0d0712f929 100755 --- a/src/languages/en.js +++ b/src/languages/en.js @@ -89,6 +89,8 @@ export default { more: 'More', debitCard: 'Debit card', payPalMe: 'PayPal.me', + join: 'Join', + decline: 'Decline', }, attachmentPicker: { cameraPermissionRequired: 'Camera permission required', @@ -803,4 +805,8 @@ export default { newGroup: 'New group screen', }, }, + guides: { + screenShare: 'Screen share', + screenShareRequest: 'Expensify is inviting you to a screen share', + }, }; diff --git a/src/languages/es.js b/src/languages/es.js index 3ce7f2a9bd35..1b317c411d63 100644 --- a/src/languages/es.js +++ b/src/languages/es.js @@ -89,6 +89,8 @@ export default { more: 'Más', debitCard: 'Tarjeta de débito', payPalMe: 'PayPal.me', + join: 'Join', + decline: 'Decline', }, attachmentPicker: { cameraPermissionRequired: 'Se necesita permiso para usar la cámara', @@ -805,4 +807,8 @@ export default { newGroup: 'Nueva pantalla de grupo', }, }, + guides: { + screenShare: 'Screen share', + screenShareRequest: 'Expensify is inviting you to a screen share', + }, }; diff --git a/src/libs/actions/User.js b/src/libs/actions/User.js index 7270d4317d8b..4d9c57994495 100644 --- a/src/libs/actions/User.js +++ b/src/libs/actions/User.js @@ -14,7 +14,7 @@ import Log from '../Log'; import NetworkConnection from '../NetworkConnection'; import NameValuePair from './NameValuePair'; import getSkinToneEmojiFromIndex from '../../pages/home/report/EmojiPickerMenu/getSkinToneEmojiFromIndex'; -import {openOldDotLink} from './Link'; +import * as Link from './Link'; let sessionAuthToken = ''; let sessionEmail = ''; @@ -351,6 +351,23 @@ function clearUserErrorMessage() { Onyx.merge(ONYXKEYS.USER, {error: ''}); } +/** + * Clear the data about a screen share request from Onyx. + */ +function clearScreenShareRequest() { + Onyx.set(ONYXKEYS.SCREEN_SHARE_REQUEST, null); +} + +/** + * Open an OldDot tab linking to a screen share request. + * @param {String} accessToken Access token required to join a screen share room, generated by the backend + * @param {String} roomName Name of the screen share room to join + */ +function joinScreenShare(accessToken, roomName) { + Link.openOldDotLink(`inbox?action=screenShare&accessToken=${accessToken}&name=${roomName}`); + clearScreenShareRequest(); +} + export { changePasswordAndNavigate, getBetas, @@ -367,4 +384,6 @@ export { clearUserErrorMessage, subscribeToExpensifyCardUpdates, setFrequentlyUsedEmojis, + joinScreenShare, + clearScreenShareRequest, }; From c5d9ffbb661da8dcb055637f5cc57d8570c780f8 Mon Sep 17 00:00:00 2001 From: Francois Laithier Date: Wed, 8 Dec 2021 14:01:47 -0800 Subject: [PATCH 3/6] Add Spanish translations --- src/languages/es.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/languages/es.js b/src/languages/es.js index 1b317c411d63..fdc82386146e 100644 --- a/src/languages/es.js +++ b/src/languages/es.js @@ -89,8 +89,8 @@ export default { more: 'Más', debitCard: 'Tarjeta de débito', payPalMe: 'PayPal.me', - join: 'Join', - decline: 'Decline', + join: 'Unirse', + decline: 'Declinar', }, attachmentPicker: { cameraPermissionRequired: 'Se necesita permiso para usar la cámara', @@ -808,7 +808,7 @@ export default { }, }, guides: { - screenShare: 'Screen share', - screenShareRequest: 'Expensify is inviting you to a screen share', + screenShare: 'Compartir pantalla', + screenShareRequest: 'Expensify te está invitando a un compartimiento de pantalla', }, }; From 4edb857a9253c196134ea90d414b756ce44e84f0 Mon Sep 17 00:00:00 2001 From: Francois Laithier Date: Wed, 8 Dec 2021 15:04:09 -0800 Subject: [PATCH 4/6] Add missing const for pusher notification type --- src/libs/Pusher/EventType.js | 1 + src/libs/actions/User.js | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libs/Pusher/EventType.js b/src/libs/Pusher/EventType.js index 76cb1b354c1d..b44a92310c40 100644 --- a/src/libs/Pusher/EventType.js +++ b/src/libs/Pusher/EventType.js @@ -8,4 +8,5 @@ export default { REPORT_TOGGLE_PINNED: 'reportTogglePinned', PREFERRED_LOCALE: 'preferredLocale', EXPENSIFY_CARD_UPDATE: 'expensifyCardUpdate', + SCREEN_SHARE_REQUEST: 'screenshareRequest', }; diff --git a/src/libs/actions/User.js b/src/libs/actions/User.js index 4d9c57994495..c87c0849b632 100644 --- a/src/libs/actions/User.js +++ b/src/libs/actions/User.js @@ -282,8 +282,7 @@ function subscribeToUserEvents() { }); // Subscribe to screen share requests sent by GuidesPlus agents - // TODO use const for push notification type - Pusher.subscribe(pusherChannelName, 'screenshareRequest', (pushJSON) => { + Pusher.subscribe(pusherChannelName, Pusher.TYPE.SCREEN_SHARE_REQUEST, (pushJSON) => { Onyx.merge(ONYXKEYS.SCREEN_SHARE_REQUEST, pushJSON); }, false, () => { From eb69a279ee2ea1ee848afff112faf6dfd70cab58 Mon Sep 17 00:00:00 2001 From: Francois Laithier Date: Thu, 9 Dec 2021 11:15:54 -0800 Subject: [PATCH 5/6] Update translations, add prop types definitions, rename prop --- src/Expensify.js | 14 +++++++++----- src/languages/en.js | 1 - src/languages/es.js | 5 ++--- src/pages/iou/IOUTransactions.js | 2 +- 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/Expensify.js b/src/Expensify.js index 3b849b9ab0c4..49465bb888db 100644 --- a/src/Expensify.js +++ b/src/Expensify.js @@ -55,8 +55,12 @@ const propTypes = { isSidebarLoaded: PropTypes.bool, /** Information about a screen share call requested by a GuidesPlus agent */ - screenShareRequested: PropTypes.objectOf(PropTypes.shape({ + screenShareRequest: PropTypes.objectOf(PropTypes.shape({ + + /** Access token required to join a screen share room, generated by the backend */ accessToken: PropTypes.string, + + /** Name of the screen share room to join */ roomName: PropTypes.string, })), @@ -71,7 +75,7 @@ const defaultProps = { updateAvailable: false, initialReportDataLoaded: false, isSidebarLoaded: false, - screenShareRequested: null, + screenShareRequest: null, }; class Expensify extends PureComponent { @@ -184,10 +188,10 @@ class Expensify extends PureComponent { {/* We include the modal for showing a new update at the top level so the option is always present. */} {this.props.updateAvailable ? : null} - {this.props.screenShareRequested ? ( + {this.props.screenShareRequest ? ( User.joinScreenShare(this.props.screenShareRequested.accessToken, this.props.screenShareRequested.roomName)} + onConfirm={() => User.joinScreenShare(this.props.screenShareRequest.accessToken, this.props.screenShareRequest.roomName)} onCancel={User.clearScreenShareRequest} prompt={this.props.translate('guides.screenShareRequest')} confirmText={this.props.translate('common.join')} @@ -218,7 +222,7 @@ export default compose( isSidebarLoaded: { key: ONYXKEYS.IS_SIDEBAR_LOADED, }, - screenShareRequested: { + screenShareRequest: { key: ONYXKEYS.SCREEN_SHARE_REQUEST, }, }), diff --git a/src/languages/en.js b/src/languages/en.js index 69713c0d4e88..6a55c2c58420 100755 --- a/src/languages/en.js +++ b/src/languages/en.js @@ -195,7 +195,6 @@ export default { viewDetails: 'View details', settleExpensify: 'Pay with Expensify', settleElsewhere: 'I\'ll settle up elsewhere', - decline: 'Decline', settlePaypalMe: 'Pay with PayPal.me', settleVenmo: 'Pay with Venmo', request: ({amount}) => `Request ${amount}`, diff --git a/src/languages/es.js b/src/languages/es.js index 7b2d3268ae2a..34984d92b850 100644 --- a/src/languages/es.js +++ b/src/languages/es.js @@ -91,7 +91,7 @@ export default { payPalMe: 'PayPal.me', bankAccount: 'Cuenta bancaria', join: 'Unirse', - decline: 'Declinar', + decline: 'Rechazar', }, attachmentPicker: { cameraPermissionRequired: 'Se necesita permiso para usar la cámara', @@ -195,7 +195,6 @@ export default { viewDetails: 'Ver detalles', settleExpensify: 'Pagar con Expensify', settleElsewhere: 'Voy a pagar de otra forma', - decline: 'Rechazar', settlePaypalMe: 'Pagar con PayPal.me', settleVenmo: 'Pagar con Venmo', request: ({amount}) => `Solicitar ${amount}`, @@ -811,6 +810,6 @@ export default { }, guides: { screenShare: 'Compartir pantalla', - screenShareRequest: 'Expensify te está invitando a un compartimiento de pantalla', + screenShareRequest: 'Expensify te está invitando a compartir la pantalla', }, }; diff --git a/src/pages/iou/IOUTransactions.js b/src/pages/iou/IOUTransactions.js index 00e87170d7a4..1532697fc1f3 100644 --- a/src/pages/iou/IOUTransactions.js +++ b/src/pages/iou/IOUTransactions.js @@ -92,7 +92,7 @@ class IOUTransactions extends Component { canBeRejected={canBeRejected} rejectButtonLabelText={isCurrentUserTransactionCreator ? this.props.translate('common.cancel') - : this.props.translate('iou.decline')} + : this.props.translate('common.decline')} /> ); })} From e11ff4d1c26f8b49639a362c3e6fb51d21c857ed Mon Sep 17 00:00:00 2001 From: Francois Laithier Date: Mon, 13 Dec 2021 15:36:28 -0800 Subject: [PATCH 6/6] Fix propTypes for `screenShareRequest` object --- src/Expensify.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Expensify.js b/src/Expensify.js index 49465bb888db..0644e294e131 100644 --- a/src/Expensify.js +++ b/src/Expensify.js @@ -55,14 +55,14 @@ const propTypes = { isSidebarLoaded: PropTypes.bool, /** Information about a screen share call requested by a GuidesPlus agent */ - screenShareRequest: PropTypes.objectOf(PropTypes.shape({ + screenShareRequest: PropTypes.shape({ /** Access token required to join a screen share room, generated by the backend */ accessToken: PropTypes.string, /** Name of the screen share room to join */ roomName: PropTypes.string, - })), + }), ...withLocalizePropTypes, };