From d743e91a09a1c5e7f3a55f45cada2dd9d55a16e2 Mon Sep 17 00:00:00 2001 From: Francois Laithier Date: Tue, 7 Mar 2023 10:37:05 -0800 Subject: [PATCH 1/3] Remove `RequestCallPage` and `actions/Inbox.js` --- .../Navigation/AppNavigator/AuthScreens.js | 6 - .../AppNavigator/ModalStackNavigators.js | 9 - src/libs/actions/Inbox.js | 82 ---- src/pages/RequestCallPage.js | 351 ------------------ 4 files changed, 448 deletions(-) delete mode 100644 src/libs/actions/Inbox.js delete mode 100644 src/pages/RequestCallPage.js diff --git a/src/libs/Navigation/AppNavigator/AuthScreens.js b/src/libs/Navigation/AppNavigator/AuthScreens.js index 6ee162b78ef1..ec8b31b5880c 100644 --- a/src/libs/Navigation/AppNavigator/AuthScreens.js +++ b/src/libs/Navigation/AppNavigator/AuthScreens.js @@ -303,12 +303,6 @@ class AuthScreens extends React.Component { component={ModalStackNavigators.AddPersonalBankAccountModalStackNavigator} listeners={modalScreenListeners} /> - { - const RequestCallPage = require('../../../pages/RequestCallPage').default; - return RequestCallPage; - }, - name: 'RequestCall_Root', -}]); - const WalletStatementStackNavigator = createModalStackNavigator([{ getComponent: () => { const WalletStatementPage = require('../../../pages/wallet/WalletStatementPage').default; @@ -542,6 +534,5 @@ export { EnablePaymentsStackNavigator, AddPersonalBankAccountModalStackNavigator, ReimbursementAccountModalStackNavigator, - RequestCallModalStackNavigator, WalletStatementStackNavigator, }; diff --git a/src/libs/actions/Inbox.js b/src/libs/actions/Inbox.js deleted file mode 100644 index b40bbbcb1fc6..000000000000 --- a/src/libs/actions/Inbox.js +++ /dev/null @@ -1,82 +0,0 @@ -import Onyx from 'react-native-onyx'; -import CONST from '../../CONST'; -import ONYXKEYS from '../../ONYXKEYS'; -import * as API from '../API'; - -/** - * Requests a call from Guides - * - * @param {Object} params - * @param {String} params.taskID - * @param {String} params.policyID - * @param {String} params.firstName - * @param {String} params.lastName - * @param {String} params.phoneNumber - * @param {String} params.phoneNumberExtension - */ -function requestCall({ - taskID, policyID, firstName, lastName, phoneNumber, phoneNumberExtension, -}) { - const optimisticData = [{ - onyxMethod: CONST.ONYX.METHOD.MERGE, - key: ONYXKEYS.FORMS.REQUEST_CALL_FORM, - value: { - isLoading: true, - }, - }]; - - const successData = [ - { - onyxMethod: CONST.ONYX.METHOD.MERGE, - key: ONYXKEYS.FORMS.REQUEST_CALL_FORM, - value: { - isLoading: false, - error: '', - didRequestCallSucceed: true, - }, - }, - ]; - - const failureData = [{ - onyxMethod: CONST.ONYX.METHOD.MERGE, - key: ONYXKEYS.FORMS.REQUEST_CALL_FORM, - value: { - isLoading: false, - }, - }]; - - API.write( - 'RequestCall', - { - policyID, - firstName, - lastName, - phoneNumber, - phoneNumberExtension, - taskID, - }, - {optimisticData, successData, failureData}, - ); -} - -function openRequestCallPage() { - // Reset the error message in case we had one set from a previous failed attempt at requesting a call. - const optimisticData = [{ - onyxMethod: CONST.ONYX.METHOD.MERGE, - key: ONYXKEYS.FORMS.REQUEST_CALL_FORM, - value: { - error: '', - }, - }]; - API.read('OpenRequestCallPage', {}, {optimisticData}); -} - -function clearDidRequestCallSucceed() { - Onyx.merge(ONYXKEYS.FORMS.REQUEST_CALL_FORM, {didRequestCallSucceed: false}); -} - -export { - openRequestCallPage, - requestCall, - clearDidRequestCallSucceed, -}; diff --git a/src/pages/RequestCallPage.js b/src/pages/RequestCallPage.js deleted file mode 100644 index 91b6d1e5e0e8..000000000000 --- a/src/pages/RequestCallPage.js +++ /dev/null @@ -1,351 +0,0 @@ -import React, {Component} from 'react'; -import {View} from 'react-native'; -import _ from 'underscore'; -import moment from 'moment'; -import {withOnyx} from 'react-native-onyx'; -import PropTypes from 'prop-types'; -import Str from 'expensify-common/lib/str'; -import HeaderWithCloseButton from '../components/HeaderWithCloseButton'; -import Navigation from '../libs/Navigation/Navigation'; -import styles from '../styles/styles'; -import colors from '../styles/colors'; -import ScreenWrapper from '../components/ScreenWrapper'; -import withLocalize, {withLocalizePropTypes} from '../components/withLocalize'; -import ONYXKEYS from '../ONYXKEYS'; -import compose from '../libs/compose'; -import Icon from '../components/Icon'; -import CONST from '../CONST'; -import * as Inbox from '../libs/actions/Inbox'; -import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsPropTypes, withCurrentUserPersonalDetailsDefaultProps} from '../components/withCurrentUserPersonalDetails'; -import TextInput from '../components/TextInput'; -import Text from '../components/Text'; -import Section from '../components/Section'; -import * as Illustrations from '../components/Icon/Illustrations'; -import * as Expensicons from '../components/Icon/Expensicons'; -import * as LoginUtils from '../libs/LoginUtils'; -import * as ValidationUtils from '../libs/ValidationUtils'; -import * as PersonalDetails from '../libs/actions/PersonalDetails'; -import * as User from '../libs/actions/User'; -import {withNetwork} from '../components/OnyxProvider'; -import networkPropTypes from '../components/networkPropTypes'; -import Form from '../components/Form'; -import ConfirmationPage from '../components/ConfirmationPage'; - -const propTypes = { - ...withLocalizePropTypes, - ...withCurrentUserPersonalDetailsPropTypes, - - /** Login list for the user that is signed in */ - loginList: PropTypes.shape({ - /** Phone/Emails associated with user */ - partnerUserID: PropTypes.string, - }), - - /** The policies which the user has access to */ - policies: PropTypes.shape({ - /** ID of the policy */ - policyID: PropTypes.string, - - /** The type of the policy */ - type: PropTypes.string, - }).isRequired, - - /** Route object from navigation */ - route: PropTypes.shape({ - params: PropTypes.shape({ - /** The task ID to request the call for */ - taskID: PropTypes.string, - }), - }).isRequired, - - /** Used to track state for the request call form */ - requestCallForm: PropTypes.shape({ - isLoading: PropTypes.bool, - - /** Error message to display from Server */ - error: PropTypes.string, - - /** If true, we will show a confirmation screen to the user */ - didRequestCallSucceed: PropTypes.bool, - }), - - /** The number of minutes the user has to wait for an inbox call */ - inboxCallUserWaitTime: PropTypes.number, - - /** The policyID of the last workspace whose settings the user accessed */ - lastAccessedWorkspacePolicyID: PropTypes.string, - - /** The NVP describing a user's block status */ - blockedFromConcierge: PropTypes.shape({ - /** The date that the user will be unblocked */ - expiresAt: PropTypes.string, - }), - - /** Information about the network from Onyx */ - network: networkPropTypes.isRequired, -}; - -const defaultProps = { - requestCallForm: { - isLoading: false, - }, - inboxCallUserWaitTime: null, - lastAccessedWorkspacePolicyID: '', - blockedFromConcierge: {}, - loginList: {}, - ...withCurrentUserPersonalDetailsDefaultProps, -}; - -class RequestCallPage extends Component { - constructor(props) { - super(props); - - this.onSubmit = this.onSubmit.bind(this); - this.getPhoneNumber = this.getPhoneNumber.bind(this); - this.validate = this.validate.bind(this); - - Inbox.clearDidRequestCallSucceed(); - } - - componentDidMount() { - this.fetchData(); - } - - componentDidUpdate(prevProps) { - if (!prevProps.network.isOffline || this.props.network.isOffline) { - return; - } - - this.fetchData(); - } - - componentWillUnmount() { - Inbox.clearDidRequestCallSucceed(); - } - - /** - * @param {Object} values - form input values passed by the Form component - */ - onSubmit(values) { - if (User.isBlockedFromConcierge(this.props.blockedFromConcierge)) { - return; - } - - const policyForCall = _.find(this.props.policies, (policy) => { - if (!policy) { - return; - } - - if (this.props.lastAccessedWorkspacePolicyID) { - return policy.id === this.props.lastAccessedWorkspacePolicyID; - } - - return policy.type === CONST.POLICY.TYPE.PERSONAL; - }); - - Inbox.requestCall({ - taskID: this.props.route.params.taskID, - policyID: policyForCall.id, - firstName: values.firstName, - lastName: values.lastName, - phoneNumber: LoginUtils.getPhoneNumberWithoutSpecialChars(values.phoneNumber), - phoneNumberExtension: values.phoneNumberExtension, - }); - } - - /** - * Gets the user's phone number from their secondary logins. - * Returns empty string if it doesn't exist. - * - * @returns {String} - */ - getPhoneNumber() { - const secondaryLogin = _.find(_.values(this.props.loginList), login => Str.isSMSLogin(login.partnerUserID)); - return secondaryLogin ? Str.removeSMSDomain(secondaryLogin.partnerUserID) : ''; - } - - getWaitTimeMessageKey(minutes) { - if (minutes == null) { - return 'requestCallPage.waitTime.calculating'; - } - - if (minutes > 300) { - // The wait time is longer than 5 hours, so just say that. - return 'requestCallPage.waitTime.fiveHoursPlus'; - } - - if (minutes > 60) { - // The wait time is between 1 and 5 hours, so lets convert to hours and minutes. - return 'requestCallPage.waitTime.hoursAndMinutes'; - } - - // The wait time is less than an hour so just give minutes. - return 'requestCallPage.waitTime.minutes'; - } - - getWaitTimeMessage() { - let waitTimeKey = 'requestCallPage.waitTime.weekend'; - if (!this.isWeekend()) { - waitTimeKey = this.getWaitTimeMessageKey(this.props.inboxCallUserWaitTime); - } - return `${this.props.translate(waitTimeKey, {minutes: this.props.inboxCallUserWaitTime})} ${this.props.translate('requestCallPage.waitTime.guides')}`; - } - - isWeekend() { - return moment().day() === 0 || moment().day() === 6; - } - - fetchData() { - // If it is the weekend don't check the wait time - if (this.isWeekend()) { - return; - } - - Inbox.openRequestCallPage(); - } - - /** - * @param {Object} values - form input values passed by the Form component - * @returns {Boolean} - */ - validate(values) { - const errors = {}; - - if (_.isEmpty(values.firstName.trim())) { - errors.firstName = this.props.translate('requestCallPage.error.firstName'); - } - - if (_.isEmpty(values.lastName.trim())) { - errors.lastName = this.props.translate('requestCallPage.error.lastName'); - } - - const phoneNumber = LoginUtils.getPhoneNumberWithoutSpecialChars(values.phoneNumber); - if (_.isEmpty(values.phoneNumber.trim()) || !Str.isValidPhone(phoneNumber)) { - errors.phoneNumber = this.props.translate('common.error.phoneNumber'); - } - - if (!_.isEmpty(values.phoneNumberExtension) && !ValidationUtils.isPositiveInteger(values.phoneNumberExtension)) { - errors.phoneNumberExtension = this.props.translate('requestCallPage.error.phoneNumberExtension'); - } - - return errors; - } - - render() { - const {firstName, lastName} = PersonalDetails.extractFirstAndLastNameFromAvailableDetails(this.props.currentUserPersonalDetails); - - return ( - - Navigation.goBack()} - onCloseButtonPress={() => Navigation.dismissModal(true)} - /> - {this.props.requestCallForm.didRequestCallSucceed - ? ( - - ) : ( -
-
- - {this.props.translate('requestCallPage.description')} - -
- - - - - {User.isBlockedFromConcierge(this.props.blockedFromConcierge) ? ( - - - {this.props.translate('requestCallPage.blockedFromConcierge')} - - ) - : {this.getWaitTimeMessage()}} - - )} -
- ); - } -} - -RequestCallPage.propTypes = propTypes; -RequestCallPage.defaultProps = defaultProps; - -export default compose( - withLocalize, - withNetwork(), - withCurrentUserPersonalDetails, - withOnyx({ - loginList: { - key: ONYXKEYS.LOGIN_LIST, - }, - policies: { - key: ONYXKEYS.COLLECTION.POLICY, - }, - requestCallForm: { - key: ONYXKEYS.FORMS.REQUEST_CALL_FORM, - initWithStoredValues: false, - }, - inboxCallUserWaitTime: { - key: ONYXKEYS.INBOX_CALL_USER_WAIT_TIME, - initWithStoredValues: false, - }, - lastAccessedWorkspacePolicyID: { - key: ONYXKEYS.LAST_ACCESSED_WORKSPACE_POLICY_ID, - }, - blockedFromConcierge: { - key: ONYXKEYS.NVP_BLOCKED_FROM_CONCIERGE, - }, - }), -)(RequestCallPage); From 28882a61c6f3e77d6475fef19e384e88585c96aa Mon Sep 17 00:00:00 2001 From: Francois Laithier Date: Tue, 7 Mar 2023 10:42:30 -0800 Subject: [PATCH 2/3] Remove remaining unused code --- src/ONYXKEYS.js | 4 ---- src/ROUTES.js | 2 -- src/languages/en.js | 29 ---------------------------- src/languages/es.js | 29 ---------------------------- src/libs/Navigation/linkingConfig.js | 5 ----- 5 files changed, 69 deletions(-) diff --git a/src/ONYXKEYS.js b/src/ONYXKEYS.js index 9cb0d62731d1..42a4a2d651be 100755 --- a/src/ONYXKEYS.js +++ b/src/ONYXKEYS.js @@ -161,9 +161,6 @@ export default { // Set when we are loading payment methods IS_LOADING_PAYMENT_METHODS: 'isLoadingPaymentMethods', - // The number of minutes a user has to wait for a call. - INBOX_CALL_USER_WAIT_TIME: 'inboxCallUserWaitTime', - // Is report data loading? IS_LOADING_REPORT_DATA: 'isLoadingReportData', @@ -179,7 +176,6 @@ export default { // List of Form ids FORMS: { ADD_DEBIT_CARD_FORM: 'addDebitCardForm', - REQUEST_CALL_FORM: 'requestCallForm', REIMBURSEMENT_ACCOUNT_FORM: 'reimbursementAccount', WORKSPACE_SETTINGS_FORM: 'workspaceSettingsForm', CLOSE_ACCOUNT_FORM: 'closeAccount', diff --git a/src/ROUTES.js b/src/ROUTES.js index 65add35fbc58..ab7fef023204 100644 --- a/src/ROUTES.js +++ b/src/ROUTES.js @@ -131,8 +131,6 @@ export default { getWorkspaceInvoicesRoute: policyID => `workspace/${policyID}/invoices`, getWorkspaceTravelRoute: policyID => `workspace/${policyID}/travel`, getWorkspaceMembersRoute: policyID => `workspace/${policyID}/members`, - getRequestCallRoute: taskID => `request-call/${taskID}`, - REQUEST_CALL: 'request-call/:taskID', /** * @param {String} route diff --git a/src/languages/en.js b/src/languages/en.js index 0e5afed9a424..12cd89382c15 100755 --- a/src/languages/en.js +++ b/src/languages/en.js @@ -1063,35 +1063,6 @@ export default { questionMarkButtonTooltip: 'Get assistance from our team', exploreHelpDocs: 'Explore help docs', }, - requestCallPage: { - title: 'Request a call', - subtitle: 'Need help, or a demo?', - description: 'Our team is ready to help each step of the way. Enter your name and phone number, and we\'ll give you a call back ASAP.*', - phoneNumberExtension: 'Extension (Optional)', - callMe: 'Call me', - growlMessageOnSave: 'Call requested.', - callButton: 'Call', - callButtonTooltip: 'Get live help from our team', - blockedFromConcierge: 'Due to previous interactions with our staff, a call cannot be scheduled at this time.', - waitTime: { - calculating: 'Calculating wait time...', - fiveHoursPlus: 'The current wait time is longer than 5 hours.', - hoursAndMinutes: ({minutes}) => `The current wait time is ${Math.floor(minutes / 60)} hours and ${minutes % 60} minutes. `, - minutes: ({minutes}) => `The current wait time is ${minutes} minutes. `, - weekend: 'We have limited availability on the weekends. We\'ll give you a call back as soon as we can. ', - guides: 'Please note that our Guides are typically available from Sunday at 5pm CT to Friday at 5pm CT.', - }, - error: { - phoneNumberExtension: 'Please enter a valid phone extension number', - firstName: 'Please provide your first name', - lastName: 'Please provide your last name', - }, - }, - requestCallConfirmationScreen: { - callRequested: 'Call successfully requested!', - allSet: 'You’re all set. You will be receiving a call from us soon.', - gotIt: 'Got it', - }, emojiPicker: { skinTonePickerLabel: 'Change default skin tone', headers: { diff --git a/src/languages/es.js b/src/languages/es.js index f282242cecac..e4ef7402cbbe 100644 --- a/src/languages/es.js +++ b/src/languages/es.js @@ -1065,35 +1065,6 @@ export default { questionMarkButtonTooltip: 'Obtén ayuda de nuestro equipo', exploreHelpDocs: 'Explorar la documentación de ayuda', }, - requestCallPage: { - title: 'Llámame por teléfono', - subtitle: '¿Necesitas ayuda o una demostración?', - description: 'Nuestro equipo está listo para ayudarte en cada paso. Ingresa tu nombre y número de teléfono y te llamaremos lo antes posible.*', - phoneNumberExtension: 'Extensión (Opcional)', - callMe: 'Llámame', - growlMessageOnSave: 'Llamada solicitada.', - callButton: 'Llamar', - callButtonTooltip: 'Recibe ayuda telefónica de nuestro equipo', - blockedFromConcierge: 'Debido a sus interacciones pasadas con nuestro equipo, la llamada no puede ser agendada en este momento.', - waitTime: { - calculating: 'Calculando el tiempo de espera...', - fiveHoursPlus: 'El tiempo de espera actual es superior a 5 horas.', - hoursAndMinutes: ({minutes}) => `El tiempo de espera actual es de ${Math.floor(minutes / 60)} horas y ${minutes % 60} minutos. `, - minutes: ({minutes}) => `El tiempo de espera actual es de ${minutes} minutos. `, - weekend: 'Tenemos disponibilidad limitada los fines de semana. Te devolveremos la llamada tan pronto como podamos.', - guides: 'Tenga en cuenta que nuestras guías suelen estar disponibles desde el domingo a las 5pm CT hasta el viernes a las 5pm CT.', - }, - error: { - phoneNumberExtension: 'Por favor, introduce una extensión telefónica válida', - firstName: 'Por favor, ingresa tu nombre', - lastName: 'Por favor, ingresa tus apellidos', - }, - }, - requestCallConfirmationScreen: { - callRequested: '¡Llamada solicitada con éxito!', - allSet: '¡Todo listo! Pronto recibirás una llamada nuestra.', - gotIt: 'Entendido', - }, emojiPicker: { skinTonePickerLabel: 'Elige el tono de piel por defecto', headers: { diff --git a/src/libs/Navigation/linkingConfig.js b/src/libs/Navigation/linkingConfig.js index 80e043c1b40d..f4d038c7ade0 100644 --- a/src/libs/Navigation/linkingConfig.js +++ b/src/libs/Navigation/linkingConfig.js @@ -260,11 +260,6 @@ export default { EnablePayments_Root: ROUTES.ENABLE_PAYMENTS, }, }, - RequestCall: { - screens: { - RequestCall_Root: ROUTES.REQUEST_CALL, - }, - }, Wallet_Statement: { screens: { WalletStatement_Root: ROUTES.WALLET_STATEMENT_WITH_DATE, From e678132cb4e77250b18f1fb60e570e19184ed207 Mon Sep 17 00:00:00 2001 From: Francois Laithier Date: Tue, 7 Mar 2023 11:52:39 -0800 Subject: [PATCH 3/3] Remove `isPositiveInteger` --- src/libs/ValidationUtils.js | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/libs/ValidationUtils.js b/src/libs/ValidationUtils.js index 1570f072c9e3..f2e35941edc4 100644 --- a/src/libs/ValidationUtils.js +++ b/src/libs/ValidationUtils.js @@ -317,14 +317,6 @@ function isValidTwoFactorCode(code) { return Boolean(code.match(CONST.REGEX.CODE_2FA)); } -/** - * @param {String} input - * @returns {Boolean} - */ -function isPositiveInteger(input) { - return CONST.REGEX.POSITIVE_INTEGER.test(input); -} - /** * Checks whether a value is a numeric string including `(`, `)`, `-` and optional leading `+` * @param {String} input @@ -446,7 +438,6 @@ export { validateIdentity, isValidPassword, isValidTwoFactorCode, - isPositiveInteger, isNumericWithSpecialChars, isValidPaypalUsername, isValidRoutingNumber,