From 3f4df08e9622fa2c535bd15d2d5e2577738d115c Mon Sep 17 00:00:00 2001 From: Bartosz Grajdek Date: Wed, 22 Nov 2023 13:08:28 +0100 Subject: [PATCH 001/931] Add reason interstatial --- src/ROUTES.ts | 4 + src/components/MoneyRequestHeader.js | 9 ++ .../AppNavigator/ModalStackNavigators.js | 1 + src/libs/Navigation/linkingConfig.js | 1 + src/pages/iou/HoldReasonPage.js | 114 ++++++++++++++++++ 5 files changed, 129 insertions(+) create mode 100644 src/pages/iou/HoldReasonPage.js diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 57d4eb8187ec..dd04b1844317 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -254,6 +254,10 @@ export default { route: ':iouType/new/category/:reportID?', getRoute: (iouType: string, reportID = '') => `${iouType}/new/category/${reportID}`, }, + MONEY_REQUEST_HOLD_REASON: { + route: ':iouType/edit/reason/:transactionID?', + getRoute: (iouType: string, transactionID: string) => `${iouType}/edit/reason/${transactionID}`, + }, MONEY_REQUEST_TAG: { route: ':iouType/new/tag/:reportID?', getRoute: (iouType: string, reportID = '') => `${iouType}/new/tag/${reportID}`, diff --git a/src/components/MoneyRequestHeader.js b/src/components/MoneyRequestHeader.js index 178163f6569f..82df425ee858 100644 --- a/src/components/MoneyRequestHeader.js +++ b/src/components/MoneyRequestHeader.js @@ -87,6 +87,10 @@ function MoneyRequestHeader({session, parentReport, report, parentReportAction, const canModifyRequest = isActionOwner && !isSettled && !isApproved && !ReportActionsUtils.isDeletedAction(parentReportAction); + const holdMoneyRequest = () => { + Navigation.navigate(ROUTES.MONEY_REQUEST_HOLD_REASON.getRoute(transaction.type, lodashGet(parentReportAction, 'originalMessage.IOUTransactionID'))) + }; + useEffect(() => { if (canModifyRequest) { return; @@ -103,6 +107,11 @@ function MoneyRequestHeader({session, parentReport, report, parentReportAction, onSelected: () => Navigation.navigate(ROUTES.EDIT_REQUEST.getRoute(report.reportID, CONST.EDIT_REQUEST_FIELD.RECEIPT)), }); } + threeDotsMenuItems.push({ + icon: Expensicons.Hourglass, + text: "Hold request", + onSelected: () => holdMoneyRequest(), + }); threeDotsMenuItems.push({ icon: Expensicons.Trashcan, text: translate('reportActionContextMenu.deleteAction', {action: parentReportAction}), diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators.js b/src/libs/Navigation/AppNavigator/ModalStackNavigators.js index a2f9bdd7a903..4f8d83dec3bd 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators.js +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators.js @@ -47,6 +47,7 @@ const MoneyRequestModalStackNavigator = createModalStackNavigator({ Money_Request_Date: () => require('../../../pages/iou/MoneyRequestDatePage').default, Money_Request_Description: () => require('../../../pages/iou/MoneyRequestDescriptionPage').default, Money_Request_Category: () => require('../../../pages/iou/MoneyRequestCategoryPage').default, + Money_Request_Hold_Reason: () => require('../../../pages/iou/HoldReasonPage').default, Money_Request_Tag: () => require('../../../pages/iou/MoneyRequestTagPage').default, Money_Request_Merchant: () => require('../../../pages/iou/MoneyRequestMerchantPage').default, IOU_Send_Add_Bank_Account: () => require('../../../pages/AddPersonalBankAccountPage').default, diff --git a/src/libs/Navigation/linkingConfig.js b/src/libs/Navigation/linkingConfig.js index 44473998ac62..77006ad1415d 100644 --- a/src/libs/Navigation/linkingConfig.js +++ b/src/libs/Navigation/linkingConfig.js @@ -366,6 +366,7 @@ export default { Money_Request_Currency: ROUTES.MONEY_REQUEST_CURRENCY.route, Money_Request_Description: ROUTES.MONEY_REQUEST_DESCRIPTION.route, Money_Request_Category: ROUTES.MONEY_REQUEST_CATEGORY.route, + Money_Request_Hold_Reason: ROUTES.MONEY_REQUEST_HOLD_REASON.route, Money_Request_Tag: ROUTES.MONEY_REQUEST_TAG.route, Money_Request_Merchant: ROUTES.MONEY_REQUEST_MERCHANT.route, Money_Request_Waypoint: ROUTES.MONEY_REQUEST_WAYPOINT.route, diff --git a/src/pages/iou/HoldReasonPage.js b/src/pages/iou/HoldReasonPage.js new file mode 100644 index 000000000000..c45d5fbb73ae --- /dev/null +++ b/src/pages/iou/HoldReasonPage.js @@ -0,0 +1,114 @@ +// import lodashGet from 'lodash/get'; +import PropTypes from 'prop-types'; +import React, {useCallback, useRef} from 'react'; +import {withOnyx} from 'react-native-onyx'; +import HeaderWithBackButton from '@components/HeaderWithBackButton'; +import ScreenWrapper from '@components/ScreenWrapper'; +import Text from '@components/Text'; +import useLocalize from '@hooks/useLocalize'; +import compose from '@libs/compose'; +import Navigation from '@libs/Navigation/Navigation'; +import useThemeStyles from '@styles/useThemeStyles'; +import * as IOU from '@userActions/IOU'; +import ONYXKEYS from '@src/ONYXKEYS'; +import Form from "@components/Form"; +import {View} from "react-native"; +import TextInput from "@components/TextInput"; +import CONST from "@src/CONST"; +import lodashGet from "lodash/get"; +import _ from "underscore"; +import * as API from '@libs/API'; + +const propTypes = { + /** Navigation route context info provided by react navigation */ + route: PropTypes.shape({ + /** Route specific parameters used on this screen via route :iouType/new/category/:reportID? */ + params: PropTypes.shape({ + /** The type of IOU report, i.e. bill, request, send */ + iouType: PropTypes.string, + + /** The report ID of the IOU */ + reportID: PropTypes.string, + }), + }).isRequired +}; + +function HoldReasonPage({route}) { + const styles = useThemeStyles(); + const {translate} = useLocalize(); + const reasonRef = useRef(); + + const transactionID = lodashGet(route, 'params.transactionID', ''); + // const iouType = lodashGet(route, 'params.iouType', ''); + + const navigateBack = () => { + Navigation.goBack(); + }; + + const onSubmit = (values) => { + // eslint-disable-next-line rulesdir/no-api-in-views + API.write('HoldRequest', { + transactionID, + comment: values.reason + }) + } + + const validate = useCallback((value) => { + const errors = {}; + + if (_.isEmpty(value.reason)) { + errors.reason = 'common.error.fieldRequired'; + } + + return errors; + }, []); + + return ( + + +
+ Explain why you're holding this request + + (reasonRef.current = e)} + autoFocus + /> + +
+
+ ); +} + +HoldReasonPage.displayName = 'MoneyRequestHoldReasonPage'; +HoldReasonPage.propTypes = propTypes; + +export default compose( + withOnyx({ + iou: { + key: ONYXKEYS.IOU, + }, + }), + // eslint-disable-next-line rulesdir/no-multiple-onyx-in-file + withOnyx({ + report: { + key: ({route, iou}) => { + const reportID = IOU.getIOUReportID(iou, route); + + return `${ONYXKEYS.COLLECTION.REPORT}${reportID}`; + }, + }, + }), +)(HoldReasonPage); From f4297cd218cb7860b606d93b53edbaf8e9a6edd5 Mon Sep 17 00:00:00 2001 From: Bartosz Grajdek Date: Thu, 23 Nov 2023 12:01:21 +0100 Subject: [PATCH 002/931] Hold banner --- assets/images/stopwatch.svg | 3 + src/components/Icon/Expensicons.ts | 2 + src/components/MoneyRequestHeader.js | 23 +++++--- .../ReportActionItem/MoneyRequestView.js | 1 + src/components/TextPill.tsx | 22 ++++++++ src/languages/en.ts | 11 ++++ src/languages/es.ts | 11 ++++ src/libs/ReportUtils.js | 12 ++++ src/libs/TransactionUtils.ts | 9 +++ src/pages/iou/HoldReasonPage.js | 55 ++++++++++--------- 10 files changed, 117 insertions(+), 32 deletions(-) create mode 100644 assets/images/stopwatch.svg create mode 100644 src/components/TextPill.tsx diff --git a/assets/images/stopwatch.svg b/assets/images/stopwatch.svg new file mode 100644 index 000000000000..d27d6b0b7c36 --- /dev/null +++ b/assets/images/stopwatch.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/components/Icon/Expensicons.ts b/src/components/Icon/Expensicons.ts index 3d4f0edb1656..f96ceb30f9c5 100644 --- a/src/components/Icon/Expensicons.ts +++ b/src/components/Icon/Expensicons.ts @@ -106,6 +106,7 @@ import Rotate from '@assets/images/rotate-image.svg'; import RotateLeft from '@assets/images/rotate-left.svg'; import Send from '@assets/images/send.svg'; import Shield from '@assets/images/shield.svg'; +import Stopwatch from '@assets/images/stopwatch.svg'; import AppleLogo from '@assets/images/signIn/apple-logo.svg'; import GoogleLogo from '@assets/images/signIn/google-logo.svg'; import Facebook from '@assets/images/social-facebook.svg'; @@ -240,6 +241,7 @@ export { RotateLeft, Send, Shield, + Stopwatch, Sync, Task, ThreeDots, diff --git a/src/components/MoneyRequestHeader.js b/src/components/MoneyRequestHeader.js index 82df425ee858..f55f93112365 100644 --- a/src/components/MoneyRequestHeader.js +++ b/src/components/MoneyRequestHeader.js @@ -3,6 +3,8 @@ import PropTypes from 'prop-types'; import React, {useCallback, useEffect, useState} from 'react'; import {View} from 'react-native'; import {withOnyx} from 'react-native-onyx'; +import Text from '@components/Text'; +import TextPill from '@components/TextPill'; import useLocalize from '@hooks/useLocalize'; import useWindowDimensions from '@hooks/useWindowDimensions'; import compose from '@libs/compose'; @@ -72,6 +74,7 @@ function MoneyRequestHeader({session, parentReport, report, parentReportAction, const moneyRequestReport = parentReport; const isSettled = ReportUtils.isSettled(moneyRequestReport.reportID); const isApproved = ReportUtils.isReportApproved(moneyRequestReport); + const isHold = true; const {isSmallScreenWidth, windowWidth} = useWindowDimensions(); // Only the requestor can take delete the request, admins can only edit it. @@ -87,8 +90,10 @@ function MoneyRequestHeader({session, parentReport, report, parentReportAction, const canModifyRequest = isActionOwner && !isSettled && !isApproved && !ReportActionsUtils.isDeletedAction(parentReportAction); + // console.log('MYTRANSACTION', transaction); + const holdMoneyRequest = () => { - Navigation.navigate(ROUTES.MONEY_REQUEST_HOLD_REASON.getRoute(transaction.type, lodashGet(parentReportAction, 'originalMessage.IOUTransactionID'))) + Navigation.navigate(ROUTES.MONEY_REQUEST_HOLD_REASON.getRoute(transaction.type, lodashGet(parentReportAction, 'originalMessage.IOUTransactionID'))); }; useEffect(() => { @@ -100,6 +105,11 @@ function MoneyRequestHeader({session, parentReport, report, parentReportAction, }, [canModifyRequest]); const threeDotsMenuItems = [HeaderUtils.getPinMenuItem(report)]; if (canModifyRequest) { + threeDotsMenuItems.push({ + icon: Expensicons.Stopwatch, + text: !isHold ? translate('iou.holdRequest') : translate('iou.unholdRequest'), + onSelected: () => holdMoneyRequest(), + }); if (!TransactionUtils.hasReceipt(transaction)) { threeDotsMenuItems.push({ icon: Expensicons.Receipt, @@ -107,11 +117,6 @@ function MoneyRequestHeader({session, parentReport, report, parentReportAction, onSelected: () => Navigation.navigate(ROUTES.EDIT_REQUEST.getRoute(report.reportID, CONST.EDIT_REQUEST_FIELD.RECEIPT)), }); } - threeDotsMenuItems.push({ - icon: Expensicons.Hourglass, - text: "Hold request", - onSelected: () => holdMoneyRequest(), - }); threeDotsMenuItems.push({ icon: Expensicons.Trashcan, text: translate('reportActionContextMenu.deleteAction', {action: parentReportAction}), @@ -123,7 +128,7 @@ function MoneyRequestHeader({session, parentReport, report, parentReportAction, <> )} + + {translate('iou.hold')} + {translate('iou.requestOnHold')} + {children}; +} + +TextPill.displayName = 'TextPill'; + +export default TextPill; diff --git a/src/languages/en.ts b/src/languages/en.ts index 4c6ea25eb2c8..5c9e2d7b27e3 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -599,6 +599,17 @@ export default { }, waitingOnEnabledWallet: ({submitterDisplayName}: WaitingOnBankAccountParams) => `Started settling up, payment is held until ${submitterDisplayName} enables their Wallet`, enableWallet: 'Enable Wallet', + hold: 'Hold', + holdRequest: 'Hold Request', + unholdRequest: 'Unhold Request', + explainHold: "Explain why you're holding this request.", + reason: 'Reason', + holdReasonRequired: 'A reason is required when holding.', + requestOnHold: 'This request was put on hold. Review the comments for next steps.', + confirmApprove: 'Confirm what to approve', + confirmApprovalAmount: 'Approve the entire report total or only the amount not on hold.', + confirmPay: 'Confirm what to pay', + confirmPayAmount: 'Pay all out-of-pocket spend or only the amount not on hold.', }, notificationPreferencesPage: { header: 'Notification preferences', diff --git a/src/languages/es.ts b/src/languages/es.ts index 85eab5c3f14d..90876a3fbc6d 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -593,6 +593,17 @@ export default { }, waitingOnEnabledWallet: ({submitterDisplayName}: WaitingOnBankAccountParams) => `Inició el pago, pero no se procesará hasta que ${submitterDisplayName} active su Billetera`, enableWallet: 'Habilitar Billetera', + hold: 'En espera', + holdRequest: 'Solicitud de retención', + unholdRequest: 'Solicitud de cancelación de retención', + explainHold: 'Explique por qué mantiene esta solicitud.', + reason: 'Razón', + holdReasonRequired: 'Se requiere una razón al sostener.', + requestOnHold: 'Esta solicitud quedó en suspenso. Revise los comentarios para los próximos pasos.', + confirmApprove: 'Confirmar qué aprobar', + confirmApprovalAmount: 'Aprobar el total del informe completo o solo el monto no retenido.', + confirmPay: 'Confirmar que pagar', + confirmPayAmount: 'Pague todos los gastos de bolsillo o solo el monto no retenido.', }, notificationPreferencesPage: { header: 'Preferencias de avisos', diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index db836549234d..ed3c6ad3e244 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -4315,6 +4315,18 @@ function shouldDisableWelcomeMessage(report, policy) { return isMoneyRequestReport(report) || isArchivedRoom(report) || !isChatRoom(report) || isChatThread(report) || !PolicyUtils.isPolicyAdmin(policy); } +/** + * Put money request on HOLD + * @param transactionID + * @param comment + */ +function putOnHold(transactionID, comment) { + API.write('HoldRequest', { + transactionID, // the money request being held + comment, // the reason given for the hold + }); +} + export { getReportParticipantsTitle, isReportMessageAttachment, diff --git a/src/libs/TransactionUtils.ts b/src/libs/TransactionUtils.ts index 00ce8c55dbd7..efa1fe84382c 100644 --- a/src/libs/TransactionUtils.ts +++ b/src/libs/TransactionUtils.ts @@ -450,6 +450,14 @@ function getRecentTransactions(transactions: Record, size = 2): .slice(0, size); } +/** + * Check if transaction is on hold + */ +function isOnHold(transaction: Transaction): boolean { + // TODO - add logic + return !!transaction; +} + export { buildOptimisticTransaction, getUpdatedTransaction, @@ -477,6 +485,7 @@ export { isExpensifyCardTransaction, isPending, isPosted, + isOnHold, getWaypoints, isAmountMissing, isMerchantMissing, diff --git a/src/pages/iou/HoldReasonPage.js b/src/pages/iou/HoldReasonPage.js index c45d5fbb73ae..449672ddc1ff 100644 --- a/src/pages/iou/HoldReasonPage.js +++ b/src/pages/iou/HoldReasonPage.js @@ -1,23 +1,22 @@ // import lodashGet from 'lodash/get'; import PropTypes from 'prop-types'; import React, {useCallback, useRef} from 'react'; +import {View} from 'react-native'; import {withOnyx} from 'react-native-onyx'; +import _ from 'underscore'; +import FormProvider from '@components/Form/FormProvider'; +import InputWrapper from '@components/Form/InputWrapper'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import ScreenWrapper from '@components/ScreenWrapper'; import Text from '@components/Text'; +import TextInput from '@components/TextInput'; import useLocalize from '@hooks/useLocalize'; import compose from '@libs/compose'; import Navigation from '@libs/Navigation/Navigation'; import useThemeStyles from '@styles/useThemeStyles'; import * as IOU from '@userActions/IOU'; +import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; -import Form from "@components/Form"; -import {View} from "react-native"; -import TextInput from "@components/TextInput"; -import CONST from "@src/CONST"; -import lodashGet from "lodash/get"; -import _ from "underscore"; -import * as API from '@libs/API'; const propTypes = { /** Navigation route context info provided by react navigation */ @@ -30,7 +29,7 @@ const propTypes = { /** The report ID of the IOU */ reportID: PropTypes.string, }), - }).isRequired + }).isRequired, }; function HoldReasonPage({route}) { @@ -38,7 +37,7 @@ function HoldReasonPage({route}) { const {translate} = useLocalize(); const reasonRef = useRef(); - const transactionID = lodashGet(route, 'params.transactionID', ''); + // const transactionID = lodashGet(route, 'params.transactionID', ''); // const iouType = lodashGet(route, 'params.iouType', ''); const navigateBack = () => { @@ -46,17 +45,15 @@ function HoldReasonPage({route}) { }; const onSubmit = (values) => { + // TODO - add a helper function for API call // eslint-disable-next-line rulesdir/no-api-in-views - API.write('HoldRequest', { - transactionID, - comment: values.reason - }) - } + console.log(values); + }; const validate = useCallback((value) => { const errors = {}; - if (_.isEmpty(value.reason)) { + if (_.isEmpty(value.comment)) { errors.reason = 'common.error.fieldRequired'; } @@ -70,24 +67,32 @@ function HoldReasonPage({route}) { testID={HoldReasonPage.displayName} > -
- Explain why you're holding this request + + {translate('iou.explainHold')} - (reasonRef.current = e)} autoFocus /> - +
); } From 317f5fc08df54b987c534aad6c4dbcf2e77c097e Mon Sep 17 00:00:00 2001 From: Bartosz Grajdek Date: Tue, 5 Dec 2023 16:47:44 +0100 Subject: [PATCH 003/931] Add new translations --- src/languages/en.ts | 2 ++ src/languages/es.ts | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/languages/en.ts b/src/languages/en.ts index 5c9e2d7b27e3..9b3dd9f1944f 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -610,6 +610,8 @@ export default { confirmApprovalAmount: 'Approve the entire report total or only the amount not on hold.', confirmPay: 'Confirm what to pay', confirmPayAmount: 'Pay all out-of-pocket spend or only the amount not on hold.', + payOnly: 'Pay only', + approveOnly: 'Approve only' }, notificationPreferencesPage: { header: 'Notification preferences', diff --git a/src/languages/es.ts b/src/languages/es.ts index 90876a3fbc6d..f112aeb8a5fc 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -604,6 +604,8 @@ export default { confirmApprovalAmount: 'Aprobar el total del informe completo o solo el monto no retenido.', confirmPay: 'Confirmar que pagar', confirmPayAmount: 'Pague todos los gastos de bolsillo o solo el monto no retenido.', + payOnly: 'Paga solo', + approveOnly: 'Aprobar sólo' }, notificationPreferencesPage: { header: 'Preferencias de avisos', From da7e0a69921289525d8e5398f2c9265d40341cbb Mon Sep 17 00:00:00 2001 From: Bartosz Grajdek Date: Tue, 5 Dec 2023 16:48:15 +0100 Subject: [PATCH 004/931] Change Header styles --- src/components/Header.tsx | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/components/Header.tsx b/src/components/Header.tsx index 46fe1a25c920..b48883e25175 100644 --- a/src/components/Header.tsx +++ b/src/components/Header.tsx @@ -1,5 +1,5 @@ import React, {ReactElement} from 'react'; -import {StyleProp, TextStyle, View} from 'react-native'; +import {StyleProp, TextStyle, View, ViewStyle} from 'react-native'; import useThemeStyles from '@styles/useThemeStyles'; import EnvironmentBadge from './EnvironmentBadge'; import Text from './Text'; @@ -16,12 +16,15 @@ type HeaderProps = { /** Additional text styles */ textStyles?: StyleProp; + + /** Additional text styles */ + containerStyles?: StyleProp; }; -function Header({title = '', subtitle = '', textStyles = [], shouldShowEnvironmentBadge = false}: HeaderProps) { +function Header({title = '', subtitle = '', textStyles = [], containerStyles = [], shouldShowEnvironmentBadge = false}: HeaderProps) { const styles = useThemeStyles(); return ( - + {typeof title === 'string' ? Boolean(title) && ( From d38c0f69f3f059809d0021d3bc66f004f9a8b6cc Mon Sep 17 00:00:00 2001 From: Bartosz Grajdek Date: Tue, 5 Dec 2023 17:15:59 +0100 Subject: [PATCH 005/931] Add full boolean to IOU requests --- src/libs/actions/IOU.js | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index 939a11dad511..54e47fce8705 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -2440,9 +2440,10 @@ function getSendMoneyParams(report, amount, currency, comment, paymentMethodType * @param {Object} iouReport * @param {Object} recipient * @param {String} paymentMethodType + * @param {Boolean} full * @returns {Object} */ -function getPayMoneyRequestParams(chatReport, iouReport, recipient, paymentMethodType) { +function getPayMoneyRequestParams(chatReport, iouReport, recipient, paymentMethodType, full) { const optimisticIOUReportAction = ReportUtils.buildOptimisticIOUReportAction( CONST.IOU.REPORT_ACTION_TYPE.PAY, -iouReport.total, @@ -2557,6 +2558,7 @@ function getPayMoneyRequestParams(chatReport, iouReport, recipient, paymentMetho chatReportID: chatReport.reportID, reportActionID: optimisticIOUReportAction.reportActionID, paymentMethodType, + full }, optimisticData, successData, @@ -2600,7 +2602,7 @@ function sendMoneyWithWallet(report, amount, currency, comment, managerID, recip Report.notifyNewAction(params.chatReportID, managerID); } -function approveMoneyRequest(expenseReport) { +function approveMoneyRequest(expenseReport, full) { const optimisticApprovedReportAction = ReportUtils.buildOptimisticApprovedReportAction(expenseReport.total, expenseReport.currency, expenseReport.reportID); const optimisticReportActionsData = { @@ -2650,7 +2652,7 @@ function approveMoneyRequest(expenseReport) { }, ]; - API.write('ApproveMoneyRequest', {reportID: expenseReport.reportID, approvedReportActionID: optimisticApprovedReportAction.reportActionID}, {optimisticData, successData, failureData}); + API.write('ApproveMoneyRequest', {reportID: expenseReport.reportID, approvedReportActionID: optimisticApprovedReportAction.reportActionID, full}, {optimisticData, successData, failureData}); } /** @@ -2730,11 +2732,11 @@ function submitReport(expenseReport) { * @param {String} paymentType * @param {Object} chatReport * @param {Object} iouReport - * @param {String} reimbursementBankAccountState + * @param {Boolean} full */ -function payMoneyRequest(paymentType, chatReport, iouReport) { +function payMoneyRequest(paymentType, chatReport, iouReport, full) { const recipient = {accountID: iouReport.ownerAccountID}; - const {params, optimisticData, successData, failureData} = getPayMoneyRequestParams(chatReport, iouReport, recipient, paymentType); + const {params, optimisticData, successData, failureData} = getPayMoneyRequestParams(chatReport, iouReport, recipient, paymentType, full); // For now we need to call the PayMoneyRequestWithWallet API since PayMoneyRequest was not updated to work with // Expensify Wallets. From 818a84187c1cf33d3be5e063cee4c50479b05e73 Mon Sep 17 00:00:00 2001 From: Bartosz Grajdek Date: Tue, 5 Dec 2023 17:16:21 +0100 Subject: [PATCH 006/931] Mock Report & Transaction Utils --- src/libs/ReportUtils.js | 19 +++++++++++++------ src/libs/TransactionUtils.ts | 3 +-- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index ed3c6ad3e244..bbed6796eea3 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -4317,14 +4317,19 @@ function shouldDisableWelcomeMessage(report, policy) { /** * Put money request on HOLD - * @param transactionID - * @param comment + * @param {string} transactionID + * @param {string} comment */ function putOnHold(transactionID, comment) { - API.write('HoldRequest', { - transactionID, // the money request being held - comment, // the reason given for the hold - }); + return; +} + +/** + * Check if Report has any held expenses + * @param {Object} report + */ +function hasHeldExpenses(report) { + return true; } export { @@ -4492,4 +4497,6 @@ export { getRoom, shouldDisableWelcomeMessage, canEditWriteCapability, + hasHeldExpenses, + putOnHold }; diff --git a/src/libs/TransactionUtils.ts b/src/libs/TransactionUtils.ts index efa1fe84382c..3df67742ea88 100644 --- a/src/libs/TransactionUtils.ts +++ b/src/libs/TransactionUtils.ts @@ -454,8 +454,7 @@ function getRecentTransactions(transactions: Record, size = 2): * Check if transaction is on hold */ function isOnHold(transaction: Transaction): boolean { - // TODO - add logic - return !!transaction; + return true; } export { From ed3fe5eca317c348752aa82a8c2676fbc1526bbb Mon Sep 17 00:00:00 2001 From: Bartosz Grajdek Date: Thu, 14 Dec 2023 10:15:46 +0100 Subject: [PATCH 007/931] Add Offline Support --- src/ROUTES.ts | 2 +- src/components/DecisionModal.js | 102 +++++++++++++++ src/components/Icon/Expensicons.ts | 2 +- src/components/MoneyReportHeader.js | 47 ++++++- src/components/MoneyRequestHeader.js | 30 +++-- src/components/ProcessMoneyRequestHoldMenu.js | 92 ++++++++++++++ src/languages/en.ts | 2 +- src/languages/es.ts | 2 +- src/libs/ReportUtils.js | 31 +++-- src/libs/TransactionUtils.ts | 5 +- src/libs/actions/IOU.js | 116 +++++++++++++++++- src/pages/iou/HoldReasonPage.js | 15 +-- src/types/onyx/Transaction.ts | 1 + 13 files changed, 408 insertions(+), 39 deletions(-) create mode 100644 src/components/DecisionModal.js create mode 100644 src/components/ProcessMoneyRequestHoldMenu.js diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 23da11673499..ad606cebad3c 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -272,7 +272,7 @@ export default { }, MONEY_REQUEST_HOLD_REASON: { route: ':iouType/edit/reason/:transactionID?', - getRoute: (iouType: string, transactionID: string) => `${iouType}/edit/reason/${transactionID}`, + getRoute: (iouType: string, transactionID: string, reportID: string, backTo: string) => `${iouType}/edit/reason/${transactionID}?reportID=${reportID}&backTo=${backTo}`, }, MONEY_REQUEST_TAG: { route: ':iouType/new/tag/:reportID?', diff --git a/src/components/DecisionModal.js b/src/components/DecisionModal.js new file mode 100644 index 000000000000..52c1974e6af9 --- /dev/null +++ b/src/components/DecisionModal.js @@ -0,0 +1,102 @@ +import PropTypes from 'prop-types'; +import React from 'react'; +import {View} from 'react-native'; +import Button from '@components/Button'; +import Header from '@components/Header'; +import Icon from '@components/Icon'; +import * as Expensicons from '@components/Icon/Expensicons'; +import Modal from '@components/Modal'; +import PressableWithoutFeedback from '@components/Pressable/PressableWithoutFeedback'; +import Text from '@components/Text'; +import Tooltip from '@components/Tooltip'; +import useLocalize from '@hooks/useLocalize'; +import useThemeStyles from '@styles/useThemeStyles'; +import CONST from '@src/CONST'; + +const propTypes = { + /** Title describing purpose of modal */ + title: PropTypes.string.isRequired, + + /** Modal subtitle/description */ + prompt: PropTypes.string, + + /** Text content used in first button */ + firstOptionText: PropTypes.string.isRequired, + + /** Text content used in second button */ + secondOptionText: PropTypes.string.isRequired, + + /** onSubmit callback fired after clicking on first button */ + onFirstOptionSubmit: PropTypes.func.isRequired, + + /** onSubmit callback fired after clicking on */ + onSecondOptionSubmit: PropTypes.func.isRequired, + + /** Is the window width narrow, like on a mobile device? */ + isSmallScreenWidth: PropTypes.bool.isRequired, + + /** Callback for closing modal */ + onClose: PropTypes.func.isRequired, + + /** Whether modal is visible */ + isVisible: PropTypes.bool.isRequired, +}; + +const defaultProps = { + prompt: '', +}; + +function DecisionModal({title, prompt, firstOptionText, secondOptionText, onFirstOptionSubmit, onSecondOptionSubmit, isSmallScreenWidth, onClose, isVisible}) { + const {translate} = useLocalize(); + const styles = useThemeStyles(); + + return ( + + + + +
+ + + + + + + + {prompt} + + + ) : ( + + )} + From a8b03dfc8579f1b6d801c7297e65bcc6240fcc77 Mon Sep 17 00:00:00 2001 From: Jakub Szymczak Date: Mon, 11 Mar 2024 14:12:38 +0100 Subject: [PATCH 217/931] fix lint --- .../Attachments/AttachmentCarousel/index.native.tsx | 5 ++++- src/components/ImageView/index.native.tsx | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/components/Attachments/AttachmentCarousel/index.native.tsx b/src/components/Attachments/AttachmentCarousel/index.native.tsx index 08a6323691de..9e5cd90c3d57 100644 --- a/src/components/Attachments/AttachmentCarousel/index.native.tsx +++ b/src/components/Attachments/AttachmentCarousel/index.native.tsx @@ -1,7 +1,7 @@ import React, {useCallback, useEffect, useRef, useState} from 'react'; import {Keyboard, View} from 'react-native'; import {withOnyx} from 'react-native-onyx'; -import type {Attachment} from '@components/Attachments/types'; +import type {Attachment, AttachmentSource} from '@components/Attachments/types'; import BlockingView from '@components/BlockingViews/BlockingView'; import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator'; import * as Illustrations from '@components/Icon/Illustrations'; @@ -32,6 +32,7 @@ function AttachmentCarousel({ const [page, setPage] = useState(); const [attachments, setAttachments] = useState([]); const {shouldShowArrows, setShouldShowArrows, autoHideArrows, cancelAutoHideArrows} = useCarouselArrows(); + const [activeSource, setActiveSource] = useState(source); const compareImage = useCallback((attachment: Attachment) => attachment.source === source, [source]); @@ -72,6 +73,7 @@ function AttachmentCarousel({ const item = attachments[newPageIndex]; setPage(newPageIndex); + setActiveSource(item.source); onNavigate(item); }, @@ -146,6 +148,7 @@ function AttachmentCarousel({ updatePage(newPage)} onClose={onClose} diff --git a/src/components/ImageView/index.native.tsx b/src/components/ImageView/index.native.tsx index b1084a885688..c27869f0e281 100644 --- a/src/components/ImageView/index.native.tsx +++ b/src/components/ImageView/index.native.tsx @@ -6,7 +6,7 @@ import type ImageViewProps from './types'; function ImageView({isAuthTokenRequired = false, url, style, zoomRange = DEFAULT_ZOOM_RANGE, onError}: ImageViewProps) { return ( Date: Mon, 11 Mar 2024 15:09:36 +0100 Subject: [PATCH 218/931] [TS migration] Migrate 'reviewerChecklist.test.js' workflow test --- package-lock.json | 1460 +++-------------- package.json | 3 +- tsconfig.json | 2 +- workflow_tests/jest.config.js | 3 +- ...list.test.js => reviewerChecklist.test.ts} | 21 +- 5 files changed, 214 insertions(+), 1275 deletions(-) rename workflow_tests/{reviewerChecklist.test.js => reviewerChecklist.test.ts} (80%) diff --git a/package-lock.json b/package-lock.json index d009c9d3ad3c..209b2ee12676 100644 --- a/package-lock.json +++ b/package-lock.json @@ -236,6 +236,7 @@ "shellcheck": "^1.1.0", "style-loader": "^2.0.0", "time-analytics-webpack-plugin": "^0.1.17", + "ts-jest": "^29.1.2", "ts-node": "^10.9.2", "type-fest": "^4.10.2", "typescript": "^5.3.2", @@ -5962,30 +5963,6 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@jest/console/node_modules/@jest/types": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", - "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", - "dependencies": { - "@jest/schemas": "^29.6.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/console/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dependencies": { - "@types/yargs-parser": "*" - } - }, "node_modules/@jest/console/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -6101,30 +6078,6 @@ } } }, - "node_modules/@jest/core/node_modules/@jest/types": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", - "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", - "dependencies": { - "@jest/schemas": "^29.6.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/core/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dependencies": { - "@types/yargs-parser": "*" - } - }, "node_modules/@jest/core/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -6206,94 +6159,6 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@jest/create-cache-key-function/node_modules/@jest/types": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", - "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", - "dependencies": { - "@jest/schemas": "^29.6.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/create-cache-key-function/node_modules/@types/yargs": { - "version": "17.0.31", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.31.tgz", - "integrity": "sha512-bocYSx4DI8TmdlvxqGpVNXOgCNR1Jj0gNPhhAY+iz1rgKDAaYrAYdFYnhDV1IFuiuVc9HkOwyDcFxaTElF3/wg==", - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/@jest/create-cache-key-function/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@jest/create-cache-key-function/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/@jest/create-cache-key-function/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@jest/create-cache-key-function/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/@jest/create-cache-key-function/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/create-cache-key-function/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/@jest/environment": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", @@ -6308,94 +6173,6 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@jest/environment/node_modules/@jest/types": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", - "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", - "dependencies": { - "@jest/schemas": "^29.6.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/environment/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/@jest/environment/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@jest/environment/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/@jest/environment/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@jest/environment/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/@jest/environment/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/environment/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/@jest/expect": { "version": "29.6.2", "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.6.2.tgz", @@ -6435,94 +6212,6 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@jest/fake-timers/node_modules/@jest/types": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", - "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", - "dependencies": { - "@jest/schemas": "^29.6.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/fake-timers/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/@jest/fake-timers/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@jest/fake-timers/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/@jest/fake-timers/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@jest/fake-timers/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/@jest/fake-timers/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/fake-timers/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/@jest/globals": { "version": "29.5.0", "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.5.0.tgz", @@ -6537,94 +6226,6 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@jest/globals/node_modules/@jest/types": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", - "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", - "dependencies": { - "@jest/schemas": "^29.6.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/globals/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/@jest/globals/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@jest/globals/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/@jest/globals/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@jest/globals/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/@jest/globals/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/globals/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/@jest/reporters": { "version": "29.4.1", "license": "MIT", @@ -6666,30 +6267,6 @@ } } }, - "node_modules/@jest/reporters/node_modules/@jest/types": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", - "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", - "dependencies": { - "@jest/schemas": "^29.6.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/reporters/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dependencies": { - "@types/yargs-parser": "*" - } - }, "node_modules/@jest/reporters/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -6825,100 +6402,6 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@jest/test-result/node_modules/@jest/types": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", - "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", - "dependencies": { - "@jest/schemas": "^29.6.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/test-result/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/@jest/test-result/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@jest/test-result/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/@jest/test-result/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@jest/test-result/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "license": "MIT" - }, - "node_modules/@jest/test-result/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/test-result/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/@jest/test-sequencer": { "version": "29.4.1", "license": "MIT", @@ -6957,30 +6440,6 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@jest/transform/node_modules/@jest/types": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", - "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", - "dependencies": { - "@jest/schemas": "^29.6.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/transform/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dependencies": { - "@types/yargs-parser": "*" - } - }, "node_modules/@jest/transform/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -7063,19 +6522,19 @@ } }, "node_modules/@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", - "license": "MIT", + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", "dependencies": { + "@jest/schemas": "^29.6.3", "@types/istanbul-lib-coverage": "^2.0.0", "@types/istanbul-reports": "^3.0.0", "@types/node": "*", - "@types/yargs": "^15.0.0", + "@types/yargs": "^17.0.8", "chalk": "^4.0.0" }, "engines": { - "node": ">= 10.14.2" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/@jest/types/node_modules/ansi-styles": { @@ -9442,6 +8901,29 @@ "ws": "^7.5.1" } }, + "node_modules/@react-native-community/cli-server-api/node_modules/@jest/types": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", + "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^15.0.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/@react-native-community/cli-server-api/node_modules/@types/yargs": { + "version": "15.0.19", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.19.tgz", + "integrity": "sha512-2XUaGVmyQjgyAZldf0D0c14vvo/yv0MhQBSTJcejMMaitsn3nxCB6TmH4G0ZQf+uxROOa9mpanoSm8h6SG/1ZA==", + "dependencies": { + "@types/yargs-parser": "*" + } + }, "node_modules/@react-native-community/cli-server-api/node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -9464,6 +8946,21 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/@react-native-community/cli-server-api/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "node_modules/@react-native-community/cli-server-api/node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -9480,6 +8977,14 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, + "node_modules/@react-native-community/cli-server-api/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, "node_modules/@react-native-community/cli-server-api/node_modules/pretty-format": { "version": "26.6.2", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", @@ -9499,6 +9004,17 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" }, + "node_modules/@react-native-community/cli-server-api/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/@react-native-community/cli-server-api/node_modules/ws": { "version": "7.5.9", "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", @@ -21229,18 +20745,17 @@ } }, "node_modules/@types/yargs": { - "version": "15.0.15", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.15.tgz", - "integrity": "sha512-IziEYMU9XoVj8hWg7k+UJrXALkGFjWJhn5QFEv9q4p+v40oZhSuC135M38st8XPjICL7Ey4TV64ferBGUoJhBg==", + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", "dependencies": { "@types/yargs-parser": "*" } }, "node_modules/@types/yargs-parser": { - "version": "21.0.0", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", - "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", - "license": "MIT" + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==" }, "node_modules/@types/yauzl": { "version": "2.10.0", @@ -25048,6 +24563,18 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, + "node_modules/bs-logger": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", + "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", + "dev": true, + "dependencies": { + "fast-json-stable-stringify": "2.x" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/bser": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", @@ -35692,30 +35219,6 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-circus/node_modules/@jest/types": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", - "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", - "dependencies": { - "@jest/schemas": "^29.6.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-circus/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dependencies": { - "@types/yargs-parser": "*" - } - }, "node_modules/jest-circus/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -35820,30 +35323,6 @@ } } }, - "node_modules/jest-cli/node_modules/@jest/types": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", - "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", - "dependencies": { - "@jest/schemas": "^29.6.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-cli/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dependencies": { - "@types/yargs-parser": "*" - } - }, "node_modules/jest-cli/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -36006,30 +35485,6 @@ } } }, - "node_modules/jest-config/node_modules/@jest/types": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", - "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", - "dependencies": { - "@jest/schemas": "^29.6.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-config/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dependencies": { - "@types/yargs-parser": "*" - } - }, "node_modules/jest-config/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -36208,30 +35663,6 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-each/node_modules/@jest/types": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", - "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", - "dependencies": { - "@jest/schemas": "^29.6.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-each/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dependencies": { - "@types/yargs-parser": "*" - } - }, "node_modules/jest-each/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -36327,30 +35758,6 @@ } } }, - "node_modules/jest-environment-jsdom/node_modules/@jest/types": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", - "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", - "dependencies": { - "@jest/schemas": "^29.6.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-environment-jsdom/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dependencies": { - "@types/yargs-parser": "*" - } - }, "node_modules/jest-environment-jsdom/node_modules/acorn": { "version": "8.11.3", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", @@ -36362,55 +35769,6 @@ "node": ">=0.4.0" } }, - "node_modules/jest-environment-jsdom/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-environment-jsdom/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-environment-jsdom/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-environment-jsdom/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "license": "MIT" - }, "node_modules/jest-environment-jsdom/node_modules/cssstyle": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", @@ -36464,15 +35822,6 @@ "node": ">= 6" } }, - "node_modules/jest-environment-jsdom/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/jest-environment-jsdom/node_modules/html-encoding-sniffer": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz", @@ -36539,18 +35888,6 @@ "url": "https://github.com/inikulin/parse5?sponsor=1" } }, - "node_modules/jest-environment-jsdom/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/jest-environment-jsdom/node_modules/tr46": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", @@ -36628,94 +35965,6 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-environment-node/node_modules/@jest/types": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", - "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", - "dependencies": { - "@jest/schemas": "^29.6.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-environment-node/node_modules/@types/yargs": { - "version": "17.0.31", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.31.tgz", - "integrity": "sha512-bocYSx4DI8TmdlvxqGpVNXOgCNR1Jj0gNPhhAY+iz1rgKDAaYrAYdFYnhDV1IFuiuVc9HkOwyDcFxaTElF3/wg==", - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/jest-environment-node/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-environment-node/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-environment-node/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-environment-node/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/jest-environment-node/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-environment-node/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/jest-expo": { "version": "50.0.1", "resolved": "https://registry.npmjs.org/jest-expo/-/jest-expo-50.0.1.tgz", @@ -36788,75 +36037,6 @@ "fsevents": "^2.3.2" } }, - "node_modules/jest-haste-map/node_modules/@jest/types": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", - "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", - "dependencies": { - "@jest/schemas": "^29.6.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-haste-map/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/jest-haste-map/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-haste-map/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-haste-map/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-haste-map/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, "node_modules/jest-haste-map/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -36893,17 +36073,6 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, - "node_modules/jest-haste-map/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/jest-leak-detector": { "version": "29.4.1", "license": "MIT", @@ -37018,30 +36187,6 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-message-util/node_modules/@jest/types": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", - "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", - "dependencies": { - "@jest/schemas": "^29.6.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-message-util/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dependencies": { - "@types/yargs-parser": "*" - } - }, "node_modules/jest-message-util/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -37119,94 +36264,6 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-mock/node_modules/@jest/types": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", - "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", - "dependencies": { - "@jest/schemas": "^29.6.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-mock/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/jest-mock/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-mock/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-mock/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-mock/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/jest-mock/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-mock/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/jest-pnp-resolver": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", @@ -37361,30 +36418,6 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-runner/node_modules/@jest/types": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", - "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", - "dependencies": { - "@jest/schemas": "^29.6.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-runner/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dependencies": { - "@types/yargs-parser": "*" - } - }, "node_modules/jest-runner/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -37526,30 +36559,6 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-runtime/node_modules/@jest/types": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", - "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", - "dependencies": { - "@jest/schemas": "^29.6.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-runtime/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dependencies": { - "@types/yargs-parser": "*" - } - }, "node_modules/jest-runtime/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -37650,30 +36659,6 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-snapshot/node_modules/@jest/types": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", - "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", - "dependencies": { - "@jest/schemas": "^29.6.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-snapshot/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dependencies": { - "@types/yargs-parser": "*" - } - }, "node_modules/jest-snapshot/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -37764,30 +36749,6 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-util/node_modules/@jest/types": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", - "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", - "dependencies": { - "@jest/schemas": "^29.6.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-util/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dependencies": { - "@types/yargs-parser": "*" - } - }, "node_modules/jest-util/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -37868,30 +36829,6 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-validate/node_modules/@jest/types": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", - "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", - "dependencies": { - "@jest/schemas": "^29.6.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-validate/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dependencies": { - "@types/yargs-parser": "*" - } - }, "node_modules/jest-validate/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -38212,30 +37149,6 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-watcher/node_modules/@jest/types": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", - "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", - "dependencies": { - "@jest/schemas": "^29.6.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-watcher/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dependencies": { - "@types/yargs-parser": "*" - } - }, "node_modules/jest-watcher/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -38353,100 +37266,6 @@ "node": ">=8" } }, - "node_modules/jest/node_modules/@jest/types": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", - "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", - "dependencies": { - "@jest/schemas": "^29.6.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/jest/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "license": "MIT" - }, - "node_modules/jest/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/jest/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/jimp-compact": { "version": "0.16.1", "resolved": "https://registry.npmjs.org/jimp-compact/-/jimp-compact-0.16.1.tgz", @@ -39228,6 +38047,12 @@ "dev": true, "peer": true }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", + "dev": true + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -45174,6 +43999,29 @@ "node": ">=8" } }, + "node_modules/react-native/node_modules/@jest/types": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", + "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^15.0.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/react-native/node_modules/@types/yargs": { + "version": "15.0.19", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.19.tgz", + "integrity": "sha512-2XUaGVmyQjgyAZldf0D0c14vvo/yv0MhQBSTJcejMMaitsn3nxCB6TmH4G0ZQf+uxROOa9mpanoSm8h6SG/1ZA==", + "dependencies": { + "@types/yargs-parser": "*" + } + }, "node_modules/react-native/node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -45196,6 +44044,21 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/react-native/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "node_modules/react-native/node_modules/cliui": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", @@ -45238,6 +44101,14 @@ "node": ">=18" } }, + "node_modules/react-native/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, "node_modules/react-native/node_modules/mkdirp": { "version": "0.5.6", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", @@ -45292,6 +44163,17 @@ "loose-envify": "^1.1.0" } }, + "node_modules/react-native/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/react-native/node_modules/ws": { "version": "6.2.2", "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.2.tgz", @@ -50354,6 +49236,58 @@ "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==" }, + "node_modules/ts-jest": { + "version": "29.1.2", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.1.2.tgz", + "integrity": "sha512-br6GJoH/WUX4pu7FbZXuWGKGNDuU7b8Uj77g/Sp7puZV6EXzuByl6JrECvm0MzVzSTkSHWTihsXt+5XYER5b+g==", + "dev": true, + "dependencies": { + "bs-logger": "0.x", + "fast-json-stable-stringify": "2.x", + "jest-util": "^29.0.0", + "json5": "^2.2.3", + "lodash.memoize": "4.x", + "make-error": "1.x", + "semver": "^7.5.3", + "yargs-parser": "^21.0.1" + }, + "bin": { + "ts-jest": "cli.js" + }, + "engines": { + "node": "^16.10.0 || ^18.0.0 || >=20.0.0" + }, + "peerDependencies": { + "@babel/core": ">=7.0.0-beta.0 <8", + "@jest/types": "^29.0.0", + "babel-jest": "^29.0.0", + "jest": "^29.0.0", + "typescript": ">=4.3 <6" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "@jest/types": { + "optional": true + }, + "babel-jest": { + "optional": true + }, + "esbuild": { + "optional": true + } + } + }, + "node_modules/ts-jest/node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "engines": { + "node": ">=12" + } + }, "node_modules/ts-node": { "version": "10.9.2", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", diff --git a/package.json b/package.json index 62da9d177dca..20779c73e402 100644 --- a/package.json +++ b/package.json @@ -157,8 +157,8 @@ "react-native-plaid-link-sdk": "10.8.0", "react-native-qrcode-svg": "^6.2.0", "react-native-quick-sqlite": "^8.0.0-beta.2", - "react-native-release-profiler": "^0.1.6", "react-native-reanimated": "^3.7.2", + "react-native-release-profiler": "^0.1.6", "react-native-render-html": "6.3.1", "react-native-safe-area-context": "4.8.2", "react-native-screens": "3.29.0", @@ -287,6 +287,7 @@ "shellcheck": "^1.1.0", "style-loader": "^2.0.0", "time-analytics-webpack-plugin": "^0.1.17", + "ts-jest": "^29.1.2", "ts-node": "^10.9.2", "type-fest": "^4.10.2", "typescript": "^5.3.2", diff --git a/tsconfig.json b/tsconfig.json index 30708f63d12b..79413fdd2ca7 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -48,6 +48,6 @@ } }, "exclude": ["**/node_modules/*", "**/dist/*", ".github/actions/**/index.js", "**/docs/*"], - "include": ["src", "desktop", "web", "website", "docs", "assets", "config", "tests", "jest", "__mocks__", ".github/**/*", ".storybook/**/*"], + "include": ["src", "desktop", "web", "website", "docs", "assets", "config", "tests", "jest", "__mocks__", ".github/**/*", ".storybook/**/*", "workflow_tests"], "extends": "expo/tsconfig.base" } diff --git a/workflow_tests/jest.config.js b/workflow_tests/jest.config.js index c8a4534764e3..91857765b439 100644 --- a/workflow_tests/jest.config.js +++ b/workflow_tests/jest.config.js @@ -1,7 +1,8 @@ module.exports = { + preset: 'ts-jest', verbose: true, transform: { - '^.+\\.jsx?$': 'babel-jest', + '^.+\\.(js|jsx|ts|tsx)$': 'ts-jest', }, clearMocks: true, resetMocks: true, diff --git a/workflow_tests/reviewerChecklist.test.js b/workflow_tests/reviewerChecklist.test.ts similarity index 80% rename from workflow_tests/reviewerChecklist.test.js rename to workflow_tests/reviewerChecklist.test.ts index 9903c3eb4b8d..209e0974a8bf 100644 --- a/workflow_tests/reviewerChecklist.test.js +++ b/workflow_tests/reviewerChecklist.test.ts @@ -1,13 +1,14 @@ -const path = require('path'); -const kieMockGithub = require('@kie/mock-github'); -const utils = require('./utils/utils'); -const assertions = require('./assertions/reviewerChecklistAssertions'); -const mocks = require('./mocks/reviewerChecklistMocks'); -const eAct = require('./utils/ExtendedAct'); +import * as kieMockGithub from '@kie/mock-github'; +import type {CreateRepositoryFile, MockGithub} from '@kie/mock-github'; +import path from 'path'; +import assertions from './assertions/reviewerChecklistAssertions'; +import mocks from './mocks/reviewerChecklistMocks'; +import eAct from './utils/ExtendedAct'; +import utils from './utils/utils'; jest.setTimeout(90 * 1000); -let mockGithub; -const FILES_TO_COPY_INTO_TEST_REPO = [ +let mockGithub: MockGithub; +const FILES_TO_COPY_INTO_TEST_REPO: CreateRepositoryFile[] = [ ...utils.deepCopy(utils.FILES_TO_COPY_INTO_TEST_REPO), { src: path.resolve(__dirname, '..', '.github', 'workflows', 'reviewerChecklist.yml'), @@ -42,11 +43,12 @@ describe('test workflow reviewerChecklist', () => { }); describe('event is pull_request_review', () => { const event = 'pull_request_review'; - const eventOptions = {}; + const eventOptions: Record = {}; it('runs the workflow', async () => { const repoPath = mockGithub.repo.getPath('testReviewerChecklistWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'reviewerChecklist.yml'); let act = new eAct.ExtendedAct(repoPath, workflowPath); + // @ts-expect-error TODO: Remove this once utils (https://github.com/Expensify/App/issues/32061) is migrated to TypeScript. act = utils.setUpActParams(act, event, eventOptions, {}, githubToken); const testMockSteps = { checklist: mocks.REVIEWERCHECKLIST__CHECKLIST__STEP_MOCKS, @@ -66,6 +68,7 @@ describe('test workflow reviewerChecklist', () => { const repoPath = mockGithub.repo.getPath('testReviewerChecklistWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'reviewerChecklist.yml'); let act = new eAct.ExtendedAct(repoPath, workflowPath); + // @ts-expect-error TODO: Remove this once utils (https://github.com/Expensify/App/issues/32061) is migrated to TypeScript. act = utils.setUpActParams(act, event, eventOptions, {}, githubToken); const testMockSteps = { checklist: mocks.REVIEWERCHECKLIST__CHECKLIST__STEP_MOCKS, From 58113e2e412573b23f1884619aea84cf4369780b Mon Sep 17 00:00:00 2001 From: VickyStash Date: Mon, 11 Mar 2024 15:25:58 +0100 Subject: [PATCH 219/931] [TS migration] Migrate 'test.test.js' workflow test --- workflow_tests/reviewerChecklist.test.ts | 7 ++-- workflow_tests/{test.test.js => test.test.ts} | 36 +++++++++++-------- 2 files changed, 26 insertions(+), 17 deletions(-) rename workflow_tests/{test.test.js => test.test.ts} (82%) diff --git a/workflow_tests/reviewerChecklist.test.ts b/workflow_tests/reviewerChecklist.test.ts index 209e0974a8bf..e786e5466ec8 100644 --- a/workflow_tests/reviewerChecklist.test.ts +++ b/workflow_tests/reviewerChecklist.test.ts @@ -1,3 +1,4 @@ +import type {MockStep} from '@kie/act-js/build/src/step-mocker/step-mocker.types'; import * as kieMockGithub from '@kie/mock-github'; import type {CreateRepositoryFile, MockGithub} from '@kie/mock-github'; import path from 'path'; @@ -43,14 +44,14 @@ describe('test workflow reviewerChecklist', () => { }); describe('event is pull_request_review', () => { const event = 'pull_request_review'; - const eventOptions: Record = {}; + const eventOptions = {}; it('runs the workflow', async () => { const repoPath = mockGithub.repo.getPath('testReviewerChecklistWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'reviewerChecklist.yml'); let act = new eAct.ExtendedAct(repoPath, workflowPath); // @ts-expect-error TODO: Remove this once utils (https://github.com/Expensify/App/issues/32061) is migrated to TypeScript. act = utils.setUpActParams(act, event, eventOptions, {}, githubToken); - const testMockSteps = { + const testMockSteps: MockStep = { checklist: mocks.REVIEWERCHECKLIST__CHECKLIST__STEP_MOCKS, }; const result = await act.runEvent(event, { @@ -70,7 +71,7 @@ describe('test workflow reviewerChecklist', () => { let act = new eAct.ExtendedAct(repoPath, workflowPath); // @ts-expect-error TODO: Remove this once utils (https://github.com/Expensify/App/issues/32061) is migrated to TypeScript. act = utils.setUpActParams(act, event, eventOptions, {}, githubToken); - const testMockSteps = { + const testMockSteps: MockStep = { checklist: mocks.REVIEWERCHECKLIST__CHECKLIST__STEP_MOCKS, }; const result = await act.runEvent(event, { diff --git a/workflow_tests/test.test.js b/workflow_tests/test.test.ts similarity index 82% rename from workflow_tests/test.test.js rename to workflow_tests/test.test.ts index 6efe8d260928..56b9179dafa2 100644 --- a/workflow_tests/test.test.js +++ b/workflow_tests/test.test.ts @@ -1,13 +1,15 @@ -const path = require('path'); -const kieMockGithub = require('@kie/mock-github'); -const utils = require('./utils/utils'); -const assertions = require('./assertions/testAssertions'); -const mocks = require('./mocks/testMocks'); -const eAct = require('./utils/ExtendedAct'); +import type {MockStep} from '@kie/act-js/build/src/step-mocker/step-mocker.types'; +import * as kieMockGithub from '@kie/mock-github'; +import type {CreateRepositoryFile, MockGithub} from '@kie/mock-github'; +import path from 'path'; +import assertions from './assertions/testAssertions'; +import mocks from './mocks/testMocks'; +import eAct from './utils/ExtendedAct'; +import utils from './utils/utils'; jest.setTimeout(90 * 1000); -let mockGithub; -const FILES_TO_COPY_INTO_TEST_REPO = [ +let mockGithub: MockGithub; +const FILES_TO_COPY_INTO_TEST_REPO: CreateRepositoryFile[] = [ ...utils.deepCopy(utils.FILES_TO_COPY_INTO_TEST_REPO), { src: path.resolve(__dirname, '..', '.github', 'workflows', 'test.yml'), @@ -52,8 +54,9 @@ describe('test workflow test', () => { const repoPath = mockGithub.repo.getPath('testTestWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'test.yml'); let act = new eAct.ExtendedAct(repoPath, workflowPath); + // @ts-expect-error TODO: Remove this once utils (https://github.com/Expensify/App/issues/32061) is migrated to TypeScript. act = utils.setUpActParams(act, event, eventOptions, {}, githubToken); - const testMockSteps = { + const testMockSteps: MockStep = { jest: mocks.TEST__JEST__STEP_MOCKS, shellTests: mocks.TEST__SHELLTESTS__STEP_MOCKS, }; @@ -72,8 +75,9 @@ describe('test workflow test', () => { const repoPath = mockGithub.repo.getPath('testTestWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'test.yml'); let act = new eAct.ExtendedAct(repoPath, workflowPath); + // @ts-expect-error TODO: Remove this once utils (https://github.com/Expensify/App/issues/32061) is migrated to TypeScript. act = utils.setUpActParams(act, event, eventOptions, {}, githubToken); - const testMockSteps = { + const testMockSteps: MockStep = { jest: mocks.TEST__JEST__STEP_MOCKS, shellTests: mocks.TEST__SHELLTESTS__STEP_MOCKS, }; @@ -99,8 +103,9 @@ describe('test workflow test', () => { const repoPath = mockGithub.repo.getPath('testTestWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'test.yml'); let act = new eAct.ExtendedAct(repoPath, workflowPath); + // @ts-expect-error TODO: Remove this once utils (https://github.com/Expensify/App/issues/32061) is migrated to TypeScript. act = utils.setUpActParams(act, event, eventOptions, {}, githubToken); - const testMockSteps = { + const testMockSteps: MockStep = { jest: mocks.TEST__JEST__STEP_MOCKS, shellTests: mocks.TEST__SHELLTESTS__STEP_MOCKS, }; @@ -119,8 +124,9 @@ describe('test workflow test', () => { const repoPath = mockGithub.repo.getPath('testTestWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'test.yml'); let act = new eAct.ExtendedAct(repoPath, workflowPath); + // @ts-expect-error TODO: Remove this once utils (https://github.com/Expensify/App/issues/32061) is migrated to TypeScript. act = utils.setUpActParams(act, event, eventOptions, {}, githubToken); - const testMockSteps = { + const testMockSteps: MockStep = { jest: mocks.TEST__JEST__STEP_MOCKS, shellTests: mocks.TEST__SHELLTESTS__STEP_MOCKS, }; @@ -144,8 +150,9 @@ describe('test workflow test', () => { const repoPath = mockGithub.repo.getPath('testTestWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'test.yml'); let act = new eAct.ExtendedAct(repoPath, workflowPath); + // @ts-expect-error TODO: Remove this once utils (https://github.com/Expensify/App/issues/32061) is migrated to TypeScript. act = utils.setUpActParams(act, event, eventOptions, {}, githubToken); - const testMockSteps = { + const testMockSteps: MockStep = { jest: mocks.TEST__JEST__STEP_MOCKS, shellTests: mocks.TEST__SHELLTESTS__STEP_MOCKS, }; @@ -164,8 +171,9 @@ describe('test workflow test', () => { const repoPath = mockGithub.repo.getPath('testTestWorkflowRepo') || ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'test.yml'); let act = new eAct.ExtendedAct(repoPath, workflowPath); + // @ts-expect-error TODO: Remove this once utils (https://github.com/Expensify/App/issues/32061) is migrated to TypeScript. act = utils.setUpActParams(act, event, eventOptions, {}, githubToken); - const testMockSteps = { + const testMockSteps: MockStep = { jest: mocks.TEST__JEST__STEP_MOCKS, shellTests: mocks.TEST__SHELLTESTS__STEP_MOCKS, }; From 825c3b79e8daa6039046b59d19a22d0a9921e5fc Mon Sep 17 00:00:00 2001 From: VickyStash Date: Mon, 11 Mar 2024 15:36:20 +0100 Subject: [PATCH 220/931] Fix lint problems --- workflow_tests/reviewerChecklist.test.ts | 6 +++--- workflow_tests/test.test.ts | 14 +++++++------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/workflow_tests/reviewerChecklist.test.ts b/workflow_tests/reviewerChecklist.test.ts index e786e5466ec8..e34e6a0e07fd 100644 --- a/workflow_tests/reviewerChecklist.test.ts +++ b/workflow_tests/reviewerChecklist.test.ts @@ -21,7 +21,7 @@ describe('test workflow reviewerChecklist', () => { const githubToken = 'dummy_github_token'; const actor = 'Dummy Actor'; - beforeAll(async () => { + beforeAll(() => { // in case of the tests being interrupted without cleanup the mock repo directory may be left behind // which breaks the next test run, this removes any possible leftovers utils.removeMockRepoDir(); @@ -46,7 +46,7 @@ describe('test workflow reviewerChecklist', () => { const event = 'pull_request_review'; const eventOptions = {}; it('runs the workflow', async () => { - const repoPath = mockGithub.repo.getPath('testReviewerChecklistWorkflowRepo') || ''; + const repoPath = mockGithub.repo.getPath('testReviewerChecklistWorkflowRepo') ?? ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'reviewerChecklist.yml'); let act = new eAct.ExtendedAct(repoPath, workflowPath); // @ts-expect-error TODO: Remove this once utils (https://github.com/Expensify/App/issues/32061) is migrated to TypeScript. @@ -66,7 +66,7 @@ describe('test workflow reviewerChecklist', () => { describe('actor is OSBotify', () => { const osbotifyActor = 'OSBotify'; it('does not run the workflow', async () => { - const repoPath = mockGithub.repo.getPath('testReviewerChecklistWorkflowRepo') || ''; + const repoPath = mockGithub.repo.getPath('testReviewerChecklistWorkflowRepo') ?? ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'reviewerChecklist.yml'); let act = new eAct.ExtendedAct(repoPath, workflowPath); // @ts-expect-error TODO: Remove this once utils (https://github.com/Expensify/App/issues/32061) is migrated to TypeScript. diff --git a/workflow_tests/test.test.ts b/workflow_tests/test.test.ts index 56b9179dafa2..8e6258c09b8b 100644 --- a/workflow_tests/test.test.ts +++ b/workflow_tests/test.test.ts @@ -22,7 +22,7 @@ describe('test workflow test', () => { const actor = 'Dummy Actor'; const osbotifyActor = 'OSBotify'; - beforeAll(async () => { + beforeAll(() => { // in case of the tests being interrupted without cleanup the mock repo directory may be left behind // which breaks the next test run, this removes any possible leftovers utils.removeMockRepoDir(); @@ -51,7 +51,7 @@ describe('test workflow test', () => { action: 'opened', }; it('runs all tests', async () => { - const repoPath = mockGithub.repo.getPath('testTestWorkflowRepo') || ''; + const repoPath = mockGithub.repo.getPath('testTestWorkflowRepo') ?? ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'test.yml'); let act = new eAct.ExtendedAct(repoPath, workflowPath); // @ts-expect-error TODO: Remove this once utils (https://github.com/Expensify/App/issues/32061) is migrated to TypeScript. @@ -72,7 +72,7 @@ describe('test workflow test', () => { }); describe('actor is OSBotify', () => { it('does not run tests', async () => { - const repoPath = mockGithub.repo.getPath('testTestWorkflowRepo') || ''; + const repoPath = mockGithub.repo.getPath('testTestWorkflowRepo') ?? ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'test.yml'); let act = new eAct.ExtendedAct(repoPath, workflowPath); // @ts-expect-error TODO: Remove this once utils (https://github.com/Expensify/App/issues/32061) is migrated to TypeScript. @@ -100,7 +100,7 @@ describe('test workflow test', () => { action: 'synchronize', }; it('runs all tests', async () => { - const repoPath = mockGithub.repo.getPath('testTestWorkflowRepo') || ''; + const repoPath = mockGithub.repo.getPath('testTestWorkflowRepo') ?? ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'test.yml'); let act = new eAct.ExtendedAct(repoPath, workflowPath); // @ts-expect-error TODO: Remove this once utils (https://github.com/Expensify/App/issues/32061) is migrated to TypeScript. @@ -121,7 +121,7 @@ describe('test workflow test', () => { }); describe('actor is OSBotify', () => { it('does not run tests', async () => { - const repoPath = mockGithub.repo.getPath('testTestWorkflowRepo') || ''; + const repoPath = mockGithub.repo.getPath('testTestWorkflowRepo') ?? ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'test.yml'); let act = new eAct.ExtendedAct(repoPath, workflowPath); // @ts-expect-error TODO: Remove this once utils (https://github.com/Expensify/App/issues/32061) is migrated to TypeScript. @@ -147,7 +147,7 @@ describe('test workflow test', () => { const event = 'workflow_call'; const eventOptions = {}; it('runs all tests', async () => { - const repoPath = mockGithub.repo.getPath('testTestWorkflowRepo') || ''; + const repoPath = mockGithub.repo.getPath('testTestWorkflowRepo') ?? ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'test.yml'); let act = new eAct.ExtendedAct(repoPath, workflowPath); // @ts-expect-error TODO: Remove this once utils (https://github.com/Expensify/App/issues/32061) is migrated to TypeScript. @@ -168,7 +168,7 @@ describe('test workflow test', () => { }); describe('actor is OSBotify', () => { it('runs all tests normally', async () => { - const repoPath = mockGithub.repo.getPath('testTestWorkflowRepo') || ''; + const repoPath = mockGithub.repo.getPath('testTestWorkflowRepo') ?? ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'test.yml'); let act = new eAct.ExtendedAct(repoPath, workflowPath); // @ts-expect-error TODO: Remove this once utils (https://github.com/Expensify/App/issues/32061) is migrated to TypeScript. From ec0d55355e71ea71f81f29a013eb5185a34cf119 Mon Sep 17 00:00:00 2001 From: Julian Kobrynski Date: Mon, 11 Mar 2024 17:32:37 +0100 Subject: [PATCH 221/931] migrate bumpVersion.js to TypeScript --- .../{bumpVersion.js => bumpVersion.ts} | 29 +++++++++---------- 1 file changed, 14 insertions(+), 15 deletions(-) rename .github/actions/javascript/bumpVersion/{bumpVersion.js => bumpVersion.ts} (73%) diff --git a/.github/actions/javascript/bumpVersion/bumpVersion.js b/.github/actions/javascript/bumpVersion/bumpVersion.ts similarity index 73% rename from .github/actions/javascript/bumpVersion/bumpVersion.js rename to .github/actions/javascript/bumpVersion/bumpVersion.ts index 647c295fdc52..d08293c856be 100644 --- a/.github/actions/javascript/bumpVersion/bumpVersion.js +++ b/.github/actions/javascript/bumpVersion/bumpVersion.ts @@ -1,17 +1,16 @@ -const {promisify} = require('util'); -const fs = require('fs'); -const exec = promisify(require('child_process').exec); -const _ = require('underscore'); -const core = require('@actions/core'); -const versionUpdater = require('../../../libs/versionUpdater'); -const {updateAndroidVersion, updateiOSVersion, generateAndroidVersionCode} = require('../../../libs/nativeVersionUpdater'); +import * as core from '@actions/core'; +import {exec as originalExec} from 'child_process'; +import fs from 'fs'; +import {promisify} from 'util'; +import {generateAndroidVersionCode, updateAndroidVersion, updateiOSVersion} from '../../../libs/nativeVersionUpdater'; +import * as versionUpdater from '../../../libs/versionUpdater'; + +const exec = promisify(originalExec); /** * Update the native app versions. - * - * @param {String} version */ -function updateNativeVersions(version) { +function updateNativeVersions(version: string) { console.log(`Updating native versions to ${version}`); // Update Android @@ -28,7 +27,7 @@ function updateNativeVersions(version) { // Update iOS try { const cfBundleVersion = updateiOSVersion(version); - if (_.isString(cfBundleVersion) && cfBundleVersion.split('.').length === 4) { + if (typeof cfBundleVersion === 'string' && cfBundleVersion.split('.').length === 4) { core.setOutput('NEW_IOS_VERSION', cfBundleVersion); console.log('Successfully updated iOS!'); } else { @@ -36,17 +35,17 @@ function updateNativeVersions(version) { } } catch (err) { console.error('Error updating iOS'); - core.setFailed(err); + core.setFailed(err as string); } } -let semanticVersionLevel = core.getInput('SEMVER_LEVEL', {require: true}); -if (!semanticVersionLevel || !_.contains(versionUpdater.SEMANTIC_VERSION_LEVELS, semanticVersionLevel)) { +let semanticVersionLevel = core.getInput('SEMVER_LEVEL', {required: true}); +if (!semanticVersionLevel || !Object.keys(versionUpdater.SEMANTIC_VERSION_LEVELS).includes(semanticVersionLevel)) { semanticVersionLevel = versionUpdater.SEMANTIC_VERSION_LEVELS.BUILD; console.log(`Invalid input for 'SEMVER_LEVEL': ${semanticVersionLevel}`, `Defaulting to: ${semanticVersionLevel}`); } -const {version: previousVersion} = JSON.parse(fs.readFileSync('./package.json')); +const {version: previousVersion} = JSON.parse(fs.readFileSync('./package.json').toString()); const newVersion = versionUpdater.incrementVersion(previousVersion, semanticVersionLevel); console.log(`Previous version: ${previousVersion}`, `New version: ${newVersion}`); From 7068222b62669118304ac6a424deda12388b695d Mon Sep 17 00:00:00 2001 From: Julian Kobrynski Date: Mon, 11 Mar 2024 17:33:05 +0100 Subject: [PATCH 222/931] start migrating markPullRequestsAsDeployed to TypeScript --- ...loyed.js => markPullRequestsAsDeployed.ts} | 38 ++++++++----------- 1 file changed, 16 insertions(+), 22 deletions(-) rename .github/actions/javascript/markPullRequestsAsDeployed/{markPullRequestsAsDeployed.js => markPullRequestsAsDeployed.ts} (84%) diff --git a/.github/actions/javascript/markPullRequestsAsDeployed/markPullRequestsAsDeployed.js b/.github/actions/javascript/markPullRequestsAsDeployed/markPullRequestsAsDeployed.ts similarity index 84% rename from .github/actions/javascript/markPullRequestsAsDeployed/markPullRequestsAsDeployed.js rename to .github/actions/javascript/markPullRequestsAsDeployed/markPullRequestsAsDeployed.ts index d03a947cdec8..cf132794ce46 100644 --- a/.github/actions/javascript/markPullRequestsAsDeployed/markPullRequestsAsDeployed.js +++ b/.github/actions/javascript/markPullRequestsAsDeployed/markPullRequestsAsDeployed.ts @@ -1,17 +1,15 @@ -const _ = require('underscore'); -const core = require('@actions/core'); -const {context} = require('@actions/github'); -const CONST = require('../../../libs/CONST'); -const ActionUtils = require('../../../libs/ActionUtils'); -const GithubUtils = require('../../../libs/GithubUtils'); +import core from '@actions/core'; +import {context} from '@actions/github'; +import * as ActionUtils from '../../../libs/ActionUtils'; +import CONST from '../../../libs/CONST'; +import * as GithubUtils from '../../../libs/GithubUtils'; + +type PlatformResult = 'success' | 'cancelled' | 'skipped' | 'failure'; /** * Return a nicely formatted message for the table based on the result of the GitHub action job - * - * @param {String} platformResult - * @returns {String} */ -function getDeployTableMessage(platformResult) { +function getDeployTableMessage(platformResult: PlatformResult) { switch (platformResult) { case 'success': return `${platformResult} ✅`; @@ -27,10 +25,6 @@ function getDeployTableMessage(platformResult) { /** * Comment Single PR - * - * @param {Number} PR - * @param {String} message - * @returns {Promise} */ async function commentPR(PR, message) { try { @@ -45,7 +39,7 @@ async function commentPR(PR, message) { const workflowURL = `${process.env.GITHUB_SERVER_URL}/${process.env.GITHUB_REPOSITORY}/actions/runs/${process.env.GITHUB_RUN_ID}`; async function run() { - const prList = _.map(ActionUtils.getJSONInput('PR_LIST', {required: true}), (num) => Number.parseInt(num, 10)); + const prList = ActionUtils.getJSONInput('PR_LIST', {required: true}).map((num: string) => Number.parseInt(num, 10)); const isProd = ActionUtils.getJSONInput('IS_PRODUCTION_DEPLOY', {required: true}); const version = core.getInput('DEPLOY_VERSION', {required: true}); @@ -55,10 +49,10 @@ async function run() { const webResult = getDeployTableMessage(core.getInput('WEB', {required: true})); /** - * @param {String} deployer - * @param {String} deployVerb - * @param {String} prTitle - * @returns {String} + * @param deployer + * @param deployVerb + * @param prTitle + * @returns */ function getDeployMessage(deployer, deployVerb, prTitle) { let message = `🚀 [${deployVerb}](${workflowURL}) to ${isProd ? 'production' : 'staging'}`; @@ -83,7 +77,7 @@ async function run() { labels: CONST.LABELS.STAGING_DEPLOY, state: 'closed', }); - const previousChecklistID = _.first(deployChecklists).number; + const previousChecklistID = deployChecklists[0].number; // who closed the last deploy checklist? const deployer = await GithubUtils.getActorWhoClosedIssue(previousChecklistID); @@ -102,7 +96,7 @@ async function run() { repo: CONST.APP_REPO, per_page: 100, }); - const currentTag = _.find(recentTags, (tag) => tag.name === version); + const currentTag = recentTags.find((tag) => tag.name === version); if (!currentTag) { const err = `Could not find tag matching ${version}`; console.error(err); @@ -139,4 +133,4 @@ if (require.main === module) { run(); } -module.exports = run; +export default run; From 2260d2a4a9fcecb00e2dd2c64bcd3379b40a5c70 Mon Sep 17 00:00:00 2001 From: Julian Kobrynski Date: Mon, 11 Mar 2024 17:33:21 +0100 Subject: [PATCH 223/931] start migrating GithubUtils to TypeScript --- .../libs/{GithubUtils.js => GithubUtils.ts} | 235 +++++++++--------- 1 file changed, 120 insertions(+), 115 deletions(-) rename .github/libs/{GithubUtils.js => GithubUtils.ts} (71%) diff --git a/.github/libs/GithubUtils.js b/.github/libs/GithubUtils.ts similarity index 71% rename from .github/libs/GithubUtils.js rename to .github/libs/GithubUtils.ts index e988167850ec..046701a94a9c 100644 --- a/.github/libs/GithubUtils.js +++ b/.github/libs/GithubUtils.ts @@ -1,10 +1,12 @@ -const _ = require('underscore'); -const lodashGet = require('lodash/get'); -const core = require('@actions/core'); -const {GitHub, getOctokitOptions} = require('@actions/github/lib/utils'); -const {throttling} = require('@octokit/plugin-throttling'); -const {paginateRest} = require('@octokit/plugin-paginate-rest'); -const CONST = require('./CONST'); +import * as core from '@actions/core'; +import {getOctokitOptions, GitHub} from '@actions/github/lib/utils'; +import type {Octokit as OctokitCore} from '@octokit/core'; +import type {PaginateInterface} from '@octokit/plugin-paginate-rest'; +import {paginateRest} from '@octokit/plugin-paginate-rest'; +import {throttling} from '@octokit/plugin-throttling'; +import _ from 'underscore'; +import {isEmptyObject} from '@src/types/utils/EmptyObject'; +import CONST from './CONST'; const GITHUB_BASE_URL_REGEX = new RegExp('https?://(?:github\\.com|api\\.github\\.com)'); const PULL_REQUEST_REGEX = new RegExp(`${GITHUB_BASE_URL_REGEX.source}/.*/.*/pull/([0-9]+).*`); @@ -14,11 +16,14 @@ const ISSUE_OR_PULL_REQUEST_REGEX = new RegExp(`${GITHUB_BASE_URL_REGEX.source}/ /** * The standard rate in ms at which we'll poll the GitHub API to check for status changes. * It's 10 seconds :) - * @type {number} */ const POLL_RATE = 10000; +type OctokitOptions = {method: string; url: string; request: {retryCount: number}}; + class GithubUtils { + static internalOctokit: OctokitCore & {paginate: PaginateInterface}; + /** * Initialize internal octokit * @@ -33,7 +38,7 @@ class GithubUtils { getOctokitOptions(token, { throttle: { retryAfterBaseValue: 2000, - onRateLimit: (retryAfter, options) => { + onRateLimit: (retryAfter: number, options: OctokitOptions) => { console.warn(`Request quota exhausted for request ${options.method} ${options.url}`); // Retry five times when hitting a rate limit error, then give up @@ -42,7 +47,7 @@ class GithubUtils { return true; } }, - onAbuseLimit: (retryAfter, options) => { + onAbuseLimit: (retryAfter: number, options: OctokitOptions) => { // does not retry, only logs a warning console.warn(`Abuse detected for request ${options.method} ${options.url}`); }, @@ -98,7 +103,7 @@ class GithubUtils { /** * Finds one open `StagingDeployCash` issue via GitHub octokit library. * - * @returns {Promise} + * @returns */ static getStagingDeployCash() { return this.octokit.issues @@ -128,8 +133,8 @@ class GithubUtils { /** * Takes in a GitHub issue object and returns the data we want. * - * @param {Object} issue - * @returns {Object} + * @param issue + * @returns */ static getStagingDeployCashData(issue) { try { @@ -158,8 +163,8 @@ class GithubUtils { * * @private * - * @param {Object} issue - * @returns {Array} - [{url: String, number: Number, isVerified: Boolean}] + * @param issue + * @returns - [{url: String, number: Number, isVerified: Boolean}] */ static getStagingDeployCashPRList(issue) { let PRListSection = issue.body.match(/pull requests:\*\*\r?\n((?:-.*\r?\n)+)\r?\n\r?\n?/) || []; @@ -169,7 +174,7 @@ class GithubUtils { return []; } PRListSection = PRListSection[1]; - const PRList = _.map([...PRListSection.matchAll(new RegExp(`- \\[([ x])] (${PULL_REQUEST_REGEX.source})`, 'g'))], (match) => ({ + const PRList = [...PRListSection.matchAll(new RegExp(`- \\[([ x])] (${PULL_REQUEST_REGEX.source})`, 'g'))].map((match) => ({ url: match[2], number: Number.parseInt(match[3], 10), isVerified: match[1] === 'x', @@ -182,8 +187,8 @@ class GithubUtils { * * @private * - * @param {Object} issue - * @returns {Array} - [{URL: String, number: Number, isResolved: Boolean}] + * @param issue + * @returns - [{URL: String, number: Number, isResolved: Boolean}] */ static getStagingDeployCashDeployBlockers(issue) { let deployBlockerSection = issue.body.match(/Deploy Blockers:\*\*\r?\n((?:-.*\r?\n)+)/) || []; @@ -191,7 +196,7 @@ class GithubUtils { return []; } deployBlockerSection = deployBlockerSection[1]; - const deployBlockers = _.map([...deployBlockerSection.matchAll(new RegExp(`- \\[([ x])]\\s(${ISSUE_OR_PULL_REQUEST_REGEX.source})`, 'g'))], (match) => ({ + const deployBlockers = [...deployBlockerSection.matchAll(new RegExp(`- \\[([ x])]\\s(${ISSUE_OR_PULL_REQUEST_REGEX.source})`, 'g'))].map((match) => ({ url: match[2], number: Number.parseInt(match[3], 10), isResolved: match[1] === 'x', @@ -204,8 +209,8 @@ class GithubUtils { * * @private * - * @param {Object} issue - * @returns {Array} - [{URL: String, number: Number, isResolved: Boolean}] + * @param issue + * @returns - [{URL: String, number: Number, isResolved: Boolean}] */ static getStagingDeployCashInternalQA(issue) { let internalQASection = issue.body.match(/Internal QA:\*\*\r?\n((?:- \[[ x]].*\r?\n)+)/) || []; @@ -213,7 +218,7 @@ class GithubUtils { return []; } internalQASection = internalQASection[1]; - const internalQAPRs = _.map([...internalQASection.matchAll(new RegExp(`- \\[([ x])]\\s(${PULL_REQUEST_REGEX.source})`, 'g'))], (match) => ({ + const internalQAPRs = [...internalQASection.matchAll(new RegExp(`- \\[([ x])]\\s(${PULL_REQUEST_REGEX.source})`, 'g'))].map((match) => ({ url: match[2].split('-')[0].trim(), number: Number.parseInt(match[3], 10), isResolved: match[1] === 'x', @@ -224,54 +229,52 @@ class GithubUtils { /** * Generate the issue body for a StagingDeployCash. * - * @param {String} tag - * @param {Array} PRList - The list of PR URLs which are included in this StagingDeployCash - * @param {Array} [verifiedPRList] - The list of PR URLs which have passed QA. - * @param {Array} [deployBlockers] - The list of DeployBlocker URLs. - * @param {Array} [resolvedDeployBlockers] - The list of DeployBlockers URLs which have been resolved. - * @param {Array} [resolvedInternalQAPRs] - The list of Internal QA PR URLs which have been resolved. - * @param {Boolean} [isTimingDashboardChecked] - * @param {Boolean} [isFirebaseChecked] - * @param {Boolean} [isGHStatusChecked] - * @returns {Promise} + * @param tag + * @param PRList - The list of PR URLs which are included in this StagingDeployCash + * @param [verifiedPRList] - The list of PR URLs which have passed QA. + * @param [deployBlockers] - The list of DeployBlocker URLs. + * @param [resolvedDeployBlockers] - The list of DeployBlockers URLs which have been resolved. + * @param [resolvedInternalQAPRs] - The list of Internal QA PR URLs which have been resolved. + * @param [isTimingDashboardChecked] + * @param [isFirebaseChecked] + * @param [isGHStatusChecked] + * @returns */ static generateStagingDeployCashBody( - tag, - PRList, - verifiedPRList = [], - deployBlockers = [], - resolvedDeployBlockers = [], - resolvedInternalQAPRs = [], + tag: string, + PRList: string[], + verifiedPRList: string[] = [], + deployBlockers: string[] = [], + resolvedDeployBlockers: string[] = [], + resolvedInternalQAPRs: string[] = [], isTimingDashboardChecked = false, isFirebaseChecked = false, isGHStatusChecked = false, ) { - return this.fetchAllPullRequests(_.map(PRList, this.getPullRequestNumberFromURL)) + return this.fetchAllPullRequests(PRList.map(this.getPullRequestNumberFromURL)) .then((data) => { // The format of this map is following: // { // 'https://github.com/Expensify/App/pull/9641': 'PauloGasparSv', // 'https://github.com/Expensify/App/pull/9642': 'mountiny' // } - const internalQAPRMap = _.reduce( - _.filter(data, (pr) => !_.isEmpty(_.findWhere(pr.labels, {name: CONST.LABELS.INTERNAL_QA}))), - (map, pr) => { + const internalQAPRMap = data + .filter((pr) => !isEmptyObject(_.findWhere(pr.labels, {name: CONST.LABELS.INTERNAL_QA}))) + .reduce((map, pr) => { // eslint-disable-next-line no-param-reassign map[pr.html_url] = pr.merged_by.login; return map; - }, - {}, - ); + }, {}); console.log('Found the following Internal QA PRs:', internalQAPRMap); const noQAPRs = _.pluck( - _.filter(data, (PR) => /\[No\s?QA]/i.test(PR.title)), + data.filter((PR) => /\[No\s?QA]/i.test(PR.title)), 'html_url', ); console.log('Found the following NO QA PRs:', noQAPRs); const verifiedOrNoQAPRs = _.union(verifiedPRList, noQAPRs); - const sortedPRList = _.chain(PRList).difference(_.keys(internalQAPRMap)).unique().sortBy(GithubUtils.getPullRequestNumberFromURL).value(); + const sortedPRList = _.chain(PRList).difference(Object.keys(internalQAPRMap)).unique().sortBy(GithubUtils.getPullRequestNumberFromURL).value(); const sortedDeployBlockers = _.sortBy(_.unique(deployBlockers), GithubUtils.getIssueOrPullRequestNumberFromURL); // Tag version and comparison URL @@ -279,22 +282,22 @@ class GithubUtils { let issueBody = `**Release Version:** \`${tag}\`\r\n**Compare Changes:** https://github.com/Expensify/App/compare/production...staging\r\n`; // PR list - if (!_.isEmpty(sortedPRList)) { + if (!isEmptyObject(sortedPRList)) { issueBody += '\r\n**This release contains changes from the following pull requests:**\r\n'; - _.each(sortedPRList, (URL) => { - issueBody += _.contains(verifiedOrNoQAPRs, URL) ? '- [x]' : '- [ ]'; + sortedPRList.forEach((URL) => { + issueBody += verifiedOrNoQAPRs.includes(URL) ? '- [x]' : '- [ ]'; issueBody += ` ${URL}\r\n`; }); issueBody += '\r\n\r\n'; } // Internal QA PR list - if (!_.isEmpty(internalQAPRMap)) { + if (!isEmptyObject(internalQAPRMap)) { console.log('Found the following verified Internal QA PRs:', resolvedInternalQAPRs); issueBody += '**Internal QA:**\r\n'; - _.each(internalQAPRMap, (merger, URL) => { + internalQAPRMap.each((merger, URL) => { const mergerMention = `@${merger}`; - issueBody += `${_.contains(resolvedInternalQAPRs, URL) ? '- [x]' : '- [ ]'} `; + issueBody += `${resolvedInternalQAPRs.includes(URL) ? '- [x]' : '- [ ]'} `; issueBody += `${URL}`; issueBody += ` - ${mergerMention}`; issueBody += '\r\n'; @@ -303,10 +306,10 @@ class GithubUtils { } // Deploy blockers - if (!_.isEmpty(deployBlockers)) { + if (!isEmptyObject(deployBlockers)) { issueBody += '**Deploy Blockers:**\r\n'; - _.each(sortedDeployBlockers, (URL) => { - issueBody += _.contains(resolvedDeployBlockers, URL) ? '- [x] ' : '- [ ] '; + sortedDeployBlockers.forEach((URL) => { + issueBody += resolvedDeployBlockers.includes(URL) ? '- [x] ' : '- [ ] '; issueBody += URL; issueBody += '\r\n'; }); @@ -326,7 +329,7 @@ class GithubUtils { issueBody += `\r\n- [${isGHStatusChecked ? 'x' : ' '}] I checked [GitHub Status](https://www.githubstatus.com/) and verified there is no reported incident with Actions.`; issueBody += '\r\n\r\ncc @Expensify/applauseleads\r\n'; - const issueAssignees = _.values(internalQAPRMap); + const issueAssignees = Object.values(internalQAPRMap); const issue = {issueBody, issueAssignees}; return issue; }) @@ -335,12 +338,9 @@ class GithubUtils { /** * Fetch all pull requests given a list of PR numbers. - * - * @param {Array} pullRequestNumbers - * @returns {Promise} */ - static fetchAllPullRequests(pullRequestNumbers) { - const oldestPR = _.first(_.sortBy(pullRequestNumbers)); + static fetchAllPullRequests(pullRequestNumbers: number[]) { + const oldestPR = _.sortBy(pullRequestNumbers)[0]; return this.paginate( this.octokit.pulls.list, { @@ -352,19 +352,19 @@ class GithubUtils { per_page: 100, }, ({data}, done) => { - if (_.find(data, (pr) => pr.number === oldestPR)) { + if (data.find((pr) => pr.number === oldestPR)) { done(); } return data; }, ) - .then((prList) => _.filter(prList, (pr) => _.contains(pullRequestNumbers, pr.number))) + .then((prList) => prList.filter((pr) => pullRequestNumbers.includes(pr.number))) .catch((err) => console.error('Failed to get PR list', err)); } /** - * @param {Number} pullRequestNumber - * @returns {Promise} + * @param pullRequestNumber + * @returns */ static getPullRequestBody(pullRequestNumber) { return this.octokit.pulls @@ -377,8 +377,8 @@ class GithubUtils { } /** - * @param {Number} pullRequestNumber - * @returns {Promise} + * @param pullRequestNumber + * @returns */ static getAllReviewComments(pullRequestNumber) { return this.paginate( @@ -389,13 +389,13 @@ class GithubUtils { pull_number: pullRequestNumber, per_page: 100, }, - (response) => _.map(response.data, (review) => review.body), + (response) => response.data.map((review) => review.body), ); } /** - * @param {Number} issueNumber - * @returns {Promise} + * @param issueNumber + * @returns */ static getAllComments(issueNumber) { return this.paginate( @@ -406,17 +406,17 @@ class GithubUtils { issue_number: issueNumber, per_page: 100, }, - (response) => _.map(response.data, (comment) => comment.body), + (response) => response.data.map((comment) => comment.body), ); } /** * Create comment on pull request * - * @param {String} repo - The repo to search for a matching pull request or issue number - * @param {Number} number - The pull request or issue number - * @param {String} messageBody - The comment message - * @returns {Promise} + * @param repo - The repo to search for a matching pull request or issue number + * @param number - The pull request or issue number + * @param messageBody - The comment message + * @returns */ static createComment(repo, number, messageBody) { console.log(`Writing comment on #${number}`); @@ -431,50 +431,53 @@ class GithubUtils { /** * Get the most recent workflow run for the given New Expensify workflow. * - * @param {String} workflow - * @returns {Promise} + * @param workflow + * @returns */ static getLatestWorkflowRunID(workflow) { console.log(`Fetching New Expensify workflow runs for ${workflow}...`); - return this.octokit.actions - .listWorkflowRuns({ - owner: CONST.GITHUB_OWNER, - repo: CONST.APP_REPO, - workflow_id: workflow, - }) - .then((response) => lodashGet(response, 'data.workflow_runs[0].id')); + return ( + this.octokit.actions + .listWorkflowRuns({ + owner: CONST.GITHUB_OWNER, + repo: CONST.APP_REPO, + workflow_id: workflow, + }) + // .then((response) => lodashGet(response, 'data.workflow_runs[0].id')); + .then((response) => response.data.workflow_runs[0].id) + ); } /** * Generate the well-formatted body of a production release. * - * @param {Array} pullRequests - * @returns {String} + * @param pullRequests + * @returns */ static getReleaseBody(pullRequests) { - return _.map(pullRequests, (number) => `- ${this.getPullRequestURLFromNumber(number)}`).join('\r\n'); + return pullRequests.map((number) => `- ${this.getPullRequestURLFromNumber(number)}`).join('\r\n'); } /** * Generate the URL of an New Expensify pull request given the PR number. * - * @param {Number} number - * @returns {String} + * @param number + * @returns */ - static getPullRequestURLFromNumber(number) { - return `${CONST.APP_REPO_URL}/pull/${number}`; + static getPullRequestURLFromNumber(value: number): string { + return `${CONST.APP_REPO_URL}/pull/${value}`; } /** * Parse the pull request number from a URL. * - * @param {String} URL - * @returns {Number} + * @param URL + * @returns * @throws {Error} If the URL is not a valid Github Pull Request. */ - static getPullRequestNumberFromURL(URL) { + static getPullRequestNumberFromURL(URL: string): number { const matches = URL.match(PULL_REQUEST_REGEX); - if (!_.isArray(matches) || matches.length !== 2) { + if (!Array.isArray(matches) || matches.length !== 2) { throw new Error(`Provided URL ${URL} is not a Github Pull Request!`); } return Number.parseInt(matches[1], 10); @@ -483,13 +486,13 @@ class GithubUtils { /** * Parse the issue number from a URL. * - * @param {String} URL - * @returns {Number} + * @param URL + * @returns * @throws {Error} If the URL is not a valid Github Issue. */ static getIssueNumberFromURL(URL) { const matches = URL.match(ISSUE_REGEX); - if (!_.isArray(matches) || matches.length !== 2) { + if (!Array.isArray(matches) || matches.length !== 2) { throw new Error(`Provided URL ${URL} is not a Github Issue!`); } return Number.parseInt(matches[1], 10); @@ -498,13 +501,13 @@ class GithubUtils { /** * Parse the issue or pull request number from a URL. * - * @param {String} URL - * @returns {Number} + * @param URL + * @returns * @throws {Error} If the URL is not a valid Github Issue or Pull Request. */ static getIssueOrPullRequestNumberFromURL(URL) { const matches = URL.match(ISSUE_OR_PULL_REQUEST_REGEX); - if (!_.isArray(matches) || matches.length !== 2) { + if (!Array.isArray(matches) || matches.length !== 2) { throw new Error(`Provided URL ${URL} is not a valid Github Issue or Pull Request!`); } return Number.parseInt(matches[1], 10); @@ -513,18 +516,21 @@ class GithubUtils { /** * Return the login of the actor who closed an issue or PR. If the issue is not closed, return an empty string. * - * @param {Number} issueNumber - * @returns {Promise} + * @param issueNumber + * @returns */ static getActorWhoClosedIssue(issueNumber) { - return this.paginate(this.octokit.issues.listEvents, { - owner: CONST.GITHUB_OWNER, - repo: CONST.APP_REPO, - issue_number: issueNumber, - per_page: 100, - }) - .then((events) => _.filter(events, (event) => event.event === 'closed')) - .then((closedEvents) => lodashGet(_.last(closedEvents), 'actor.login', '')); + return ( + this.paginate(this.octokit.issues.listEvents, { + owner: CONST.GITHUB_OWNER, + repo: CONST.APP_REPO, + issue_number: issueNumber, + per_page: 100, + }) + .then((events) => events.filter((event) => event.event === 'closed')) + // .then((closedEvents) => lodashGet(_.last(closedEvents), 'actor.login', '')); + .then((closedEvents) => _.last(closedEvents).actor.login ?? '') + ); } static getArtifactByName(artefactName) { @@ -536,6 +542,5 @@ class GithubUtils { } } -module.exports = GithubUtils; -module.exports.ISSUE_OR_PULL_REQUEST_REGEX = ISSUE_OR_PULL_REQUEST_REGEX; -module.exports.POLL_RATE = POLL_RATE; +export default GithubUtils; +export {ISSUE_OR_PULL_REQUEST_REGEX, POLL_RATE}; From 50d4ce0ccb5e1e3491c70017d8f51747df216dfb Mon Sep 17 00:00:00 2001 From: VickyStash Date: Mon, 11 Mar 2024 18:19:17 +0100 Subject: [PATCH 224/931] [TS migration] Migrate 'lockDeploys.test.js' workflow test --- ...ockDeploys.test.js => lockDeploys.test.ts} | 66 +++++++++++-------- 1 file changed, 39 insertions(+), 27 deletions(-) rename workflow_tests/{lockDeploys.test.js => lockDeploys.test.ts} (88%) diff --git a/workflow_tests/lockDeploys.test.js b/workflow_tests/lockDeploys.test.ts similarity index 88% rename from workflow_tests/lockDeploys.test.js rename to workflow_tests/lockDeploys.test.ts index a57ed8847fd3..b72db2c3bb85 100644 --- a/workflow_tests/lockDeploys.test.js +++ b/workflow_tests/lockDeploys.test.ts @@ -1,13 +1,15 @@ -const path = require('path'); -const kieMockGithub = require('@kie/mock-github'); -const utils = require('./utils/utils'); -const assertions = require('./assertions/lockDeploysAssertions'); -const mocks = require('./mocks/lockDeploysMocks'); -const eAct = require('./utils/ExtendedAct'); +import type {MockStep} from '@kie/act-js/build/src/step-mocker/step-mocker.types'; +import * as kieMockGithub from '@kie/mock-github'; +import type {CreateRepositoryFile, MockGithub} from '@kie/mock-github'; +import path from 'path'; +import assertions from './assertions/lockDeploysAssertions'; +import mocks from './mocks/lockDeploysMocks'; +import eAct from './utils/ExtendedAct'; +import utils from './utils/utils'; jest.setTimeout(90 * 1000); -let mockGithub; -const FILES_TO_COPY_INTO_TEST_REPO = [ +let mockGithub: MockGithub; +const FILES_TO_COPY_INTO_TEST_REPO: CreateRepositoryFile[] = [ ...utils.deepCopy(utils.FILES_TO_COPY_INTO_TEST_REPO), { src: path.resolve(__dirname, '..', '.github', 'workflows', 'lockDeploys.yml'), @@ -16,7 +18,7 @@ const FILES_TO_COPY_INTO_TEST_REPO = [ ]; describe('test workflow lockDeploys', () => { - beforeAll(async () => { + beforeAll(() => { // in case of the tests being interrupted without cleanup the mock repo directory may be left behind // which breaks the next test run, this removes any possible leftovers utils.removeMockRepoDir(); @@ -43,11 +45,12 @@ describe('test workflow lockDeploys', () => { describe('issue has StagingDeployCash', () => { describe('actor is not OSBotify', () => { it('job triggered, comment left in StagingDeployCash', async () => { - const repoPath = mockGithub.repo.getPath('testLockDeploysWorkflowRepo') || ''; + const repoPath = mockGithub.repo.getPath('testLockDeploysWorkflowRepo') ?? ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'lockDeploys.yml'); let act = new eAct.ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams( act, + // @ts-expect-error TODO: Remove this once utils (https://github.com/Expensify/App/issues/32061) is migrated to TypeScript. 'issues', { action: 'labeled', @@ -71,7 +74,7 @@ describe('test workflow lockDeploys', () => { }, workflowPath, ); - const testMockSteps = { + const testMockSteps: MockStep = { lockStagingDeploys: mocks.LOCKDEPLOYS__LOCKSTAGINGDEPLOYS__STEP_MOCKS, }; const result = await act.runEvent('issues', { @@ -85,11 +88,12 @@ describe('test workflow lockDeploys', () => { }); it('one step fails, comment not left in StagingDeployCash, announced failure in Slack', async () => { - const repoPath = mockGithub.repo.getPath('testLockDeploysWorkflowRepo') || ''; + const repoPath = mockGithub.repo.getPath('testLockDeploysWorkflowRepo') ?? ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'lockDeploys.yml'); let act = new eAct.ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams( act, + // @ts-expect-error TODO: Remove this once utils (https://github.com/Expensify/App/issues/32061) is migrated to TypeScript. 'issues', { action: 'labeled', @@ -113,12 +117,13 @@ describe('test workflow lockDeploys', () => { }, workflowPath, ); - const testMockSteps = { + const testMockSteps: MockStep = { lockStagingDeploys: mocks.LOCKDEPLOYS__LOCKSTAGINGDEPLOYS__STEP_MOCKS, }; testMockSteps.lockStagingDeploys[1] = utils.createMockStep( 'Wait for staging deploys to finish', 'Waiting for staging deploys to finish', + // @ts-expect-error TODO: Remove this once utils (https://github.com/Expensify/App/issues/32061) is migrated to TypeScript. 'LOCKSTAGINGDEPLOYS', ['GITHUB_TOKEN'], [], @@ -139,11 +144,12 @@ describe('test workflow lockDeploys', () => { describe('actor is OSBotify', () => { it('job not triggered, comment not left in StagingDeployCash', async () => { - const repoPath = mockGithub.repo.getPath('testLockDeploysWorkflowRepo') || ''; + const repoPath = mockGithub.repo.getPath('testLockDeploysWorkflowRepo') ?? ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'lockDeploys.yml'); let act = new eAct.ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams( act, + // @ts-expect-error TODO: Remove this once utils (https://github.com/Expensify/App/issues/32061) is migrated to TypeScript. 'issues', { action: 'labeled', @@ -167,7 +173,7 @@ describe('test workflow lockDeploys', () => { }, workflowPath, ); - const testMockSteps = { + const testMockSteps: MockStep = { lockStagingDeploys: mocks.LOCKDEPLOYS__LOCKSTAGINGDEPLOYS__STEP_MOCKS, }; const result = await act.runEvent('issues', { @@ -185,11 +191,12 @@ describe('test workflow lockDeploys', () => { describe('issue does not have StagingDeployCash', () => { describe('actor is not OSBotify', () => { it('job not triggered, comment not left in StagingDeployCash', async () => { - const repoPath = mockGithub.repo.getPath('testLockDeploysWorkflowRepo') || ''; + const repoPath = mockGithub.repo.getPath('testLockDeploysWorkflowRepo') ?? ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'lockDeploys.yml'); let act = new eAct.ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams( act, + // @ts-expect-error TODO: Remove this once utils (https://github.com/Expensify/App/issues/32061) is migrated to TypeScript. 'issues', { action: 'labeled', @@ -213,7 +220,7 @@ describe('test workflow lockDeploys', () => { }, workflowPath, ); - const testMockSteps = { + const testMockSteps: MockStep = { lockStagingDeploys: mocks.LOCKDEPLOYS__LOCKSTAGINGDEPLOYS__STEP_MOCKS, }; const result = await act.runEvent('issues', { @@ -229,11 +236,12 @@ describe('test workflow lockDeploys', () => { describe('actor is OSBotify', () => { it('job not triggered, comment not left in StagingDeployCash', async () => { - const repoPath = mockGithub.repo.getPath('testLockDeploysWorkflowRepo') || ''; + const repoPath = mockGithub.repo.getPath('testLockDeploysWorkflowRepo') ?? ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'lockDeploys.yml'); let act = new eAct.ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams( act, + // @ts-expect-error TODO: Remove this once utils (https://github.com/Expensify/App/issues/32061) is migrated to TypeScript. 'issues', { action: 'labeled', @@ -257,7 +265,7 @@ describe('test workflow lockDeploys', () => { }, workflowPath, ); - const testMockSteps = { + const testMockSteps: MockStep = { lockStagingDeploys: mocks.LOCKDEPLOYS__LOCKSTAGINGDEPLOYS__STEP_MOCKS, }; const result = await act.runEvent('issues', { @@ -277,11 +285,12 @@ describe('test workflow lockDeploys', () => { describe('issue has StagingDeployCash', () => { describe('actor is not OSBotify', () => { it('job not triggered, comment not left in StagingDeployCash', async () => { - const repoPath = mockGithub.repo.getPath('testLockDeploysWorkflowRepo') || ''; + const repoPath = mockGithub.repo.getPath('testLockDeploysWorkflowRepo') ?? ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'lockDeploys.yml'); let act = new eAct.ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams( act, + // @ts-expect-error TODO: Remove this once utils (https://github.com/Expensify/App/issues/32061) is migrated to TypeScript. 'issues', { action: 'labeled', @@ -305,7 +314,7 @@ describe('test workflow lockDeploys', () => { }, workflowPath, ); - const testMockSteps = { + const testMockSteps: MockStep = { lockStagingDeploys: mocks.LOCKDEPLOYS__LOCKSTAGINGDEPLOYS__STEP_MOCKS, }; const result = await act.runEvent('issues', { @@ -321,11 +330,12 @@ describe('test workflow lockDeploys', () => { describe('actor is OSBotify', () => { it('job not triggered, comment not left in StagingDeployCash', async () => { - const repoPath = mockGithub.repo.getPath('testLockDeploysWorkflowRepo') || ''; + const repoPath = mockGithub.repo.getPath('testLockDeploysWorkflowRepo') ?? ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'lockDeploys.yml'); let act = new eAct.ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams( act, + // @ts-expect-error TODO: Remove this once utils (https://github.com/Expensify/App/issues/32061) is migrated to TypeScript. 'issues', { action: 'labeled', @@ -349,7 +359,7 @@ describe('test workflow lockDeploys', () => { }, workflowPath, ); - const testMockSteps = { + const testMockSteps: MockStep = { lockStagingDeploys: mocks.LOCKDEPLOYS__LOCKSTAGINGDEPLOYS__STEP_MOCKS, }; const result = await act.runEvent('issues', { @@ -367,11 +377,12 @@ describe('test workflow lockDeploys', () => { describe('issue does not have StagingDeployCash', () => { describe('actor is not OSBotify', () => { it('job not triggered, comment not left in StagingDeployCash', async () => { - const repoPath = mockGithub.repo.getPath('testLockDeploysWorkflowRepo') || ''; + const repoPath = mockGithub.repo.getPath('testLockDeploysWorkflowRepo') ?? ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'lockDeploys.yml'); let act = new eAct.ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams( act, + // @ts-expect-error TODO: Remove this once utils (https://github.com/Expensify/App/issues/32061) is migrated to TypeScript. 'issues', { action: 'labeled', @@ -395,7 +406,7 @@ describe('test workflow lockDeploys', () => { }, workflowPath, ); - const testMockSteps = { + const testMockSteps: MockStep = { lockStagingDeploys: mocks.LOCKDEPLOYS__LOCKSTAGINGDEPLOYS__STEP_MOCKS, }; const result = await act.runEvent('issues', { @@ -411,11 +422,12 @@ describe('test workflow lockDeploys', () => { describe('actor is OSBotify', () => { it('job not triggered, comment not left in StagingDeployCash', async () => { - const repoPath = mockGithub.repo.getPath('testLockDeploysWorkflowRepo') || ''; + const repoPath = mockGithub.repo.getPath('testLockDeploysWorkflowRepo') ?? ''; const workflowPath = path.join(repoPath, '.github', 'workflows', 'lockDeploys.yml'); let act = new eAct.ExtendedAct(repoPath, workflowPath); act = utils.setUpActParams( act, + // @ts-expect-error TODO: Remove this once utils (https://github.com/Expensify/App/issues/32061) is migrated to TypeScript. 'issues', { action: 'labeled', @@ -439,7 +451,7 @@ describe('test workflow lockDeploys', () => { }, workflowPath, ); - const testMockSteps = { + const testMockSteps: MockStep = { lockStagingDeploys: mocks.LOCKDEPLOYS__LOCKSTAGINGDEPLOYS__STEP_MOCKS, }; const result = await act.runEvent('issues', { From 7c1cf629aa902962e3f738c9f84669135c03afac Mon Sep 17 00:00:00 2001 From: FitseTLT Date: Mon, 11 Mar 2024 20:55:23 +0300 Subject: [PATCH 225/931] fix typescript --- src/pages/TransactionReceiptPage.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/TransactionReceiptPage.tsx b/src/pages/TransactionReceiptPage.tsx index 8db9e05a5139..f6f2c90e5d2c 100644 --- a/src/pages/TransactionReceiptPage.tsx +++ b/src/pages/TransactionReceiptPage.tsx @@ -28,7 +28,7 @@ type TransactionReceiptProps = TransactionReceiptOnyxProps & StackScreenProps Date: Tue, 12 Mar 2024 00:44:10 +0100 Subject: [PATCH 226/931] Fixes --- src/CONST.ts | 1 + src/ONYXKEYS.ts | 4 +- .../LHNOptionsList/OptionRowLHN.tsx | 2 +- src/libs/GroupChatUtils.ts | 21 +--- src/libs/ReportUtils.ts | 113 ++++-------------- src/libs/SidebarUtils.ts | 5 +- src/libs/actions/IOU.ts | 2 +- src/libs/actions/Report.ts | 30 ++--- src/pages/NewChatConfirmPage.tsx | 64 +++++----- src/pages/NewChatPage.tsx | 28 ++--- src/pages/home/HeaderView.tsx | 4 +- .../settings/Report/ReportSettingsPage.tsx | 2 +- src/types/onyx/NewGroupChat.ts | 6 - src/types/onyx/NewGroupChatDraft.ts | 6 + src/types/onyx/index.ts | 4 +- 15 files changed, 98 insertions(+), 194 deletions(-) delete mode 100644 src/types/onyx/NewGroupChat.ts create mode 100644 src/types/onyx/NewGroupChatDraft.ts diff --git a/src/CONST.ts b/src/CONST.ts index 9228a83de21e..cfbf50262ba9 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -1376,6 +1376,7 @@ const CONST = { ADMIN: 'admin', AUDITOR: 'auditor', USER: 'user', + MEMBER: 'member', }, AUTO_REPORTING_FREQUENCIES: { INSTANT: 'instant', diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index b2f1facea713..61e6e9366e5d 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -278,7 +278,7 @@ const ONYXKEYS = { SHOULD_STORE_LOGS: 'shouldStoreLogs', /** Stores new group chat draft */ - NEW_GROUP: 'newGroupChat', + NEW_GROUP_CHAT_DRAFT: 'newGroupChatDraft', // Paths of PDF file that has been cached during one session CACHED_PDF_PATHS: 'cachedPDFPaths', @@ -508,7 +508,7 @@ type OnyxValuesMapping = { [ONYXKEYS.IOU]: OnyxTypes.IOU; [ONYXKEYS.MODAL]: OnyxTypes.Modal; [ONYXKEYS.NETWORK]: OnyxTypes.Network; - [ONYXKEYS.NEW_GROUP]: OnyxTypes.NewGroupChat; + [ONYXKEYS.NEW_GROUP_CHAT_DRAFT]: OnyxTypes.NewGroupChatDraft; [ONYXKEYS.CUSTOM_STATUS_DRAFT]: OnyxTypes.CustomStatusDraft; [ONYXKEYS.INPUT_FOCUSED]: boolean; [ONYXKEYS.PERSONAL_DETAILS_LIST]: OnyxTypes.PersonalDetailsList; diff --git a/src/components/LHNOptionsList/OptionRowLHN.tsx b/src/components/LHNOptionsList/OptionRowLHN.tsx index 923337ba9ada..a27424ceb392 100644 --- a/src/components/LHNOptionsList/OptionRowLHN.tsx +++ b/src/components/LHNOptionsList/OptionRowLHN.tsx @@ -116,7 +116,7 @@ function OptionRowLHN({reportID, isFocused = false, onSelectRow = () => {}, opti const isStatusVisible = !!emojiCode && ReportUtils.isOneOnOneChat(!isEmptyObject(report) ? report : null); const isGroupChat = optionItem.type === CONST.REPORT.TYPE.CHAT && !optionItem.chatType && !optionItem.isThread && (optionItem.displayNamesWithTooltips?.length ?? 0) > 2; - const fullTitle = isGroupChat ? getGroupChatName(!isEmptyObject(report) ? report : null) : optionItem.text; + const fullTitle = isGroupChat ? getGroupChatName(!isEmptyObject(report) && report.participantAccountIDs ? report.participantAccountIDs : []) : optionItem.text; const subscriptAvatarBorderColor = isFocused ? focusedBackgroundColor : theme.sidebar; return ( diff --git a/src/libs/GroupChatUtils.ts b/src/libs/GroupChatUtils.ts index d694099989a6..8c64100df153 100644 --- a/src/libs/GroupChatUtils.ts +++ b/src/libs/GroupChatUtils.ts @@ -1,27 +1,11 @@ -import type {OnyxEntry} from 'react-native-onyx'; -import type {Report} from '@src/types/onyx'; import localeCompare from './LocaleCompare'; -import type {OptionData} from './ReportUtils'; import * as ReportUtils from './ReportUtils'; -/** - * Returns the group chat name for confirm page - */ -function getGroupChatConfirmName(participants: OptionData[]): string | undefined { - const isMultipleParticipantReport = participants.length > 1; - - return participants - .map((participant) => ReportUtils.getDisplayNameForParticipant(participant.accountID ?? undefined, isMultipleParticipantReport)) - .sort((first, second) => localeCompare(first ?? '', second ?? '')) - .filter(Boolean) - .join(', '); -} - /** * Returns the report name if the report is a group chat */ -function getGroupChatName(report: OnyxEntry): string | undefined { - const participants = report?.participantAccountIDs ?? []; +function getGroupChatName(participantAccountIDs: number[]): string | undefined { + const participants = participantAccountIDs ?? []; const isMultipleParticipantReport = participants.length > 1; return participants @@ -34,5 +18,4 @@ function getGroupChatName(report: OnyxEntry): string | undefined { export { // eslint-disable-next-line import/prefer-default-export getGroupChatName, - getGroupChatConfirmName, }; diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 7715917cee9e..63cf6269b09e 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -46,7 +46,7 @@ import type { ReimbursementDeQueuedMessage, } from '@src/types/onyx/OriginalMessage'; import type {Status} from '@src/types/onyx/PersonalDetails'; -import type {NotificationPreference, Participants, PendingChatMember} from '@src/types/onyx/Report'; +import type {NotificationPreference, Participants, PendingChatMember, Participant as ReportParticipant} from '@src/types/onyx/Report'; import type {Message, ReportActionBase, ReportActions} from '@src/types/onyx/ReportAction'; import type {Receipt, TransactionChanges, WaypointCollection} from '@src/types/onyx/Transaction'; import type {EmptyObject} from '@src/types/utils/EmptyObject'; @@ -244,6 +244,7 @@ type OptimisticChatReport = Pick< | 'pendingFields' | 'parentReportActionID' | 'parentReportID' + | 'participants' | 'participantAccountIDs' | 'visibleChatMemberAccountIDs' | 'policyID' @@ -258,39 +259,6 @@ type OptimisticChatReport = Pick< isOptimisticReport: true; }; -type OptimisticGroupChatReport = Pick< - Report, - | 'type' - | 'chatType' - | 'chatReportID' - | 'iouReportID' - | 'isOwnPolicyExpenseChat' - | 'isPinned' - | 'lastActorAccountID' - | 'lastMessageTranslationKey' - | 'lastMessageHtml' - | 'lastMessageText' - | 'lastReadTime' - | 'lastVisibleActionCreated' - | 'notificationPreference' - | 'oldPolicyName' - | 'ownerAccountID' - | 'pendingFields' - | 'parentReportActionID' - | 'parentReportID' - | 'participants' - | 'policyID' - | 'reportID' - | 'reportName' - | 'stateNum' - | 'statusNum' - | 'visibility' - | 'description' - | 'writeCapability' -> & { - isOptimisticReport: true; -}; - type OptimisticTaskReportAction = Pick< ReportAction, | 'reportActionID' @@ -957,7 +925,7 @@ function isSelfDM(report: OnyxEntry): boolean { return getChatType(report) === CONST.REPORT.CHAT_TYPE.SELF_DM; } -function isGroupChatType(report: OnyxEntry): boolean { +function isGroupChat(report: OnyxEntry): boolean { return getChatType(report) === CONST.REPORT.CHAT_TYPE.GROUP_CHAT; } @@ -3575,6 +3543,16 @@ function buildOptimisticChatReport( parentReportID = '', description = '', ): OptimisticChatReport { + const participants: Participants = participantList.reduce((acc: Participants, accountID: number) => { + const participant: ReportParticipant = { + hidden: false, + role: accountID === currentUserAccountID ? CONST.POLICY.ROLE.ADMIN : CONST.POLICY.ROLE.MEMBER, + }; + // eslint-disable-next-line @typescript-eslint/no-unsafe-return + return {...acc, [accountID]: participant}; + }, {} as Participants); + const isGroup = chatType === CONST.REPORT.CHAT_TYPE.GROUP_CHAT; + const currentNotificationPreference = isGroup ? CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN : notificationPreference; const currentTime = DateUtils.getDBTime(); const isNewlyCreatedWorkspaceChat = chatType === CONST.REPORT.CHAT_TYPE.POLICY_EXPENSE_CHAT && isOwnPolicyExpenseChat; return { @@ -3589,64 +3567,16 @@ function buildOptimisticChatReport( lastMessageText: undefined, lastReadTime: currentTime, lastVisibleActionCreated: currentTime, - notificationPreference, + notificationPreference: currentNotificationPreference, oldPolicyName, ownerAccountID: ownerAccountID || CONST.REPORT.OWNER_ACCOUNT_ID_FAKE, parentReportActionID, parentReportID, // When creating a report the participantsAccountIDs and visibleChatMemberAccountIDs are the same - participantAccountIDs: participantList, - visibleChatMemberAccountIDs: participantList, - policyID, - reportID: generateReportID(), - reportName, - stateNum: 0, - statusNum: 0, - visibility, - description, - writeCapability, - }; -} - -/** - * Builds an optimistic group chat report with a randomly generated reportID and as much information as we currently have - */ -function buildOptimisticGroupChatReport( - participantList: Participants, - reportName: string = CONST.REPORT.DEFAULT_REPORT_NAME, - chatType: ValueOf | undefined = undefined, - policyID: string = CONST.POLICY.OWNER_EMAIL_FAKE, - ownerAccountID: number = CONST.REPORT.OWNER_ACCOUNT_ID_FAKE, - isOwnPolicyExpenseChat = false, - oldPolicyName = '', - visibility: ValueOf | undefined = undefined, - writeCapability: ValueOf | undefined = undefined, - notificationPreference: NotificationPreference = CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS, - parentReportActionID = '', - parentReportID = '', - description = '', -): OptimisticGroupChatReport { - const currentTime = DateUtils.getDBTime(); - const isNewlyCreatedWorkspaceChat = chatType === CONST.REPORT.CHAT_TYPE.POLICY_EXPENSE_CHAT && isOwnPolicyExpenseChat; - return { - isOptimisticReport: true, - type: CONST.REPORT.TYPE.CHAT, - chatType, - isOwnPolicyExpenseChat, - isPinned: reportName === CONST.REPORT.WORKSPACE_CHAT_ROOMS.ADMINS || isNewlyCreatedWorkspaceChat, - lastActorAccountID: 0, - lastMessageTranslationKey: '', - lastMessageHtml: '', - lastMessageText: undefined, - lastReadTime: currentTime, - lastVisibleActionCreated: currentTime, - notificationPreference, - oldPolicyName, - ownerAccountID: ownerAccountID || CONST.REPORT.OWNER_ACCOUNT_ID_FAKE, - parentReportActionID, - parentReportID, - // For group chats we need to have participants object - participants: participantList, + participantAccountIDs: !isGroup ? participantList : undefined, + visibleChatMemberAccountIDs: !isGroup ? participantList : undefined, + // For group chats we need to have participants object as we are migrating away from `participantAccountIDs` and `visibleChatMemberAccountIDs`. See https://github.com/Expensify/App/issues/34692 + participants: isGroup ? participants : undefined, policyID, reportID: generateReportID(), reportName, @@ -5022,7 +4952,7 @@ function getIOUReportActionDisplayMessage(reportAction: OnyxEntry) * - More than 2 participants. * */ -function isGroupChat(report: OnyxEntry): boolean { +function isDeprecatedGroupDM(report: OnyxEntry): boolean { return Boolean( report && !isChatThread(report) && @@ -5364,7 +5294,6 @@ export { buildOptimisticWorkspaceChats, buildOptimisticTaskReport, buildOptimisticChatReport, - buildOptimisticGroupChatReport, buildOptimisticClosedReportAction, buildOptimisticCreatedReportAction, buildOptimisticRenamedRoomReportAction, @@ -5464,7 +5393,7 @@ export { hasMissingSmartscanFields, getIOUReportActionDisplayMessage, isWaitingForAssigneeToCompleteTask, - isGroupChat, + isDeprecatedGroupDM, isOpenExpenseReport, shouldUseFullTitleToDisplay, parseReportRouteParams, @@ -5506,7 +5435,7 @@ export { isJoinRequestInAdminRoom, canAddOrDeleteTransactions, shouldCreateNewMoneyRequestReport, - isGroupChatType, + isGroupChat, }; export type { diff --git a/src/libs/SidebarUtils.ts b/src/libs/SidebarUtils.ts index 71b3fd23a03c..012132ac124c 100644 --- a/src/libs/SidebarUtils.ts +++ b/src/libs/SidebarUtils.ts @@ -384,7 +384,10 @@ function getOptionData({ .join(' '); } - result.alternateText = ReportUtils.isGroupChat(report) && lastActorDisplayName ? `${lastActorDisplayName}: ${lastMessageText}` : lastMessageText || formattedLogin; + result.alternateText = + ReportUtils.isDeprecatedGroupDM(report) || (ReportUtils.isGroupChat(report) && lastActorDisplayName) + ? `${lastActorDisplayName}: ${lastMessageText}` + : lastMessageText || formattedLogin; } result.isIOUReportOwner = ReportUtils.isIOUOwnedByCurrentUser(result as Report); diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 40dcd18255bc..4b88bb7a77a8 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -1657,7 +1657,7 @@ function createSplitsAndOnyxData( const currentUserEmailForIOUSplit = PhoneNumber.addSMSDomainIfPhoneNumber(currentUserLogin); const participantAccountIDs = participants.map((participant) => Number(participant.accountID)); const existingSplitChatReport = - participants.length > 1 && (existingSplitChatReportID || participants[0].reportID) + existingSplitChatReportID || participants[0].reportID ? allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${existingSplitChatReportID || participants[0].reportID}`] : ReportUtils.getChatByParticipants(participantAccountIDs); const splitChatReport = existingSplitChatReport ?? ReportUtils.buildOptimisticChatReport(participantAccountIDs); diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 731d2b4f3f26..e2ca61f07fa6 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -71,7 +71,7 @@ import type {Route} from '@src/ROUTES'; import ROUTES from '@src/ROUTES'; import INPUT_IDS from '@src/types/form/NewRoomForm'; import type { - NewGroupChat, + NewGroupChatDraft, PersonalDetails, PersonalDetailsList, PolicyReportField, @@ -81,7 +81,7 @@ import type { ReportUserIsTyping, } from '@src/types/onyx'; import type {Decision, OriginalMessageIOU} from '@src/types/onyx/OriginalMessage'; -import type {NotificationPreference, Participant, Participants, RoomVisibility, WriteCapability} from '@src/types/onyx/Report'; +import type {NotificationPreference, RoomVisibility, WriteCapability} from '@src/types/onyx/Report'; import type Report from '@src/types/onyx/Report'; import type {Message, ReportActionBase, ReportActions} from '@src/types/onyx/ReportAction'; import type ReportAction from '@src/types/onyx/ReportAction'; @@ -244,14 +244,14 @@ Onyx.connect({ callback: (val) => (allRecentlyUsedReportFields = val), }); -let newGroupDraft: OnyxEntry; +let newGroupDraft: OnyxEntry; Onyx.connect({ - key: ONYXKEYS.NEW_GROUP, + key: ONYXKEYS.NEW_GROUP_CHAT_DRAFT, callback: (value) => (newGroupDraft = value), }); function clearGroupChat() { - Onyx.set(ONYXKEYS.NEW_GROUP, null); + Onyx.set(ONYXKEYS.NEW_GROUP_CHAT_DRAFT, null); } function startNewChat() { @@ -664,7 +664,7 @@ function openReport( if (newReportObject.chatType === CONST.REPORT.CHAT_TYPE.GROUP_CHAT) { parameters.chatType = CONST.REPORT.CHAT_TYPE.GROUP_CHAT; parameters.groupChatAdminLogins = currentUserEmail; - parameters.optimisticAccountIDList = participantAccountIDList ? participantAccountIDList.join(',') : ''; + parameters.optimisticAccountIDList = participantAccountIDList.join(','); parameters.reportName = newReportObject.reportName ?? ''; } @@ -808,23 +808,15 @@ function navigateToAndOpenReport(userLogins: string[], shouldDismissModal = true if (!newGroupDraft) { chat = ReportUtils.getChatByParticipants(participantAccountIDs); } - if (!chat) { + + if (isEmptyObject(chat)) { if (newGroupDraft) { - const participants: Participants = participantAccountIDs.reduce((acc: Participants, accountID: number) => { - const participant: Participant = { - hidden: false, - role: accountID === currentUserAccountID ? 'admin' : 'member', - }; - // eslint-disable-next-line @typescript-eslint/no-unsafe-return - return {...acc, [accountID]: participant}; - }, {} as Participants); - - newChat = ReportUtils.buildOptimisticGroupChatReport(participants, reportName, CONST.REPORT.CHAT_TYPE.GROUP_CHAT); + newChat = ReportUtils.buildOptimisticChatReport(participantAccountIDs, reportName, CONST.REPORT.CHAT_TYPE.GROUP_CHAT); } else { newChat = ReportUtils.buildOptimisticChatReport(participantAccountIDs); } } - const report = chat ?? newChat; + const report = isEmptyObject(chat) ? newChat : chat; // We want to pass newChat here because if anything is passed in that param (even an existing chat), we will try to create a chat on the server openReport(report.reportID, userLogins, newChat); @@ -3011,7 +3003,7 @@ function resolveActionableMentionWhisper(reportId: string, reportAction: OnyxEnt } function setGroupDraft(invitedUsersIDs: number[], reportName = '') { - Onyx.set(ONYXKEYS.NEW_GROUP, {selectedOptions: invitedUsersIDs, reportName}); + Onyx.merge(ONYXKEYS.NEW_GROUP_CHAT_DRAFT, {participantAccountIDs: invitedUsersIDs, reportName}); } export { diff --git a/src/pages/NewChatConfirmPage.tsx b/src/pages/NewChatConfirmPage.tsx index 7b09152e7815..905660d240ff 100644 --- a/src/pages/NewChatConfirmPage.tsx +++ b/src/pages/NewChatConfirmPage.tsx @@ -27,7 +27,7 @@ import type * as OnyxTypes from '@src/types/onyx'; type NewChatConfirmPageOnyxProps = { /** New group chat draft data */ - newGroupDraft: OnyxEntry; + newGroupDraft: OnyxEntry; /** All of the personal details for everyone */ allPersonalDetails: OnyxEntry; @@ -35,29 +35,34 @@ type NewChatConfirmPageOnyxProps = { type NewChatConfirmPageProps = NewChatConfirmPageOnyxProps; +type Section = ListItem & {value: string}; + function NewChatConfirmPage({newGroupDraft, allPersonalDetails}: NewChatConfirmPageProps) { const {translate} = useLocalize(); const StyleUtils = useStyleUtils(); const styles = useThemeStyles(); - const personalData = useCurrentUserPersonalDetails() || CONST.EMPTY_OBJECT; + const personalData = useCurrentUserPersonalDetails(); - const selectedOptions = useMemo(() => { - const invitedUsersPersonalDetails = OptionsListUtils.getPersonalDetailsForAccountIDs(newGroupDraft?.selectedOptions, allPersonalDetails); + const selectedOptions = useMemo((): OptionData[] => { + const invitedUsersPersonalDetails = OptionsListUtils.getPersonalDetailsForAccountIDs(newGroupDraft?.participantAccountIDs, allPersonalDetails); const members = OptionsListUtils.getMemberInviteOptions(invitedUsersPersonalDetails); const currentUserOptionData = members.currentUserOption; - const options = [...members.personalDetails, currentUserOptionData] as OptionData[]; + if (!currentUserOptionData) { + return members.personalDetails; + } + const options = [...members.personalDetails, currentUserOptionData]; return options; }, [newGroupDraft, allPersonalDetails]); - const groupName = GroupChatUtils.getGroupChatConfirmName(selectedOptions); + const groupName = GroupChatUtils.getGroupChatName(newGroupDraft?.participantAccountIDs ?? []); - const sections = useMemo( + const sections: Section[] = useMemo( () => selectedOptions - .map((selectedOption) => { + .map((selectedOption: OptionData) => { const accountID = selectedOption.accountID; + const isAdmin = personalData.accountID === accountID; let roleBadge = null; - const isAdmin = personalData.accountID === selectedOption.accountID; if (isAdmin) { roleBadge = ( ); } - return { + + const section: Section = { value: selectedOption?.text ?? '', text: selectedOption?.text ?? '', keyForList: selectedOption?.keyForList ?? '', @@ -76,27 +82,21 @@ function NewChatConfirmPage({newGroupDraft, allPersonalDetails}: NewChatConfirmP accountID, icons: selectedOption?.icons, }; + return section; }) .sort((a, b) => a.text.toLowerCase().localeCompare(b.text.toLowerCase())), [selectedOptions, personalData.accountID, translate, styles.textStrong, styles.justifyContentCenter, styles.badgeBordered, styles.activeItemBadge, StyleUtils], ); + /** * Removes a selected option from list if already selected. */ const unselectOption = (option: ListItem) => { - if (!selectedOptions) { - return; - } - const isOptionInList = selectedOptions.some((selectedOption) => selectedOption.accountID === option.accountID); - - if (isOptionInList && personalData && option.accountID === personalData.accountID) { + if (!newGroupDraft) { return; } - - if (isOptionInList) { - const newSelectedAccountIDs = selectedOptions.filter((selectedOption) => selectedOption.accountID !== option.accountID).map((optionData) => optionData.accountID) as number[]; - Report.setGroupDraft(newSelectedAccountIDs); - } + const newSelectedAccountIDs = newGroupDraft.participantAccountIDs.filter((participantAccountID) => participantAccountID !== option.accountID); + Report.setGroupDraft(newSelectedAccountIDs); }; const createGroup = () => { @@ -104,8 +104,6 @@ function NewChatConfirmPage({newGroupDraft, allPersonalDetails}: NewChatConfirmP if (logins.length < 1) { return; } - const accountIDs = selectedOptions.map((selectedOption: OptionData) => selectedOption.accountID) as number[]; - Report.setGroupDraft(accountIDs, groupName); Report.navigateToAndOpenReport(logins, true, ''); }; @@ -134,16 +132,14 @@ function NewChatConfirmPage({newGroupDraft, allPersonalDetails}: NewChatConfirmP shouldCheckActionAllowedOnPress={false} description={translate('groupConfirmPage.groupName')} /> - - - + 1} + confirmButtonText={translate('newChatPage.startGroup')} + onConfirm={createGroup} + /> ); } @@ -152,7 +148,7 @@ NewChatConfirmPage.displayName = 'NewChatConfirmPage'; export default withOnyx({ newGroupDraft: { - key: ONYXKEYS.NEW_GROUP, + key: ONYXKEYS.NEW_GROUP_CHAT_DRAFT, }, allPersonalDetails: { key: ONYXKEYS.PERSONAL_DETAILS_LIST, diff --git a/src/pages/NewChatPage.tsx b/src/pages/NewChatPage.tsx index fc106f08642d..254ab581b6aa 100755 --- a/src/pages/NewChatPage.tsx +++ b/src/pages/NewChatPage.tsx @@ -32,7 +32,7 @@ type NewChatPageWithOnyxProps = { reports: OnyxCollection; /** New group chat draft data */ - newGroupDraft: OnyxEntry; + newGroupDraft: OnyxEntry; /** All of the personal details for everyone */ personalDetails: OnyxEntry; @@ -64,7 +64,7 @@ function NewChatPage({betas, isGroupChat, personalDetails, reports, isSearchingF const {isSmallScreenWidth} = useWindowDimensions(); const [didScreenTransitionEnd, setDidScreenTransitionEnd] = useState(false); - const personalData = useCurrentUserPersonalDetails() || CONST.EMPTY_OBJECT; + const personalData = useCurrentUserPersonalDetails(); const maxParticipantsReached = selectedOptions.length === CONST.REPORT.MAXIMUM_PARTICIPANTS; const setSearchTermAndSearchInServer = useSearchTermAndSearch(setSearchTerm, maxParticipantsReached); @@ -166,21 +166,21 @@ function NewChatPage({betas, isGroupChat, personalDetails, reports, isSearchingF * or navigates to the existing chat if one with those participants already exists. */ const createChat = (option: OptionData) => { - if (!option.login) { + if ((!option.login && selectedOptions.length !== 1) || !selectedOptions[0].login) { return; } - Report.navigateToAndOpenReport([option.login]); + const login = option.login ?? selectedOptions[0].login; + Report.navigateToAndOpenReport([login]); }; /** * Navigates to create group confirm page */ const navigateToConfirmPage = () => { - if (selectedOptions.length < 1) { - return; - } - const selectedAccountIDs = selectedOptions.map((option) => option.accountID) as number[]; + const selectedAccountIDs: number[] = selectedOptions + .map((option: OptionData) => option.accountID) + .filter((accountID): accountID is number => accountID !== null && accountID !== undefined); if (personalData) { - const accountIDs = [...selectedAccountIDs, personalData.accountID] as number[]; + const accountIDs = [...selectedAccountIDs, personalData.accountID]; Report.setGroupDraft(accountIDs); Navigation.navigate(ROUTES.NEW_CHAT_CONFIRM); } @@ -234,12 +234,12 @@ function NewChatPage({betas, isGroupChat, personalDetails, reports, isSearchingF return; } updateOptions(); - if (newGroupDraft?.selectedOptions) { - const invitedUsersPersonalDetails = OptionsListUtils.getPersonalDetailsForAccountIDs(newGroupDraft?.selectedOptions, personalDetails); + if (newGroupDraft?.participantAccountIDs) { + const invitedUsersPersonalDetails = OptionsListUtils.getPersonalDetailsForAccountIDs(newGroupDraft?.participantAccountIDs, personalDetails); const groupSelectedOptions = OptionsListUtils.getMemberInviteOptions(invitedUsersPersonalDetails).personalDetails; setSelectedOptions(groupSelectedOptions); } - }, [didScreenTransitionEnd, updateOptions, newGroupDraft?.selectedOptions, personalDetails]); + }, [didScreenTransitionEnd, updateOptions, newGroupDraft?.participantAccountIDs, personalDetails]); const {inputCallbackRef} = useAutoFocusInput(); @@ -281,7 +281,7 @@ function NewChatPage({betas, isGroupChat, personalDetails, reports, isSearchingF referralContentType={CONST.REFERRAL_PROGRAM.CONTENT_TYPES.START_CHAT} confirmButtonText={selectedOptions.length > 1 ? translate('common.next') : translate('newChatPage.createChat')} textInputAlert={isOffline ? [`${translate('common.youAppearToBeOffline')} ${translate('search.resultsAreLimited')}`, {isTranslated: true}] : ''} - onConfirmSelection={navigateToConfirmPage} + onConfirmSelection={selectedOptions.length > 1 ? navigateToConfirmPage : createChat} textInputLabel={translate('optionsSelector.nameEmailOrPhoneNumber')} safeAreaPaddingBottomStyle={safeAreaPaddingBottomStyle} isLoadingNewOptions={isSearchingForReports} @@ -303,7 +303,7 @@ export default withOnyx({ selector: (data) => data?.dismissedReferralBanners ?? {}, }, newGroupDraft: { - key: ONYXKEYS.NEW_GROUP, + key: ONYXKEYS.NEW_GROUP_CHAT_DRAFT, }, reports: { key: ONYXKEYS.COLLECTION.REPORT, diff --git a/src/pages/home/HeaderView.tsx b/src/pages/home/HeaderView.tsx index 8322477df07b..e26108a456e8 100644 --- a/src/pages/home/HeaderView.tsx +++ b/src/pages/home/HeaderView.tsx @@ -74,7 +74,7 @@ function HeaderView({report, personalDetails, parentReport, policy, session, rep const theme = useTheme(); const styles = useThemeStyles(); const isSelfDM = ReportUtils.isSelfDM(report); - const isGroupChat = ReportUtils.isGroupChat(report) || ReportUtils.isGroupChatType(report); + const isGroupChat = ReportUtils.isGroupChat(report) || ReportUtils.isDeprecatedGroupDM(report); // Currently, currentUser is not included in participantAccountIDs, so for selfDM, we need to add the currentUser as participants. const participants = isSelfDM ? [session?.accountID ?? -1] : report?.participantAccountIDs ?? []; const participantPersonalDetails = OptionsListUtils.getPersonalDetailsForAccountIDs(participants, personalDetails); @@ -87,7 +87,7 @@ function HeaderView({report, personalDetails, parentReport, policy, session, rep const isTaskReport = ReportUtils.isTaskReport(report); const reportHeaderData = !isTaskReport && !isChatThread && report.parentReportID ? parentReport : report; // Use sorted display names for the title for group chats on native small screen widths - const title = isGroupChat ? getGroupChatName(report) : ReportUtils.getReportName(reportHeaderData); + const title = isGroupChat ? getGroupChatName(report.participantAccountIDs ?? []) : ReportUtils.getReportName(reportHeaderData); const subtitle = ReportUtils.getChatRoomSubtitle(reportHeaderData); const parentNavigationSubtitleData = ReportUtils.getParentNavigationSubtitle(reportHeaderData); const isConcierge = ReportUtils.hasSingleParticipant(report) && participants.includes(CONST.ACCOUNT_ID.CONCIERGE); diff --git a/src/pages/settings/Report/ReportSettingsPage.tsx b/src/pages/settings/Report/ReportSettingsPage.tsx index 383cbbcb0833..12fcc5ee2bad 100644 --- a/src/pages/settings/Report/ReportSettingsPage.tsx +++ b/src/pages/settings/Report/ReportSettingsPage.tsx @@ -48,7 +48,7 @@ function ReportSettingsPage({report, policies}: ReportSettingsPageProps) { const shouldShowNotificationPref = !isMoneyRequestReport && report?.notificationPreference !== CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN; const roomNameLabel = translate(isMoneyRequestReport ? 'workspace.editor.nameInputLabel' : 'newRoomPage.roomName'); - const reportName = ReportUtils.isGroupChat(report) ? getGroupChatName(report) : ReportUtils.getReportName(report); + const reportName = ReportUtils.isDeprecatedGroupDM(report) || ReportUtils.isGroupChat(report) ? getGroupChatName(report.participantAccountIDs ?? []) : ReportUtils.getReportName(report); const shouldShowWriteCapability = !isMoneyRequestReport; diff --git a/src/types/onyx/NewGroupChat.ts b/src/types/onyx/NewGroupChat.ts deleted file mode 100644 index 57fd2b1c93ae..000000000000 --- a/src/types/onyx/NewGroupChat.ts +++ /dev/null @@ -1,6 +0,0 @@ -type NewGroupChat = { - selectedOptions: number[]; - reportName: string; -}; - -export default NewGroupChat; diff --git a/src/types/onyx/NewGroupChatDraft.ts b/src/types/onyx/NewGroupChatDraft.ts new file mode 100644 index 000000000000..6a948d398157 --- /dev/null +++ b/src/types/onyx/NewGroupChatDraft.ts @@ -0,0 +1,6 @@ +type NewGroupChatDraft = { + participantAccountIDs: number[]; + reportName: string; +}; + +export default NewGroupChatDraft; diff --git a/src/types/onyx/index.ts b/src/types/onyx/index.ts index 9130520e99f1..ac17c962be62 100644 --- a/src/types/onyx/index.ts +++ b/src/types/onyx/index.ts @@ -26,7 +26,7 @@ import type Login from './Login'; import type MapboxAccessToken from './MapboxAccessToken'; import type Modal from './Modal'; import type Network from './Network'; -import type NewGroupChat from './NewGroupChat'; +import type NewGroupChatDraft from './NewGroupChatDraft'; import type {OnyxUpdateEvent, OnyxUpdatesFromServer} from './OnyxUpdatesFromServer'; import type {DecisionName, OriginalMessageIOU} from './OriginalMessage'; import type PersonalBankAccount from './PersonalBankAccount'; @@ -161,7 +161,7 @@ export type { LastPaymentMethod, LastSelectedDistanceRates, InvitedEmailsToAccountIDs, - NewGroupChat, + NewGroupChatDraft, Log, PolicyJoinMember, }; From ca090a701cfd42e80015cfb236fd437ea040362f Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Tue, 12 Mar 2024 05:23:14 +0530 Subject: [PATCH 227/931] setup theme for helpdot --- docs/_sass/_colors.scss | 58 +++++++++++++++++++++++++++++------------ 1 file changed, 41 insertions(+), 17 deletions(-) diff --git a/docs/_sass/_colors.scss b/docs/_sass/_colors.scss index f0c89d31c580..c9473925d791 100644 --- a/docs/_sass/_colors.scss +++ b/docs/_sass/_colors.scss @@ -1,22 +1,46 @@ -// Product Color Spectrum -$color-product-dark-100: #061B09; -$color-product-dark-200: #072419; -$color-product-dark-300: #0A2E25; -$color-product-dark-400: #1A3D32; -$color-product-dark-500: #224F41; -$color-product-dark-600: #2A604F; -$color-product-dark-700: #8B9C8F; -$color-product-dark-800: #AFBBB0; -$color-product-dark-900: #E7ECE9; +@media (prefers-color-scheme: dark) { + // Product Color Spectrum + $color-product-dark-100: #061B09; + $color-product-dark-200: #072419; + $color-product-dark-300: #0A2E25; + $color-product-dark-400: #1A3D32; + $color-product-dark-500: #224F41; + $color-product-dark-600: #2A604F; + $color-product-dark-700: #8B9C8F; + $color-product-dark-800: #AFBBB0; + $color-product-dark-900: #E7ECE9; -// Colors for Links and Success -$color-blue200: #B0D9FF; -$color-blue300: #5AB0FF; -$color-green400: #03D47C; -$color-green500: #00a862; + // Colors for Links and Success + $color-blue200: #B0D9FF; + $color-blue300: #5AB0FF; + $color-green400: #03D47C; + $color-green500: #00a862; -// Overlay BG color -$color-overlay-background: rgba(26, 61, 50, 0.72); + // Overlay BG color + $color-overlay-background: rgba(26, 61, 50, 0.72); +} + +@media (prefers-color-scheme: light) { + // Product Color Spectrum + $color-product-dark-100: #061B09; + $color-product-dark-200: #072419; + $color-product-dark-300: #0A2E25; + $color-product-dark-400: #1A3D32; + $color-product-dark-500: #224F41; + $color-product-dark-600: #2A604F; + $color-product-dark-700: #8B9C8F; + $color-product-dark-800: #AFBBB0; + $color-product-dark-900: #E7ECE9; + + // Colors for Links and Success + $color-blue200: #B0D9FF; + $color-blue300: #5AB0FF; + $color-green400: #03D47C; + $color-green500: #00a862; + + // Overlay BG color + $color-overlay-background: rgba(26, 61, 50, 0.72); +} // UI Colors $color-text: $color-product-dark-900; From 283c4de6983d0fe856e280d068a2e2b320b329e1 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Tue, 12 Mar 2024 05:23:21 +0530 Subject: [PATCH 228/931] setup theme for helpdot --- docs/_sass/_colors.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/_sass/_colors.scss b/docs/_sass/_colors.scss index c9473925d791..22af28974281 100644 --- a/docs/_sass/_colors.scss +++ b/docs/_sass/_colors.scss @@ -58,3 +58,4 @@ $color-button-background: $color-product-dark-400; $color-button-background-hover: $color-product-dark-500; $color-button-success-background: $color-green400; $color-button-success-background-hover: $color-green500; +$color-overlay: $color-overlay-background; From efaa96a5f02d592032bb7ed48d2850dbd65a5be0 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Tue, 12 Mar 2024 05:23:25 +0530 Subject: [PATCH 229/931] setup theme for helpdot --- docs/_sass/_search-bar.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/_sass/_search-bar.scss b/docs/_sass/_search-bar.scss index f414d25fc266..5c58d70b5851 100644 --- a/docs/_sass/_search-bar.scss +++ b/docs/_sass/_search-bar.scss @@ -67,7 +67,7 @@ left: 0; right: 0; bottom: 0; - background-color: $color-overlay-background; + background-color: $color-overlay; z-index: 1; } From a5131ed735744c847d4dd7f5351383a88b61f3b8 Mon Sep 17 00:00:00 2001 From: Pedro Guerreiro Date: Tue, 12 Mar 2024 03:20:52 +0000 Subject: [PATCH 230/931] refactor(typescript): resolve type issues --- tests/e2e/compare/output/console.ts | 4 +- tests/e2e/compare/output/markdown.ts | 27 ++++++------- tests/e2e/compare/types.ts | 57 ---------------------------- tests/e2e/measure/math.ts | 11 +++++- 4 files changed, 26 insertions(+), 73 deletions(-) delete mode 100644 tests/e2e/compare/types.ts diff --git a/tests/e2e/compare/output/console.ts b/tests/e2e/compare/output/console.ts index de8e5d913893..3da0100b603f 100644 --- a/tests/e2e/compare/output/console.ts +++ b/tests/e2e/compare/output/console.ts @@ -13,6 +13,8 @@ type Entry = { type Data = { significance: Entry[]; meaningless: Entry[]; + errors: string[]; + warnings: string[]; }; const printRegularLine = (entry: Entry) => { @@ -36,4 +38,4 @@ export default (data: Data) => { console.debug(''); }; -export type {Entry}; +export type {Data, Entry}; diff --git a/tests/e2e/compare/output/markdown.ts b/tests/e2e/compare/output/markdown.ts index 07cf9897e570..716dbd6d09a4 100644 --- a/tests/e2e/compare/output/markdown.ts +++ b/tests/e2e/compare/output/markdown.ts @@ -1,16 +1,17 @@ // From: https://raw.githubusercontent.com/callstack/reassure/main/packages/reassure-compare/src/output/markdown.ts import fs from 'node:fs/promises'; import path from 'path'; +import type {Stats} from 'tests/e2e/measure/math'; import * as Logger from '../../utils/logger'; -import type {AddedEntry, CompareEntry, CompareResult, PerformanceEntry, RemovedEntry} from '../types'; +import type {Data, Entry} from './console'; import * as format from './format'; import markdownTable from './markdownTable'; const tableHeader = ['Name', 'Duration']; -const collapsibleSection = (title: string, content: string): string => `
\n${title}\n\n${content}\n
\n\n`; +const collapsibleSection = (title: string, content: string) => `
\n${title}\n\n${content}\n
\n\n`; -const buildDurationDetails = (title: string, entry: PerformanceEntry): string => { +const buildDurationDetails = (title: string, entry: Stats) => { const relativeStdev = entry.stdev / entry.mean; return [ @@ -23,25 +24,25 @@ const buildDurationDetails = (title: string, entry: PerformanceEntry): string => .join('
'); }; -const buildDurationDetailsEntry = (entry: CompareEntry | AddedEntry | RemovedEntry): string => +const buildDurationDetailsEntry = (entry: Entry) => ['baseline' in entry ? buildDurationDetails('Baseline', entry.baseline) : '', 'current' in entry ? buildDurationDetails('Current', entry.current) : ''] .filter(Boolean) .join('

'); -const formatEntryDuration = (entry: CompareEntry | AddedEntry | RemovedEntry): string => { - if ('baseline' in entry && 'current' in entry) { +const formatEntryDuration = (entry: Entry) => { + if (entry.baseline && entry.current) { return format.formatDurationDiffChange(entry); } - if ('baseline' in entry) { + if (entry.baseline) { return format.formatDuration(entry.baseline.mean); } - if ('current' in entry) { + if (entry.current) { return format.formatDuration(entry.current.mean); } return ''; }; -const buildDetailsTable = (entries: Array): string => { +const buildDetailsTable = (entries: Entry[]) => { if (!entries.length) { return ''; } @@ -52,7 +53,7 @@ const buildDetailsTable = (entries: Array, collapse = false): string => { +const buildSummaryTable = (entries: Entry[], collapse = false) => { if (!entries.length) { return '_There are no entries_'; } @@ -63,7 +64,7 @@ const buildSummaryTable = (entries: Array { +const buildMarkdown = (data: Data) => { let result = '## Performance Comparison Report 📊'; if (data.errors?.length) { @@ -91,7 +92,7 @@ const buildMarkdown = (data: CompareResult): string => { return result; }; -const writeToFile = (filePath: string, content: string): Promise => +const writeToFile = (filePath: string, content: string) => fs .writeFile(filePath, content) .then(() => { @@ -105,7 +106,7 @@ const writeToFile = (filePath: string, content: string): Promise => throw error; }); -const writeToMarkdown = (filePath: string, data: CompareResult): Promise => { +const writeToMarkdown = (filePath: string, data: Data) => { const markdown = buildMarkdown(data); return writeToFile(filePath, markdown).catch((error) => { console.error(error); diff --git a/tests/e2e/compare/types.ts b/tests/e2e/compare/types.ts deleted file mode 100644 index e0be36716977..000000000000 --- a/tests/e2e/compare/types.ts +++ /dev/null @@ -1,57 +0,0 @@ -type Entries = number[]; - -/** Metadata information for performance results. */ - -/** Entry in the performance results file. */ -type PerformanceEntry = { - /** Number of times the measurement test was run. */ - runs: number; - - /** Arithmetic average of measured render/execution durations for each run. */ - mean: number; - - /** Standard deviation of measured render/execution durations for each run. */ - stdev: number; - - /** Array of measured render/execution durations for each run. */ - entries: Entries; -}; - -/** - * Compare entry for tests that have both baseline and current entry - */ -type CompareEntry = { - name: string; - current: PerformanceEntry; - baseline: PerformanceEntry; - durationDiff: number; - relativeDurationDiff: number; -}; - -/** - * Compare entry for tests that have only current entry - */ -type AddedEntry = { - name: string; - current: PerformanceEntry; -}; - -/** - * Compare entry for tests that have only baseline entry - */ -type RemovedEntry = { - name: string; - baseline: PerformanceEntry; -}; - -/** Output of compare function. */ -type CompareResult = { - significance: CompareEntry[]; - meaningless: CompareEntry[]; - added: AddedEntry[]; - removed: RemovedEntry[]; - errors?: string[]; - warnings?: string[]; -}; - -export type {Entries, PerformanceEntry, CompareEntry, AddedEntry, RemovedEntry, CompareResult}; diff --git a/tests/e2e/measure/math.ts b/tests/e2e/measure/math.ts index e632e9bec232..d444ab0e79da 100644 --- a/tests/e2e/measure/math.ts +++ b/tests/e2e/measure/math.ts @@ -1,4 +1,11 @@ -import type {Entries, PerformanceEntry} from '../compare/types'; +type Entries = number[]; + +type Stats = { + mean: number; + stdev: number; + runs: number; + entries: Entries; +}; const filterOutliersViaIQR = (data: Entries): Entries => { let q1; @@ -28,7 +35,7 @@ const std = (arr: Entries): number => { return Math.sqrt(arr.map((i) => (i - avg) ** 2).reduce((a, b) => a + b) / arr.length); }; -const getStats = (entries: Entries): PerformanceEntry => { +const getStats = (entries: Entries): Stats => { const cleanedEntries = filterOutliersViaIQR(entries); const meanDuration = mean(cleanedEntries); const stdevDuration = std(cleanedEntries); From 2e4c65f989ce4f835fe19c876e646ad4bf94d2db Mon Sep 17 00:00:00 2001 From: burczu Date: Tue, 12 Mar 2024 10:17:53 +0100 Subject: [PATCH 231/931] transfer balance confirmation copy handled --- src/languages/en.ts | 6 +++ src/languages/es.ts | 6 +++ .../members/WorkspaceMemberDetailsPage.tsx | 2 +- .../members/WorkspaceOwnerChangeCheckPage.tsx | 48 ++++++++++++++++--- 4 files changed, 54 insertions(+), 8 deletions(-) diff --git a/src/languages/en.ts b/src/languages/en.ts index e096aa091c95..51c3623aaaed 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -1967,6 +1967,12 @@ export default { updateCurrencyPrompt: 'It looks like your Workspace is currently set to a different currency than USD. Please click the button below to update your currency to USD now.', updateToUSD: 'Update to USD', }, + changeOwner: { + changeOwnerPageTitle: 'Change owner', + outstandingBalance: 'Outstanding balance', + transferBalance: 'Transfer balance', + transferBalanceFirstParagraph: ({email, amount}) => `The account owing this workspace (${email}) has an outstanding balance.\n\nDo you want to transfer this amount ${amount} in order to take over billing for this workspace? Your payment card will be charged immediately.`, + } }, getAssistancePage: { title: 'Get assistance', diff --git a/src/languages/es.ts b/src/languages/es.ts index 99bb64e0af37..6c5b5c73e589 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -1993,6 +1993,12 @@ export default { 'Parece que tu espacio de trabajo está configurado actualmente en una moneda diferente a USD. Por favor, haz clic en el botón de abajo para actualizar tu moneda a USD ahora.', updateToUSD: 'Actualizar a USD', }, + changeOwner: { + changeOwnerPageTitle: 'Cambio de propietario', + outstandingBalance: 'Saldo pendiente', + transferBalance: 'Transfer balance', + transferBalanceFirstParagraph: ({email, amount}) => `La cuenta que debe este espacio de trabajo (${email}) tiene un saldo pendiente.\n\n¿Desea transferir este monto ${amount} para hacerse cargo de la facturación de este espacio de trabajo? El cargo en su tarjeta de pago se realizará inmediatamente.`, + } }, getAssistancePage: { title: 'Obtener ayuda', diff --git a/src/pages/workspace/members/WorkspaceMemberDetailsPage.tsx b/src/pages/workspace/members/WorkspaceMemberDetailsPage.tsx index d12d0235a699..294138c7daa9 100644 --- a/src/pages/workspace/members/WorkspaceMemberDetailsPage.tsx +++ b/src/pages/workspace/members/WorkspaceMemberDetailsPage.tsx @@ -94,7 +94,7 @@ function WorkspaceMemberDetailsPage({personalDetails, policyMembers, policy, rou }, [policyID]); const temporaryOpenCheckPage = () => { - Navigation.navigate(ROUTES.WORKSPACE_OWNER_CHANGE_CHECK.getRoute(policyID, CONST.POLICY.OWNERSHIP_ERRORS.NO_BILLING_CARD)); + Navigation.navigate(ROUTES.WORKSPACE_OWNER_CHANGE_CHECK.getRoute(policyID, CONST.POLICY.OWNERSHIP_ERRORS.AMOUNT_OWED)); }; return ( diff --git a/src/pages/workspace/members/WorkspaceOwnerChangeCheckPage.tsx b/src/pages/workspace/members/WorkspaceOwnerChangeCheckPage.tsx index 8ae4dc5a232a..f1a01366ad9a 100644 --- a/src/pages/workspace/members/WorkspaceOwnerChangeCheckPage.tsx +++ b/src/pages/workspace/members/WorkspaceOwnerChangeCheckPage.tsx @@ -1,5 +1,5 @@ import type {StackScreenProps} from '@react-navigation/stack'; -import React, {useCallback} from 'react'; +import React, {useCallback, useMemo} from 'react'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import Text from '@components/Text'; import ScreenWrapper from '@components/ScreenWrapper'; @@ -9,9 +9,10 @@ import AdminPolicyAccessOrNotFoundWrapper from '@pages/workspace/AdminPolicyAcce import PaidPolicyAccessOrNotFoundWrapper from '@pages/workspace/PaidPolicyAccessOrNotFoundWrapper'; import type SCREENS from '@src/SCREENS'; import CONST from "@src/CONST"; -import Button from "@components/Button"; +import Button from '@components/Button'; import {View} from "react-native"; import useThemeStyles from "@hooks/useThemeStyles"; +import useLocalize from "@hooks/useLocalize"; type WorkspaceMemberDetailsPageProps = StackScreenProps; @@ -24,6 +25,7 @@ const CONFIRMABLE_ERRORS: string[] = [ function WorkspaceOwnerChangeCheckPage({route}: WorkspaceMemberDetailsPageProps) { const styles = useThemeStyles(); + const {translate} = useLocalize(); const policyID = route.params.policyID; const error = route.params.error; @@ -35,29 +37,61 @@ function WorkspaceOwnerChangeCheckPage({route}: WorkspaceMemberDetailsPageProps) }, []); const cancel = useCallback(() => { - + }, []); + const confirmationTitle = useMemo(() => { + switch (error) { + case CONST.POLICY.OWNERSHIP_ERRORS.AMOUNT_OWED: + return translate('workspace.changeOwner.outstandingBalance'); + default: + return null; + } + }, [error, translate]); + + const confirmationButtonText = useMemo(() => { + switch (error) { + case CONST.POLICY.OWNERSHIP_ERRORS.AMOUNT_OWED: + return translate('workspace.changeOwner.transferBalance'); + default: + return ''; + } + }, [error, translate]); + + const confirmationText = useMemo(() => { + switch (error) { + case CONST.POLICY.OWNERSHIP_ERRORS.AMOUNT_OWED: + return translate('workspace.changeOwner.transferBalanceFirstParagraph', {email: 'test@test.com', amount: '$50.00'}); + default: + return null; + } + }, [error, translate]); + return ( Navigation.goBack()} /> - Current error: {error} + {confirmationTitle} + {confirmationText} {shouldAskForConfirmation ? ( + text={confirmationButtonText} + /> ) : ( + text={translate('common.buttonConfirm')} + /> )} From 000491f03e57981cc5a1ba6e7e1643f50458f428 Mon Sep 17 00:00:00 2001 From: ruben-rebelo Date: Tue, 12 Mar 2024 09:49:51 +0000 Subject: [PATCH 232/931] [TS migration][G3] Feedback --- tests/utils/TestHelper.ts | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/tests/utils/TestHelper.ts b/tests/utils/TestHelper.ts index 097433e8813d..10313ad46d47 100644 --- a/tests/utils/TestHelper.ts +++ b/tests/utils/TestHelper.ts @@ -1,12 +1,11 @@ import Str from 'expensify-common/lib/str'; -import type {OnyxUpdate} from 'react-native-onyx'; import Onyx from 'react-native-onyx'; import CONST from '@src/CONST'; import * as Session from '@src/libs/actions/Session'; import HttpUtils from '@src/libs/HttpUtils'; import * as NumberUtils from '@src/libs/NumberUtils'; import ONYXKEYS from '@src/ONYXKEYS'; -import type {PersonalDetails, Report} from '@src/types/onyx'; +import type {Response as OnyxResponse, PersonalDetails, Report} from '@src/types/onyx'; import waitForBatchedUpdates from './waitForBatchedUpdates'; type MockFetch = ReturnType & { @@ -19,14 +18,7 @@ type MockFetch = ReturnType & { resume?: () => Promise; }; -type Response = { - ok?: boolean; - json?: () => Promise<{jsonCode: number}>; - jsonCode?: number; - onyxData?: OnyxUpdate[]; -}; - -type QueueItem = (value: Response | PromiseLike) => void; +type QueueItem = (value: Partial | PromiseLike>) => void; type FormData = { entries: () => Array<[string, string | Blob]>; @@ -58,7 +50,7 @@ function signInWithTestUser(accountID = 1, login = 'test@user.com', password = ' HttpUtils.xhr = jest.fn().mockImplementation(() => { // Your mocked response object - const mockedResponse: Response = { + const mockedResponse: OnyxResponse = { onyxData: [ { onyxMethod: Onyx.METHOD.MERGE, @@ -176,7 +168,7 @@ function getGlobalFetchMock() { let isPaused = false; let shouldFail = false; - const getResponse = () => + const getResponse = (): Partial => shouldFail ? { ok: true, @@ -256,4 +248,4 @@ const createAddListenerMock = () => { return {triggerTransitionEnd, addListener}; }; -export {getGlobalFetchMock, signInWithTestUser, signOutTestUser, setPersonalDetails, buildPersonalDetails, buildTestReportComment, assertFormDataMatchesObject, createAddListenerMock}; +export {assertFormDataMatchesObject, buildPersonalDetails, buildTestReportComment, createAddListenerMock, getGlobalFetchMock, setPersonalDetails, signInWithTestUser, signOutTestUser}; From 1acd6eaca8c525191a4a21f5b75a90132b66326d Mon Sep 17 00:00:00 2001 From: ruben-rebelo Date: Tue, 12 Mar 2024 10:02:12 +0000 Subject: [PATCH 233/931] [TS migration][storybook] Fixed styling and feedback --- .storybook/webpack.config.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.storybook/webpack.config.ts b/.storybook/webpack.config.ts index 6f7ee023643c..bff8c3fa6747 100644 --- a/.storybook/webpack.config.ts +++ b/.storybook/webpack.config.ts @@ -1,7 +1,5 @@ /* eslint-disable no-underscore-dangle */ - /* eslint-disable no-param-reassign */ - /* eslint-disable @typescript-eslint/naming-convention */ import dotenv from 'dotenv'; import path from 'path'; @@ -18,7 +16,7 @@ type CustomWebpackConfig = { }; }; -let envFile; +let envFile: string | null; switch (process.env.ENV) { case 'production': envFile = '.env.production'; From bdd24df98b2eb03f364e43e29a872666e5d2912d Mon Sep 17 00:00:00 2001 From: ruben-rebelo Date: Tue, 12 Mar 2024 10:07:59 +0000 Subject: [PATCH 234/931] [TS migration][g11] Fixed type of drag and drop --- src/components/DragAndDrop/Provider/types.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/DragAndDrop/Provider/types.ts b/src/components/DragAndDrop/Provider/types.ts index 57d0fb47c637..b4394056cac5 100644 --- a/src/components/DragAndDrop/Provider/types.ts +++ b/src/components/DragAndDrop/Provider/types.ts @@ -8,7 +8,7 @@ type DragAndDropProviderProps = { isDisabled?: boolean; /** Indicate that users are dragging file or not */ - setIsDraggingOver?: (value: boolean) => void; + setIsDraggingOver: (value: boolean) => void; }; type SetOnDropHandlerCallback = (event: DragEvent) => void; From 075f940a96e195fbb64ea73f825dbf68cc683b1c Mon Sep 17 00:00:00 2001 From: Jakub Butkiewicz Date: Tue, 12 Mar 2024 11:09:11 +0100 Subject: [PATCH 235/931] fix: adjust descriptions --- src/components/TagPicker/index.tsx | 2 +- src/pages/EditRequestTagPage.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/TagPicker/index.tsx b/src/components/TagPicker/index.tsx index 4998751309ee..f1700205f487 100644 --- a/src/components/TagPicker/index.tsx +++ b/src/components/TagPicker/index.tsx @@ -19,7 +19,7 @@ type SelectedTagOption = { }; type TagPickerOnyxProps = { - /** Collection of tags attached to a policy */ + /** Collection of tag list on a policy */ policyTags: OnyxEntry; /** List of recently used tags */ diff --git a/src/pages/EditRequestTagPage.js b/src/pages/EditRequestTagPage.js index 3eda5184263a..ca5bdc05530d 100644 --- a/src/pages/EditRequestTagPage.js +++ b/src/pages/EditRequestTagPage.js @@ -15,7 +15,7 @@ const propTypes = { /** The policyID we are getting tags for */ policyID: PropTypes.string.isRequired, - /** The tag name to which the default tag belongs to */ + /** The tag list name to which the default tag belongs to */ tagListName: PropTypes.string, /** The index of a tag list */ From fd7802b60ce2ca3348ae8d2a4bc77145777780d9 Mon Sep 17 00:00:00 2001 From: ruben-rebelo Date: Tue, 12 Mar 2024 10:21:44 +0000 Subject: [PATCH 236/931] [TS migration][G3] Feedback --- tests/unit/SidebarTest.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/unit/SidebarTest.ts b/tests/unit/SidebarTest.ts index fd068336d545..499af3031553 100644 --- a/tests/unit/SidebarTest.ts +++ b/tests/unit/SidebarTest.ts @@ -59,13 +59,13 @@ describe('Sidebar', () => { waitForBatchedUpdates() // When Onyx is updated with the data and the sidebar re-renders .then(() => { - const reportCollection: ReportActionCollectionDataSet = { + const reportCollection: ReportCollectionDataSet = { [`${ONYXKEYS.COLLECTION.REPORT}${report.reportID}`]: report, - } as ReportCollectionDataSet; + } const reportAction: ReportActionCollectionDataSet = { [`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report.reportID}`]: {[action.reportActionID]: action}, - } as ReportActionCollectionDataSet; + } as ReportActionCollectionDataSet return Onyx.multiSet({ [ONYXKEYS.BETAS]: betas, @@ -113,11 +113,11 @@ describe('Sidebar', () => { .then(() => { const reportCollection: ReportCollectionDataSet = { [`${ONYXKEYS.COLLECTION.REPORT}${report.reportID}`]: report, - } as ReportCollectionDataSet; + } const reportAction: ReportActionCollectionDataSet = { [`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report.reportID}`]: {[action.reportActionID]: action}, - } as ReportActionCollectionDataSet; + } as ReportActionCollectionDataSet return Onyx.multiSet({ [ONYXKEYS.BETAS]: betas, From 4fb5eaedbe6dd48fcc4b09bc5fb8718e6322727a Mon Sep 17 00:00:00 2001 From: ruben-rebelo Date: Tue, 12 Mar 2024 10:23:48 +0000 Subject: [PATCH 237/931] Revert "[TS migration][g11] Fixed type of drag and drop" This reverts commit bdd24df98b2eb03f364e43e29a872666e5d2912d. --- src/components/DragAndDrop/Provider/types.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/DragAndDrop/Provider/types.ts b/src/components/DragAndDrop/Provider/types.ts index b4394056cac5..57d0fb47c637 100644 --- a/src/components/DragAndDrop/Provider/types.ts +++ b/src/components/DragAndDrop/Provider/types.ts @@ -8,7 +8,7 @@ type DragAndDropProviderProps = { isDisabled?: boolean; /** Indicate that users are dragging file or not */ - setIsDraggingOver: (value: boolean) => void; + setIsDraggingOver?: (value: boolean) => void; }; type SetOnDropHandlerCallback = (event: DragEvent) => void; From 1fb509f9469de830ca27b66c644cb97df364c324 Mon Sep 17 00:00:00 2001 From: burczu Date: Tue, 12 Mar 2024 11:28:12 +0100 Subject: [PATCH 238/931] temporary copy added --- src/languages/en.ts | 18 ++++++++-- src/languages/es.ts | 19 +++++++++-- .../members/WorkspaceMemberDetailsPage.tsx | 7 +--- .../members/WorkspaceOwnerChangeCheckPage.tsx | 33 ++++++++++++++++--- 4 files changed, 61 insertions(+), 16 deletions(-) diff --git a/src/languages/en.ts b/src/languages/en.ts index 51c3623aaaed..37a2cfbd03e6 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -1969,9 +1969,21 @@ export default { }, changeOwner: { changeOwnerPageTitle: 'Change owner', - outstandingBalance: 'Outstanding balance', - transferBalance: 'Transfer balance', - transferBalanceFirstParagraph: ({email, amount}) => `The account owing this workspace (${email}) has an outstanding balance.\n\nDo you want to transfer this amount ${amount} in order to take over billing for this workspace? Your payment card will be charged immediately.`, + amountOwedTitle: 'Amount owed title', + amountOwedButtonText: 'Amount owed button text', + amountOwedText: 'Amount owed paragraph text.', + ownerOwesAmountTitle: 'Owner owes amount title', + ownerOwesAmountButtonText: 'Owner owes amount button text', + ownerOwesAmountText: 'Owner owes amount paragraph text.', + subscriptionTitle: 'Subscription title', + subscriptionButtonText: 'Subscription button text', + subscriptionText: 'Subscription paragraph text.', + duplicateSubscriptionTitle: 'Duplicate subscription title', + duplicateSubscriptionButtonText: 'Duplicate subscription button text', + duplicateSubscriptionText: 'Duplicate subscription paragraph text.', + hasFailedSettlementsTitle: 'Has failed settlements title', + hasFailedSettlementsButtonText: 'Has failed settlements button text', + hasFailedSettlementsText: 'Has failed settlements paragraph text.', } }, getAssistancePage: { diff --git a/src/languages/es.ts b/src/languages/es.ts index 6c5b5c73e589..51701d38c501 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -1995,9 +1995,22 @@ export default { }, changeOwner: { changeOwnerPageTitle: 'Cambio de propietario', - outstandingBalance: 'Saldo pendiente', - transferBalance: 'Transfer balance', - transferBalanceFirstParagraph: ({email, amount}) => `La cuenta que debe este espacio de trabajo (${email}) tiene un saldo pendiente.\n\n¿Desea transferir este monto ${amount} para hacerse cargo de la facturación de este espacio de trabajo? El cargo en su tarjeta de pago se realizará inmediatamente.`, + // TODO: add spanish translations below + amountOwedTitle: 'Amount owed title', + amountOwedButtonText: 'Amount owed button text', + amountOwedText: 'Amount owed paragraph text.', + ownerOwesAmountTitle: 'Owner owes amount title', + ownerOwesAmountButtonText: 'Owner owes amount button text', + ownerOwesAmountText: 'Owner owes amount paragraph text.', + subscriptionTitle: 'Subscription title', + subscriptionButtonText: 'Subscription button text', + subscriptionText: 'Subscription paragraph text.', + duplicateSubscriptionTitle: 'Duplicate subscription title', + duplicateSubscriptionButtonText: 'Duplicate subscription button text', + duplicateSubscriptionText: 'Duplicate subscription paragraph text.', + hasFailedSettlementTitle: 'Has failed settlement title', + hasFailedSettlementButtonText: 'Has failed settlement button text', + hasFailedSettlementText: 'Has failed settlement paragraph text.', } }, getAssistancePage: { diff --git a/src/pages/workspace/members/WorkspaceMemberDetailsPage.tsx b/src/pages/workspace/members/WorkspaceMemberDetailsPage.tsx index 294138c7daa9..f914d4697a31 100644 --- a/src/pages/workspace/members/WorkspaceMemberDetailsPage.tsx +++ b/src/pages/workspace/members/WorkspaceMemberDetailsPage.tsx @@ -93,10 +93,6 @@ function WorkspaceMemberDetailsPage({personalDetails, policyMembers, policy, rou Policy.requestWorkspaceOwnerChange(policyID); }, [policyID]); - const temporaryOpenCheckPage = () => { - Navigation.navigate(ROUTES.WORKSPACE_OWNER_CHANGE_CHECK.getRoute(policyID, CONST.POLICY.OWNERSHIP_ERRORS.AMOUNT_OWED)); - }; - return ( @@ -128,8 +124,7 @@ function WorkspaceMemberDetailsPage({personalDetails, policyMembers, policy, rou {isSelectedMemberOwner && isCurrentUserAdmin && !isCurrentUserOwner ? (